diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..230b4e2 Binary files /dev/null and b/.DS_Store differ diff --git a/Unit-2-Journal/.DS_Store b/Unit-2-Journal/.DS_Store new file mode 100644 index 0000000..c084e5c Binary files /dev/null and b/Unit-2-Journal/.DS_Store differ diff --git a/Unit-2-Journal/Podfile b/Unit-2-Journal/Podfile new file mode 100644 index 0000000..c489430 --- /dev/null +++ b/Unit-2-Journal/Podfile @@ -0,0 +1,9 @@ +pod 'FBSDKCoreKit', '~> 4.7' +pod 'FBSDKShareKit', '~> 4.7' +pod 'FBSDKLoginKit', '~> 4.7' +pod 'Parse' +pod 'RestKit/Testing', '~> 0.24.0' +pod 'FoldingTabBar', '~> 1.0.1’ +pod 'pop', '~> 1.0' + + diff --git a/Unit-2-Journal/Podfile.lock b/Unit-2-Journal/Podfile.lock new file mode 100644 index 0000000..87b4d91 --- /dev/null +++ b/Unit-2-Journal/Podfile.lock @@ -0,0 +1,69 @@ +PODS: + - AFNetworking (1.3.4) + - Bolts (1.3.0): + - Bolts/AppLinks (= 1.3.0) + - Bolts/Tasks (= 1.3.0) + - Bolts/AppLinks (1.3.0): + - Bolts/Tasks + - Bolts/Tasks (1.3.0) + - FBSDKCoreKit (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/arc (= 4.7.0) + - FBSDKCoreKit/no-arc (= 4.7.0) + - FBSDKCoreKit/arc (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/no-arc (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/arc + - FBSDKLoginKit (4.7.0): + - FBSDKCoreKit + - FBSDKShareKit (4.7.0): + - FBSDKCoreKit + - FoldingTabBar (1.0.1) + - ISO8601DateFormatterValueTransformer (0.6.1): + - RKValueTransformers (~> 1.1.0) + - Parse (1.9.0): + - Bolts/Tasks (>= 1.3.0) + - pop (1.0.8) + - RestKit/Network (0.24.1): + - AFNetworking (~> 1.3.0) + - RestKit/ObjectMapping + - RestKit/Support + - SOCKit + - RestKit/ObjectMapping (0.24.1): + - ISO8601DateFormatterValueTransformer (~> 0.6.0) + - RestKit/Support + - RKValueTransformers (~> 1.1.0) + - RestKit/Support (0.24.1): + - TransitionKit (~> 2.1.0) + - RestKit/Testing (0.24.1): + - RestKit/Network + - RKValueTransformers (1.1.2) + - SOCKit (1.1) + - TransitionKit (2.1.1) + +DEPENDENCIES: + - FBSDKCoreKit (~> 4.7) + - FBSDKLoginKit (~> 4.7) + - FBSDKShareKit (~> 4.7) + - FoldingTabBar (~> 1.0.1) + - Parse + - pop (~> 1.0) + - RestKit/Testing (~> 0.24.0) + +SPEC CHECKSUMS: + AFNetworking: cf8e418e16f0c9c7e5c3150d019a3c679d015018 + Bolts: 805a4a87413e49d4a0c2b7d469084cbc46b09342 + FBSDKCoreKit: eb580bfc2040ad44f4c0b4f4d0befb1d35bce59c + FBSDKLoginKit: 01bce8dd3f3a26a023b0ba4ffdde7ef5062889fe + FBSDKShareKit: 1f927bb05e4d36a99d5d5bf2f4b1ff294ce3e15c + FoldingTabBar: 3e04c49dbe2b02c529561a4182bf017b928d04d2 + ISO8601DateFormatterValueTransformer: 52da467d6ec899d6aedda8e48280ac92e8ee97e6 + Parse: 712efbc476d4f47b0f96b70db7e53101575753aa + pop: bb773ae2c791ca2629de13b347e7a8b450fa6a57 + RestKit: 1987b5efef289c6b27bd980714d6ca48d3871b78 + RKValueTransformers: 66ac5e4f077fdbe3496e792d89eeff4c3eb67701 + SOCKit: c7376ac262bea9115b8f749358f762522a47d392 + TransitionKit: 3a14b6acc7cf2d1dd3e454e24dbad1cfab9a1ef1 + +COCOAPODS: 0.39.0 diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.h new file mode 100644 index 0000000..3826b6f --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.h @@ -0,0 +1,641 @@ +// AFHTTPClient.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +#import + +/** + `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. + + ## Automatic Content Parsing + + Instances of `AFHTTPClient` may specify which types of requests it expects and should handle by registering HTTP operation classes for automatic parsing. Registered classes will determine whether they can handle a particular request, and then construct a request operation accordingly in `enqueueHTTPRequestOperationWithRequest:success:failure`. + + ## Subclassing Notes + + In most cases, one should create an `AFHTTPClient` subclass for each website or web application that your application communicates with. It is often useful, also, to define a class method that returns a singleton shared HTTP client in each subclass, that persists authentication credentials and other configuration across the entire application. + + ## Methods to Override + + To change the behavior of all url request construction for an `AFHTTPClient` subclass, override `requestWithMethod:path:parameters`. + + To change the behavior of all request operation construction for an `AFHTTPClient` subclass, override `HTTPRequestOperationWithRequest:success:failure`. + + ## Default Headers + + By default, `AFHTTPClient` sets the following HTTP headers: + + - `Accept-Language: (comma-delimited preferred languages), en-us;q=0.8` + - `User-Agent: (generated user agent)` + + You can override these HTTP headers or define new ones using `setDefaultHeader:value:`. + + ## URL Construction Using Relative Paths + + Both `-requestWithMethod:path:parameters:` and `-multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` construct URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`. Below are a few examples of how `baseURL` and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Also important to note is that a trailing slash will be added to any `baseURL` without one, which would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash. + + ## NSCoding / NSCopying Conformance + + `AFHTTPClient` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. There are a few minor caveats to keep in mind, however: + + - Archives and copies of HTTP clients will be initialized with an empty operation queue. + - NSCoding cannot serialize / deserialize block properties, so an archive of an HTTP client will not include any reachability callback block that may be set. + */ + +#ifdef _SYSTEMCONFIGURATION_H +typedef enum { + AFNetworkReachabilityStatusUnknown = -1, + AFNetworkReachabilityStatusNotReachable = 0, + AFNetworkReachabilityStatusReachableViaWWAN = 1, + AFNetworkReachabilityStatusReachableViaWiFi = 2, +} AFNetworkReachabilityStatus; +#else +#pragma message("SystemConfiguration framework not found in project, or not included in precompiled header. Network reachability functionality will not be available.") +#endif + +#ifndef __UTTYPE__ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#pragma message("MobileCoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.") +#else +#pragma message("CoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.") +#endif +#endif + +typedef enum { + AFFormURLParameterEncoding, + AFJSONParameterEncoding, + AFPropertyListParameterEncoding, +} AFHTTPClientParameterEncoding; + +@class AFHTTPRequestOperation; +@protocol AFMultipartFormData; + +@interface AFHTTPClient : NSObject + +///--------------------------------------- +/// @name Accessing HTTP Client Properties +///--------------------------------------- + +/** + The url used as the base for paths specified in methods such as `getPath:parameters:success:failure` + */ +@property (readonly, nonatomic, strong) NSURL *baseURL; + +/** + The string encoding used in constructing url requests. This is `NSUTF8StringEncoding` by default. + */ +@property (nonatomic, assign) NSStringEncoding stringEncoding; + +/** + The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body for request methods other than `GET`, `HEAD` or `DELETE`. This is `AFFormURLParameterEncoding` by default. + + @warning Some nested parameter structures, such as a keyed array of hashes containing inconsistent keys (i.e. `@{@"": @[@{@"a" : @(1)}, @{@"b" : @(2)}]}`), cannot be unambiguously represented in query strings. It is strongly recommended that an unambiguous encoding, such as `AFJSONParameterEncoding`, is used when posting complicated or nondeterministic parameter structures. + */ +@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding; + +/** + The operation queue which manages operations enqueued by the HTTP client. + */ +@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue; + +/** + The reachability status from the device to the current `baseURL` of the `AFHTTPClient`. + + @warning This property requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +#endif + +/** + Default SSL pinning mode for each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:`. + */ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode defaultSSLPinningMode; + +/** + Whether each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:` should accept an invalid SSL certificate. + + If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`. + */ +@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate; + +///--------------------------------------------- +/// @name Creating and Initializing HTTP Clients +///--------------------------------------------- + +/** + Creates and initializes an `AFHTTPClient` object with the specified base URL. + + @param url The base URL for the HTTP client. This argument must not be `nil`. + + @return The newly-initialized HTTP client + */ ++ (instancetype)clientWithBaseURL:(NSURL *)url; + +/** + Initializes an `AFHTTPClient` object with the specified base URL. + + This is the designated initializer. + + @param url The base URL for the HTTP client. This argument must not be `nil`. + + @return The newly-initialized HTTP client + */ +- (id)initWithBaseURL:(NSURL *)url; + +///----------------------------------- +/// @name Managing Reachability Status +///----------------------------------- + +/** + Sets a callback to be executed when the network availability of the `baseURL` host changes. + + @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. + + @warning This method requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; +#endif + +///------------------------------- +/// @name Managing HTTP Operations +///------------------------------- + +/** + Attempts to register a subclass of `AFHTTPRequestOperation`, adding it to a chain to automatically generate request operations from a URL request. + + When `enqueueHTTPRequestOperationWithRequest:success:failure` is invoked, each registered class is consulted in turn to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithURLRequest:` and do `setCompletionBlockWithSuccess:failure:`. There is no guarantee that all registered classes will be consulted. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list. + + @param operationClass The subclass of `AFHTTPRequestOperation` to register + + @return `YES` if the registration is successful, `NO` otherwise. The only failure condition is if `operationClass` is not a subclass of `AFHTTPRequestOperation`. + */ +- (BOOL)registerHTTPOperationClass:(Class)operationClass; + +/** + Unregisters the specified subclass of `AFHTTPRequestOperation` from the chain of classes consulted when `-requestWithMethod:path:parameters` is called. + + @param operationClass The subclass of `AFHTTPRequestOperation` to register + */ +- (void)unregisterHTTPOperationClass:(Class)operationClass; + +///---------------------------------- +/// @name Managing HTTP Header Values +///---------------------------------- + +/** + Returns the value for the HTTP headers set in request objects created by the HTTP client. + + @param header The HTTP header to return the default value for + + @return The default value for the HTTP header, or `nil` if unspecified + */ +- (NSString *)defaultValueForHeader:(NSString *)header; + +/** + Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. + + @param header The HTTP header to set a default value for + @param value The value set as default for the specified header, or `nil + */ +- (void)setDefaultHeader:(NSString *)header + value:(NSString *)value; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. + + @param username The HTTP basic auth username + @param password The HTTP basic auth password + */ +- (void)setAuthorizationHeaderWithUsername:(NSString *)username + password:(NSString *)password; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a token-based authentication value, such as an OAuth access token. This overwrites any existing value for this header. + + @param token The authentication token + */ +- (void)setAuthorizationHeaderWithToken:(NSString *)token; + + +/** + Clears any existing value for the "Authorization" HTTP header. + */ +- (void)clearAuthorizationHeader; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Set the default URL credential to be set for request operations. + + @param credential The URL credential + */ +- (void)setDefaultCredential:(NSURLCredential *)credential; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path. + + If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. + + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If `nil`, no path will be appended to the base URL. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream. + + @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block; + +///------------------------------- +/// @name Creating HTTP Operations +///------------------------------- + +/** + Creates an `AFHTTPRequestOperation`. + + In order to determine what kind of operation is created, each registered subclass conforming to the `AFHTTPClient` protocol is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to generate an operation using `HTTPRequestOperationWithRequest:success:failure:`. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + */ +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +///---------------------------------------- +/// @name Managing Enqueued HTTP Operations +///---------------------------------------- + +/** + Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue. + + @param operation The HTTP request operation to be enqueued. + */ +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation; + +/** + Cancels all operations in the HTTP client's operation queue whose URLs match the specified HTTP method and path. + + This method only cancels `AFHTTPRequestOperations` whose request URL matches the HTTP client base URL with the path appended. For complete control over the lifecycle of enqueued operations, you can access the `operationQueue` property directly, which allows you to, for instance, cancel operations filtered by a predicate, or simply use `-cancelAllRequests`. Note that the operation queue may include non-HTTP operations, so be sure to check the type before attempting to directly introspect an operation's `request` property. + + @param method The HTTP method to match for the cancelled requests, such as `GET`, `POST`, `PUT`, or `DELETE`. If `nil`, all request operations with URLs matching the path will be cancelled. + @param path The path appended to the HTTP client base URL to match against the cancelled requests. If `nil`, no path will be appended to the base URL. + */ +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path; + +///--------------------------------------- +/// @name Batching HTTP Request Operations +///--------------------------------------- + +/** + Creates and enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue for each specified request object into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + Operations are created by passing the specified `NSURLRequest` objects in `requests`, using `-HTTPRequestOperationWithRequest:success:failure:`, with `nil` for both the `success` and `failure` parameters. + + @param urlRequests The `NSURLRequest` objects used to create and enqueue operations. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +/** + Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @param operations The request operations used to be batched and enqueued. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +///--------------------------- +/// @name Making HTTP Requests +///--------------------------- + +/** + Creates an `AFHTTPRequestOperation` with a `GET` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `POST` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PUT` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `DELETE` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PATCH` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## Network Reachability + + The following constants are provided by `AFHTTPClient` as possible network reachability statuses. + + enum { + AFNetworkReachabilityStatusUnknown, + AFNetworkReachabilityStatusNotReachable, + AFNetworkReachabilityStatusReachableViaWWAN, + AFNetworkReachabilityStatusReachableViaWiFi, + } + + `AFNetworkReachabilityStatusUnknown` + The `baseURL` host reachability is not known. + + `AFNetworkReachabilityStatusNotReachable` + The `baseURL` host cannot be reached. + + `AFNetworkReachabilityStatusReachableViaWWAN` + The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS. + + `AFNetworkReachabilityStatusReachableViaWiFi` + The `baseURL` host can be reached via a Wi-Fi connection. + + ### Keys for Notification UserInfo Dictionary + + Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification. + + `AFNetworkingReachabilityNotificationStatusItem` + A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. + The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. + + ## Parameter Encoding + + The following constants are provided by `AFHTTPClient` as possible methods for serializing parameters into query string or message body values. + + enum { + AFFormURLParameterEncoding, + AFJSONParameterEncoding, + AFPropertyListParameterEncoding, + } + + `AFFormURLParameterEncoding` + Parameters are encoded into field/key pairs in the URL query string for `GET` `HEAD` and `DELETE` requests, and in the message body otherwise. Dictionary keys are sorted with the `caseInsensitiveCompare:` selector of their description, in order to mitigate the possibility of ambiguous query strings being generated non-deterministically. See the warning for the `parameterEncoding` property for additional information. + + `AFJSONParameterEncoding` + Parameters are encoded into JSON in the message body. + + `AFPropertyListParameterEncoding` + Parameters are encoded into a property list in the message body. + */ + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a query string constructed by a set of parameters, using the specified encoding. + + Query strings are constructed by collecting each key-value pair, percent escaping a string representation of the key-value pair, and then joining the pairs with "&". + + If a query string pair has a an `NSArray` for its value, each member of the array will be represented in the format `field[]=value1&field[]value2`. Otherwise, the pair will be formatted as "field=value". String representations of both keys and values are derived using the `-description` method. The constructed query string does not include the ? character used to delimit the query component. + + @param parameters The parameters used to construct the query string + @param encoding The encoding to use in constructing the query string. If you are uncertain of the correct encoding, you should use UTF-8 (`NSUTF8StringEncoding`), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + + @return A percent-escaped query string + */ +extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding encoding); + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when network reachability changes. + This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability. + + @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +extern NSString * const AFNetworkingReachabilityDidChangeNotification; +extern NSString * const AFNetworkingReachabilityNotificationStatusItem; +#endif + +#pragma mark - + +extern NSUInteger const kAFUploadStream3GSuggestedPacketSize; +extern NSTimeInterval const kAFUploadStream3GSuggestedDelay; + +/** + The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. + */ +@protocol AFMultipartFormData + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary. + + The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended, otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`. + @param mimeType The declared MIME type of the file data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary. + + @param inputStream The input stream to be appended to the form data + @param name The name to be associated with the specified input stream. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`. + @param length The length of the specified input stream in bytes. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(unsigned long long)length + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified data. This parameter must not be `nil`. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + */ + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name; + + +/** + Appends HTTP headers, followed by the encoded data and the multipart form boundary. + + @param headers The HTTP headers to be appended to the form data. + @param body The data to be encoded and appended to the form data. + */ +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body; + +/** + Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream. + + When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, as of iOS 6, there is no definite way to distinguish between a 3G, EDGE, or LTE connection. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth. + + @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 32kb. + @param delay Duration of delay each time a packet is read. By default, no delay is set. + */ +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay; + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.m new file mode 100644 index 0000000..2902e77 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPClient.m @@ -0,0 +1,1403 @@ +// AFHTTPClient.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "AFHTTPClient.h" +#import "AFHTTPRequestOperation.h" + +#import + +#ifdef _SYSTEMCONFIGURATION_H +#import +#import +#import +#import +#import +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +#ifdef _SYSTEMCONFIGURATION_H +NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; +NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem"; + +typedef SCNetworkReachabilityRef AFNetworkReachabilityRef; +typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); +#else +typedef id AFNetworkReachabilityRef; +#endif + +typedef void (^AFCompletionBlock)(void); + +static NSString * AFBase64EncodedStringFromString(NSString *string) { + NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; + NSUInteger length = [data length]; + NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; + + uint8_t *input = (uint8_t *)[data bytes]; + uint8_t *output = (uint8_t *)[mutableData mutableBytes]; + + for (NSUInteger i = 0; i < length; i += 3) { + NSUInteger value = 0; + for (NSUInteger j = i; j < (i + 3); j++) { + value <<= 8; + if (j < length) { + value |= (0xFF & input[j]); + } + } + + static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + NSUInteger idx = (i / 3) * 4; + output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; + output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; + output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; + output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; + } + + return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding]; +} + +static NSString * const kAFCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*"; + +static NSString * AFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const kAFCharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +#pragma mark - + +@interface AFQueryStringPair : NSObject +@property (readwrite, nonatomic, strong) id field; +@property (readwrite, nonatomic, strong) id value; + +- (id)initWithField:(id)field value:(id)value; + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; +@end + +@implementation AFQueryStringPair +@synthesize field = _field; +@synthesize value = _value; + +- (id)initWithField:(id)field value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.field = field; + self.value = value; + + return self; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + if (!self.value || [self.value isEqual:[NSNull null]]) { + return AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); + } else { + return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; + } +} + +@end + +#pragma mark - + +extern NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary); +extern NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value); + +NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutablePairs = [NSMutableArray array]; + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutablePairs componentsJoinedByString:@"&"]; +} + +NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) { + return AFQueryStringPairsFromKeyAndValue(nil, dictionary); +} + +NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(caseInsensitiveCompare:)]; + for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + id nestedValue = [dictionary objectForKey:nestedKey]; + if (nestedValue) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + for (id nestedValue in array) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + } + } else if ([value isKindOfClass:[NSSet class]]) { + NSSet *set = value; + for (id obj in set) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; + } + } else { + [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]]; + } + + return mutableQueryStringComponents; +} + +@interface AFStreamingMultipartFormData : NSObject +- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding; + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData; +@end + +#pragma mark - + +@interface AFHTTPClient () +@property (readwrite, nonatomic, strong) NSURL *baseURL; +@property (readwrite, nonatomic, strong) NSMutableArray *registeredHTTPOperationClassNames; +@property (readwrite, nonatomic, strong) NSMutableDictionary *defaultHeaders; +@property (readwrite, nonatomic, strong) NSURLCredential *defaultCredential; +@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@property (readwrite, nonatomic, assign) AFNetworkReachabilityRef networkReachability; +@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; +#endif + +#ifdef _SYSTEMCONFIGURATION_H +- (void)startMonitoringNetworkReachability; +- (void)stopMonitoringNetworkReachability; +#endif +@end + +@implementation AFHTTPClient +@synthesize baseURL = _baseURL; +@synthesize stringEncoding = _stringEncoding; +@synthesize parameterEncoding = _parameterEncoding; +@synthesize registeredHTTPOperationClassNames = _registeredHTTPOperationClassNames; +@synthesize defaultHeaders = _defaultHeaders; +@synthesize defaultCredential = _defaultCredential; +@synthesize operationQueue = _operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@synthesize networkReachability = _networkReachability; +@synthesize networkReachabilityStatus = _networkReachabilityStatus; +@synthesize networkReachabilityStatusBlock = _networkReachabilityStatusBlock; +#endif +@synthesize defaultSSLPinningMode = _defaultSSLPinningMode; +@synthesize allowsInvalidSSLCertificate = _allowsInvalidSSLCertificate; + ++ (instancetype)clientWithBaseURL:(NSURL *)url { + return [[self alloc] initWithBaseURL:url]; +} + +- (id)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke `initWithBaseURL:` instead.", NSStringFromClass([self class])] userInfo:nil]; +} + +- (id)initWithBaseURL:(NSURL *)url { + NSParameterAssert(url); + + self = [super init]; + if (!self) { + return nil; + } + + // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected + if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { + url = [url URLByAppendingPathComponent:@""]; + } + + self.baseURL = url; + + self.stringEncoding = NSUTF8StringEncoding; + self.parameterEncoding = AFFormURLParameterEncoding; + + self.registeredHTTPOperationClassNames = [NSMutableArray array]; + + self.defaultHeaders = [NSMutableDictionary dictionary]; + + // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 + NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; + [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + float q = 1.0f - (idx * 0.1f); + [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]]; + *stop = q <= 0.5f; + }]; + [self setDefaultHeader:@"Accept-Language" value:[acceptLanguagesComponents componentsJoinedByString:@", "]]; + + NSString *userAgent = nil; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], (__bridge id)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), kCFBundleVersionKey) ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0f)]; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]; +#endif +#pragma clang diagnostic pop + if (userAgent) { + if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) { + NSMutableString *mutableUserAgent = [userAgent mutableCopy]; + if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, kCFStringTransformToLatin, false)) { + userAgent = mutableUserAgent; + } + } + [self setDefaultHeader:@"User-Agent" value:userAgent]; + } + +#ifdef _SYSTEMCONFIGURATION_H + self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; + [self startMonitoringNetworkReachability]; +#endif + + self.operationQueue = [[NSOperationQueue alloc] init]; + [self.operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; + + // #ifdef included for backwards-compatibility +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + self.allowsInvalidSSLCertificate = YES; +#endif + + return self; +} + +- (void)dealloc { +#ifdef _SYSTEMCONFIGURATION_H + [self stopMonitoringNetworkReachability]; +#endif +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, defaultHeaders: %@, registeredOperationClasses: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.defaultHeaders, self.registeredHTTPOperationClassNames, self.operationQueue]; +} + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +static BOOL AFURLHostIsIPAddress(NSURL *url) { + struct sockaddr_in sa_in; + struct sockaddr_in6 sa_in6; + + return [url host] && (inet_pton(AF_INET, [[url host] UTF8String], &sa_in) == 1 || inet_pton(AF_INET6, [[url host] UTF8String], &sa_in6) == 1); +} + +static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { + BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); + BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); + BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); + BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); + BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); + + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; + if (isNetworkReachable == NO) { + status = AFNetworkReachabilityStatusNotReachable; + } +#if TARGET_OS_IPHONE + else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { + status = AFNetworkReachabilityStatusReachableViaWWAN; + } +#endif + else { + status = AFNetworkReachabilityStatusReachableViaWiFi; + } + + return status; +} + +static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info; + if (block) { + block(status); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:status] forKey:AFNetworkingReachabilityNotificationStatusItem]]; + }); +} + +static const void * AFNetworkReachabilityRetainCallback(const void *info) { + return Block_copy(info); +} + +static void AFNetworkReachabilityReleaseCallback(const void *info) { + if (info) { + Block_release(info); + } +} + +- (void)startMonitoringNetworkReachability { + [self stopMonitoringNetworkReachability]; + + if (!self.baseURL) { + return; + } + + self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]); + + if (!self.networkReachability) { + return; + } + + __weak __typeof(&*self)weakSelf = self; + AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + strongSelf.networkReachabilityStatus = status; + if (strongSelf.networkReachabilityStatusBlock) { + strongSelf.networkReachabilityStatusBlock(status); + } + }; + + SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; + SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); + + /* Network reachability monitoring does not establish a baseline for IP addresses as it does for hostnames, so if the base URL host is an IP address, the initial reachability callback is manually triggered. + */ + if (AFURLHostIsIPAddress(self.baseURL)) { + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(self.networkReachability, &flags); + dispatch_async(dispatch_get_main_queue(), ^{ + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + callback(status); + }); + } + + SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); +} + +- (void)stopMonitoringNetworkReachability { + if (self.networkReachability) { + SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); + + CFRelease(_networkReachability); + _networkReachability = NULL; + } +} + +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { + self.networkReachabilityStatusBlock = block; +} +#endif + +#pragma mark - + +- (BOOL)registerHTTPOperationClass:(Class)operationClass { + if (![operationClass isSubclassOfClass:[AFHTTPRequestOperation class]]) { + return NO; + } + + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; + [self.registeredHTTPOperationClassNames insertObject:className atIndex:0]; + + return YES; +} + +- (void)unregisterHTTPOperationClass:(Class)operationClass { + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; +} + +#pragma mark - + +- (NSString *)defaultValueForHeader:(NSString *)header { + return [self.defaultHeaders valueForKey:header]; +} + +- (void)setDefaultHeader:(NSString *)header value:(NSString *)value { + [self.defaultHeaders setValue:value forKey:header]; +} + +- (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password { + NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password]; + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)]]; +} + +- (void)setAuthorizationHeaderWithToken:(NSString *)token { + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Token token=\"%@\"", token]]; +} + +- (void)clearAuthorizationHeader { + [self.defaultHeaders removeObjectForKey:@"Authorization"]; +} + +#pragma mark - + +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + NSParameterAssert(method); + + if (!path) { + path = @""; + } + + NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; + [request setHTTPMethod:method]; + [request setAllHTTPHeaderFields:self.defaultHeaders]; + + if (parameters) { + if ([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"]) { + url = [NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:[path rangeOfString:@"?"].location == NSNotFound ? @"?%@" : @"&%@", AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding)]]; + [request setURL:url]; + } else { + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding)); + NSError *error = nil; + + switch (self.parameterEncoding) { + case AFFormURLParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]]; + break; + case AFJSONParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:(NSJSONWritingOptions)0 error:&error]]; + break; + case AFPropertyListParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-plist; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]]; + break; + } + + if (error) { + NSLog(@"%@ %@: %@", [self class], NSStringFromSelector(_cmd), error); + } + } + } + + return request; +} + +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block +{ + NSParameterAssert(method); + NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]); + + NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil]; + + __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding]; + + if (parameters) { + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + NSData *data = nil; + if ([pair.value isKindOfClass:[NSData class]]) { + data = pair.value; + } else if ([pair.value isEqual:[NSNull null]]) { + data = [NSData data]; + } else { + data = [[pair.value description] dataUsingEncoding:self.stringEncoding]; + } + + if (data) { + [formData appendPartWithFormData:data name:[pair.field description]]; + } + } + } + + if (block) { + block(formData); + } + + return [formData requestByFinalizingMultipartFormData]; +} + +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + AFHTTPRequestOperation *operation = nil; + + for (NSString *className in self.registeredHTTPOperationClassNames) { + Class operationClass = NSClassFromString(className); + if (operationClass && [operationClass canProcessRequest:urlRequest]) { + operation = [(AFHTTPRequestOperation *)[operationClass alloc] initWithRequest:urlRequest]; + break; + } + } + + if (!operation) { + operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest]; + } + + [operation setCompletionBlockWithSuccess:success failure:failure]; + + operation.credential = self.defaultCredential; + operation.SSLPinningMode = self.defaultSSLPinningMode; + operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate; + + return operation; +} + +#pragma mark - + +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation { + [self.operationQueue addOperation:operation]; +} + +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method + path:(NSString *)path +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + NSString *pathToBeMatched = [[[self requestWithMethod:(method ?: @"GET") path:path parameters:nil] URL] path]; +#pragma clang diagnostic pop + + for (NSOperation *operation in [self.operationQueue operations]) { + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) { + continue; + } + + BOOL hasMatchingMethod = !method || [method isEqualToString:[[(AFHTTPRequestOperation *)operation request] HTTPMethod]]; + BOOL hasMatchingPath = [[[[(AFHTTPRequestOperation *)operation request] URL] path] isEqual:pathToBeMatched]; + + if (hasMatchingMethod && hasMatchingPath) { + [operation cancel]; + } + } +} + +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + NSMutableArray *mutableOperations = [NSMutableArray array]; + for (NSURLRequest *request in urlRequests) { + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:nil failure:nil]; + [mutableOperations addObject:operation]; + } + + [self enqueueBatchOfHTTPRequestOperations:mutableOperations progressBlock:progressBlock completionBlock:completionBlock]; +} + +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(operations); + } + }); +#if !OS_OBJECT_USE_OBJC + dispatch_release(dispatchGroup); +#endif + }]; + + for (AFHTTPRequestOperation *operation in operations) { + AFCompletionBlock originalCompletionBlock = [operation.completionBlock copy]; + __weak __typeof(&*operation)weakOperation = operation; + operation.completionBlock = ^{ + __strong __typeof(&*weakOperation)strongOperation = weakOperation; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_queue_t queue = strongOperation.successCallbackQueue ?: dispatch_get_main_queue(); +#pragma clang diagnostic pop + dispatch_group_async(dispatchGroup, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) { + return [op isFinished]; + }] count]; + + if (progressBlock) { + progressBlock(numberOfFinishedOperations, [operations count]); + } + + dispatch_group_leave(dispatchGroup); + }); + }; + + dispatch_group_enter(dispatchGroup); + [batchedOperation addDependency:operation]; + } + [self.operationQueue addOperations:operations waitUntilFinished:NO]; + [self.operationQueue addOperation:batchedOperation]; +} + +#pragma mark - + +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PATCH" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + NSURL *baseURL = [aDecoder decodeObjectForKey:@"baseURL"]; + + self = [self initWithBaseURL:baseURL]; + if (!self) { + return nil; + } + + self.stringEncoding = [aDecoder decodeIntegerForKey:@"stringEncoding"]; + self.parameterEncoding = (AFHTTPClientParameterEncoding) [aDecoder decodeIntegerForKey:@"parameterEncoding"]; + self.registeredHTTPOperationClassNames = [aDecoder decodeObjectForKey:@"registeredHTTPOperationClassNames"]; + self.defaultHeaders = [aDecoder decodeObjectForKey:@"defaultHeaders"]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.baseURL forKey:@"baseURL"]; + [aCoder encodeInteger:(NSInteger)self.stringEncoding forKey:@"stringEncoding"]; + [aCoder encodeInteger:self.parameterEncoding forKey:@"parameterEncoding"]; + [aCoder encodeObject:self.registeredHTTPOperationClassNames forKey:@"registeredHTTPOperationClassNames"]; + [aCoder encodeObject:self.defaultHeaders forKey:@"defaultHeaders"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPClient *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL]; + + HTTPClient.stringEncoding = self.stringEncoding; + HTTPClient.parameterEncoding = self.parameterEncoding; + HTTPClient.registeredHTTPOperationClassNames = [self.registeredHTTPOperationClassNames mutableCopyWithZone:zone]; + HTTPClient.defaultHeaders = [self.defaultHeaders mutableCopyWithZone:zone]; +#ifdef _SYSTEMCONFIGURATION_H + HTTPClient.networkReachabilityStatusBlock = self.networkReachabilityStatusBlock; +#endif + return HTTPClient; +} + +@end + +#pragma mark - + +static NSString * AFCreateMultipartFormBoundary() { + return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()]; +} + +static NSString * const kAFMultipartFormCRLF = @"\r\n"; + +static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFContentTypeForPathExtension(NSString *extension) { +#ifdef __UTTYPE__ + NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL); + NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType); + if (!contentType) { + return @"application/octet-stream"; + } else { + return contentType; + } +#else + return @"application/octet-stream"; +#endif +} + +NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16; +NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2; + +@interface AFHTTPBodyPart : NSObject +@property (nonatomic, assign) NSStringEncoding stringEncoding; +@property (nonatomic, strong) NSDictionary *headers; +@property (nonatomic, strong) id body; +@property (nonatomic, assign) unsigned long long bodyContentLength; +@property (nonatomic, strong) NSInputStream *inputStream; + +@property (nonatomic, copy) NSString *boundary; +@property (nonatomic, assign) BOOL hasInitialBoundary; +@property (nonatomic, assign) BOOL hasFinalBoundary; + +@property (nonatomic, readonly, getter = hasBytesAvailable) BOOL bytesAvailable; +@property (nonatomic, readonly) unsigned long long contentLength; + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@interface AFMultipartBodyStream : NSInputStream +@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; +@property (nonatomic, assign) NSTimeInterval delay; +@property (nonatomic, strong) NSInputStream *inputStream; +@property (nonatomic, readonly) unsigned long long contentLength; +@property (nonatomic, readonly, getter = isEmpty) BOOL empty; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding; +- (void)setInitialAndFinalBoundaries; +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart; +@end + +#pragma mark - + +@interface AFStreamingMultipartFormData () +@property (readwrite, nonatomic, copy) NSMutableURLRequest *request; +@property (nonatomic, copy) NSString *boundary; +@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream; +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@end + +@implementation AFStreamingMultipartFormData +@synthesize request = _request; +@synthesize bodyStream = _bodyStream; +@synthesize stringEncoding = _stringEncoding; + +- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding +{ + self = [super init]; + if (!self) { + return nil; + } + + self.request = urlRequest; + self.stringEncoding = encoding; + self.boundary = AFCreateMultipartFormBoundary(); + self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding]; + + return self; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + + NSString *fileName = [fileURL lastPathComponent]; + NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]); + + return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error]; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + if (![fileURL isFileURL]) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey]; + if (error != NULL) { + *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey]; + if (error != NULL) { + *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = fileURL; + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil]; + bodyPart.bodyContentLength = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue]; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; + + return YES; +} + + +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(unsigned long long)length + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = inputStream; + + bodyPart.bodyContentLength = length; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name +{ + NSParameterAssert(name); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body +{ + NSParameterAssert(body); + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = headers; + bodyPart.boundary = self.boundary; + bodyPart.bodyContentLength = [body length]; + bodyPart.body = body; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay +{ + self.bodyStream.numberOfBytesInPacket = numberOfBytes; + self.bodyStream.delay = delay; +} + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData { + if ([self.bodyStream isEmpty]) { + return self.request; + } + + // Reset the initial and final boundaries to ensure correct Content-Length + [self.bodyStream setInitialAndFinalBoundaries]; + + [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"]; + [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"]; + [self.request setHTTPBodyStream:self.bodyStream]; + + return self.request; +} + +@end + +#pragma mark - + +@interface AFMultipartBodyStream () +@property (nonatomic, assign) NSStreamStatus streamStatus; +@property (nonatomic, strong) NSError *streamError; +@property (nonatomic, assign) NSStringEncoding stringEncoding; +@property (nonatomic, strong) NSMutableArray *HTTPBodyParts; +@property (nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; +@property (nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart; +@property (nonatomic, strong) NSOutputStream *outputStream; +@property (nonatomic, strong) NSMutableData *buffer; +@end + +@implementation AFMultipartBodyStream +@synthesize streamStatus = _streamStatus; +@synthesize streamError = _streamError; +@synthesize stringEncoding = _stringEncoding; +@synthesize HTTPBodyParts = _HTTPBodyParts; +@synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator; +@synthesize currentHTTPBodyPart = _currentHTTPBodyPart; +@synthesize inputStream = _inputStream; +@synthesize outputStream = _outputStream; +@synthesize buffer = _buffer; +@synthesize numberOfBytesInPacket = _numberOfBytesInPacket; +@synthesize delay = _delay; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = encoding; + self.HTTPBodyParts = [NSMutableArray array]; + self.numberOfBytesInPacket = NSIntegerMax; + + return self; +} + +- (void)setInitialAndFinalBoundaries { + if ([self.HTTPBodyParts count] > 0) { + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + bodyPart.hasInitialBoundary = NO; + bodyPart.hasFinalBoundary = NO; + } + + [[self.HTTPBodyParts objectAtIndex:0] setHasInitialBoundary:YES]; + [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; + } +} + +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart { + [self.HTTPBodyParts addObject:bodyPart]; +} + +- (BOOL)isEmpty { + return [self.HTTPBodyParts count] == 0; +} + +#pragma mark - NSInputStream + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + if ([self streamStatus] == NSStreamStatusClosed) { + return 0; + } + + NSInteger totalNumberOfBytesRead = 0; + + while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { + if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { + if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { + break; + } + } else { + NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead; + NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; + if (numberOfBytesRead == -1) { + self.streamError = self.currentHTTPBodyPart.inputStream.streamError; + break; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if (self.delay > 0.0f) { + [NSThread sleepForTimeInterval:self.delay]; + } + } + } + } + + return totalNumberOfBytesRead; +} + +- (BOOL)getBuffer:(__unused uint8_t **)buffer + length:(__unused NSUInteger *)len +{ + return NO; +} + +- (BOOL)hasBytesAvailable { + return [self streamStatus] == NSStreamStatusOpen; +} + +#pragma mark - NSStream + +- (void)open { + if (self.streamStatus == NSStreamStatusOpen) { + return; + } + + self.streamStatus = NSStreamStatusOpen; + + [self setInitialAndFinalBoundaries]; + self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator]; +} + +- (void)close { + self.streamStatus = NSStreamStatusClosed; +} + +- (id)propertyForKey:(__unused NSString *)key { + return nil; +} + +- (BOOL)setProperty:(__unused id)property + forKey:(__unused NSString *)key +{ + return NO; +} + +- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + length += [bodyPart contentLength]; + } + + return length; +} + +#pragma mark - Undocumented CFReadStream Bridged Methods + +- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags + callback:(__unused CFReadStreamClientCallBack)inCallback + context:(__unused CFStreamClientContext *)inContext { + return NO; +} + +#pragma mark - NSCopying + +-(id)copyWithZone:(NSZone *)zone { + AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; + + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; + } + + [bodyStreamCopy setInitialAndFinalBoundaries]; + + return bodyStreamCopy; +} + +@end + +#pragma mark - + +typedef enum { + AFEncapsulationBoundaryPhase = 1, + AFHeaderPhase = 2, + AFBodyPhase = 3, + AFFinalBoundaryPhase = 4, +} AFHTTPBodyPartReadPhase; + +@interface AFHTTPBodyPart () { + AFHTTPBodyPartReadPhase _phase; + NSInputStream *_inputStream; + unsigned long long _phaseReadOffset; +} + +- (BOOL)transitionToNextPhase; +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@implementation AFHTTPBodyPart +@synthesize stringEncoding = _stringEncoding; +@synthesize headers = _headers; +@synthesize body = _body; +@synthesize bodyContentLength = _bodyContentLength; +@synthesize inputStream = _inputStream; +@synthesize hasInitialBoundary = _hasInitialBoundary; +@synthesize hasFinalBoundary = _hasFinalBoundary; + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [self transitionToNextPhase]; + + return self; +} + +- (void)dealloc { + if (_inputStream) { + [_inputStream close]; + _inputStream = nil; + } +} + +- (NSInputStream *)inputStream { + if (!_inputStream) { + if ([self.body isKindOfClass:[NSData class]]) { + _inputStream = [NSInputStream inputStreamWithData:self.body]; + } else if ([self.body isKindOfClass:[NSURL class]]) { + _inputStream = [NSInputStream inputStreamWithURL:self.body]; + } else if ([self.body isKindOfClass:[NSInputStream class]]) { + _inputStream = self.body; + } + } + + return _inputStream; +} + +- (NSString *)stringForHeaders { + NSMutableString *headerString = [NSMutableString string]; + for (NSString *field in [self.headers allKeys]) { + [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]]; + } + [headerString appendString:kAFMultipartFormCRLF]; + + return [NSString stringWithString:headerString]; +} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + length += [encapsulationBoundaryData length]; + + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + length += [headersData length]; + + length += _bodyContentLength; + + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + length += [closingBoundaryData length]; + + return length; +} + +- (BOOL)hasBytesAvailable { + // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer + if (_phase == AFFinalBoundaryPhase) { + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (self.inputStream.streamStatus) { + case NSStreamStatusNotOpen: + case NSStreamStatusOpening: + case NSStreamStatusOpen: + case NSStreamStatusReading: + case NSStreamStatusWriting: + return YES; + case NSStreamStatusAtEnd: + case NSStreamStatusClosed: + case NSStreamStatusError: + default: + return NO; + } +#pragma clang diagnostic pop +} + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + NSUInteger totalNumberOfBytesRead = 0; + + if (_phase == AFEncapsulationBoundaryPhase) { + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFHeaderPhase) { + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFBodyPhase) { + NSInteger numberOfBytesRead = 0; + + numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + if (numberOfBytesRead == -1) { + return -1; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) { + [self transitionToNextPhase]; + } + } + } + + if (_phase == AFFinalBoundaryPhase) { + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + return totalNumberOfBytesRead; +} + +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length)); + [data getBytes:buffer range:range]; +#pragma clang diagnostic pop + + _phaseReadOffset += range.length; + + if (((NSUInteger)_phaseReadOffset) >= [data length]) { + [self transitionToNextPhase]; + } + + return (NSInteger)range.length; +} + +- (BOOL)transitionToNextPhase { + if (![[NSThread currentThread] isMainThread]) { + [self performSelectorOnMainThread:@selector(transitionToNextPhase) withObject:nil waitUntilDone:YES]; + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (_phase) { + case AFEncapsulationBoundaryPhase: + _phase = AFHeaderPhase; + break; + case AFHeaderPhase: + [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [self.inputStream open]; + _phase = AFBodyPhase; + break; + case AFBodyPhase: + [self.inputStream close]; + _phase = AFFinalBoundaryPhase; + break; + case AFFinalBoundaryPhase: + default: + _phase = AFEncapsulationBoundaryPhase; + break; + } + _phaseReadOffset = 0; +#pragma clang diagnostic pop + + return YES; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init]; + + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = self.headers; + bodyPart.bodyContentLength = self.bodyContentLength; + bodyPart.body = self.body; + + return bodyPart; +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h new file mode 100644 index 0000000..b40e3d5 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1,133 @@ +// AFHTTPRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +/** + `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. + */ +@interface AFHTTPRequestOperation : AFURLConnectionOperation + +///---------------------------------------------- +/// @name Getting HTTP URL Connection Information +///---------------------------------------------- + +/** + The last HTTP response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSHTTPURLResponse *response; + +///---------------------------------------------------------- +/// @name Managing And Checking For Acceptable HTTP Responses +///---------------------------------------------------------- + +/** + A Boolean value that corresponds to whether the status code of the response is within the specified set of acceptable status codes. Returns `YES` if `acceptableStatusCodes` is `nil`. + */ +@property (nonatomic, readonly) BOOL hasAcceptableStatusCode; + +/** + A Boolean value that corresponds to whether the MIME type of the response is among the specified set of acceptable content types. Returns `YES` if `acceptableContentTypes` is `nil`. + */ +@property (nonatomic, readonly) BOOL hasAcceptableContentType; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; + +///------------------------------------------------------------ +/// @name Managing Acceptable HTTP Status Codes & Content Types +///------------------------------------------------------------ + +/** + Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + + By default, this is the range 200 to 299, inclusive. + */ ++ (NSIndexSet *)acceptableStatusCodes; + +/** + Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendants. + + @param statusCodes The status codes to be added to the set of acceptable HTTP status codes + */ ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes; + +/** + Returns an `NSSet` object containing the acceptable MIME types. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 + + By default, this is `nil`. + */ ++ (NSSet *)acceptableContentTypes; + +/** + Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendants. + + @param contentTypes The content types to be added to the set of acceptable MIME types + */ ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes; + + +///----------------------------------------------------- +/// @name Determining Whether A Request Can Be Processed +///----------------------------------------------------- + +/** + A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. + + @param urlRequest The request that is determined to be supported or not supported for this class. + */ ++ (BOOL)canProcessRequest:(NSURLRequest *)urlRequest; + +///----------------------------------------------------------- +/// @name Setting Completion Block Success / Failure Callbacks +///----------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. + + This method should be overridden in subclasses in order to specify the response object passed into the success block. + + @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +@end + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header. + */ +extern NSSet * AFContentTypesFromHTTPHeader(NSString *string); + diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m new file mode 100644 index 0000000..940b6e7 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m @@ -0,0 +1,327 @@ +// AFHTTPRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPRequestOperation.h" +#import + +// Workaround for change in imp_implementationWithBlock() with Xcode 4.5 +#if defined(__IPHONE_6_0) || defined(__MAC_10_8) +#define AF_CAST_TO_BLOCK id +#else +#define AF_CAST_TO_BLOCK __bridge void * +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-selector-match" + +NSSet * AFContentTypesFromHTTPHeader(NSString *string) { + if (!string) { + return nil; + } + + NSArray *mediaRanges = [string componentsSeparatedByString:@","]; + NSMutableSet *mutableContentTypes = [NSMutableSet setWithCapacity:mediaRanges.count]; + + [mediaRanges enumerateObjectsUsingBlock:^(NSString *mediaRange, __unused NSUInteger idx, __unused BOOL *stop) { + NSRange parametersRange = [mediaRange rangeOfString:@";"]; + if (parametersRange.location != NSNotFound) { + mediaRange = [mediaRange substringToIndex:parametersRange.location]; + } + + mediaRange = [mediaRange stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if (mediaRange.length > 0) { + [mutableContentTypes addObject:mediaRange]; + } + }]; + + return [NSSet setWithSet:mutableContentTypes]; +} + +static void AFGetMediaTypeAndSubtypeWithString(NSString *string, NSString **type, NSString **subtype) { + if (!string) { + return; + } + + NSScanner *scanner = [NSScanner scannerWithString:string]; + [scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + [scanner scanUpToString:@"/" intoString:type]; + [scanner scanString:@"/" intoString:nil]; + [scanner scanUpToString:@";" intoString:subtype]; +} + +static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { + NSMutableString *string = [NSMutableString string]; + + NSRange range = NSMakeRange([indexSet firstIndex], 1); + while (range.location != NSNotFound) { + NSUInteger nextIndex = [indexSet indexGreaterThanIndex:range.location]; + while (nextIndex == range.location + range.length) { + range.length++; + nextIndex = [indexSet indexGreaterThanIndex:nextIndex]; + } + + if (string.length) { + [string appendString:@","]; + } + + if (range.length == 1) { + [string appendFormat:@"%lu", (long)range.location]; + } else { + NSUInteger firstIndex = range.location; + NSUInteger lastIndex = firstIndex + range.length - 1; + [string appendFormat:@"%lu-%lu", (long)firstIndex, (long)lastIndex]; + } + + range.location = nextIndex; + range.length = 1; + } + + return string; +} + +static void AFSwizzleClassMethodWithClassAndSelectorUsingBlock(Class klass, SEL selector, id block) { + Method originalMethod = class_getClassMethod(klass, selector); + IMP implementation = imp_implementationWithBlock((AF_CAST_TO_BLOCK)block); + class_replaceMethod(objc_getMetaClass([NSStringFromClass(klass) UTF8String]), selector, implementation, method_getTypeEncoding(originalMethod)); +} + +#pragma mark - + +@interface AFHTTPRequestOperation () +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSHTTPURLResponse *response; +@property (readwrite, nonatomic, strong) NSError *HTTPError; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation AFHTTPRequestOperation +@synthesize HTTPError = _HTTPError; +@synthesize successCallbackQueue = _successCallbackQueue; +@synthesize failureCallbackQueue = _failureCallbackQueue; +@dynamic lock; +@dynamic request; +@dynamic response; + +- (void)dealloc { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } +} + +- (NSError *)error { + [self.lock lock]; + if (!self.HTTPError && self.response) { + if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey]; + [userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey]; + + if (![self hasAcceptableStatusCode]) { + NSInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? [self.response statusCode] : 200; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected status code in (%@), got %ld", @"AFNetworking", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), (long)statusCode] forKey:NSLocalizedDescriptionKey]; + self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; + } else if (![self hasAcceptableContentType]) { + // Don't invalidate content type if there is no content + if ([self.responseData length] > 0) { + [userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected content type %@, got %@", @"AFNetworking", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; + self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + } + } + [self.lock unlock]; + + if (self.HTTPError) { + return self.HTTPError; + } else { + return [super error]; + } +} + +- (NSStringEncoding)responseStringEncoding { + // When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP. Data in character sets other than "ISO-8859-1" or its subsets MUST be labeled with an appropriate charset value. + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.4.1 + if (self.response && !self.response.textEncodingName && self.responseData && [self.response respondsToSelector:@selector(allHeaderFields)]) { + NSString *type = nil; + AFGetMediaTypeAndSubtypeWithString([[self.response allHeaderFields] valueForKey:@"Content-Type"], &type, nil); + + if ([type isEqualToString:@"text"]) { + return NSISOLatin1StringEncoding; + } + } + + return [super responseStringEncoding]; +} + +- (void)pause { + unsigned long long offset = 0; + if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { + offset = [[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; + } else { + offset = [[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; + } + + NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy]; + if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) { + [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; + } + [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; + self.request = mutableURLRequest; + + [super pause]; +} + +- (BOOL)hasAcceptableStatusCode { + if (!self.response) { + return NO; + } + + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:statusCode]; +} + +- (BOOL)hasAcceptableContentType { + if (!self.response) { + return NO; + } + + // Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream". + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html + NSString *contentType = [self.response MIMEType]; + if (!contentType) { + contentType = @"application/octet-stream"; + } + + return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:contentType]; +} + +- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue { + if (successCallbackQueue != _successCallbackQueue) { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(successCallbackQueue); +#endif + _successCallbackQueue = successCallbackQueue; + } + } +} + +- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue { + if (failureCallbackQueue != _failureCallbackQueue) { + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } + + if (failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(failureCallbackQueue); +#endif + _failureCallbackQueue = failureCallbackQueue; + } + } +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^{ + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, self.responseData); + }); + } + } + }; +#pragma clang diagnostic pop +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSIndexSet *)acceptableStatusCodes { + return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; +} + ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes { + NSMutableIndexSet *mutableStatusCodes = [[NSMutableIndexSet alloc] initWithIndexSet:[self acceptableStatusCodes]]; + [mutableStatusCodes addIndexes:statusCodes]; + AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableStatusCodes), ^(__unused id _self) { + return mutableStatusCodes; + }); +} + ++ (NSSet *)acceptableContentTypes { + return nil; +} + ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes { + NSMutableSet *mutableContentTypes = [[NSMutableSet alloc] initWithSet:[self acceptableContentTypes] copyItems:YES]; + [mutableContentTypes unionSet:contentTypes]; + AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableContentTypes), ^(__unused id _self) { + return mutableContentTypes; + }); +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + if ([[self class] isEqual:[AFHTTPRequestOperation class]]) { + return YES; + } + + return [[self acceptableContentTypes] intersectsSet:AFContentTypesFromHTTPHeader([request valueForHTTPHeaderField:@"Accept"])]; +} + +@end + +#pragma clang diagnostic pop diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h new file mode 100644 index 0000000..d5e6596 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1,113 @@ +// AFImageRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#import +#endif + +/** + `AFImageRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and processing images. + + ## Acceptable Content Types + + By default, `AFImageRequestOperation` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: + + - `image/tiff` + - `image/jpeg` + - `image/gif` + - `image/png` + - `image/ico` + - `image/x-icon` + - `image/bmp` + - `image/x-bmp` + - `image/x-xbitmap` + - `image/x-win-bitmap` + */ +@interface AFImageRequestOperation : AFHTTPRequestOperation + +/** + An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error. + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@property (readonly, nonatomic, strong) UIImage *responseImage; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +@property (readonly, nonatomic, strong) NSImage *responseImage; +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +/** + The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance. + */ +@property (nonatomic, assign) CGFloat imageScale; + +/** + Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default. + */ +@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage; +#endif + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request finishes successfully. This block has no return value and takes a single argument, the image created from the response data of the request. + + @return A new image request operation + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success; +#endif + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param imageProcessingBlock A block object to be executed after the image request finishes successfully, but before the image is returned in the `success` block. This block takes a single argument, the image loaded from the response body, and returns the processed image. + @param success A block object to be executed when the request finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the image created from the response data. + @param failure A block object to be executed when the request finishes unsuccessfully. This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the error associated with the cause for the unsuccessful operation. + + @return A new image request operation + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *image))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *image))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#endif + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m new file mode 100644 index 0000000..7023b37 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m @@ -0,0 +1,321 @@ +// AFImageRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFImageRequestOperation.h" + +static dispatch_queue_t image_request_operation_processing_queue() { + static dispatch_queue_t af_image_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_image_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.image-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_image_request_operation_processing_queue; +} + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import + +static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) { + UIImage *image = [[UIImage alloc] initWithData:data]; + + return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation]; +} + +static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) { + if (!data || [data length] == 0) { + return nil; + } + + UIImage *image = AFImageWithDataAtScale(data, scale); + if (image.images) { + return image; + } + + CGImageRef imageRef = nil; + CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); + + if ([response.MIMEType isEqualToString:@"image/png"]) { + imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) { + imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + } + + if (!imageRef) { + imageRef = CGImageCreateCopy([image CGImage]); + + if (!imageRef) { + CGDataProviderRelease(dataProvider); + return image; + } + } + + CGDataProviderRelease(dataProvider); + + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate() + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + + if (CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { + int alpha = (bitmapInfo & kCGBitmapAlphaInfoMask); + if (alpha == kCGImageAlphaNone) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaNoneSkipFirst; + } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaPremultipliedFirst; + } + } + + CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); + + CGColorSpaceRelease(colorSpace); + + if (!context) { + CGImageRelease(imageRef); + + return image; + } + + CGRect rect = CGRectMake(0.0f, 0.0f, width, height); + CGContextDrawImage(context, rect, imageRef); + CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation]; + CGImageRelease(inflatedImageRef); + CGImageRelease(imageRef); + + return inflatedImage; +} +#endif + +@interface AFImageRequestOperation () +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@property (readwrite, nonatomic, strong) UIImage *responseImage; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +@property (readwrite, nonatomic, strong) NSImage *responseImage; +#endif +@end + +@implementation AFImageRequestOperation +@synthesize responseImage = _responseImage; +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@synthesize imageScale = _imageScale; +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, UIImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, NSImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#endif + + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + UIImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + UIImage *processedImage = imageProcessingBlock(image); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); +#pragma clang diagnostic pop + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + + return requestOperation; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + NSImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + NSImage *processedImage = imageProcessingBlock(image); + + dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + return requestOperation; +} +#endif + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + self.imageScale = [[UIScreen mainScreen] scale]; + self.automaticallyInflatesResponseImage = YES; +#endif + + return self; +} + + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (UIImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + if (self.automaticallyInflatesResponseImage) { + self.responseImage = AFInflatedImageFromResponseWithDataAtScale(self.response, self.responseData, self.imageScale); + } else { + self.responseImage = AFImageWithDataAtScale(self.responseData, self.imageScale); + } + } + + return _responseImage; +} + +- (void)setImageScale:(CGFloat)imageScale { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" + if (imageScale == _imageScale) { + return; + } +#pragma clang diagnostic pop + + _imageScale = imageScale; + + self.responseImage = nil; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +- (NSImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + // Ensure that the image is set to it's correct pixel width and height + NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:self.responseData]; + self.responseImage = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])]; + [self.responseImage addRepresentation:bitimage]; + } + + return _responseImage; +} +#endif + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + static NSSet * _acceptablePathExtension = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _acceptablePathExtension = [[NSSet alloc] initWithObjects:@"tif", @"tiff", @"jpg", @"jpeg", @"gif", @"png", @"ico", @"bmp", @"cur", nil]; + }); + + return [_acceptablePathExtension containsObject:[[request URL] pathExtension]] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + + self.completionBlock = ^ { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + UIImage *image = nil; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + NSImage *image = nil; +#endif + + image = self.responseImage; + + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, image); + }); + } + } + }); + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h new file mode 100644 index 0000000..5493a40 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1,71 @@ +// AFJSONRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFJSONRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with JSON response data. + + ## Acceptable Content Types + + By default, `AFJSONRequestOperation` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types: + + - `application/json` + - `text/json` + + @warning JSON parsing will use the built-in `NSJSONSerialization` class. + */ +@interface AFJSONRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + A JSON object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, strong) id responseJSON; + +/** + Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". + */ +@property (nonatomic, assign) NSJSONReadingOptions JSONReadingOptions; + +///---------------------------------- +/// @name Creating Request Operations +///---------------------------------- + +/** + Creates and returns an `AFJSONRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new JSON request operation + */ ++ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure; + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m new file mode 100644 index 0000000..fffc60c --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m @@ -0,0 +1,150 @@ +// AFJSONRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFJSONRequestOperation.h" + +static dispatch_queue_t json_request_operation_processing_queue() { + static dispatch_queue_t af_json_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_json_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.json-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_json_request_operation_processing_queue; +} + +@interface AFJSONRequestOperation () +@property (readwrite, nonatomic, strong) id responseJSON; +@property (readwrite, nonatomic, strong) NSError *JSONError; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation AFJSONRequestOperation +@synthesize responseJSON = _responseJSON; +@synthesize JSONReadingOptions = _JSONReadingOptions; +@synthesize JSONError = _JSONError; +@dynamic lock; + ++ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure +{ + AFJSONRequestOperation *requestOperation = [(AFJSONRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]); + } + }]; + + return requestOperation; +} + + +- (id)responseJSON { + [self.lock lock]; + if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) { + NSError *error = nil; + + // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. + // See https://github.com/rails/rails/issues/1742 + if (self.responseString && ![self.responseString isEqualToString:@" "]) { + // Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character + // See http://stackoverflow.com/a/12843465/157142 + NSData *data = [self.responseString dataUsingEncoding:NSUTF8StringEncoding]; + + if (data) { + self.responseJSON = [NSJSONSerialization JSONObjectWithData:data options:self.JSONReadingOptions error:&error]; + } else { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:@"Operation responseData failed decoding as a UTF-8 string" forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[NSString stringWithFormat:@"Could not decode string: %@", self.responseString] forKey:NSLocalizedFailureReasonErrorKey]; + error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + + self.JSONError = error; + } + [self.lock unlock]; + + return _responseJSON; +} + +- (NSError *)error { + if (_JSONError) { + return _JSONError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"json"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + + self.completionBlock = ^ { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(json_request_operation_processing_queue(), ^{ + id JSON = self.responseJSON; + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, JSON); + }); + } + } + }); + } + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 100644 index 0000000..714193b --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1,75 @@ +// AFNetworkActivityIndicatorManager.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import + +/** + `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. + + You should enable the shared instance of `AFNetworkActivityIndicatorManager` when your application finishes launching. In `AppDelegate application:didFinishLaunchingWithOptions:` you can do so with the following code: + + [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]; + + By setting `isNetworkActivityIndicatorVisible` to `YES` for `sharedManager`, the network activity indicator will show and hide automatically as requests start and finish. You should not ever need to call `incrementActivityCount` or `decrementActivityCount` yourself. + + See the Apple Human Interface Guidelines section about the Network Activity Indicator for more information: + http://developer.apple.com/library/iOS/#documentation/UserExperience/Conceptual/MobileHIG/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW44 + */ +@interface AFNetworkActivityIndicatorManager : NSObject + +/** + A Boolean value indicating whether the manager is enabled. + + If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO. + */ +@property (nonatomic, assign, getter = isEnabled) BOOL enabled; + +/** + A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. + */ +@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible; + +/** + Returns the shared network activity indicator manager object for the system. + + @return The systemwide network activity indicator manager. + */ ++ (instancetype)sharedManager; + +/** + Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator. + */ +- (void)incrementActivityCount; + +/** + Decrements the number of active network requests. If this number becomes zero before decrementing, this will stop animating the status bar network activity indicator. + */ +- (void)decrementActivityCount; + +@end + +#endif diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m new file mode 100644 index 0000000..68cbd33 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m @@ -0,0 +1,157 @@ +// AFNetworkActivityIndicatorManager.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFNetworkActivityIndicatorManager.h" + +#import "AFHTTPRequestOperation.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.17; + +@interface AFNetworkActivityIndicatorManager () +@property (readwrite, nonatomic, assign) NSInteger activityCount; +@property (readwrite, nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer; +@property (readonly, nonatomic, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; + +- (void)updateNetworkActivityIndicatorVisibility; +- (void)updateNetworkActivityIndicatorVisibilityDelayed; +@end + +@implementation AFNetworkActivityIndicatorManager +@synthesize activityCount = _activityCount; +@synthesize activityIndicatorVisibilityTimer = _activityIndicatorVisibilityTimer; +@synthesize enabled = _enabled; +@dynamic networkActivityIndicatorVisible; + ++ (instancetype)sharedManager { + static AFNetworkActivityIndicatorManager *_sharedManager = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _sharedManager = [[self alloc] init]; + }); + + return _sharedManager; +} + ++ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible { + return [NSSet setWithObject:@"activityCount"]; +} + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidStart:) name:AFNetworkingOperationDidStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil]; + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [_activityIndicatorVisibilityTimer invalidate]; + +} + +- (void)updateNetworkActivityIndicatorVisibilityDelayed { + if (self.enabled) { + // Delay hiding of activity indicator for a short interval, to avoid flickering + if (![self isNetworkActivityIndicatorVisible]) { + [self.activityIndicatorVisibilityTimer invalidate]; + self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes]; + } else { + [self performSelectorOnMainThread:@selector(updateNetworkActivityIndicatorVisibility) withObject:nil waitUntilDone:NO modes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + } + } +} + +- (BOOL)isNetworkActivityIndicatorVisible { + return _activityCount > 0; +} + +- (void)updateNetworkActivityIndicatorVisibility { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]]; +} + +// Not exposed, but used if activityCount is set via KVC. +- (NSInteger)activityCount { + return _activityCount; +} + +- (void)setActivityCount:(NSInteger)activityCount { + @synchronized(self) { + _activityCount = activityCount; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)incrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { + _activityCount++; + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)decrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + _activityCount = MAX(_activityCount - 1, 0); +#pragma clang diagnostic pop + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)networkingOperationDidStart:(NSNotification *)notification { + AFURLConnectionOperation *connectionOperation = [notification object]; + if (connectionOperation.request.URL) { + [self incrementActivityCount]; + } +} + +- (void)networkingOperationDidFinish:(NSNotification *)notification { + AFURLConnectionOperation *connectionOperation = [notification object]; + if (connectionOperation.request.URL) { + [self decrementActivityCount]; + } +} + +@end + +#endif diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworking.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworking.h new file mode 100644 index 0000000..b8f840b --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFNetworking.h @@ -0,0 +1,43 @@ +// AFNetworking.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#ifndef _AFNETWORKING_ + #define _AFNETWORKING_ + + #import "AFURLConnectionOperation.h" + + #import "AFHTTPRequestOperation.h" + #import "AFJSONRequestOperation.h" + #import "AFXMLRequestOperation.h" + #import "AFPropertyListRequestOperation.h" + #import "AFHTTPClient.h" + + #import "AFImageRequestOperation.h" + + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + #import "AFNetworkActivityIndicatorManager.h" + #import "UIImageView+AFNetworking.h" + #endif +#endif /* _AFNETWORKING_ */ diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h new file mode 100644 index 0000000..9ebb605 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1,68 @@ +// AFPropertyListRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFPropertyListRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and deserializing objects with property list (plist) response data. + + ## Acceptable Content Types + + By default, `AFPropertyListRequestOperation` accepts the following MIME types: + + - `application/x-plist` + */ +@interface AFPropertyListRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An object deserialized from a plist constructed using the response data. + */ +@property (readonly, nonatomic) id responsePropertyList; + +///-------------------------------------- +/// @name Managing Property List Behavior +///-------------------------------------- + +/** + One of the `NSPropertyListMutabilityOptions` options, specifying the mutability of objects deserialized from the property list. By default, this is `NSPropertyListImmutable`. + */ +@property (nonatomic, assign) NSPropertyListReadOptions propertyListReadOptions; + +/** + Creates and returns an `AFPropertyListRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the object deserialized from a plist constructed using the response data. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while deserializing the object from a property list. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new property list request operation + */ ++ (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure; + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m new file mode 100644 index 0000000..370e12b --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m @@ -0,0 +1,143 @@ +// AFPropertyListRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFPropertyListRequestOperation.h" + +static dispatch_queue_t property_list_request_operation_processing_queue() { + static dispatch_queue_t af_property_list_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_property_list_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.property-list-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_property_list_request_operation_processing_queue; +} + +@interface AFPropertyListRequestOperation () +@property (readwrite, nonatomic) id responsePropertyList; +@property (readwrite, nonatomic, assign) NSPropertyListFormat propertyListFormat; +@property (readwrite, nonatomic) NSError *propertyListError; +@end + +@implementation AFPropertyListRequestOperation +@synthesize responsePropertyList = _responsePropertyList; +@synthesize propertyListReadOptions = _propertyListReadOptions; +@synthesize propertyListFormat = _propertyListFormat; +@synthesize propertyListError = _propertyListError; + ++ (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure +{ + AFPropertyListRequestOperation *requestOperation = [(AFPropertyListRequestOperation *)[self alloc] initWithRequest:request]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFPropertyListRequestOperation *)operation responsePropertyList]); + } + }]; + + return requestOperation; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + + self.propertyListReadOptions = NSPropertyListImmutable; + + return self; +} + + +- (id)responsePropertyList { + if (!_responsePropertyList && [self.responseData length] > 0 && [self isFinished]) { + NSPropertyListFormat format; + NSError *error = nil; + self.responsePropertyList = [NSPropertyListSerialization propertyListWithData:self.responseData options:self.propertyListReadOptions format:&format error:&error]; + self.propertyListFormat = format; + self.propertyListError = error; + } + + return _responsePropertyList; +} + +- (NSError *)error { + if (_propertyListError) { + return _propertyListError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/x-plist", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"plist"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^ { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(property_list_request_operation_processing_queue(), ^(void) { + id propertyList = self.responsePropertyList; + + if (self.propertyListError) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, propertyList); + }); + } + } + }); + } + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h new file mode 100644 index 0000000..0ac9e10 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1,370 @@ +// AFURLConnectionOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +/** + `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods. + + ## Subclassing Notes + + This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors. + + If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes. + + ## NSURLConnection Delegate Methods + + `AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods: + + - `connection:didReceiveResponse:` + - `connection:didReceiveData:` + - `connectionDidFinishLoading:` + - `connection:didFailWithError:` + - `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:` + - `connection:willCacheResponse:` + - `connectionShouldUseCredentialStorage:` + - `connection:willSendRequestForAuthenticationChallenge:` + + If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first. + + ## Class Constructors + + Class constructors, or methods that return an unowned instance, are the preferred way for subclasses to encapsulate any particular logic for handling the setup or parsing of response data. For instance, `AFJSONRequestOperation` provides `JSONRequestOperationWithRequest:success:failure:`, which takes block arguments, whose parameter on for a successful request is the JSON object initialized from the `response data`. + + ## Callbacks and Completion Blocks + + The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. + + Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/). + + ## SSL Pinning + + Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle. + + SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice. + + When `defaultSSLPinningMode` is defined on `AFHTTPClient` and the Security framework is linked, connections will be validated on all matching certificates with a `.cer` extension in the bundle root. + + ## NSCoding & NSCopying Conformance + + `AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind: + + ### NSCoding Caveats + + - Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`. + - Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged. + + ### NSCopying Caveats + + - `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations. + - A copy of an operation will not include the `outputStream` of the original. + - Operation copies do not include `completionBlock`. `completionBlock` often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied. + */ + +typedef enum { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, +} AFURLConnectionOperationSSLPinningMode; + +@interface AFURLConnectionOperation : NSOperation = 50000) || \ + (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) +NSURLConnectionDataDelegate, +#endif +NSCoding, NSCopying> + +///------------------------------- +/// @name Accessing Run Loop Modes +///------------------------------- + +/** + The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. + */ +@property (nonatomic, strong) NSSet *runLoopModes; + +///----------------------------------------- +/// @name Getting URL Connection Information +///----------------------------------------- + +/** + The request used by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLRequest *request; + +/** + The last response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLResponse *response; + +/** + The error, if any, that occurred in the lifecycle of the request. + */ +@property (readonly, nonatomic, strong) NSError *error; + +/** + Whether the connection should accept an invalid SSL certificate. + + If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`. + */ +@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate; + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + The data received during the request. + */ +@property (readonly, nonatomic, strong) NSData *responseData; + +/** + The string representation of the response data. + */ +@property (readonly, nonatomic, copy) NSString *responseString; + +/** + The string encoding of the response. + + If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`. + */ +@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. + + This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage; + +/** + The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. + + This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. + */ +@property (nonatomic, strong) NSURLCredential *credential; + +/** + The pinning mode which will be used for SSL connections. `AFSSLPinningModePublicKey` by default. + + SSL Pinning requires that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation`" header for more information. + */ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode; + +///------------------------ +/// @name Accessing Streams +///------------------------ + +/** + The input stream used to read data to be sent during the request. + + This property acts as a proxy to the `HTTPBodyStream` property of `request`. + */ +@property (nonatomic, strong) NSInputStream *inputStream; + +/** + The output stream that is used to write data received until the request is finished. + + By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set. + */ +@property (nonatomic, strong) NSOutputStream *outputStream; + +///--------------------------------------------- +/// @name Managing Request Operation Information +///--------------------------------------------- + +/** + The user info dictionary for the receiver. + */ +@property (nonatomic, strong) NSDictionary *userInfo; + +///------------------------------------------------------ +/// @name Initializing an AFURLConnectionOperation Object +///------------------------------------------------------ + +/** + Initializes and returns a newly allocated operation object with a url connection configured with the specified url request. + + This is the designated initializer. + + @param urlRequest The request object to be used by the operation connection. + */ +- (id)initWithRequest:(NSURLRequest *)urlRequest; + +///---------------------------------- +/// @name Pausing / Resuming Requests +///---------------------------------- + +/** + Pauses the execution of the request operation. + + A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect. + */ +- (void)pause; + +/** + Whether the request operation is currently paused. + + @return `YES` if the operation is currently paused, otherwise `NO`. + */ +- (BOOL)isPaused; + +/** + Resumes the execution of the paused request operation. + + Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. + */ +- (void)resume; + +///---------------------------------------------- +/// @name Configuring Backgrounding Task Behavior +///---------------------------------------------- + +/** + Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. + + @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; +#endif + +///--------------------------------- +/// @name Setting Progress Callbacks +///--------------------------------- + +/** + Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; + +/** + Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; + +///------------------------------------------------- +/// @name Setting NSURLConnection Delegate Callbacks +///------------------------------------------------- + +/** + Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`. + + @param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol). + + If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates. + */ +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block; + +/** + Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequest:redirectResponse:`. + + @param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect. + */ +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block; + +/** + Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`. + + @param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request. + */ +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## SSL Pinning Options + + The following constants are provided by `AFURLConnectionOperation` as possible SSL Pinning options. + + enum { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, + } + + `AFSSLPinningModeNone` + Do not pin SSL connections + + `AFSSLPinningModePublicKey` + Pin SSL connections to certificate public key (SPKI). + + `AFSSLPinningModeCertificate` + Pin SSL connections to exact certificate. This may cause problems when your certificate expires and needs re-issuance. + + ## User info dictionary keys + + These keys may exist in the user info dictionary, in addition to those defined for NSError. + + - `NSString * const AFNetworkingOperationFailingURLRequestErrorKey` + - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey` + + ### Constants + + `AFNetworkingOperationFailingURLRequestErrorKey` + The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`. + + `AFNetworkingOperationFailingURLResponseErrorKey` + The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`. + + ## Error Domains + + The following error domain is predefined. + + - `NSString * const AFNetworkingErrorDomain` + + ### Constants + + `AFNetworkingErrorDomain` + AFNetworking errors. Error codes for `AFNetworkingErrorDomain` correspond to codes in `NSURLErrorDomain`. + */ +extern NSString * const AFNetworkingErrorDomain; +extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey; +extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey; + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when an operation begins executing. + */ +extern NSString * const AFNetworkingOperationDidStartNotification; + +/** + Posted when an operation finishes. + */ +extern NSString * const AFNetworkingOperationDidFinishNotification; diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m new file mode 100644 index 0000000..5885369 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m @@ -0,0 +1,862 @@ +// AFURLConnectionOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLConnectionOperation.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +#if !__has_feature(objc_arc) +#error AFNetworking must be built with ARC. +// You can turn on ARC for only AFNetworking files by adding -fobjc-arc to the build phase for each of its files. +#endif + +typedef enum { + AFOperationPausedState = -1, + AFOperationReadyState = 1, + AFOperationExecutingState = 2, + AFOperationFinishedState = 3, +} _AFOperationState; + +typedef signed short AFOperationState; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier; +#else +typedef id AFBackgroundTaskIdentifier; +#endif + +static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock"; + +NSString * const AFNetworkingErrorDomain = @"AFNetworkingErrorDomain"; +NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"AFNetworkingOperationFailingURLRequestErrorKey"; +NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"AFNetworkingOperationFailingURLResponseErrorKey"; + +NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start"; +NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish"; + +typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected); +typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge); +typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse); +typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse); + +static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { + switch (state) { + case AFOperationReadyState: + return @"isReady"; + case AFOperationExecutingState: + return @"isExecuting"; + case AFOperationFinishedState: + return @"isFinished"; + case AFOperationPausedState: + return @"isPaused"; + default: + return @"state"; + } +} + +static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) { + switch (fromState) { + case AFOperationReadyState: + switch (toState) { + case AFOperationPausedState: + case AFOperationExecutingState: + return YES; + case AFOperationFinishedState: + return isCancelled; + default: + return NO; + } + case AFOperationExecutingState: + switch (toState) { + case AFOperationPausedState: + case AFOperationFinishedState: + return YES; + default: + return NO; + } + case AFOperationFinishedState: + return NO; + case AFOperationPausedState: + return toState == AFOperationReadyState; + default: + return YES; + } +} + +#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +static NSData *AFSecKeyGetData(SecKeyRef key) { + CFDataRef data = NULL; + +#if defined(NS_BLOCK_ASSERTIONS) + SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data); +#else + OSStatus status = SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data); + NSCAssert(status == errSecSuccess, @"SecItemExport error: %ld", (long int)status); +#endif + + NSCParameterAssert(data); + + return (__bridge_transfer NSData *)data; +} +#endif + +static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + return [(__bridge id)key1 isEqual:(__bridge id)key2]; +#else + return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)]; +#endif +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, assign) AFOperationState state; +@property (readwrite, nonatomic, assign, getter = isCancelled) BOOL cancelled; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@property (readwrite, nonatomic, strong) NSURLConnection *connection; +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSURLResponse *response; +@property (readwrite, nonatomic, strong) NSError *error; +@property (readwrite, nonatomic, strong) NSData *responseData; +@property (readwrite, nonatomic, copy) NSString *responseString; +@property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding; +@property (readwrite, nonatomic, assign) long long totalBytesRead; +@property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse; + +- (void)operationDidStart; +- (void)finish; +- (void)cancelConnection; +@end + +@implementation AFURLConnectionOperation +@synthesize state = _state; +@synthesize cancelled = _cancelled; +@synthesize connection = _connection; +@synthesize runLoopModes = _runLoopModes; +@synthesize request = _request; +@synthesize response = _response; +@synthesize error = _error; +@synthesize allowsInvalidSSLCertificate = _allowsInvalidSSLCertificate; +@synthesize responseData = _responseData; +@synthesize responseString = _responseString; +@synthesize responseStringEncoding = _responseStringEncoding; +@synthesize totalBytesRead = _totalBytesRead; +@dynamic inputStream; +@synthesize outputStream = _outputStream; +@synthesize credential = _credential; +@synthesize SSLPinningMode = _SSLPinningMode; +@synthesize shouldUseCredentialStorage = _shouldUseCredentialStorage; +@synthesize userInfo = _userInfo; +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier; +@synthesize uploadProgress = _uploadProgress; +@synthesize downloadProgress = _downloadProgress; +@synthesize authenticationChallenge = _authenticationChallenge; +@synthesize cacheResponse = _cacheResponse; +@synthesize redirectResponse = _redirectResponse; +@synthesize lock = _lock; + ++ (void)networkRequestThreadEntryPoint:(id __unused)object { + @autoreleasepool { + [[NSThread currentThread] setName:@"AFNetworking"]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; + [runLoop run]; + } +} + ++ (NSThread *)networkRequestThread { + static NSThread *_networkRequestThread = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; + [_networkRequestThread start]; + }); + + return _networkRequestThread; +} + ++ (NSArray *)pinnedCertificates { + static NSArray *_pinnedCertificates = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *bundle = [NSBundle mainBundle]; + NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; + + NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]]; + for (NSString *path in paths) { + NSData *certificateData = [NSData dataWithContentsOfFile:path]; + [certificates addObject:certificateData]; + } + + _pinnedCertificates = [[NSArray alloc] initWithArray:certificates]; + }); + + return _pinnedCertificates; +} + ++ (NSArray *)pinnedPublicKeys { + static NSArray *_pinnedPublicKeys = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSArray *pinnedCertificates = [self pinnedCertificates]; + NSMutableArray *publicKeys = [NSMutableArray arrayWithCapacity:[pinnedCertificates count]]; + + for (NSData *data in pinnedCertificates) { + SecCertificateRef allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); + NSParameterAssert(allowedCertificate); + + SecCertificateRef allowedCertificates[] = {allowedCertificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustRef allowedTrust = NULL; + OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &allowedTrust); + NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status); + if (status == errSecSuccess && allowedTrust) { + SecTrustResultType result = 0; + status = SecTrustEvaluate(allowedTrust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + if (status == errSecSuccess) { + SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(allowedTrust); + NSParameterAssert(allowedPublicKey); + if (allowedPublicKey) { + [publicKeys addObject:(__bridge_transfer id)allowedPublicKey]; + } + } + + CFRelease(allowedTrust); + } + + CFRelease(policy); + CFRelease(certificates); + CFRelease(allowedCertificate); + } + + _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys]; + }); + + return _pinnedPublicKeys; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + NSParameterAssert(urlRequest); + + self = [super init]; + if (!self) { + return nil; + } + + self.lock = [[NSRecursiveLock alloc] init]; + self.lock.name = kAFNetworkingLockName; + + self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes]; + + self.request = urlRequest; + + self.shouldUseCredentialStorage = YES; + + // #ifdef included for backwards-compatibility +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + self.allowsInvalidSSLCertificate = YES; +#endif + + self.state = AFOperationReadyState; + + return self; +} + +- (void)dealloc { + if (_outputStream) { + [_outputStream close]; + _outputStream = nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + if (_backgroundTaskIdentifier) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +#endif +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response]; +} + +- (void)setCompletionBlock:(void (^)(void))block { + [self.lock lock]; + if (!block) { + [super setCompletionBlock:nil]; + } else { + __weak __typeof(&*self)weakSelf = self; + [super setCompletionBlock:^ { + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + + block(); + [strongSelf setCompletionBlock:nil]; + }]; + } + [self.lock unlock]; +} + +- (NSInputStream *)inputStream { + return self.request.HTTPBodyStream; +} + +- (void)setInputStream:(NSInputStream *)inputStream { + [self willChangeValueForKey:@"inputStream"]; + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + mutableRequest.HTTPBodyStream = inputStream; + self.request = mutableRequest; + [self didChangeValueForKey:@"inputStream"]; +} + +- (NSOutputStream *)outputStream { + if (!_outputStream) { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + + return _outputStream; +} + +- (void)setOutputStream:(NSOutputStream *)outputStream { + [self.lock lock]; + if (outputStream != _outputStream) { + [self willChangeValueForKey:@"outputStream"]; + if (_outputStream) { + [_outputStream close]; + } + _outputStream = outputStream; + [self didChangeValueForKey:@"outputStream"]; + } + [self.lock unlock]; +} + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler { + [self.lock lock]; + if (!self.backgroundTaskIdentifier) { + UIApplication *application = [UIApplication sharedApplication]; + __weak __typeof(&*self)weakSelf = self; + self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + + if (handler) { + handler(); + } + + if (strongSelf) { + [strongSelf cancel]; + + [application endBackgroundTask:strongSelf.backgroundTaskIdentifier]; + strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + }]; + } + [self.lock unlock]; +} +#endif + +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block { + self.uploadProgress = block; +} + +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block { + self.downloadProgress = block; +} + +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block { + self.authenticationChallenge = block; +} + +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block { + self.cacheResponse = block; +} + +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block { + self.redirectResponse = block; +} + +- (void)setState:(AFOperationState)state { + if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) { + return; + } + + [self.lock lock]; + NSString *oldStateKey = AFKeyPathFromOperationState(self.state); + NSString *newStateKey = AFKeyPathFromOperationState(state); + + [self willChangeValueForKey:newStateKey]; + [self willChangeValueForKey:oldStateKey]; + _state = state; + [self didChangeValueForKey:oldStateKey]; + [self didChangeValueForKey:newStateKey]; + [self.lock unlock]; +} + +- (NSString *)responseString { + [self.lock lock]; + if (!_responseString && self.response && self.responseData) { + self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding]; + } + [self.lock unlock]; + + return _responseString; +} + +- (NSStringEncoding)responseStringEncoding { + [self.lock lock]; + if (!_responseStringEncoding && self.response) { + NSStringEncoding stringEncoding = NSUTF8StringEncoding; + if (self.response.textEncodingName) { + CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName); + if (IANAEncoding != kCFStringEncodingInvalidId) { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding); + } + } + + self.responseStringEncoding = stringEncoding; + } + [self.lock unlock]; + + return _responseStringEncoding; +} + +- (void)pause { + if ([self isPaused] || [self isFinished] || [self isCancelled]) { + return; + } + + [self.lock lock]; + + if ([self isExecuting]) { + [self.connection performSelector:@selector(cancel) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); + } + + self.state = AFOperationPausedState; + + [self.lock unlock]; +} + +- (BOOL)isPaused { + return self.state == AFOperationPausedState; +} + +- (void)resume { + if (![self isPaused]) { + return; + } + + [self.lock lock]; + self.state = AFOperationReadyState; + + [self start]; + [self.lock unlock]; +} + +#pragma mark - NSOperation + +- (BOOL)isReady { + return self.state == AFOperationReadyState && [super isReady]; +} + +- (BOOL)isExecuting { + return self.state == AFOperationExecutingState; +} + +- (BOOL)isFinished { + return self.state == AFOperationFinishedState; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (void)start { + [self.lock lock]; + if ([self isReady]) { + self.state = AFOperationExecutingState; + + [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)operationDidStart { + [self.lock lock]; + if (![self isCancelled]) { + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + for (NSString *runLoopMode in self.runLoopModes) { + [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode]; + [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; + } + + [self.connection start]; + } + [self.lock unlock]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self]; + }); + + if ([self isCancelled]) { + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + self.error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; + + [self finish]; + } +} + +- (void)finish { + self.state = AFOperationFinishedState; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); +} + +- (void)cancel { + [self.lock lock]; + if (![self isFinished] && ![self isCancelled]) { + [self willChangeValueForKey:@"isCancelled"]; + _cancelled = YES; + [super cancel]; + [self didChangeValueForKey:@"isCancelled"]; + + // Cancel the connection on the thread it runs on to prevent race conditions + [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)cancelConnection { + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; + + if (![self isFinished] && self.connection) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:error]; + } +} + +#pragma mark - NSURLConnectionDelegate + +- (void)connection:(NSURLConnection *)connection +willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (self.authenticationChallenge) { + self.authenticationChallenge(connection, challenge); + return; + } + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustEvaluate(serverTrust, NULL); + CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); + NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:certificateCount]; + + for (CFIndex i = 0; i < certificateCount; i++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); + + if (self.SSLPinningMode == AFSSLPinningModeCertificate) { + [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; + } else if (self.SSLPinningMode == AFSSLPinningModePublicKey) { + SecCertificateRef someCertificates[] = {certificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); + + SecTrustRef trust = NULL; + + OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust); + NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status); + if (status == errSecSuccess && trust) { + SecTrustResultType result; + status = SecTrustEvaluate(trust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + if (status == errSecSuccess) { + [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; + } + + CFRelease(trust); + } + + CFRelease(certificates); + } + } + + CFRelease(policy); + + switch (self.SSLPinningMode) { + case AFSSLPinningModePublicKey: { + NSArray *pinnedPublicKeys = [self.class pinnedPublicKeys]; + NSAssert([pinnedPublicKeys count] > 0, @"AFSSLPinningModePublicKey needs at least one key file in the application bundle"); + + for (id publicKey in trustChain) { + for (id pinnedPublicKey in pinnedPublicKeys) { + if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)publicKey, (__bridge SecKeyRef)pinnedPublicKey)) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + return; + } + } + } + + NSLog(@"Error: Unknown Public Key during Pinning operation"); + [[challenge sender] cancelAuthenticationChallenge:challenge]; + break; + } + case AFSSLPinningModeCertificate: { + NSAssert([[self.class pinnedCertificates] count] > 0, @"AFSSLPinningModeCertificate needs at least one certificate file in the application bundle"); + for (id serverCertificateData in trustChain) { + if ([[self.class pinnedCertificates] containsObject:serverCertificateData]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + return; + } + } + + NSLog(@"Error: Unknown Certificate during Pinning operation"); + [[challenge sender] cancelAuthenticationChallenge:challenge]; + break; + } + case AFSSLPinningModeNone: { + if (self.allowsInvalidSSLCertificate){ + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + SecTrustResultType result = 0; + OSStatus status = SecTrustEvaluate(serverTrust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + + if (status == errSecSuccess && (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed)) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; + } + } + break; + } + } + } else { + if ([challenge previousFailureCount] == 0) { + if (self.credential) { + [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection { + return self.shouldUseCredentialStorage; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse +{ + if (self.redirectResponse) { + return self.redirectResponse(connection, request, redirectResponse); + } else { + return request; + } +} + +- (void)connection:(NSURLConnection __unused *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + if (self.uploadProgress) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + }); + } +} + +- (void)connection:(NSURLConnection __unused *)connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = response; + + [self.outputStream open]; +} + +- (void)connection:(NSURLConnection __unused *)connection + didReceiveData:(NSData *)data +{ + NSUInteger length = [data length]; + while (YES) { + NSUInteger totalNumberOfBytesWritten = 0; + if ([self.outputStream hasSpaceAvailable]) { + const uint8_t *dataBuffer = (uint8_t *)[data bytes]; + + NSInteger numberOfBytesWritten = 0; + while (totalNumberOfBytesWritten < length) { + numberOfBytesWritten = [self.outputStream write:&dataBuffer[0] maxLength:length]; + if (numberOfBytesWritten == -1) { + break; + } + + totalNumberOfBytesWritten += numberOfBytesWritten; + } + + break; + } + + if (self.outputStream.streamError) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError]; + return; + } + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self.totalBytesRead += length; + + if (self.downloadProgress) { + self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength); + } + }); +} + +- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection { + self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (void)connection:(NSURLConnection __unused *)connection + didFailWithError:(NSError *)error +{ + self.error = error; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + if (self.cacheResponse) { + return self.cacheResponse(connection, cachedResponse); + } else { + if ([self isCancelled]) { + return nil; + } + + return cachedResponse; + } +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + NSURLRequest *request = [aDecoder decodeObjectForKey:@"request"]; + + self = [self initWithRequest:request]; + if (!self) { + return nil; + } + + self.state = (AFOperationState)[aDecoder decodeIntegerForKey:@"state"]; + self.cancelled = [aDecoder decodeBoolForKey:@"isCancelled"]; + self.response = [aDecoder decodeObjectForKey:@"response"]; + self.error = [aDecoder decodeObjectForKey:@"error"]; + self.responseData = [aDecoder decodeObjectForKey:@"responseData"]; + self.totalBytesRead = [[aDecoder decodeObjectForKey:@"totalBytesRead"] longLongValue]; + self.allowsInvalidSSLCertificate = [[aDecoder decodeObjectForKey:@"allowsInvalidSSLCertificate"] boolValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [self pause]; + + [aCoder encodeObject:self.request forKey:@"request"]; + + switch (self.state) { + case AFOperationExecutingState: + case AFOperationPausedState: + [aCoder encodeInteger:AFOperationReadyState forKey:@"state"]; + break; + default: + [aCoder encodeInteger:self.state forKey:@"state"]; + break; + } + + [aCoder encodeBool:[self isCancelled] forKey:@"isCancelled"]; + [aCoder encodeObject:self.response forKey:@"response"]; + [aCoder encodeObject:self.error forKey:@"error"]; + [aCoder encodeObject:self.responseData forKey:@"responseData"]; + [aCoder encodeObject:[NSNumber numberWithLongLong:self.totalBytesRead] forKey:@"totalBytesRead"]; + [aCoder encodeObject:[NSNumber numberWithBool:self.allowsInvalidSSLCertificate] forKey:@"allowsInvalidSSLCertificate"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request]; + + operation.uploadProgress = self.uploadProgress; + operation.downloadProgress = self.downloadProgress; + operation.authenticationChallenge = self.authenticationChallenge; + operation.cacheResponse = self.cacheResponse; + operation.redirectResponse = self.redirectResponse; + operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate; + + return operation; +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h new file mode 100644 index 0000000..4130932 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1,89 @@ +// AFXMLRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +/** + `AFXMLRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with XML response data. + + ## Acceptable Content Types + + By default, `AFXMLRequestOperation` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: + + - `application/xml` + - `text/xml` + + ## Use With AFHTTPClient + + When `AFXMLRequestOperation` is registered with `AFHTTPClient`, the response object in the success callback of `HTTPRequestOperationWithRequest:success:failure:` will be an instance of `NSXMLParser`. On platforms that support `NSXMLDocument`, you have the option to ignore the response object, and simply use the `responseXMLDocument` property of the operation argument of the callback. + */ +@interface AFXMLRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An `NSXMLParser` object constructed from the response data. + */ +@property (readonly, nonatomic, strong) NSXMLParser *responseXMLParser; + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +/** + An `NSXMLDocument` object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, strong) NSXMLDocument *responseXMLDocument; +#endif + +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML parser constructed with the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network error that occurred. + + @return A new XML request operation + */ ++ (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure; + + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML document created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as XML. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new XML request operation + */ ++ (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure; +#endif + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m new file mode 100644 index 0000000..a97cd88 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m @@ -0,0 +1,167 @@ +// AFXMLRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFXMLRequestOperation.h" + +#include + +static dispatch_queue_t xml_request_operation_processing_queue() { + static dispatch_queue_t af_xml_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_xml_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.xml-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_xml_request_operation_processing_queue; +} + +@interface AFXMLRequestOperation () +@property (readwrite, nonatomic, strong) NSXMLParser *responseXMLParser; +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +@property (readwrite, nonatomic, strong) NSXMLDocument *responseXMLDocument; +#endif +@property (readwrite, nonatomic, strong) NSError *XMLError; +@end + +@implementation AFXMLRequestOperation +@synthesize responseXMLParser = _responseXMLParser; +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +@synthesize responseXMLDocument = _responseXMLDocument; +#endif +@synthesize XMLError = _XMLError; + ++ (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure +{ + AFXMLRequestOperation *requestOperation = [(AFXMLRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFXMLRequestOperation *)operation responseXMLParser]); + } + }]; + + return requestOperation; +} + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED ++ (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure +{ + AFXMLRequestOperation *requestOperation = [[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject) { + if (success) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + success(operation.request, operation.response, XMLDocument); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + failure(operation.request, operation.response, error, XMLDocument); + } + }]; + + return requestOperation; +} +#endif + + +- (NSXMLParser *)responseXMLParser { + if (!_responseXMLParser && [self.responseData length] > 0 && [self isFinished]) { + self.responseXMLParser = [[NSXMLParser alloc] initWithData:self.responseData]; + } + + return _responseXMLParser; +} + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +- (NSXMLDocument *)responseXMLDocument { + if (!_responseXMLDocument && [self.responseData length] > 0 && [self isFinished]) { + NSError *error = nil; + self.responseXMLDocument = [[NSXMLDocument alloc] initWithData:self.responseData options:0 error:&error]; + self.XMLError = error; + } + + return _responseXMLDocument; +} +#endif + +- (NSError *)error { + if (_XMLError) { + return _XMLError; + } else { + return [super error]; + } +} + +#pragma mark - NSOperation + +- (void)cancel { + [super cancel]; + + self.responseXMLParser.delegate = nil; +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/xml", @"text/xml", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"xml"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^ { + dispatch_async(xml_request_operation_processing_queue(), ^(void) { + NSXMLParser *XMLParser = self.responseXMLParser; + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, XMLParser); + }); + } + } + }); + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h new file mode 100644 index 0000000..bafb790 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1,78 @@ +// UIImageView+AFNetworking.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFImageRequestOperation.h" + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import + +/** + This category adds methods to the UIKit framework's `UIImageView` class. The methods in this category provide support for loading remote images asynchronously from a URL. + */ +@interface UIImageView (AFNetworking) + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL, and sets it the request is finished. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + */ +- (void)setImageWithURL:(NSURL *)url; + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + */ +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage; + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image with the specified URL request object. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + If a success block is specified, it is the responsibility of the block to set the image of the image view before returning. If no success block is specified, the default behavior of setting the image with `self.image = image` is executed. + + @param urlRequest The URL request used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + @param success A block to be executed when the image request operation finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the request and response parameters will be `nil`. + @param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred. + */ +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; + +/** + Cancels any executing image request operation for the receiver, if one exists. + */ +- (void)cancelImageRequestOperation; + +@end + +#endif diff --git a/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m new file mode 100644 index 0000000..839a2b8 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m @@ -0,0 +1,191 @@ +// UIImageView+AFNetworking.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import "UIImageView+AFNetworking.h" + +@interface AFImageCache : NSCache +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request; +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request; +@end + +#pragma mark - + +static char kAFImageRequestOperationObjectKey; + +@interface UIImageView (_AFNetworking) +@property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFImageRequestOperation *af_imageRequestOperation; +@end + +@implementation UIImageView (_AFNetworking) +@dynamic af_imageRequestOperation; +@end + +#pragma mark - + +@implementation UIImageView (AFNetworking) + +- (AFHTTPRequestOperation *)af_imageRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, &kAFImageRequestOperationObjectKey); +} + +- (void)af_setImageRequestOperation:(AFImageRequestOperation *)imageRequestOperation { + objc_setAssociatedObject(self, &kAFImageRequestOperationObjectKey, imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + ++ (NSOperationQueue *)af_sharedImageRequestOperationQueue { + static NSOperationQueue *_af_imageRequestOperationQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_imageRequestOperationQueue = [[NSOperationQueue alloc] init]; + [_af_imageRequestOperationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; + }); + + return _af_imageRequestOperationQueue; +} + ++ (AFImageCache *)af_sharedImageCache { + static AFImageCache *_af_imageCache = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _af_imageCache = [[AFImageCache alloc] init]; + }); + + return _af_imageCache; +} + +#pragma mark - + +- (void)setImageWithURL:(NSURL *)url { + [self setImageWithURL:url placeholderImage:nil]; +} + +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; + + [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; +} + +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + [self cancelImageRequestOperation]; + + UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest]; + if (cachedImage) { + self.af_imageRequestOperation = nil; + + if (success) { + success(nil, nil, cachedImage); + } else { + self.image = cachedImage; + } + } else { + if (placeholderImage) { + self.image = placeholderImage; + } + + AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest]; + +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + requestOperation.allowsInvalidSSLCertificate = YES; +#endif + + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) { + if (self.af_imageRequestOperation == operation) { + self.af_imageRequestOperation = nil; + } + + if (success) { + success(operation.request, operation.response, responseObject); + } else if (responseObject) { + self.image = responseObject; + } + } + + [[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) { + if (self.af_imageRequestOperation == operation) { + self.af_imageRequestOperation = nil; + } + + if (failure) { + failure(operation.request, operation.response, error); + } + } + }]; + + self.af_imageRequestOperation = requestOperation; + + [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation]; + } +} + +- (void)cancelImageRequestOperation { + [self.af_imageRequestOperation cancel]; + self.af_imageRequestOperation = nil; +} + +@end + +#pragma mark - + +static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) { + return [[request URL] absoluteString]; +} + +@implementation AFImageCache + +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request { + switch ([request cachePolicy]) { + case NSURLRequestReloadIgnoringCacheData: + case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: + return nil; + default: + break; + } + + return [self objectForKey:AFImageCacheKeyFromURLRequest(request)]; +} + +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request +{ + if (image && request) { + [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; + } +} + +@end + +#endif diff --git a/Unit-2-Journal/Pods/AFNetworking/LICENSE b/Unit-2-Journal/Pods/AFNetworking/LICENSE new file mode 100644 index 0000000..0616192 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Unit-2-Journal/Pods/AFNetworking/README.md b/Unit-2-Journal/Pods/AFNetworking/README.md new file mode 100644 index 0000000..da30989 --- /dev/null +++ b/Unit-2-Journal/Pods/AFNetworking/README.md @@ -0,0 +1,206 @@ +

+ AFNetworking +

+ +AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of [NSURLConnection](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html), [NSOperation](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html), and other familiar Foundation technologies. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use. For example, here's how easy it is to get JSON from a URL: + +```objective-c +NSURL *url = [NSURL URLWithString:@"https://alpha-api.app.net/stream/0/posts/stream/global"]; +NSURLRequest *request = [NSURLRequest requestWithURL:url]; +AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { + NSLog(@"App.net Global Stream: %@", JSON); +} failure:nil]; +[operation start]; +``` + +Perhaps the most important feature of all, however, is the amazing community of developers who use and contribute to AFNetworking every day. AFNetworking powers some of the most popular and critically-acclaimed apps on the iPhone, iPad, and Mac. + +Choose AFNetworking for your next project, or migrate over your existing projects—you'll be happy you did! + +## How To Get Started + +- [Download AFNetworking](https://github.com/AFNetworking/AFNetworking/zipball/master) and try out the included Mac and iPhone example apps +- Read the ["Getting Started" guide](https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking), [FAQ](https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ), or [other articles in the wiki](https://github.com/AFNetworking/AFNetworking/wiki) +- Check out the [complete documentation](http://cocoadocs.org/docsets/AFNetworking/) for a comprehensive look at the APIs available in AFNetworking +- Watch the [NSScreencast episode about AFNetworking](http://nsscreencast.com/episodes/6-afnetworking) for a quick introduction to how to use it in your application +- Questions? [Stack Overflow](http://stackoverflow.com/questions/tagged/afnetworking) is the best place to find answers + +## Overview + +AFNetworking is architected to be as small and modular as possible, in order to make it simple to use and extend. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Core
AFURLConnectionOperationAn NSOperation that implements the NSURLConnection delegate methods.
HTTP Requests
AFHTTPRequestOperationA subclass of AFURLConnectionOperation for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
AFJSONRequestOperationA subclass of AFHTTPRequestOperation for downloading and working with JSON response data.
AFXMLRequestOperationA subclass of AFHTTPRequestOperation for downloading and working with XML response data.
AFPropertyListRequestOperationA subclass of AFHTTPRequestOperation for downloading and deserializing objects with property list response data.
HTTP Client
AFHTTPClient + Captures the common patterns of communicating with an web application over HTTP, including: + +
    +
  • Making requests from relative paths of a base URL
  • +
  • Setting HTTP headers to be added automatically to requests
  • +
  • Authenticating requests with HTTP Basic credentials or an OAuth token
  • +
  • Managing an NSOperationQueue for requests made by the client
  • +
  • Generating query strings or HTTP bodies from an NSDictionary
  • +
  • Constructing multipart form requests
  • +
  • Automatically parsing HTTP response data into its corresponding object representation
  • +
  • Monitoring and responding to changes in network reachability
  • +
+
Images
AFImageRequestOperationA subclass of AFHTTPRequestOperation for downloading and processing images.
UIImageView+AFNetworkingAdds methods to UIImageView for loading remote images asynchronously from a URL.
+ +## Example Usage + +### XML Request + +```objective-c +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://api.flickr.com/services/rest/?method=flickr.groups.browse&api_key=b6300e17ad3c506e706cb0072175d047&cat_id=34427469792%40N01&format=rest"]]; +AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) { + XMLParser.delegate = self; + [XMLParser parse]; +} failure:nil]; +[operation start]; +``` + +### Image Request + +```objective-c +UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)]; +[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]]; +``` + +### API Client Request + +```objective-c +// AFAppDotNetAPIClient is a subclass of AFHTTPClient, which defines the base URL and default HTTP headers for NSURLRequests it creates +[[AFAppDotNetAPIClient sharedClient] getPath:@"stream/0/posts/stream/global" parameters:nil success:^(AFHTTPRequestOperation *operation, id JSON) { + NSLog(@"App.net Global Stream: %@", JSON); +} failure:nil]; +``` + +### File Upload with Progress Callback + +```objective-c +NSURL *url = [NSURL URLWithString:@"http://api-base-url.com"]; +AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; +NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"avatar.jpg"], 0.5); +NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:@"/upload" parameters:nil constructingBodyWithBlock: ^(id formData) { + [formData appendPartWithFileData:imageData name:@"avatar" fileName:@"avatar.jpg" mimeType:@"image/jpeg"]; +}]; + +AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { + NSLog(@"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite); +}]; +[httpClient enqueueHTTPRequestOperation:operation]; +``` + +### Streaming Request + +```objective-c +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/encode"]]; + +AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +operation.inputStream = [NSInputStream inputStreamWithFileAtPath:[[NSBundle mainBundle] pathForResource:@"large-image" ofType:@"tiff"]]; +operation.outputStream = [NSOutputStream outputStreamToMemory]; +[operation start]; +``` + +## Requirements + +AFNetworking 1.0 and higher requires either [iOS 5.0](http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html) and above, or [Mac OS 10.7](http://developer.apple.com/library/mac/#releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_6.html#//apple_ref/doc/uid/TP40008898-SW7) ([64-bit with modern Cocoa runtime](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html)) and above. + +For compatibility with iOS 4.3, use the latest 0.10.x release. + +### ARC + +AFNetworking uses ARC as of its 1.0 release. + +If you are using AFNetworking 1.0 in your non-arc project, you will need to set a `-fobjc-arc` compiler flag on all of the AFNetworking source files. Conversely, if you are adding a pre-1.0 version of AFNetworking, you will need to set a `-fno-objc-arc` compiler flag. + +To set a compiler flag in Xcode, go to your active target and select the "Build Phases" tab. Now select all AFNetworking source files, press Enter, insert `-fobjc-arc` or `-fno-objc-arc` and then "Done" to enable or disable ARC for AFNetworking. + +## Unit Tests + +AFNetworking includes a suite of unit tests within the Tests subdirectory. In order to run the unit tests, you must install the testing dependencies via CocoaPods. To do so: + + $ gem install cocoapods # If necessary + $ cd Tests + $ pod install + +Once CocoaPods has finished the installation, you can execute the test suite via the 'iOS Tests' and 'OS X Tests' schemes within Xcode. + +### Test Logging + +By default, the unit tests do not emit any output during execution. For debugging purposes, it can be useful to enable logging of the requests and responses. Logging support is provided by the [AFHTTPRequestOperationLogger](https://github.com/AFNetworking/AFHTTPRequestOperationLogger) extension, which is installed via CocoaPods into the test targets. To enable logging, edit the test Scheme and add an environment variable named `AFTestsLoggingEnabled` with a value of `YES`. + +### Using xctool + +If you wish to execute the tests from the command line or within a continuous integration environment, you will need to install [xctool](https://github.com/facebook/xctool). The recommended installation method is [Homebrew](http://mxcl.github.io/homebrew/). + +To install the commandline testing support via Homebrew: + + $ brew update + $ brew install xctool --HEAD + +Once xctool is installed, you can execute the suite via `rake test`. + +## Credits + +AFNetworking was created by [Scott Raymond](https://github.com/sco/) and [Mattt Thompson](https://github.com/mattt/) in the development of [Gowalla for iPhone](http://en.wikipedia.org/wiki/Gowalla). + +AFNetworking's logo was designed by [Alan Defibaugh](http://www.alandefibaugh.com/). + +And most of all, thanks to AFNetworking's [growing list of contributors](https://github.com/AFNetworking/AFNetworking/contributors). + +## Contact + +Follow AFNetworking on Twitter ([@AFNetworking](https://twitter.com/AFNetworking)) + +### Creators + +[Mattt Thompson](http://github.com/mattt) +[@mattt](https://twitter.com/mattt) + +[Scott Raymond](http://github.com/sco) +[@sco](https://twitter.com/sco) + +## License + +AFNetworking is available under the MIT license. See the LICENSE file for more info. diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationToken.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationToken.h new file mode 100644 index 0000000..90a20d7 --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationToken.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationToken.m new file mode 100644 index 0000000..b5006d0 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationToken.m @@ -0,0 +1,139 @@ +/* + * 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]; + if (millis < -1) { + [NSException raise:NSInvalidArgumentException format:@"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 { + if (self.disposed) { + [NSException raise:NSInternalInconsistencyException format:@"Object already disposed"]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h new file mode 100644 index 0000000..3e7b711 --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m new file mode 100644 index 0000000..9c8a7ae --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h new file mode 100644 index 0000000..bd6e7a1 --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m new file mode 100644 index 0000000..947f725 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m @@ -0,0 +1,60 @@ +/* + * 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 BFCancellationToken (BFCancellationTokenSource) + +- (void)cancel; +- (void)cancelAfterDelay:(int)millis; + +- (void)dispose; +- (void)throwIfDisposed; + +@end + +@implementation BFCancellationTokenSource + +#pragma mark - Initializer + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _token = [BFCancellationToken new]; + + return self; +} + ++ (instancetype)cancellationTokenSource { + return [BFCancellationTokenSource new]; +} + +#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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFDefines.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFDefines.h new file mode 100644 index 0000000..cf7dcdf --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFDefines.h @@ -0,0 +1,18 @@ +/* + * 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 + +#if __has_feature(objc_generics) || __has_extension(objc_generics) +# define BF_GENERIC(type) +#else +# define BF_GENERIC(type) +# define BFGenericType id +#endif diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFExecutor.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFExecutor.h new file mode 100644 index 0000000..02af9ba --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFExecutor.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFExecutor.m new file mode 100644 index 0000000..292e27c --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.h new file mode 100644 index 0000000..827071d --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.h @@ -0,0 +1,259 @@ +/* + * 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 + +/*! + 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; + +/*! + 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 BF_GENERIC(__covariant BFGenericType) : NSObject + +/*! + A block that can act as a continuation for a task. + */ +typedef id(^BFContinuationBlock)(BFTask BF_GENERIC(BFGenericType) *task); + +/*! + Creates a task that is already completed with the given result. + @param result The result for the task. + */ ++ (instancetype)taskWithResult:(BFGenericType)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) BFGenericType 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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.m new file mode 100644 index 0000000..4985cfa --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTask.m @@ -0,0 +1,470 @@ +/* + * 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:^id(BFTask *task) { + return 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 (cancellationToken.cancellationRequested || 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]; + } + + } 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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h new file mode 100644 index 0000000..23366c1 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h @@ -0,0 +1,87 @@ +/* + * 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 + +@class BFTask BF_GENERIC(BFGenericType); + +/*! + 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 BF_GENERIC(__covariant BFGenericType) : NSObject + +/*! + Creates a new unfinished task. + */ ++ (instancetype)taskCompletionSource; + +/*! + The task associated with this TaskCompletionSource. + */ +@property (nonatomic, strong, readonly) BFTask BF_GENERIC(BFGenericType) *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:(BFGenericType)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:(BFGenericType)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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m new file mode 100644 index 0000000..bd66835 --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/Bolts.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/Bolts.h new file mode 100644 index 0000000..35d6c7c --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/Bolts.h @@ -0,0 +1,43 @@ +/* + * 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 +#import + +#if __has_include() && TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV +#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/Unit-2-Journal/Pods/Bolts/Bolts/Common/Bolts.m b/Unit-2-Journal/Pods/Bolts/Bolts/Common/Bolts.m new file mode 100644 index 0000000..9a3e75c --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/Bolts/Common/BoltsVersion.h b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BoltsVersion.h new file mode 100644 index 0000000..afb6fcb --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/Common/BoltsVersion.h @@ -0,0 +1 @@ +#define BOLTS_VERSION @"1.3.0" diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.h new file mode 100644 index 0000000..aa89efc --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.h @@ -0,0 +1,49 @@ +/* + * 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 + +/*! The version of the App Link protocol that this library supports */ +FOUNDATION_EXPORT NSString *const BFAppLinkVersion; + +/*! + Contains App Link metadata relevant for navigation on this device + derived from the HTML at a given URL. + */ +@interface BFAppLink : NSObject + +/*! + Creates a BFAppLink with the given list of BFAppLinkTargets and target URL. + + Generally, this will only be used by implementers of the BFAppLinkResolving protocol, + as these implementers will produce App Link metadata for a given URL. + + @param sourceURL the URL from which this App Link is derived + @param targets an ordered list of BFAppLinkTargets for this platform derived + from App Link metadata. + @param webURL the fallback web URL, if any, for the app link. + */ ++ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL + targets:(NSArray *)targets + webURL:(NSURL *)webURL; + +/*! The URL from which this BFAppLink was derived */ +@property (nonatomic, strong, readonly) NSURL *sourceURL; + +/*! + The ordered list of targets applicable to this platform that will be used + for navigation. + */ +@property (nonatomic, copy, readonly) NSArray *targets; + +/*! The fallback web URL to use if no targets are installed on this device. */ +@property (nonatomic, strong, readonly) NSURL *webURL; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.m new file mode 100644 index 0000000..77fd311 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink.m @@ -0,0 +1,62 @@ +/* + * 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 "BFAppLink_Internal.h" + +NSString *const BFAppLinkDataParameterName = @"al_applink_data"; +NSString *const BFAppLinkTargetKeyName = @"target_url"; +NSString *const BFAppLinkUserAgentKeyName = @"user_agent"; +NSString *const BFAppLinkExtrasKeyName = @"extras"; +NSString *const BFAppLinkRefererAppLink = @"referer_app_link"; +NSString *const BFAppLinkRefererAppName = @"app_name"; +NSString *const BFAppLinkRefererUrl = @"url"; +NSString *const BFAppLinkVersionKeyName = @"version"; +NSString *const BFAppLinkVersion = @"1.0"; + +@interface BFAppLink () + +@property (nonatomic, strong, readwrite) NSURL *sourceURL; +@property (nonatomic, copy, readwrite) NSArray *targets; +@property (nonatomic, strong, readwrite) NSURL *webURL; + +@property (nonatomic, assign, readwrite, getter=isBackToReferrer) BOOL backToReferrer; + +@end + +@implementation BFAppLink + ++ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL + targets:(NSArray *)targets + webURL:(NSURL *)webURL + isBackToReferrer:(BOOL)isBackToReferrer { + BFAppLink *link = [[self alloc] initWithIsBackToReferrer:isBackToReferrer]; + link.sourceURL = sourceURL; + link.targets = [targets copy]; + link.webURL = webURL; + return link; +} + ++ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL + targets:(NSArray *)targets + webURL:(NSURL *)webURL { + return [self appLinkWithSourceURL:sourceURL + targets:targets + webURL:webURL + isBackToReferrer:NO]; +} + +- (BFAppLink *)initWithIsBackToReferrer:(BOOL)backToReferrer { + if ((self = [super init])) { + _backToReferrer = backToReferrer; + } + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.h new file mode 100644 index 0000000..d459f72 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.h @@ -0,0 +1,93 @@ +/* + * 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 + +/*! + The result of calling navigate on a BFAppLinkNavigation + */ +typedef NS_ENUM(NSInteger, BFAppLinkNavigationType) { + /*! Indicates that the navigation failed and no app was opened */ + BFAppLinkNavigationTypeFailure, + /*! Indicates that the navigation succeeded by opening the URL in the browser */ + BFAppLinkNavigationTypeBrowser, + /*! Indicates that the navigation succeeded by opening the URL in an app on the device */ + BFAppLinkNavigationTypeApp +}; + +@protocol BFAppLinkResolving; +@class BFTask; + +/*! + Represents a pending request to navigate to an App Link. Most developers will + simply use navigateToURLInBackground: to open a URL, but developers can build + custom requests with additional navigation and app data attached to them by + creating BFAppLinkNavigations themselves. + */ +@interface BFAppLinkNavigation : NSObject + +/*! + The extras for the AppLinkNavigation. This will generally contain application-specific + data that should be passed along with the request, such as advertiser or affiliate IDs or + other such metadata relevant on this device. + */ +@property (nonatomic, copy, readonly) NSDictionary *extras; + +/*! + The al_applink_data for the AppLinkNavigation. This will generally contain data common to + navigation attempts such as back-links, user agents, and other information that may be used + in routing and handling an App Link request. + */ +@property (nonatomic, copy, readonly) NSDictionary *appLinkData; + +/*! The AppLink to navigate to */ +@property (nonatomic, strong, readonly) BFAppLink *appLink; + +/*! Creates an AppLinkNavigation with the given link, extras, and App Link data */ ++ (instancetype)navigationWithAppLink:(BFAppLink *)appLink + extras:(NSDictionary *)extras + appLinkData:(NSDictionary *)appLinkData; + +/*! Performs the navigation */ +- (BFAppLinkNavigationType)navigate:(NSError **)error; + +/*! Returns a BFAppLink for the given URL */ ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination; + +/*! Returns a BFAppLink for the given URL using the given App Link resolution strategy */ ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination resolver:(id)resolver; + +/*! Navigates to a BFAppLink and returns whether it opened in-app or in-browser */ ++ (BFAppLinkNavigationType)navigateToAppLink:(BFAppLink *)link error:(NSError **)error; + +/*! Navigates to a URL (an asynchronous action) and returns a BFNavigationType */ ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination; + +/*! + Navigates to a URL (an asynchronous action) using the given App Link resolution + strategy and returns a BFNavigationType + */ ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination resolver:(id)resolver; + +/*! + Gets the default resolver to be used for App Link resolution. If the developer has not set one explicitly, + a basic, built-in resolver will be used. + */ ++ (id)defaultResolver; + +/*! + Sets the default resolver to be used for App Link resolution. Setting this to nil will revert the + default resolver to the basic, built-in resolver provided by Bolts. + */ ++ (void)setDefaultResolver:(id)resolver; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.m new file mode 100644 index 0000000..5d287be --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.m @@ -0,0 +1,248 @@ +/* + * 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 "BFAppLinkNavigation.h" +#import "BFTaskCompletionSource.h" +#import "BFAppLinkTarget.h" +#import "BoltsVersion.h" +#import "BFWebViewAppLinkResolver.h" +#import "BFExecutor.h" +#import "BFTask.h" +#import "BFMeasurementEvent_Internal.h" +#import "BFAppLink_Internal.h" + +FOUNDATION_EXPORT NSString *const BFAppLinkDataParameterName; +FOUNDATION_EXPORT NSString *const BFAppLinkTargetKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkUserAgentKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkExtrasKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkVersionKeyName; + +static id defaultResolver; + +@interface BFAppLinkNavigation () + +@property (nonatomic, copy, readwrite) NSDictionary *extras; +@property (nonatomic, copy, readwrite) NSDictionary *appLinkData; +@property (nonatomic, strong, readwrite) BFAppLink *appLink; + +@end + +@implementation BFAppLinkNavigation + ++ (instancetype)navigationWithAppLink:(BFAppLink *)appLink + extras:(NSDictionary *)extras + appLinkData:(NSDictionary *)appLinkData { + BFAppLinkNavigation *navigation = [[self alloc] init]; + navigation.appLink = appLink; + navigation.extras = extras; + navigation.appLinkData = appLinkData; + return navigation; +} + +- (NSString *)stringByEscapingQueryString:(NSString *)string { +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9 + return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; +#else + return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, + (CFStringRef)string, + NULL, + (CFStringRef) @":/?#[]@!$&'()*+,;=", + kCFStringEncodingUTF8)); +#endif +} + +- (NSURL *)appLinkURLWithTargetURL:(NSURL *)targetUrl error:(NSError **)error { + NSMutableDictionary *appLinkData = [NSMutableDictionary dictionaryWithDictionary:self.appLinkData ?: @{}]; + + // Add applink protocol data + if (!appLinkData[BFAppLinkUserAgentKeyName]) { + appLinkData[BFAppLinkUserAgentKeyName] = [NSString stringWithFormat:@"Bolts iOS %@", BOLTS_VERSION]; + } + if (!appLinkData[BFAppLinkVersionKeyName]) { + appLinkData[BFAppLinkVersionKeyName] = BFAppLinkVersion; + } + appLinkData[BFAppLinkTargetKeyName] = [self.appLink.sourceURL absoluteString]; + appLinkData[BFAppLinkExtrasKeyName] = self.extras ?: @{}; + + // JSON-ify the applink data + NSError *jsonError = nil; + NSData *jsonBlob = [NSJSONSerialization dataWithJSONObject:appLinkData options:0 error:&jsonError]; + if (!jsonError) { + NSString *jsonString = [[NSString alloc] initWithData:jsonBlob encoding:NSUTF8StringEncoding]; + NSString *encoded = [self stringByEscapingQueryString:jsonString]; + + NSString *endUrlString = [NSString stringWithFormat:@"%@%@%@=%@", + [targetUrl absoluteString], + targetUrl.query ? @"&" : @"?", + BFAppLinkDataParameterName, + encoded]; + + return [NSURL URLWithString:endUrlString]; + } else { + if (error) { + *error = jsonError; + } + + // If there was an error encoding the app link data, fail hard. + return nil; + } +} + +- (BFAppLinkNavigationType)navigate:(NSError **)error { + NSURL *openedURL = nil; + NSError *encodingError = nil; + BFAppLinkNavigationType retType = BFAppLinkNavigationTypeFailure; + + // Find the first eligible/launchable target in the BFAppLink. + for (BFAppLinkTarget *target in self.appLink.targets) { + NSURL *appLinkAppURL = [self appLinkURLWithTargetURL:target.URL error:&encodingError]; + if (encodingError || !appLinkAppURL) { + if (error) { + *error = encodingError; + } + } else if ([[UIApplication sharedApplication] openURL:appLinkAppURL]) { + retType = BFAppLinkNavigationTypeApp; + openedURL = appLinkAppURL; + break; + } + } + + if (!openedURL && self.appLink.webURL) { + // Fall back to opening the url in the browser if available. + NSURL *appLinkBrowserURL = [self appLinkURLWithTargetURL:self.appLink.webURL error:&encodingError]; + if (encodingError || !appLinkBrowserURL) { + // If there was an error encoding the app link data, fail hard. + if (error) { + *error = encodingError; + } + } else if ([[UIApplication sharedApplication] openURL:appLinkBrowserURL]) { + // This was a browser navigation. + retType = BFAppLinkNavigationTypeBrowser; + openedURL = appLinkBrowserURL; + } + } + + [self postAppLinkNavigateEventNotificationWithTargetURL:openedURL + error:error ? *error : nil + type:retType]; + return retType; +} + +- (void)postAppLinkNavigateEventNotificationWithTargetURL:(NSURL *)outputURL error:(NSError *)error type:(BFAppLinkNavigationType)type { + NSString *const EVENT_YES_VAL = @"1"; + NSString *const EVENT_NO_VAL = @"0"; + NSMutableDictionary *logData = [[NSMutableDictionary alloc] init]; + + NSString *outputURLScheme = [outputURL scheme]; + NSString *outputURLString = [outputURL absoluteString]; + if (outputURLScheme) { + logData[@"outputURLScheme"] = outputURLScheme; + } + if (outputURLString) { + logData[@"outputURL"] = outputURLString; + } + + NSString *sourceURLString = [self.appLink.sourceURL absoluteString]; + NSString *sourceURLHost = [self.appLink.sourceURL host]; + NSString *sourceURLScheme = [self.appLink.sourceURL scheme]; + if (sourceURLString) { + logData[@"sourceURL"] = sourceURLString; + } + if (sourceURLHost) { + logData[@"sourceHost"] = sourceURLHost; + } + if (sourceURLScheme) { + logData[@"sourceScheme"] = sourceURLScheme; + } + if ([error localizedDescription]) { + logData[@"error"] = [error localizedDescription]; + } + NSString *success = nil; //no + NSString *linkType = nil; // unknown; + switch (type) { + case BFAppLinkNavigationTypeFailure: + success = EVENT_NO_VAL; + linkType = @"fail"; + break; + case BFAppLinkNavigationTypeBrowser: + success = EVENT_YES_VAL; + linkType = @"web"; + break; + case BFAppLinkNavigationTypeApp: + success = EVENT_YES_VAL; + linkType = @"app"; + break; + default: + break; + } + if (success) { + logData[@"success"] = success; + } + if (linkType) { + logData[@"type"] = linkType; + } + + if ([self.appLink isBackToReferrer]) { + [BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateBackToReferrerEventName args:logData]; + } else { + [BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateOutEventName args:logData]; + } +} + ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination resolver:(id)resolver { + return [resolver appLinkFromURLInBackground:destination]; +} + ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination { + return [self resolveAppLinkInBackground:destination resolver:[self defaultResolver]]; +} + ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination { + return [self navigateToURLInBackground:destination + resolver:[self defaultResolver]]; +} + ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination + resolver:(id)resolver { + BFTask *resolutionTask = [self resolveAppLinkInBackground:destination + resolver:resolver]; + return [resolutionTask continueWithExecutor:[BFExecutor mainThreadExecutor] + withSuccessBlock:^id(BFTask *task) { + NSError *error = nil; + BFAppLinkNavigationType result = [self navigateToAppLink:task.result + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } else { + return @(result); + } + }]; +} + ++ (BFAppLinkNavigationType)navigateToAppLink:(BFAppLink *)link error:(NSError **)error { + return [[BFAppLinkNavigation navigationWithAppLink:link + extras:nil + appLinkData:nil] navigate:error]; +} + ++ (id)defaultResolver { + if (defaultResolver) { + return defaultResolver; + } + return [BFWebViewAppLinkResolver sharedInstance]; +} + ++ (void)setDefaultResolver:(id)resolver { + defaultResolver = resolver; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkResolving.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkResolving.h new file mode 100644 index 0000000..b67bdba --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkResolving.h @@ -0,0 +1,30 @@ +/* + * 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; + +/*! + Implement this protocol to provide an alternate strategy for resolving + App Links that may include pre-fetching, caching, or querying for App Link + data from an index provided by a service provider. + */ +@protocol BFAppLinkResolving + +/*! + Asynchronously resolves App Link data for a given URL. + + @param url The URL to resolve into an App Link. + @returns A BFTask that will return a BFAppLink for the given URL. + */ +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.h new file mode 100644 index 0000000..d19465e --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.h @@ -0,0 +1,87 @@ +/* + * 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 + +@class BFAppLink; +@class BFAppLinkReturnToRefererController; + +/*! + Protocol that a class can implement in order to be notified when the user has navigated back + to the referer of an App Link. + */ +@protocol BFAppLinkReturnToRefererControllerDelegate + +@optional + +/*! Called when the user has tapped to navigate, but before the navigation has been performed. */ +- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller + willNavigateToAppLink:(BFAppLink *)appLink; + +/*! Called after the navigation has been attempted, with an indication of whether the referer + app link was successfully opened. */ +- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller + didNavigateToAppLink:(BFAppLink *)url + type:(BFAppLinkNavigationType)type; + +@end + +/*! + A controller class that implements default behavior for a BFAppLinkReturnToRefererView, including + the ability to display the view above the navigation bar for navigation-based apps. + */ +@interface BFAppLinkReturnToRefererController : NSObject + +/*! + The delegate that will be notified when the user navigates back to the referer. + */ +@property (nonatomic, weak) id delegate; + +/*! + The BFAppLinkReturnToRefererView this controller is controlling. + */ +@property (nonatomic, strong) BFAppLinkReturnToRefererView *view; + +/*! + Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView that is to be displayed + contained within another UIView (i.e., not displayed above the navigation bar). + */ +- (instancetype)init; + +/*! + Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView that is to be displayed + displayed above the navigation bar. + */ +- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController; + +/*! + Removes the view entirely from the navigation controller it is currently displayed in. + */ +- (void)removeFromNavController; + +/*! + Shows the BFAppLinkReturnToRefererView with the specified referer information. If nil or missing data, + the view will not be displayed. */ +- (void)showViewForRefererAppLink:(BFAppLink *)refererAppLink; + +/*! + Shows the BFAppLinkReturnToRefererView with referer information extracted from the specified URL. + If nil or missing referer App Link data, the view will not be displayed. */ +- (void)showViewForRefererURL:(NSURL *)url; + +/*! + Closes the view, possibly animating it. + */ +- (void)closeViewAnimated:(BOOL)animated; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.m new file mode 100644 index 0000000..d380635 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.m @@ -0,0 +1,230 @@ +/* + * 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 "BFAppLinkReturnToRefererController.h" + +#import "BFAppLink.h" +#import "BFAppLinkReturnToRefererView_Internal.h" +#import "BFURL_Internal.h" + +static const CFTimeInterval kBFViewAnimationDuration = 0.25f; + +@implementation BFAppLinkReturnToRefererController { + UINavigationController *_navigationController; + BFAppLinkReturnToRefererView *_view; +} + +#pragma mark - Object lifecycle + +- (instancetype)init { + return [self initForDisplayAboveNavController:nil]; +} + +- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController { + self = [super init]; + if (self) { + _navigationController = navController; + + if (_navigationController != nil) { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(statusBarFrameWillChange:) + name:UIApplicationWillChangeStatusBarFrameNotification + object:nil]; + [nc addObserver:self + selector:@selector(statusBarFrameDidChange:) + name:UIApplicationDidChangeStatusBarFrameNotification + object:nil]; + [nc addObserver:self + selector:@selector(orientationDidChange:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + } + } + return self; +} + +- (void)dealloc { + _view.delegate = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Public API + +- (BFAppLinkReturnToRefererView *)view { + if (!_view) { + self.view = [[BFAppLinkReturnToRefererView alloc] initWithFrame:CGRectZero]; + if (_navigationController) { + [_navigationController.view addSubview:_view]; + } + } + return _view; +} + +- (void)setView:(BFAppLinkReturnToRefererView *)view { + if (_view != view) { + _view.delegate = nil; + } + + _view = view; + _view.delegate = self; + + if (_navigationController) { + _view.includeStatusBarInSize = BFIncludeStatusBarInSizeAlways; + } +} + +- (void)showViewForRefererAppLink:(BFAppLink *)refererAppLink { + self.view.refererAppLink = refererAppLink; + + [_view sizeToFit]; + + if (_navigationController) { + if (!_view.closed) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self moveNavigationBar]; + }); + } + } +} + +- (void)showViewForRefererURL:(NSURL *)url { + BFAppLink *appLink = [BFURL URLForRenderBackToReferrerBarURL:url].appLinkReferer; + [self showViewForRefererAppLink:appLink]; +} + +- (void)removeFromNavController { + if (_navigationController) { + [_view removeFromSuperview]; + _navigationController = nil; + } +} + +#pragma mark - BFAppLinkReturnToRefererViewDelegate + +- (void)returnToRefererViewDidTapInsideCloseButton:(BFAppLinkReturnToRefererView *)view { + [self closeViewAnimated:YES explicitlyClosed:YES]; +} + +- (void)returnToRefererViewDidTapInsideLink:(BFAppLinkReturnToRefererView *)view + link:(BFAppLink *)link { + [self openRefererAppLink:link]; + [self closeViewAnimated:NO explicitlyClosed:NO]; +} + +#pragma mark - Private + +- (void)statusBarFrameWillChange:(NSNotification *)notification { + NSValue *rectValue = [[notification userInfo] valueForKey:UIApplicationStatusBarFrameUserInfoKey]; + CGRect newFrame; + [rectValue getValue:&newFrame]; + + if (_navigationController && !_view.closed) { + if (CGRectGetHeight(newFrame) == 40) { + UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState; + [UIView animateWithDuration:kBFViewAnimationDuration delay:0.0 options:options animations:^{ + _view.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(_view.bounds), 0.0); + } completion:nil]; + } + } +} + +- (void)statusBarFrameDidChange:(NSNotification *)notification { + NSValue *rectValue = [[notification userInfo] valueForKey:UIApplicationStatusBarFrameUserInfoKey]; + CGRect newFrame; + [rectValue getValue:&newFrame]; + + if (_navigationController && !_view.closed) { + if (CGRectGetHeight(newFrame) == 40) { + UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState; + [UIView animateWithDuration:kBFViewAnimationDuration delay:0.0 options:options animations:^{ + [_view sizeToFit]; + [self moveNavigationBar]; + } completion:nil]; + } + } +} + +- (void)orientationDidChange:(NSNotificationCenter *)notification { + if (_navigationController && !_view.closed && CGRectGetHeight(_view.bounds) > 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self moveNavigationBar]; + }); + } +} + +- (void)moveNavigationBar { + if (_view.closed || !_view.refererAppLink) { + return; + } + + [self updateNavigationBarY:CGRectGetHeight(_view.bounds)]; +} + +- (void)updateNavigationBarY:(CGFloat)y { + UINavigationBar *navigationBar = _navigationController.navigationBar; + CGRect navigationBarFrame = navigationBar.frame; + CGFloat oldContainerViewY = CGRectGetMaxY(navigationBarFrame); + navigationBarFrame.origin.y = y; + navigationBar.frame = navigationBarFrame; + + CGFloat dy = CGRectGetMaxY(navigationBarFrame) - oldContainerViewY; + UIView *containerView = _navigationController.visibleViewController.view.superview; + containerView.frame = UIEdgeInsetsInsetRect(containerView.frame, UIEdgeInsetsMake(dy, 0.0, 0.0, 0.0)); +} + +- (void)closeViewAnimated:(BOOL)animated { + [self closeViewAnimated:animated explicitlyClosed:YES]; +} + +- (void)closeViewAnimated:(BOOL)animated explicitlyClosed:(BOOL)explicitlyClosed { + void (^closer)(void) = ^{ + if (_navigationController) { + [self updateNavigationBarY:_view.statusBarHeight]; + } + + CGRect frame = _view.frame; + frame.size.height = 0.0; + _view.frame = frame; + }; + + if (animated) { + [UIView animateWithDuration:kBFViewAnimationDuration animations:^{ + closer(); + } completion:^(BOOL finished) { + if (explicitlyClosed) { + _view.closed = YES; + } + }]; + } else { + closer(); + if (explicitlyClosed) { + _view.closed = YES; + } + } +} + +- (void)openRefererAppLink:(BFAppLink *)refererAppLink { + if (refererAppLink) { + id delegate = _delegate; + if ([delegate respondsToSelector:@selector(returnToRefererController:willNavigateToAppLink:)]) { + [delegate returnToRefererController:self willNavigateToAppLink:refererAppLink]; + } + + NSError *error = nil; + BFAppLinkNavigationType type = [BFAppLinkNavigation navigateToAppLink:refererAppLink error:&error]; + + if ([delegate respondsToSelector:@selector(returnToRefererController:didNavigateToAppLink:type:)]) { + [delegate returnToRefererController:self didNavigateToAppLink:refererAppLink type:type]; + } + } +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.h new file mode 100644 index 0000000..d20f73a --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.h @@ -0,0 +1,77 @@ +/* + * 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 + +@class BFAppLinkReturnToRefererView; +@class BFURL; + +typedef NS_ENUM(NSUInteger, BFIncludeStatusBarInSize) { + BFIncludeStatusBarInSizeNever, + BFIncludeStatusBarInSizeIOS7AndLater, + BFIncludeStatusBarInSizeAlways, +}; + +/*! + Protocol that a class can implement in order to be notified when the user has navigated back + to the referer of an App Link. + */ +@protocol BFAppLinkReturnToRefererViewDelegate + +/*! + Called when the user has tapped inside the close button. + */ +- (void)returnToRefererViewDidTapInsideCloseButton:(BFAppLinkReturnToRefererView *)view; + +/*! + Called when the user has tapped inside the App Link portion of the view. + */ +- (void)returnToRefererViewDidTapInsideLink:(BFAppLinkReturnToRefererView *)view + link:(BFAppLink *)link; + +@end + +/*! + Provides a UIView that displays a button allowing users to navigate back to the + application that launched the App Link currently being handled, if the App Link + contained referer data. The user can also close the view by clicking a close button + rather than navigating away. If the view is provided an App Link that does not contain + referer data, it will have zero size and no UI will be displayed. + */ +@interface BFAppLinkReturnToRefererView : UIView + +/*! + The delegate that will be notified when the user navigates back to the referer. + */ +@property (nonatomic, weak) id delegate; + +/*! + The color of the text label and close button. + */ +@property (nonatomic, strong) UIColor *textColor; + +@property (nonatomic, strong) BFAppLink *refererAppLink; + +/*! + Indicates whether to extend the size of the view to include the current status bar + size, for use in scenarios where the view might extend under the status bar on iOS 7 and + above; this property has no effect on earlier versions of iOS. + */ +@property (nonatomic, assign) BFIncludeStatusBarInSize includeStatusBarInSize; + +/*! + Indicates whether the user has closed the view by clicking the close button. + */ +@property (nonatomic, assign) BOOL closed; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.m new file mode 100644 index 0000000..2a1021d --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.m @@ -0,0 +1,269 @@ +/* + * 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 "BFAppLinkReturnToRefererView.h" + +#import "BFAppLink.h" +#import "BFAppLinkTarget.h" + +static const CGFloat BFMarginX = 8.5f; +static const CGFloat BFMarginY = 8.5f; + +static NSString *const BFRefererAppLink = @"referer_app_link"; +static NSString *const BFRefererAppName = @"app_name"; +static NSString *const BFRefererUrl = @"url"; +static const CGFloat BFCloseButtonWidth = 12.0; +static const CGFloat BFCloseButtonHeight = 12.0; + +@interface BFAppLinkReturnToRefererView () + +@property (nonatomic, strong) UILabel *labelView; +@property (nonatomic, strong) UIButton *closeButton; +@property (nonatomic, strong) UITapGestureRecognizer *insideTapGestureRecognizer; +@property (nonatomic, strong) UIView *viewToMoveWithNavController; + +@end + +@implementation BFAppLinkReturnToRefererView { + BOOL _explicitlyHidden; +} + +#pragma mark - Initialization + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self commonInit]; + [self sizeToFit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + [self commonInit]; + } + return self; +} + +- (void)commonInit { + // Initialization code + _includeStatusBarInSize = BFIncludeStatusBarInSizeIOS7AndLater; + + // iOS 7 system blue color + self.backgroundColor = [UIColor colorWithRed:0.0f green:122.0f / 255.0f blue:1.0f alpha:1.0f]; + self.textColor = [UIColor whiteColor]; + self.clipsToBounds = YES; + + [self initViews]; +} + +- (void)initViews { + if (!_labelView && !_closeButton) { + _closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _closeButton.backgroundColor = [UIColor clearColor]; + _closeButton.userInteractionEnabled = YES; + _closeButton.clipsToBounds = YES; + _closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; + _closeButton.contentMode = UIViewContentModeCenter; + [_closeButton addTarget:self action:@selector(closeButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + [self addSubview:_closeButton]; + + _labelView = [[UILabel alloc] initWithFrame:CGRectZero]; + _labelView.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]]; + _labelView.textColor = [UIColor whiteColor]; + _labelView.backgroundColor = [UIColor clearColor]; +#ifdef __IPHONE_6_0 + _labelView.textAlignment = NSTextAlignmentCenter; +#else + _labelView.textAlignment = UITextAlignmentCenter; +#endif + _labelView.clipsToBounds = YES; + [self updateLabelText]; + [self addSubview:_labelView]; + + _insideTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapInside:)]; + _labelView.userInteractionEnabled = YES; + [_labelView addGestureRecognizer:_insideTapGestureRecognizer]; + + [self updateColors]; + } +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize { + CGSize size = self.bounds.size; + if (_closed || !self.hasRefererData) { + size.height = 0.0; + } else { + CGSize labelSize = [_labelView sizeThatFits:size]; + size = CGSizeMake(size.width, labelSize.height + 2 * BFMarginY + self.statusBarHeight); + } + return size; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGRect bounds = self.bounds; + + _labelView.preferredMaxLayoutWidth = _labelView.bounds.size.width; + CGSize labelSize = [_labelView sizeThatFits:bounds.size]; + _labelView.frame = CGRectMake(BFMarginX, + CGRectGetMaxY(bounds) - labelSize.height - 1.5f * BFMarginY, + CGRectGetMaxX(bounds) - BFCloseButtonWidth - 3 * BFMarginX, + labelSize.height + BFMarginY); + + _closeButton.frame = CGRectMake(CGRectGetMaxX(bounds) - BFCloseButtonWidth - 2 * BFMarginX, + _labelView.center.y - BFCloseButtonHeight / 2.0f - BFMarginY, + BFCloseButtonWidth + 2 * BFMarginX, + BFCloseButtonHeight + 2 * BFMarginY); +} + +- (CGSize)sizeThatFits:(CGSize)size { + if (_closed || !self.hasRefererData) { + size = CGSizeMake(size.width, 0.0); + } else { + CGSize labelSize = [_labelView sizeThatFits:size]; + size = CGSizeMake(size.width, labelSize.height + 2 * BFMarginY + self.statusBarHeight); + } + return size; +} + +- (CGFloat)statusBarHeight { + UIApplication *application = [UIApplication sharedApplication]; + + BOOL include; + switch (_includeStatusBarInSize) { + case BFIncludeStatusBarInSizeAlways: + include = YES; + break; + case BFIncludeStatusBarInSizeIOS7AndLater: { + float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; + include = (systemVersion >= 7.0); + break; + } + case BFIncludeStatusBarInSizeNever: + include = NO; + break; + } + if (include && !application.statusBarHidden) { + BOOL landscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation); + CGRect statusBarFrame = application.statusBarFrame; + return landscape ? CGRectGetWidth(statusBarFrame) : CGRectGetHeight(statusBarFrame); + } + + return 0; +} + +#pragma mark - Public API + +- (void)setIncludeStatusBarInSize:(BFIncludeStatusBarInSize)includeStatusBarInSize { + _includeStatusBarInSize = includeStatusBarInSize; + [self setNeedsLayout]; + [self invalidateIntrinsicContentSize]; +} + +- (void)setTextColor:(UIColor *)textColor { + _textColor = textColor; + [self updateColors]; +} + +- (void)setRefererAppLink:(BFAppLink *)refererAppLink { + _refererAppLink = refererAppLink; + [self updateLabelText]; + [self updateHidden]; + [self invalidateIntrinsicContentSize]; +} + +- (void)setClosed:(BOOL)closed { + if (_closed != closed) { + _closed = closed; + [self updateHidden]; + [self invalidateIntrinsicContentSize]; + } +} + +- (void)setHidden:(BOOL)hidden { + _explicitlyHidden = hidden; + [self updateHidden]; +} + +#pragma mark - Private + +- (void)updateLabelText { + NSString *appName = (_refererAppLink && _refererAppLink.targets[0]) ? [_refererAppLink.targets[0] appName] : nil; + _labelView.text = [self localizedLabelForReferer:appName]; +} + +- (void)updateColors { + UIImage *closeButtonImage = [self drawCloseButtonImageWithColor:_textColor]; + + _labelView.textColor = _textColor; + [_closeButton setImage:closeButtonImage forState:UIControlStateNormal]; +} + +- (UIImage *)drawCloseButtonImageWithColor:(UIColor *)color { + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(BFCloseButtonWidth, BFCloseButtonHeight), NO, 0.0f); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetStrokeColorWithColor(context, [color CGColor]); + CGContextSetFillColorWithColor(context, [color CGColor]); + + CGContextSetLineWidth(context, 1.25f); + + CGFloat inset = 0.5f; + + CGContextMoveToPoint(context, inset, inset); + CGContextAddLineToPoint(context, BFCloseButtonWidth - inset, BFCloseButtonHeight - inset); + CGContextStrokePath(context); + + CGContextMoveToPoint(context, BFCloseButtonWidth - inset, inset); + CGContextAddLineToPoint(context, inset, BFCloseButtonHeight - inset); + CGContextStrokePath(context); + + UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return result; +} + +- (NSString *)localizedLabelForReferer:(NSString *)refererName { + if (!refererName) { + return nil; + } + + NSString *format = NSLocalizedString(@"Touch to return to %1$@", @"Format for the string to return to a calling app."); + + return [NSString stringWithFormat:format, refererName]; +} + +- (BOOL)hasRefererData { + return _refererAppLink && _refererAppLink.targets[0]; +} + +- (void)closeButtonTapped:(id)sender { + [_delegate returnToRefererViewDidTapInsideCloseButton:self]; +} + +- (void)onTapInside:(UIGestureRecognizer *)sender { + [_delegate returnToRefererViewDidTapInsideLink:self link:_refererAppLink]; +} + +- (void)updateHidden { + [super setHidden:_explicitlyHidden || _closed || !self.hasRefererData]; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h new file mode 100644 index 0000000..8b85823 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h @@ -0,0 +1,17 @@ +/* + * 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 + +@interface BFAppLinkReturnToRefererView (Internal) + +- (CGFloat)statusBarHeight; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.h new file mode 100644 index 0000000..6172126 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.h @@ -0,0 +1,33 @@ +/* + * 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 a target defined in App Link metadata, consisting of at least + a URL, and optionally an App Store ID and name. + */ +@interface BFAppLinkTarget : NSObject + +/*! Creates a BFAppLinkTarget with the given app site and target URL. */ ++ (instancetype)appLinkTargetWithURL:(NSURL *)url + appStoreId:(NSString *)appStoreId + appName:(NSString *)appName; + +/*! The URL prefix for this app link target */ +@property (nonatomic, strong, readonly) NSURL *URL; + +/*! The app ID for the app store */ +@property (nonatomic, copy, readonly) NSString *appStoreId; + +/*! The name of the app */ +@property (nonatomic, copy, readonly) NSString *appName; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.m new file mode 100644 index 0000000..5518cba --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.m @@ -0,0 +1,33 @@ +/* + * 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 "BFAppLinkTarget.h" + +@interface BFAppLinkTarget () + +@property (nonatomic, strong, readwrite) NSURL *URL; +@property (nonatomic, copy, readwrite) NSString *appStoreId; +@property (nonatomic, copy, readwrite) NSString *appName; + +@end + +@implementation BFAppLinkTarget + ++ (instancetype)appLinkTargetWithURL:(NSURL *)url + appStoreId:(NSString *)appStoreId + appName:(NSString *)appName { + BFAppLinkTarget *target = [[self alloc] init]; + target.URL = url; + target.appStoreId = appStoreId; + target.appName = appName; + return target; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink_Internal.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink_Internal.h new file mode 100644 index 0000000..6644b90 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFAppLink_Internal.h @@ -0,0 +1,23 @@ +/* + * 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 + +@interface BFAppLink (Internal) + ++ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL + targets:(NSArray *)targets + webURL:(NSURL *)webURL + isBackToReferrer:(BOOL)isBackToReferrer; + +/*! return if this AppLink is to go back to referrer. */ +@property (nonatomic, assign, readonly, getter=isBackToReferrer) BOOL backToReferrer; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.h new file mode 100644 index 0000000..b3173fc --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.h @@ -0,0 +1,45 @@ +/* + * 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 + +/*! The name of the notification posted by BFMeasurementEvent */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventNotificationName; + +/*! Defines keys in the userInfo object for the notification named BFMeasurementEventNotificationName */ +/*! The string field for the name of the event */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventNameKey; +/*! The dictionary field for the arguments of the event */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventArgsKey; + +/*! Bolts Events raised by BFMeasurementEvent for Applink */ +/*! + The name of the event posted when [BFURL URLWithURL:] is called successfully. This represents the successful parsing of an app link URL. + */ +FOUNDATION_EXPORT NSString *const BFAppLinkParseEventName; + +/*! + The name of the event posted when [BFURL URLWithInboundURL:] is called successfully. + This represents parsing an inbound app link URL from a different application + */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateInEventName; + +/*! The event raised when the user navigates from your app to other apps */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateOutEventName; + +/*! + The event raised when the user navigates out from your app and back to the referrer app. + e.g when the user leaves your app after tapping the back-to-referrer navigation bar + */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateBackToReferrerEventName; + +@interface BFMeasurementEvent : NSObject + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.m new file mode 100644 index 0000000..e3e6cde --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.m @@ -0,0 +1,62 @@ +/* + * 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 "BFMeasurementEvent_Internal.h" + +NSString *const BFMeasurementEventNotificationName = @"com.parse.bolts.measurement_event"; + +NSString *const BFMeasurementEventNameKey = @"event_name"; +NSString *const BFMeasurementEventArgsKey = @"event_args"; + +/* app Link Event raised by this BFURL */ +NSString *const BFAppLinkParseEventName = @"al_link_parse"; +NSString *const BFAppLinkNavigateInEventName = @"al_nav_in"; + +/*! AppLink events raised in this class */ +NSString *const BFAppLinkNavigateOutEventName = @"al_nav_out"; +NSString *const BFAppLinkNavigateBackToReferrerEventName = @"al_ref_back_out"; + +__attribute__((noinline)) void warnOnMissingEventName() { + NSLog(@"Warning: Missing event name when logging bolts measurement event. \n" + " Ignoring this event in logging."); +} + +@implementation BFMeasurementEvent { + NSString *_name; + NSDictionary *_args; +} + +- (void)postNotification { + if (!_name) { + warnOnMissingEventName(); + return; + } + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + NSDictionary *userInfo = @{BFMeasurementEventNameKey : _name, + BFMeasurementEventArgsKey : _args}; + + [center postNotificationName:BFMeasurementEventNotificationName + object:self + userInfo:userInfo]; +} + +- (instancetype)initEventWithName:(NSString *)name args:(NSDictionary *)args { + if ((self = [super init])) { + _name = name; + _args = args ? args : @{}; + } + return self; +} + ++ (void)postNotificationForEventName:(NSString *)name args:(NSDictionary *)args { + [[[self alloc] initEventWithName:name args:args] postNotification]; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent_Internal.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent_Internal.h new file mode 100644 index 0000000..7d46fd0 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFMeasurementEvent_Internal.h @@ -0,0 +1,19 @@ +/* + * 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 +/*! + Provides methods for posting notifications from the Bolts framework + */ +@interface BFMeasurementEvent (Internal) + ++ (void)postNotificationForEventName:(NSString *)name args:(NSDictionary *)args; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.h new file mode 100644 index 0000000..924c91d --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.h @@ -0,0 +1,75 @@ +/* + * 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 BFAppLink; + +/*! + Provides a set of utilities for working with NSURLs, such as parsing of query parameters + and handling for App Link requests. + */ +@interface BFURL : NSObject + +/*! + Creates a link target from a raw URL. + On success, this posts the BFAppLinkParseEventName measurement event. If you are constructing the BFURL within your application delegate's + application:openURL:sourceApplication:annotation:, you should instead use URLWithInboundURL:sourceApplication: + to support better BFMeasurementEvent notifications + @param url The instance of `NSURL` to create BFURL from. + */ ++ (BFURL *)URLWithURL:(NSURL *)url; + +/*! + Creates a link target from a raw URL received from an external application. This is typically called from the app delegate's + application:openURL:sourceApplication:annotation: and will post the BFAppLinkNavigateInEventName measurement event. + @param url The instance of `NSURL` to create BFURL from. + @param sourceApplication the bundle ID of the app that is requesting your app to open the URL. The same sourceApplication in application:openURL:sourceApplication:annotation: + */ ++ (BFURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication; + +/*! + Gets the target URL. If the link is an App Link, this is the target of the App Link. + Otherwise, it is the url that created the target. + */ +@property (nonatomic, strong, readonly) NSURL *targetURL; + +/*! + Gets the query parameters for the target, parsed into an NSDictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *targetQueryParameters; + +/*! + If this link target is an App Link, this is the data found in al_applink_data. + Otherwise, it is nil. + */ +@property (nonatomic, strong, readonly) NSDictionary *appLinkData; + +/*! + If this link target is an App Link, this is the data found in extras. + */ +@property (nonatomic, strong, readonly) NSDictionary *appLinkExtras; + +/*! + The App Link indicating how to navigate back to the referer app, if any. + */ +@property (nonatomic, strong, readonly) BFAppLink *appLinkReferer; + +/*! + The URL that was used to create this BFURL. + */ +@property (nonatomic, strong, readonly) NSURL *inputURL; + +/*! + The query parameters of the inputURL, parsed into an NSDictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *inputQueryParameters; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.m new file mode 100644 index 0000000..e8f2676 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL.m @@ -0,0 +1,149 @@ +/* + * 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 "BFURL_Internal.h" +#import "BFAppLink_Internal.h" +#import "BFAppLinkTarget.h" +#import "BFMeasurementEvent_Internal.h" + +FOUNDATION_EXPORT NSString *const BFAppLinkDataParameterName; +FOUNDATION_EXPORT NSString *const BFAppLinkTargetKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkUserAgentKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkExtrasKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkVersionKeyName; +FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppLink; +FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppName; +FOUNDATION_EXPORT NSString *const BFAppLinkRefererUrl; + +@implementation BFURL + +- (instancetype)initWithURL:(NSURL *)url forOpenInboundURL:(BOOL)forOpenURLEvent sourceApplication:(NSString *)sourceApplication forRenderBackToReferrerBar:(BOOL)forRenderBackToReferrerBar { + if (self = [super init]) { + _inputURL = url; + _targetURL = url; + + // Parse the query string parameters for the base URL + NSDictionary *baseQuery = [BFURL queryParametersForURL:url]; + _inputQueryParameters = baseQuery; + _targetQueryParameters = baseQuery; + + // Check for applink_data + NSString *appLinkDataString = baseQuery[BFAppLinkDataParameterName]; + if (appLinkDataString) { + // Try to parse the JSON + NSError *error = nil; + NSDictionary *applinkData = [NSJSONSerialization JSONObjectWithData:[appLinkDataString dataUsingEncoding:NSUTF8StringEncoding] + options:0 + error:&error]; + if (!error && [applinkData isKindOfClass:[NSDictionary class]]) { + // If the version is not specified, assume it is 1. + NSString *version = applinkData[BFAppLinkVersionKeyName] ?: @"1.0"; + NSString *target = applinkData[BFAppLinkTargetKeyName]; + if ([version isKindOfClass:[NSString class]] && + [version isEqual:BFAppLinkVersion]) { + // There's applink data! The target should actually be the applink target. + _appLinkData = applinkData; + id applinkExtras = applinkData[BFAppLinkExtrasKeyName]; + if (applinkExtras && [applinkExtras isKindOfClass:[NSDictionary class]]) { + _appLinkExtras = applinkExtras; + } + _targetURL = ([target isKindOfClass:[NSString class]] ? [NSURL URLWithString:target] : url); + _targetQueryParameters = [BFURL queryParametersForURL:_targetURL]; + + NSDictionary *refererAppLink = _appLinkData[BFAppLinkRefererAppLink]; + NSString *refererURLString = refererAppLink[BFAppLinkRefererUrl]; + NSString *refererAppName = refererAppLink[BFAppLinkRefererAppName]; + + if (refererURLString && refererAppName) { + BFAppLinkTarget *target = [BFAppLinkTarget appLinkTargetWithURL:[NSURL URLWithString:refererURLString] + appStoreId:nil + appName:refererAppName]; + _appLinkReferer = [BFAppLink appLinkWithSourceURL:[NSURL URLWithString:refererURLString] + targets:@[ target ] + webURL:nil + isBackToReferrer:YES]; + } + + // Raise Measurement Event + NSString *const EVENT_YES_VAL = @"1"; + NSString *const EVENT_NO_VAL = @"0"; + NSMutableDictionary *logData = [[NSMutableDictionary alloc] init]; + logData[@"version"] = version; + if (refererURLString) { + logData[@"refererURL"] = refererURLString; + } + if (refererAppName) { + logData[@"refererAppName"] = refererAppName; + } + if (sourceApplication) { + logData[@"sourceApplication"] = sourceApplication; + } + if ([_targetURL absoluteString]) { + logData[@"targetURL"] = [_targetURL absoluteString]; + } + if ([_inputURL absoluteString]) { + logData[@"inputURL"] = [_inputURL absoluteString]; + } + if ([_inputURL scheme]) { + logData[@"inputURLScheme"] = [_inputURL scheme]; + } + logData[@"forRenderBackToReferrerBar"] = forRenderBackToReferrerBar ? EVENT_YES_VAL : EVENT_NO_VAL; + logData[@"forOpenUrl"] = forOpenURLEvent ? EVENT_YES_VAL : EVENT_NO_VAL; + [BFMeasurementEvent postNotificationForEventName:BFAppLinkParseEventName args:logData]; + if (forOpenURLEvent) { + [BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateInEventName args:logData]; + } + } + } + } + } + return self; +} + ++ (BFURL *)URLWithURL:(NSURL *)url { + return [[BFURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:NO]; +} + ++ (BFURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication { + return [[BFURL alloc] initWithURL:url forOpenInboundURL:YES sourceApplication:sourceApplication forRenderBackToReferrerBar:NO]; +} + ++ (BFURL *)URLForRenderBackToReferrerBarURL:(NSURL *)url { + return [[BFURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:YES]; +} + ++ (NSString *)decodeURLString:(NSString *)string { + return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapes(NULL, + (CFStringRef)string, + CFSTR(""))); +} + ++ (NSDictionary *)queryParametersForURL:(NSURL *)url { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + NSString *query = url.query; + if ([query isEqualToString:@""]) { + return @{}; + } + NSArray *queryComponents = [query componentsSeparatedByString:@"&"]; + for (NSString *component in queryComponents) { + NSRange equalsLocation = [component rangeOfString:@"="]; + if (equalsLocation.location == NSNotFound) { + // There's no equals, so associate the key with NSNull + parameters[[self decodeURLString:component]] = [NSNull null]; + } else { + NSString *key = [self decodeURLString:[component substringToIndex:equalsLocation.location]]; + NSString *value = [self decodeURLString:[component substringFromIndex:equalsLocation.location + 1]]; + parameters[key] = value; + } + } + return [NSDictionary dictionaryWithDictionary:parameters]; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL_Internal.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL_Internal.h new file mode 100644 index 0000000..03b6bc6 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFURL_Internal.h @@ -0,0 +1,15 @@ +/* + * 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 + +@interface BFURL (Internal) ++ (BFURL *)URLForRenderBackToReferrerBarURL:(NSURL *)url; +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.h b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.h new file mode 100644 index 0000000..3782ae2 --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.h @@ -0,0 +1,26 @@ +/* + * 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 reference implementation for an App Link resolver that uses a hidden UIWebView + to parse the HTML containing App Link metadata. + */ +@interface BFWebViewAppLinkResolver : NSObject + +/*! + Gets the instance of a BFWebViewAppLinkResolver. + */ ++ (instancetype)sharedInstance; + +@end diff --git a/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.m b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.m new file mode 100644 index 0000000..720838b --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.m @@ -0,0 +1,298 @@ +/* + * 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 "BFWebViewAppLinkResolver.h" +#import "BFAppLink.h" +#import "BFAppLinkTarget.h" +#import "BFTask.h" +#import "BFTaskCompletionSource.h" +#import "BFExecutor.h" + +// Defines JavaScript to extract app link tags from HTML content +static NSString *const BFWebViewAppLinkResolverTagExtractionJavaScript = @"" +"(function() {" +" var metaTags = document.getElementsByTagName('meta');" +" var results = [];" +" for (var i = 0; i < metaTags.length; i++) {" +" var property = metaTags[i].getAttribute('property');" +" if (property && property.substring(0, 'al:'.length) === 'al:') {" +" var tag = { \"property\": metaTags[i].getAttribute('property') };" +" if (metaTags[i].hasAttribute('content')) {" +" tag['content'] = metaTags[i].getAttribute('content');" +" }" +" results.push(tag);" +" }" +" }" +" return JSON.stringify(results);" +"})()"; +static NSString *const BFWebViewAppLinkResolverIOSURLKey = @"url"; +static NSString *const BFWebViewAppLinkResolverIOSAppStoreIdKey = @"app_store_id"; +static NSString *const BFWebViewAppLinkResolverIOSAppNameKey = @"app_name"; +static NSString *const BFWebViewAppLinkResolverDictionaryValueKey = @"_value"; +static NSString *const BFWebViewAppLinkResolverPreferHeader = @"Prefer-Html-Meta-Tags"; +static NSString *const BFWebViewAppLinkResolverMetaTagPrefix = @"al"; +static NSString *const BFWebViewAppLinkResolverWebKey = @"web"; +static NSString *const BFWebViewAppLinkResolverIOSKey = @"ios"; +static NSString *const BFWebViewAppLinkResolverIPhoneKey = @"iphone"; +static NSString *const BFWebViewAppLinkResolverIPadKey = @"ipad"; +static NSString *const BFWebViewAppLinkResolverWebURLKey = @"url"; +static NSString *const BFWebViewAppLinkResolverShouldFallbackKey = @"should_fallback"; + +@interface BFWebViewAppLinkResolverWebViewDelegate : NSObject + +@property (nonatomic, copy) void (^didFinishLoad)(UIWebView *webView); +@property (nonatomic, copy) void (^didFailLoadWithError)(UIWebView *webView, NSError *error); +@property (nonatomic, assign) BOOL hasLoaded; + +@end + +@implementation BFWebViewAppLinkResolverWebViewDelegate + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + if (self.didFinishLoad) { + self.didFinishLoad(webView); + } +} + +- (void)webViewDidStartLoad:(UIWebView *)webView { +} + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + if (self.didFailLoadWithError) { + self.didFailLoadWithError(webView, error); + } +} + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + if (self.hasLoaded) { + // Consider loading a second resource to be "success", since it indicates an inner frame + // or redirect is happening. We can run the tag extraction script at this point. + self.didFinishLoad(webView); + return NO; + } + self.hasLoaded = YES; + return YES; +} + +@end + +@implementation BFWebViewAppLinkResolver + ++ (instancetype)sharedInstance { + static id instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + return instance; +} + +- (BFTask *)followRedirects:(NSURL *)url { + // This task will be resolved with either the redirect NSURL + // or a dictionary with the response data to be returned. + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request setValue:BFWebViewAppLinkResolverMetaTagPrefix forHTTPHeaderField:BFWebViewAppLinkResolverPreferHeader]; + + void (^completion)(NSURLResponse *response, NSData *data, NSError *error) = ^(NSURLResponse *response, NSData *data, NSError *error) { + if (error) { + [tcs setError:error]; + return; + } + + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + // NSURLConnection usually follows redirects automatically, but the + // documentation is unclear what the default is. This helps it along. + if (httpResponse.statusCode >= 300 && httpResponse.statusCode < 400) { + NSString *redirectString = httpResponse.allHeaderFields[@"Location"]; + NSURL *redirectURL = [NSURL URLWithString:redirectString]; + [tcs setResult:redirectURL]; + return; + } + } + + [tcs setResult:@{ @"response" : response, @"data" : data }]; + }; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9 + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + completion(response, data, error); + }] resume]; +#else + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:completion]; +#endif + + return [tcs.task continueWithSuccessBlock:^id(BFTask *task) { + // If we redirected, just keep recursing. + if ([task.result isKindOfClass:[NSURL class]]) { + return [self followRedirects:task.result]; + } + return task; + }]; +} + +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url { + return [[self followRedirects:url] continueWithExecutor:[BFExecutor mainThreadExecutor] + withSuccessBlock:^id(BFTask *task) { + NSData *responseData = task.result[@"data"]; + NSHTTPURLResponse *response = task.result[@"response"]; + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + + UIWebView *webView = [[UIWebView alloc] init]; + BFWebViewAppLinkResolverWebViewDelegate *listener = [[BFWebViewAppLinkResolverWebViewDelegate alloc] init]; + __block BFWebViewAppLinkResolverWebViewDelegate *retainedListener = listener; + listener.didFinishLoad = ^(UIWebView *view) { + if (retainedListener) { + NSDictionary *ogData = [self getALDataFromLoadedPage:view]; + [view removeFromSuperview]; + view.delegate = nil; + retainedListener = nil; + [tcs setResult:[self appLinkFromALData:ogData destination:url]]; + } + }; + listener.didFailLoadWithError = ^(UIWebView* view, NSError *error) { + if (retainedListener) { + [view removeFromSuperview]; + view.delegate = nil; + retainedListener = nil; + [tcs setError:error]; + } + }; + webView.delegate = listener; + webView.hidden = YES; + [webView loadData:responseData + MIMEType:response.MIMEType + textEncodingName:response.textEncodingName + baseURL:response.URL]; + UIWindow *window = [UIApplication sharedApplication].windows.firstObject; + [window addSubview:webView]; + + return tcs.task; + }]; +} + +/* + Builds up a data structure filled with the app link data from the meta tags on a page. + The structure of this object is a dictionary where each key holds an array of app link + data dictionaries. Values are stored in a key called "_value". + */ +- (NSDictionary *)parseALData:(NSArray *)dataArray { + NSMutableDictionary *al = [NSMutableDictionary dictionary]; + for (NSDictionary *tag in dataArray) { + NSString *name = tag[@"property"]; + if (![name isKindOfClass:[NSString class]]) { + continue; + } + NSArray *nameComponents = [name componentsSeparatedByString:@":"]; + if (![nameComponents[0] isEqualToString:BFWebViewAppLinkResolverMetaTagPrefix]) { + continue; + } + NSMutableDictionary *root = al; + for (int i = 1; i < nameComponents.count; i++) { + NSMutableArray *children = root[nameComponents[i]]; + if (!children) { + children = [NSMutableArray array]; + root[nameComponents[i]] = children; + } + NSMutableDictionary *child = children.lastObject; + if (!child || i == nameComponents.count - 1) { + child = [NSMutableDictionary dictionary]; + [children addObject:child]; + } + root = child; + } + if (tag[@"content"]) { + root[BFWebViewAppLinkResolverDictionaryValueKey] = tag[@"content"]; + } + } + return al; +} + +- (NSDictionary *)getALDataFromLoadedPage:(UIWebView *)webView { + // Run some JavaScript in the webview to fetch the meta tags. + NSString *jsonString = [webView stringByEvaluatingJavaScriptFromString:BFWebViewAppLinkResolverTagExtractionJavaScript]; + NSError *error = nil; + NSArray *arr = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] + options:0 + error:&error]; + return [self parseALData:arr]; +} + +/* + Converts app link data into a BFAppLink containing the targets relevant for this platform. + */ +- (BFAppLink *)appLinkFromALData:(NSDictionary *)appLinkDict destination:(NSURL *)destination { + NSMutableArray *linkTargets = [NSMutableArray array]; + + NSArray *platformData = nil; + switch (UI_USER_INTERFACE_IDIOM()) { + case UIUserInterfaceIdiomPad: + platformData = @[ appLinkDict[BFWebViewAppLinkResolverIPadKey] ?: @{}, + appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ]; + break; + case UIUserInterfaceIdiomPhone: + platformData = @[ appLinkDict[BFWebViewAppLinkResolverIPhoneKey] ?: @{}, + appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ]; + break; + default: + // Future-proofing. Other User Interface idioms should only hit ios. + platformData = @[ appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ]; + break; + } + + for (NSArray *platformObjects in platformData) { + for (NSDictionary *platformDict in platformObjects) { + // The schema requires a single url/app store id/app name, + // but we could find multiple of them. We'll make a best effort + // to interpret this data. + NSArray *urls = platformDict[BFWebViewAppLinkResolverIOSURLKey]; + NSArray *appStoreIds = platformDict[BFWebViewAppLinkResolverIOSAppStoreIdKey]; + NSArray *appNames = platformDict[BFWebViewAppLinkResolverIOSAppNameKey]; + + NSUInteger maxCount = MAX(urls.count, MAX(appStoreIds.count, appNames.count)); + + for (NSUInteger i = 0; i < maxCount; i++) { + NSString *urlString = urls[i][BFWebViewAppLinkResolverDictionaryValueKey]; + NSURL *url = urlString ? [NSURL URLWithString:urlString] : nil; + NSString *appStoreId = appStoreIds[i][BFWebViewAppLinkResolverDictionaryValueKey]; + NSString *appName = appNames[i][BFWebViewAppLinkResolverDictionaryValueKey]; + BFAppLinkTarget *target = [BFAppLinkTarget appLinkTargetWithURL:url + appStoreId:appStoreId + appName:appName]; + [linkTargets addObject:target]; + } + } + } + + NSDictionary *webDict = appLinkDict[BFWebViewAppLinkResolverWebKey][0]; + NSString *webUrlString = webDict[BFWebViewAppLinkResolverWebURLKey][0][BFWebViewAppLinkResolverDictionaryValueKey]; + NSString *shouldFallbackString = webDict[BFWebViewAppLinkResolverShouldFallbackKey][0][BFWebViewAppLinkResolverDictionaryValueKey]; + + NSURL *webUrl = destination; + + if (shouldFallbackString && + [@[ @"no", @"false", @"0" ] containsObject:[shouldFallbackString lowercaseString]]) { + webUrl = nil; + } + if (webUrl && webUrlString) { + webUrl = [NSURL URLWithString:webUrlString]; + } + + return [BFAppLink appLinkWithSourceURL:destination + targets:linkTargets + webURL:webUrl]; +} + +@end diff --git a/Unit-2-Journal/Pods/Bolts/LICENSE b/Unit-2-Journal/Pods/Bolts/LICENSE new file mode 100644 index 0000000..e1a5831 --- /dev/null +++ b/Unit-2-Journal/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/Unit-2-Journal/Pods/Bolts/README.md b/Unit-2-Journal/Pods/Bolts/README.md new file mode 100644 index 0000000..003a2ea --- /dev/null +++ b/Unit-2-Journal/Pods/Bolts/README.md @@ -0,0 +1,682 @@ +Bolts +============ +[![Build Status](http://img.shields.io/travis/BoltsFramework/Bolts-iOS/master.svg?style=flat)](https://travis-ci.org/BoltsFramework/Bolts-iOS) +[![Coverage Status](https://codecov.io/github/BoltsFramework/Bolts-iOS/coverage.svg?branch=master)](https://codecov.io/github/BoltsFramework/Bolts-iOS?branch=master) +[![Pod Version](http://img.shields.io/cocoapods/v/Bolts.svg?style=flat)](http://cocoadocs.org/docsets/Bolts/) +[![Pod Platform](http://img.shields.io/cocoapods/p/Bolts.svg?style=flat)](http://cocoadocs.org/docsets/Bolts/) +[![Pod License](http://img.shields.io/cocoapods/l/Bolts.svg?style=flat)](https://github.com/BoltsFramework/Bolts-iOS/blob/master/LICENSE) +[![Dependency Status](https://www.versioneye.com/objective-c/bolts/1.1.1/badge.svg?style=flat)](https://www.versioneye.com/objective-c/bolts) +[![Reference Status](https://www.versioneye.com/objective-c/bolts/reference_badge.svg?style=flat)](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/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h new file mode 100644 index 0000000..4ed0656 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h @@ -0,0 +1,166 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract Notification indicating that the `currentAccessToken` has changed. + @discussion the userInfo dictionary of the notification will contain keys + `FBSDKAccessTokenChangeOldKey` and + `FBSDKAccessTokenChangeNewKey`. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeNotification; + +/*! + @abstract A key in the notification's userInfo that will be set + if and only if the user ID changed between the old and new tokens. + @discussion Token refreshes can occur automatically with the SDK + which do not change the user. If you're only interested in user + changes (such as logging out), you should check for the existence + of this key. The value is a NSNumber with a boolValue. + + On a fresh start of the app where the SDK reads in the cached value + of an access token, this key will also exist since the access token + is moving from a null state (no user) to a non-null state (user). + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeUserID; + +/* + @abstract key in notification's userInfo object for getting the old token. + @discussion If there was no old token, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeOldKey; + +/* + @abstract key in notification's userInfo object for getting the new token. + @discussion If there is no new token, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeNewKey; + + +/*! + @class FBSDKAccessToken + @abstract Represents an immutable access token for using Facebook services. + */ +@interface FBSDKAccessToken : NSObject + +/*! + @abstract Returns the app ID. + */ +@property (readonly, copy, nonatomic) NSString *appID; + +/*! + @abstract Returns the known declined permissions. + */ +@property (readonly, copy, nonatomic) NSSet *declinedPermissions; + +/*! + @abstract Returns the expiration date. + */ +@property (readonly, copy, nonatomic) NSDate *expirationDate; + +/*! + @abstract Returns the known granted permissions. + */ +@property (readonly, copy, nonatomic) NSSet *permissions; + +/*! + @abstract Returns the date the token was last refreshed. +*/ +@property (readonly, copy, nonatomic) NSDate *refreshDate; + +/*! + @abstract Returns the opaque token string. + */ +@property (readonly, copy, nonatomic) NSString *tokenString; + +/*! + @abstract Returns the user ID. + */ +@property (readonly, copy, nonatomic) NSString *userID; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/*! + @abstract Initializes a new instance. + @param tokenString the opaque token string. + @param permissions the granted permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param declinedPermissions the declined permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param appID the app ID. + @param userID the user ID. + @param expirationDate the optional expiration date (defaults to distantFuture). + @param refreshDate the optional date the token was last refreshed (defaults to today). + @discussion This initializer should only be used for advanced apps that + manage tokens explicitly. Typical login flows only need to use `FBSDKLoginManager` + along with `+currentAccessToken`. + */ +- (instancetype)initWithTokenString:(NSString *)tokenString + permissions:(NSArray *)permissions + declinedPermissions:(NSArray *)declinedPermissions + appID:(NSString *)appID + userID:(NSString *)userID + expirationDate:(NSDate *)expirationDate + refreshDate:(NSDate *)refreshDate +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract Convenience getter to determine if a permission has been granted + @param permission The permission to check. + */ +- (BOOL)hasGranted:(NSString *)permission; + +/*! + @abstract Compares the receiver to another FBSDKAccessToken + @param token The other token + @return YES if the receiver's values are equal to the other token's values; otherwise NO + */ +- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token; + +/*! + @abstract Returns the "global" access token that represents the currently logged in user. + @discussion The `currentAccessToken` is a convenient representation of the token of the + current user and is used by other SDK components (like `FBSDKLoginManager`). + */ ++ (FBSDKAccessToken *)currentAccessToken; + +/*! + @abstract Sets the "global" access token that represents the currently logged in user. + @param token The access token to set. + @discussion This will broadcast a notification and save the token to the app keychain. + */ ++ (void)setCurrentAccessToken:(FBSDKAccessToken *)token; + +/*! + @abstract Refresh the current access token's permission state and extend the token's expiration date, + if possible. + @param completionHandler an optional callback handler that can surface any errors related to permission refreshing. + @discussion On a successful refresh, the currentAccessToken will be updated so you typically only need to + observe the `FBSDKAccessTokenDidChangeNotification` notification. + + If a token is already expired, it cannot be refreshed. + */ ++ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.m new file mode 100644 index 0000000..456400b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.m @@ -0,0 +1,200 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessToken.h" + +#import "FBSDKGraphRequestPiggybackManager.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMath.h" +#import "FBSDKSettings+Internal.h" + +NSString *const FBSDKAccessTokenDidChangeNotification = @"com.facebook.sdk.FBSDKAccessTokenData.FBSDKAccessTokenDidChangeNotification"; +NSString *const FBSDKAccessTokenDidChangeUserID = @"FBSDKAccessTokenDidChangeUserID"; +NSString *const FBSDKAccessTokenChangeNewKey = @"FBSDKAccessToken"; +NSString *const FBSDKAccessTokenChangeOldKey = @"FBSDKAccessTokenOld"; + +static FBSDKAccessToken *g_currentAccessToken; + +#define FBSDK_ACCESSTOKEN_TOKENSTRING_KEY @"tokenString" +#define FBSDK_ACCESSTOKEN_PERMISSIONS_KEY @"permissions" +#define FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY @"declinedPermissions" +#define FBSDK_ACCESSTOKEN_APPID_KEY @"appID" +#define FBSDK_ACCESSTOKEN_USERID_KEY @"userID" +#define FBSDK_ACCESSTOKEN_REFRESHDATE_KEY @"refreshDate" +#define FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY @"expirationDate" + +@implementation FBSDKAccessToken + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithTokenString:(NSString *)tokenString + permissions:(NSArray *)permissions + declinedPermissions:(NSArray *)declinedPermissions + appID:(NSString *)appID + userID:(NSString *)userID + expirationDate:(NSDate *)expirationDate + refreshDate:(NSDate *)refreshDate +{ + if ((self = [super init])) { + _tokenString = [tokenString copy]; + _permissions = [NSSet setWithArray:permissions]; + _declinedPermissions = [NSSet setWithArray:declinedPermissions]; + _appID = [appID copy]; + _userID = [userID copy]; + _expirationDate = [expirationDate copy] ?: [NSDate distantFuture]; + _refreshDate = [refreshDate copy] ?: [NSDate date]; + } + return self; +} + +- (BOOL)hasGranted:(NSString *)permission +{ + return [self.permissions containsObject:permission]; +} + ++ (FBSDKAccessToken *)currentAccessToken +{ + return g_currentAccessToken; +} + ++ (void)setCurrentAccessToken:(FBSDKAccessToken *)token +{ + if (token != g_currentAccessToken) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [FBSDKInternalUtility dictionary:userInfo setObject:token forKey:FBSDKAccessTokenChangeNewKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:g_currentAccessToken forKey:FBSDKAccessTokenChangeOldKey]; + if (![g_currentAccessToken.userID isEqualToString:token.userID]) { + userInfo[FBSDKAccessTokenDidChangeUserID] = @YES; + } + + g_currentAccessToken = token; + + // Only need to keep current session in web view for the case when token is current + // When token is abandoned cookies must to be cleaned up immediatelly + if (token == nil) { + [FBSDKInternalUtility deleteFacebookCookies]; + } + + [[FBSDKSettings accessTokenCache] cacheAccessToken:token]; + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAccessTokenDidChangeNotification + object:[self class] + userInfo:userInfo]; + } +} + ++ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler +{ + if ([FBSDKAccessToken currentAccessToken]) { + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [FBSDKGraphRequestPiggybackManager addRefreshPiggyback:connection permissionHandler:completionHandler]; + [connection start]; + } else { + if (completionHandler) { + completionHandler(nil, nil, [FBSDKError errorWithCode:FBSDKAccessTokenRequiredErrorCode message:@"No current access token to refresh"]); + } + } +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [self.tokenString hash], + [self.permissions hash], + [self.declinedPermissions hash], + [self.appID hash], + [self.userID hash], + [self.refreshDate hash], + [self.expirationDate hash] + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKAccessToken class]]) { + return NO; + } + return [self isEqualToAccessToken:(FBSDKAccessToken *)object]; +} + +- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token +{ + return (token && + [FBSDKInternalUtility object:self.tokenString isEqualToObject:token.tokenString] && + [FBSDKInternalUtility object:self.permissions isEqualToObject:token.permissions] && + [FBSDKInternalUtility object:self.declinedPermissions isEqualToObject:token.declinedPermissions] && + [FBSDKInternalUtility object:self.appID isEqualToObject:token.appID] && + [FBSDKInternalUtility object:self.userID isEqualToObject:token.userID] && + [FBSDKInternalUtility object:self.refreshDate isEqualToObject:token.refreshDate] && + [FBSDKInternalUtility object:self.expirationDate isEqualToObject:token.expirationDate] ); +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + // we're immutable. + return self; +} + +#pragma mark NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_APPID_KEY]; + NSSet *declinedPermissions = [decoder decodeObjectOfClass:[NSSet class] forKey:FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY]; + NSSet *permissions = [decoder decodeObjectOfClass:[NSSet class] forKey:FBSDK_ACCESSTOKEN_PERMISSIONS_KEY]; + NSString *tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_TOKENSTRING_KEY]; + NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_USERID_KEY]; + NSDate *refreshDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY]; + NSDate *expirationDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY]; + + return [self initWithTokenString:tokenString + permissions:[permissions allObjects] + declinedPermissions:[declinedPermissions allObjects] + appID:appID + userID:userID + expirationDate:expirationDate + refreshDate:refreshDate]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:self.appID forKey:FBSDK_ACCESSTOKEN_APPID_KEY]; + [encoder encodeObject:self.declinedPermissions forKey:FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY]; + [encoder encodeObject:self.permissions forKey:FBSDK_ACCESSTOKEN_PERMISSIONS_KEY]; + [encoder encodeObject:self.tokenString forKey:FBSDK_ACCESSTOKEN_TOKENSTRING_KEY]; + [encoder encodeObject:self.userID forKey:FBSDK_ACCESSTOKEN_USERID_KEY]; + [encoder encodeObject:self.expirationDate forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY]; + [encoder encodeObject:self.refreshDate forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h new file mode 100644 index 0000000..375d413 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h @@ -0,0 +1,462 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKMacros.h" + +@class FBSDKAccessToken; +@class FBSDKGraphRequest; + +/*! @abstract NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */ +FBSDK_EXTERN NSString *const FBSDKAppEventsLoggingResultNotification; + +/*! @abstract optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */ +FBSDK_EXTERN NSString *const FBSDKAppEventsOverrideAppIDBundleKey; + +/*! + + @typedef NS_ENUM (NSUInteger, FBSDKAppEventsFlushBehavior) + + @abstract Specifies when `FBSDKAppEvents` sends log events to the server. + + */ +typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushBehavior) +{ + + /*! Flush automatically: periodically (once a minute or every 100 logged events) and always at app reactivation. */ + FBSDKAppEventsFlushBehaviorAuto = 0, + + /*! Only flush when the `flush` method is called. When an app is moved to background/terminated, the + events are persisted and re-established at activation, but they will only be written with an + explicit call to `flush`. */ + FBSDKAppEventsFlushBehaviorExplicitOnly, + +}; + +/*! + @methodgroup Predefined event names for logging events common to many apps. Logging occurs through the `logEvent` family of methods on `FBSDKAppEvents`. + Common event parameters are provided in the `FBSDKAppEventsParameterNames*` constants. + */ + +/*! Log this event when the user has achieved a level in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAchievedLevel; + +/*! Log this event when the user has entered their payment info. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedPaymentInfo; + +/*! Log this event when the user has added an item to their cart. The valueToSum passed to logEvent should be the item's price. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToCart; + +/*! Log this event when the user has added an item to their wishlist. The valueToSum passed to logEvent should be the item's price. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToWishlist; + +/*! Log this event when a user has completed registration with the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedRegistration; + +/*! Log this event when the user has completed a tutorial in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedTutorial; + +/*! Log this event when the user has entered the checkout process. The valueToSum passed to logEvent should be the total price in the cart. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameInitiatedCheckout; + +/*! Log this event when the user has rated an item in the app. The valueToSum passed to logEvent should be the numeric rating. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameRated; + +/*! Log this event when a user has performed a search within the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameSearched; + +/*! Log this event when the user has spent app credits. The valueToSum passed to logEvent should be the number of credits spent. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameSpentCredits; + +/*! Log this event when the user has unlocked an achievement in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameUnlockedAchievement; + +/*! Log this event when a user has viewed a form of content in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameViewedContent; + +/*! + @methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family + of methods on `FBSDKAppEvents`. Common event names are provided in the `FBAppEventName*` constants. + */ + +/*! Parameter key used to specify an ID for the specific piece of content being logged about. Could be an EAN, article identifier, etc., depending on the nature of the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentID; + +/*! Parameter key used to specify a generic content type/family for the logged event, e.g. "music", "photo", "video". Options to use will vary based upon what the app is all about. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentType; + +/*! Parameter key used to specify currency used with logged event. E.g. "USD", "EUR", "GBP". See ISO-4217 for specific values. One reference for these is . */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameCurrency; + +/*! Parameter key used to specify a description appropriate to the event being logged. E.g., the name of the achievement unlocked in the `FBAppEventNameAchievementUnlocked` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameDescription; + +/*! Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameLevel; + +/*! Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameMaxRatingValue; + +/*! Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameNumItems; + +/*! Parameter key used to specify whether payment info is available for the `FBAppEventNameInitiatedCheckout` event. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable; + +/*! Parameter key used to specify method user has used to register for the app, e.g., "Facebook", "email", "Twitter", etc */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameRegistrationMethod; + +/*! Parameter key used to specify the string provided by the user for a search operation. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSearchString; + +/*! Parameter key used to specify whether the activity being logged about was successful or not. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSuccess; + +/* + @methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family + of methods on `FBSDKAppEvents`. Common event parameters are provided in the `FBSDKAppEventParameterName*` constants. + */ + +/*! Yes-valued parameter value to be used with parameter keys that need a Yes/No value */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueYes; + +/*! No-valued parameter value to be used with parameter keys that need a Yes/No value */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo; + + +/*! + + @class FBSDKAppEvents + + @abstract + Client-side event logging for specialized application analytics available through Facebook App Insights + and for use with Facebook Ads conversion tracking and optimization. + + @discussion + The `FBSDKAppEvents` static class has a few related roles: + + + Logging predefined and application-defined events to Facebook App Insights with a + numeric value to sum across a large number of events, and an optional set of key/value + parameters that define "segments" for this event (e.g., 'purchaserStatus' : 'frequent', or + 'gamerLevel' : 'intermediate') + + + Logging events to later be used for ads optimization around lifetime value. + + + Methods that control the way in which events are flushed out to the Facebook servers. + + Here are some important characteristics of the logging mechanism provided by `FBSDKAppEvents`: + + + Events are not sent immediately when logged. They're cached and flushed out to the Facebook servers + in a number of situations: + - when an event count threshold is passed (currently 100 logged events). + - when a time threshold is passed (currently 15 seconds). + - when an app has gone to background and is then brought back to the foreground. + + + Events will be accumulated when the app is in a disconnected state, and sent when the connection is + restored and one of the above 'flush' conditions are met. + + + The `FBSDKAppEvents` class is thread-safe in that events may be logged from any of the app's threads. + + + The developer can set the `flushBehavior` on `FBSDKAppEvents` to force the flushing of events to only + occur on an explicit call to the `flush` method. + + + The developer can turn on console debug output for event logging and flushing to the server by using + the `FBSDKLoggingBehaviorAppEvents` value in `[FBSettings setLoggingBehavior:]`. + + Some things to note when logging events: + + + There is a limit on the number of unique event names an app can use, on the order of 1000. + + There is a limit to the number of unique parameter names in the provided parameters that can + be used per event, on the order of 25. This is not just for an individual call, but for all + invocations for that eventName. + + Event names and parameter names (the keys in the NSDictionary) must be between 2 and 40 characters, and + must consist of alphanumeric characters, _, -, or spaces. + + The length of each parameter value can be no more than on the order of 100 characters. + + */ +@interface FBSDKAppEvents : NSObject + +/* + * Basic event logging + */ + +/*! + + @abstract + Log an event with just an eventName. + + @param eventName The name of the event to record. Limitations on number of events and name length + are given in the `FBSDKAppEvents` documentation. + + */ ++ (void)logEvent:(NSString *)eventName; + +/*! + + @abstract + Log an event with an eventName and a numeric value to be aggregated with other events of this name. + + @param eventName The name of the event to record. Limitations on number of events and name length + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum; + + +/*! + + @abstract + Log an event with an eventName and a set of key/value pairs in the parameters dictionary. + Parameter limitations are described above. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + */ ++ (void)logEvent:(NSString *)eventName + parameters:(NSDictionary *)parameters; + +/*! + + @abstract + Log an event with an eventName, a numeric value to be aggregated with other events of this name, + and a set of key/value pairs in the parameters dictionary. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum + parameters:(NSDictionary *)parameters; + + +/*! + + @abstract + Log an event with an eventName, a numeric value to be aggregated with other events of this name, + and a set of key/value pairs in the parameters dictionary. Providing session lets the developer + target a particular . If nil is provided, then `[FBSession activeSession]` will be used. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. Note that this is an NSNumber, and a value of `nil` denotes + that this event doesn't have a value associated with it for summation. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @param accessToken The optional access token to log the event as. + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken; + +/* + * Purchase logging + */ + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency. This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency; + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency, also providing a set of + additional characteristics describing the purchase. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters; + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency, also providing a set of + additional characteristics describing the purchase, as well as an to log to. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @param accessToken The optional access token to log the event as. + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken; + +/*! + + @abstract + Notifies the events system that the app has launched and, when appropriate, logs an "activated app" event. Should typically be placed in the + app delegates' `applicationDidBecomeActive:` method. + + This method also takes care of logging the event indicating the first time this app has been launched, which, among other things, is used to + track user acquisition and app install ads conversions. + + @discussion + `activateApp` will not log an event on every app launch, since launches happen every time the app is backgrounded and then foregrounded. + "activated app" events will be logged when the app has not been active for more than 60 seconds. This method also causes a "deactivated app" + event to be logged when sessions are "completed", and these events are logged with the session length, with an indication of how much + time has elapsed between sessions, and with the number of background/foreground interruptions that session had. This data + is all visible in your app's App Events Insights. + */ ++ (void)activateApp; + +/* + * Control over event batching/flushing + */ + +/*! + + @abstract + Get the current event flushing behavior specifying when events are sent back to Facebook servers. + */ ++ (FBSDKAppEventsFlushBehavior)flushBehavior; + +/*! + + @abstract + Set the current event flushing behavior specifying when events are sent back to Facebook servers. + + @param flushBehavior The desired `FBSDKAppEventsFlushBehavior` to be used. + */ ++ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior; + +/*! + @abstract + Set the 'override' App ID for App Event logging. + + @discussion + In some cases, apps want to use one Facebook App ID for login and social presence and another + for App Event logging. (An example is if multiple apps from the same company share an app ID for login, but + want distinct logging.) By default, this value is `nil`, and defers to the `FBSDKAppEventsOverrideAppIDBundleKey` + plist value. If that's not set, it defaults to `[FBSDKSettings appID]`. + + This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application + delegate's `application:didFinishLaunchingWithOptions:` delegate. + + @param appID The Facebook App ID to be used for App Event logging. + */ ++ (void)setLoggingOverrideAppID:(NSString *)appID; + +/*! + @abstract + Get the 'override' App ID for App Event logging. + + @see setLoggingOverrideAppID: + + */ ++ (NSString *)loggingOverrideAppID; + + +/*! + @abstract + Explicitly kick off flushing of events to Facebook. This is an asynchronous method, but it does initiate an immediate + kick off. Server failures will be reported through the NotificationCenter with notification ID `FBSDKAppEventsLoggingResultNotification`. + */ ++ (void)flush; + +/*! + @abstract + Creates a request representing the Graph API call to retrieve a Custom Audience "third party ID" for the app's Facebook user. + Callers will send this ID back to their own servers, collect up a set to create a Facebook Custom Audience with, + and then use the resultant Custom Audience to target ads. + + @param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app. + If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used. + + @discussion + The JSON in the request's response will include an "custom_audience_third_party_id" key/value pair, with the value being the ID retrieved. + This ID is an encrypted encoding of the Facebook user's ID and the invoking Facebook app ID. + Multiple calls with the same user will return different IDs, thus these IDs cannot be used to correlate behavior + across devices or applications, and are only meaningful when sent back to Facebook for creating Custom Audiences. + + The ID retrieved represents the Facebook user identified in the following way: if the specified access token is valid, + the ID will represent the user associated with that token; otherwise the ID will represent the user logged into the + native Facebook app on the device. If there is no native Facebook app, no one is logged into it, or the user has opted out + at the iOS level from ad tracking, then a `nil` ID will be returned. + + This method returns `nil` if either the user has opted-out (via iOS) from Ad Tracking, the app itself has limited event usage + via the `[FBSDKSettings limitEventAndDataUsage]` flag, or a specific Facebook user cannot be identified. + */ ++ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.m new file mode 100644 index 0000000..7891652 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.m @@ -0,0 +1,831 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppEvents.h" +#import "FBSDKAppEvents+Internal.h" + +#import + +#import "FBSDKAccessToken.h" +#import "FBSDKAppEventsState.h" +#import "FBSDKAppEventsStateManager.h" +#import "FBSDKAppEventsUtility.h" +#import "FBSDKConstants.h" +#import "FBSDKError.h" +#import "FBSDKGraphRequest+Internal.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKPaymentObserver.h" +#import "FBSDKServerConfiguration.h" +#import "FBSDKServerConfigurationManager.h" +#import "FBSDKSettings.h" +#import "FBSDKTimeSpentData.h" +#import "FBSDKUtility.h" + +// +// Public event names +// + +// General purpose +NSString *const FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration"; +NSString *const FBSDKAppEventNameViewedContent = @"fb_mobile_content_view"; +NSString *const FBSDKAppEventNameSearched = @"fb_mobile_search"; +NSString *const FBSDKAppEventNameRated = @"fb_mobile_rate"; +NSString *const FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion"; +NSString *const FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source"; + +// Ecommerce related +NSString *const FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart"; +NSString *const FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist"; +NSString *const FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout"; +NSString *const FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info"; + +// Gaming related +NSString *const FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved"; +NSString *const FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked"; +NSString *const FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits"; + +// +// Public event parameter names +// + +NSString *const FBSDKAppEventParameterNameCurrency = @"fb_currency"; +NSString *const FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method"; +NSString *const FBSDKAppEventParameterNameContentType = @"fb_content_type"; +NSString *const FBSDKAppEventParameterNameContentID = @"fb_content_id"; +NSString *const FBSDKAppEventParameterNameSearchString = @"fb_search_string"; +NSString *const FBSDKAppEventParameterNameSuccess = @"fb_success"; +NSString *const FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value"; +NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available"; +NSString *const FBSDKAppEventParameterNameNumItems = @"fb_num_items"; +NSString *const FBSDKAppEventParameterNameLevel = @"fb_level"; +NSString *const FBSDKAppEventParameterNameDescription = @"fb_description"; + +// +// Public event parameter values +// + +NSString *const FBSDKAppEventParameterValueNo = @"0"; +NSString *const FBSDKAppEventParameterValueYes = @"1"; + +// +// Event names internal to this file +// +NSString *const FBSDKAppEventNamePurchased = @"fb_mobile_purchase"; + +NSString *const FBSDKAppEventNameLoginViewUsage = @"fb_login_view_usage"; +NSString *const FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch"; +NSString *const FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss"; +NSString *const FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch"; +NSString *const FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss"; +NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share"; +NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo"; +NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og"; +NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og"; +NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message"; +NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo"; +NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG = @"fb_dialogs_present_message_og"; + +NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart = @"fb_dialogs_native_login_dialog_start"; +NSString *const FBSDKAppEventsNativeLoginDialogStartTime = @"fb_native_login_dialog_start_time"; + +NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd = @"fb_dialogs_native_login_dialog_end"; +NSString *const FBSDKAppEventsNativeLoginDialogEndTime = @"fb_native_login_dialog_end_time"; + +NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted = @"fb_dialogs_web_login_dialog_complete"; +NSString *const FBSDKAppEventsWebLoginE2E = @"fb_web_login_e2e"; + +NSString *const FBSDKAppEventNameFBSessionAuthStart = @"fb_mobile_login_start"; +NSString *const FBSDKAppEventNameFBSessionAuthEnd = @"fb_mobile_login_complete"; +NSString *const FBSDKAppEventNameFBSessionAuthMethodStart = @"fb_mobile_login_method_start"; +NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd = @"fb_mobile_login_method_complete"; + +NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression"; +NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression"; +NSString *const FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression"; +NSString *const FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression"; + +NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap"; +NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap"; +NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap"; +NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap"; + +NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable"; +NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like"; +NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog = @"fb_like_control_did_present_dialog"; +NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap = @"fb_like_control_did_tap"; +NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike = @"fb_like_control_did_unlike"; +NSString *const FBSDKAppEventNameFBSDKLikeControlError = @"fb_like_control_error"; +NSString *const FBSDKAppEventNameFBSDKLikeControlImpression = @"fb_like_control_impression"; +NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable = @"fb_like_control_network_unavailable"; + +NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult = @"fb_dialog_share_result"; +NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult = @"fb_messenger_dialog_share_result"; +NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result"; + +NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow = @"fb_dialog_share_show"; +NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow = @"fb_messenger_dialog_share_show"; +NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show"; + +// Event Parameters internal to this file +NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome"; +NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message"; +NSString *const FBSDKAppEventParameterDialogMode = @"fb_dialog_mode"; +NSString *const FBSDKAppEventParameterDialogShareContentType = @"fb_dialog_share_content_type"; + +// Event parameter values internal to this file +NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed"; +NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled = @"Cancelled"; +NSString *const FBSDKAppEventsDialogOutcomeValue_Failed = @"Failed"; + +NSString *const FBSDKAppEventsDialogShareModeAutomatic = @"Automatic"; +NSString *const FBSDKAppEventsDialogShareModeBrowser = @"Browser"; +NSString *const FBSDKAppEventsDialogShareModeNative = @"Native"; +NSString *const FBSDKAppEventsDialogShareModeShareSheet = @"ShareSheet"; +NSString *const FBSDKAppEventsDialogShareModeWeb = @"Web"; +NSString *const FBSDKAppEventsDialogShareModeFeedBrowser = @"FeedBrowser"; +NSString *const FBSDKAppEventsDialogShareModeFeedWeb = @"FeedWeb"; +NSString *const FBSDKAppEventsDialogShareModeUnknown = @"Unknown"; + +NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph = @"OpenGraph"; +NSString *const FBSDKAppEventsDialogShareContentTypeStatus = @"Status"; +NSString *const FBSDKAppEventsDialogShareContentTypePhoto = @"Photo"; +NSString *const FBSDKAppEventsDialogShareContentTypeVideo = @"Video"; +NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown"; + +NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification"; + +NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID"; + +#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100 +#define FLUSH_PERIOD_IN_SECONDS 15 +#define APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD 60 * 60 * 24 + +static NSString *g_overrideAppID = nil; + +@interface FBSDKAppEvents () + +@property (nonatomic, readwrite) FBSDKAppEventsFlushBehavior flushBehavior; +//for testing only. +@property (nonatomic, assign) BOOL disableTimer; +@end + +@implementation FBSDKAppEvents +{ + BOOL _explicitEventsLoggedYet; + NSTimer *_flushTimer; + NSTimer *_attributionIDRecheckTimer; + FBSDKServerConfiguration *_serverConfiguration; + FBSDKAppEventsState *_appEventsState; +} + +#pragma mark - Object Lifecycle + ++ (void)initialize +{ + if (self == [FBSDKAppEvents class]) { + g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy]; + } +} + +- (FBSDKAppEvents *)init +{ + self = [super init]; + if (self) { + _flushBehavior = FBSDKAppEventsFlushBehaviorAuto; + _flushTimer = [NSTimer scheduledTimerWithTimeInterval:FLUSH_PERIOD_IN_SECONDS + target:self + selector:@selector(flushTimerFired:) + userInfo:nil + repeats:YES]; + + _attributionIDRecheckTimer = [NSTimer scheduledTimerWithTimeInterval:APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD + target:self + selector:@selector(appSettingsFetchStateResetTimerFired:) + userInfo:nil + repeats:YES]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationMovingFromActiveStateOrTerminating) + name:UIApplicationWillResignActiveNotification + object:NULL]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationMovingFromActiveStateOrTerminating) + name:UIApplicationWillTerminateNotification + object:NULL]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationDidBecomeActive) + name:UIApplicationDidBecomeActiveNotification + object:NULL]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + // technically these timers retain self so there's a cycle but + // we're a singleton anyway. + [_flushTimer invalidate]; + [_attributionIDRecheckTimer invalidate]; +} + +#pragma mark - Public Methods + ++ (void)logEvent:(NSString *)eventName +{ + [FBSDKAppEvents logEvent:eventName + parameters:nil]; +} + ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum +{ + [FBSDKAppEvents logEvent:eventName + valueToSum:valueToSum + parameters:nil]; +} + ++ (void)logEvent:(NSString *)eventName + parameters:(NSDictionary *)parameters +{ + [FBSDKAppEvents logEvent:eventName + valueToSum:nil + parameters:parameters + accessToken:nil]; +} + ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum + parameters:(NSDictionary *)parameters +{ + [FBSDKAppEvents logEvent:eventName + valueToSum:[NSNumber numberWithDouble:valueToSum] + parameters:parameters + accessToken:nil]; +} + ++ (void)logEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken +{ + [[FBSDKAppEvents singleton] instanceLogEvent:eventName + valueToSum:valueToSum + parameters:parameters + isImplicitlyLogged:NO + accessToken:accessToken]; +} + ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency +{ + [FBSDKAppEvents logPurchase:purchaseAmount + currency:currency + parameters:nil]; +} + ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters +{ + [FBSDKAppEvents logPurchase:purchaseAmount + currency:currency + parameters:parameters + accessToken:nil]; +} + ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken +{ + + // A purchase event is just a regular logged event with a given event name + // and treating the currency value as going into the parameters dictionary. + NSDictionary *newParameters; + if (!parameters) { + newParameters = @{ FBSDKAppEventParameterNameCurrency : currency }; + } else { + newParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; + [newParameters setValue:currency forKey:FBSDKAppEventParameterNameCurrency]; + } + + [FBSDKAppEvents logEvent:FBSDKAppEventNamePurchased + valueToSum:[NSNumber numberWithDouble:purchaseAmount] + parameters:newParameters + accessToken:accessToken]; + + // Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events + // are relatively rare and relatively high value and worth getting across on wire right away. + if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) { + [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; + } +} + ++ (void)activateApp +{ + [FBSDKAppEventsUtility ensureOnMainThread]; + + // Fetch app settings and register for transaction notifications only if app supports implicit purchase + // events + FBSDKAppEvents *instance = [FBSDKAppEvents singleton]; + [instance publishInstall]; + [instance fetchServerConfiguration:NULL]; + + // Restore time spent data, indicating that we're being called from "activateApp", which will, + // when appropriate, result in logging an "activated app" and "deactivated app" (for the + // previous session) App Event. + [FBSDKTimeSpentData restore:YES]; +} + ++ (FBSDKAppEventsFlushBehavior)flushBehavior +{ + return [FBSDKAppEvents singleton].flushBehavior; +} + ++ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior +{ + [FBSDKAppEvents singleton].flushBehavior = flushBehavior; +} + ++ (NSString *)loggingOverrideAppID +{ + return g_overrideAppID; +} + ++ (void)setLoggingOverrideAppID:(NSString *)appID +{ + if (![g_overrideAppID isEqualToString:appID]) { + FBSDKConditionalLog(![FBSDKAppEvents singleton]->_explicitEventsLoggedYet, + FBSDKLoggingBehaviorDeveloperErrors, + @"[FBSDKAppEvents setLoggingOverrideAppID:] should only be called prior to any events being logged."); + g_overrideAppID = appID; + } +} + ++ (void)flush +{ + [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonExplicit]; +} + +#pragma mark - Internal Methods + ++ (void)logImplicitEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken +{ + [[FBSDKAppEvents singleton] instanceLogEvent:eventName + valueToSum:valueToSum + parameters:parameters + isImplicitlyLogged:YES + accessToken:accessToken]; +} + ++ (FBSDKAppEvents *)singleton +{ + static dispatch_once_t pred; + static FBSDKAppEvents *shared = nil; + + dispatch_once(&pred, ^{ + shared = [[FBSDKAppEvents alloc] init]; + }); + return shared; +} + +- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason +{ + // Always flush asynchronously, even on main thread, for two reasons: + // - most consistent code path for all threads. + // - allow locks being held by caller to be released prior to actual flushing work being done. + @synchronized (self) { + if (!_appEventsState) { + return; + } + FBSDKAppEventsState *copy = [_appEventsState copy]; + _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:copy.tokenString + appID:copy.appID]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self flushOnMainQueue:copy forReason:flushReason]; + }); + } +} + +#pragma mark - Private Methods +- (NSString *)appID +{ + return [FBSDKAppEvents loggingOverrideAppID] ?: [FBSDKSettings appID]; +} + +- (void)publishInstall +{ + NSString *appID = [self appID]; + NSString *lastAttributionPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastAttributionPing%@", appID]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults objectForKey:lastAttributionPingString]) { + return; + } + [self fetchServerConfiguration:^{ + NSDictionary *params = [FBSDKAppEventsUtility activityParametersDictionaryForEvent:@"MOBILE_APP_INSTALL" + implicitEventsOnly:NO + shouldAccessAdvertisingID:_serverConfiguration.isAdvertisingIDEnabled]; + NSString *path = [NSString stringWithFormat:@"%@/activities", appID]; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path + parameters:params + tokenString:nil + HTTPMethod:@"POST" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!error) { + [defaults setObject:[NSDate date] forKey:lastAttributionPingString]; + NSString *lastInstallResponseKey = [NSString stringWithFormat:@"com.facebook.sdk:lastInstallResponse%@", appID]; + [defaults setObject:result forKey:lastInstallResponseKey]; + [defaults synchronize]; + } + }]; + }]; +} + +// app events can use a server configuration up to 24 hours old to minimize network traffic. +- (void)fetchServerConfiguration:(void (^)(void))callback +{ + if (_serverConfiguration == nil) { + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) { + _serverConfiguration = serverConfiguration; + + if (_serverConfiguration.implicitPurchaseLoggingEnabled) { + [FBSDKPaymentObserver startObservingTransactions]; + } else { + [FBSDKPaymentObserver stopObservingTransactions]; + } + if (callback) { + callback(); + } + }]; + return; + } + if (callback) { + callback(); + } +} + +- (void)instanceLogEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + isImplicitlyLogged:(BOOL)isImplicitlyLogged + accessToken:(FBSDKAccessToken *)accessToken +{ + if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) { + return; + } + + if (!isImplicitlyLogged && !_explicitEventsLoggedYet) { + _explicitEventsLoggedYet = YES; + } + + __block BOOL failed = NO; + + if (![FBSDKAppEventsUtility validateIdentifier:eventName]) { + failed = YES; + } + + // Make sure parameter dictionary is well formed. Log and exit if not. + [parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if (![key isKindOfClass:[NSString class]]) { + [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The keys in the parameters must be NSStrings, '%@' is not.", key]]; + failed = YES; + } + if (![FBSDKAppEventsUtility validateIdentifier:key]) { + failed = YES; + } + if (![obj isKindOfClass:[NSString class]] && ![obj isKindOfClass:[NSNumber class]]) { + [FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The values in the parameters dictionary must be NSStrings or NSNumbers, '%@' is not.", obj]]; + failed = YES; + } + } + ]; + + if (failed) { + return; + } + + NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters]; + eventDictionary[@"_eventName"] = eventName; + eventDictionary[@"_logTime"] = @([FBSDKAppEventsUtility unixTimeNow]); + [FBSDKInternalUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"]; + if (isImplicitlyLogged) { + eventDictionary[@"_implicitlyLogged"] = @"1"; + } + + NSString *currentViewControllerName; + if ([NSThread isMainThread]) { + // We only collect the view controller when on the main thread, as the behavior off + // the main thread is unpredictable. Besides, UI state for off-main-thread computations + // isn't really relevant anyhow. + UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController; + if (vc) { + currentViewControllerName = [[vc class] description]; + } else { + currentViewControllerName = @"no_ui"; + } + } else { + currentViewControllerName = @"off_thread"; + } + eventDictionary[@"_ui"] = currentViewControllerName; + + NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken]; + NSString *appID = [self appID]; + + @synchronized (self) { + if (!_appEventsState) { + _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID]; + } else if (![_appEventsState isCompatibleWithTokenString:tokenString appID:appID]) { + if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) { + [FBSDKAppEventsStateManager persistAppEventsData:_appEventsState]; + } else { + [self flushForReason:FBSDKAppEventsFlushReasonSessionChange]; + } + _appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID]; + } + + [_appEventsState addEvent:eventDictionary isImplicit:isImplicitlyLogged]; + if (!isImplicitlyLogged) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKAppEvents: Recording event @ %ld: %@", + [FBSDKAppEventsUtility unixTimeNow], + eventDictionary]; + } + + [self checkPersistedEvents]; + + if (_appEventsState.events.count > NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER && + self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly) { + [self flushForReason:FBSDKAppEventsFlushReasonEventThreshold]; + } + } +} + +// this fetches persisted event states. +// for those matching the currently tracked events, add it. +// otherwise, either flush (if not explicitonly behavior) or persist them back. +- (void)checkPersistedEvents +{ + NSArray *existingEventsStates = [FBSDKAppEventsStateManager retrievePersistedAppEventsStates]; + if (existingEventsStates.count == 0) { + return; + } + FBSDKAppEventsState *matchingEventsPreviouslySaved = nil; + // reduce lock time by creating a new FBSDKAppEventsState to collect matching persisted events. + @synchronized(self) { + if (_appEventsState) { + matchingEventsPreviouslySaved = [[FBSDKAppEventsState alloc] initWithToken:_appEventsState.tokenString + appID:_appEventsState.appID]; + } + } + for (FBSDKAppEventsState *saved in existingEventsStates) { + if ([saved isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) { + [matchingEventsPreviouslySaved addEventsFromAppEventState:saved]; + } else { + if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) { + [FBSDKAppEventsStateManager persistAppEventsData:saved]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self flushOnMainQueue:saved forReason:FBSDKAppEventsFlushReasonPersistedEvents]; + }); + } + } + } + if (matchingEventsPreviouslySaved.events.count > 0) { + @synchronized(self) { + if ([_appEventsState isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) { + [_appEventsState addEventsFromAppEventState:matchingEventsPreviouslySaved]; + } + } + } +} + +- (void)flushOnMainQueue:(FBSDKAppEventsState *)appEventsState + forReason:(FBSDKAppEventsFlushReason)reason +{ + if (appEventsState.events.count == 0) { + return; + } + [FBSDKAppEventsUtility ensureOnMainThread]; + + [self fetchServerConfiguration:^(void) { + NSString *JSONString = [appEventsState JSONStringForEvents:_serverConfiguration.implicitLoggingEnabled]; + NSData *encodedEvents = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; + if (!encodedEvents) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + logEntry:@"FBSDKAppEvents: Flushing skipped - no events after removing implicitly logged ones.\n"]; + return; + } + NSMutableDictionary *postParameters = [FBSDKAppEventsUtility + activityParametersDictionaryForEvent:@"CUSTOM_APP_EVENTS" + implicitEventsOnly:appEventsState.areAllEventsImplicit + shouldAccessAdvertisingID:_serverConfiguration.advertisingIDEnabled]; + postParameters[@"custom_events_file"] = encodedEvents; + if (appEventsState.numSkipped > 0) { + postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped]; + } + + NSString *loggingEntry = nil; + if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorAppEvents]) { + NSData *prettyJSONData = [NSJSONSerialization dataWithJSONObject:appEventsState.events + options:NSJSONWritingPrettyPrinted + error:NULL]; + NSString *prettyPrintedJsonEvents = [[NSString alloc] initWithData:prettyJSONData + encoding:NSUTF8StringEncoding]; + // Remove this param -- just an encoding of the events which we pretty print later. + NSMutableDictionary *paramsForPrinting = [postParameters mutableCopy]; + [paramsForPrinting removeObjectForKey:@"custom_events_file"]; + + loggingEntry = [NSString stringWithFormat:@"FBSDKAppEvents: Flushed @ %ld, %lu events due to '%@' - %@\nEvents: %@", + [FBSDKAppEventsUtility unixTimeNow], + (unsigned long)appEventsState.events.count, + [FBSDKAppEventsUtility flushReasonToString:reason], + paramsForPrinting, + prettyPrintedJsonEvents]; + } + + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID] + parameters:postParameters + tokenString:appEventsState.tokenString + HTTPMethod:@"POST" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + [self handleActivitiesPostCompletion:error + loggingEntry:loggingEntry + appEventsState:(FBSDKAppEventsState *)appEventsState]; + }]; + + }]; +} + +- (void)handleActivitiesPostCompletion:(NSError *)error + loggingEntry:(NSString *)loggingEntry + appEventsState:(FBSDKAppEventsState *)appEventsState +{ + typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushResult) { + FlushResultSuccess, + FlushResultServerError, + FlushResultNoConnectivity + }; + + [FBSDKAppEventsUtility ensureOnMainThread]; + + FBSDKAppEventsFlushResult flushResult = FlushResultSuccess; + if (error) { + NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue]; + + // We interpret a 400 coming back from FBRequestConnection as a server error due to improper data being + // sent down. Otherwise we assume no connectivity, or another condition where we could treat it as no connectivity. + flushResult = errorCode == 400 ? FlushResultServerError : FlushResultNoConnectivity; + } + + if (flushResult == FlushResultServerError) { + // Only log events that developer can do something with (i.e., if parameters are incorrect). + // as opposed to cases where the token is bad. + if ([error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue] == FBSDKGraphRequestErrorCategoryOther) { + NSString *message = [NSString stringWithFormat:@"Failed to send AppEvents: %@", error]; + [FBSDKAppEventsUtility logAndNotify:message allowLogAsDeveloperError:!appEventsState.areAllEventsImplicit]; + } + } else if (flushResult == FlushResultNoConnectivity) { + @synchronized(self) { + if ([appEventsState isCompatibleWithAppEventsState:_appEventsState]) { + [_appEventsState addEventsFromAppEventState:appEventsState]; + } else { + // flush failed due to connectivity. Persist to be tried again later. + [FBSDKAppEventsStateManager persistAppEventsData:appEventsState]; + } + } + } + + NSString *resultString = @""; + switch (flushResult) { + case FlushResultSuccess: + resultString = @"Success"; + break; + + case FlushResultNoConnectivity: + resultString = @"No Connectivity"; + break; + + case FlushResultServerError: + resultString = [NSString stringWithFormat:@"Server Error - %@", [error description]]; + break; + } + + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"%@\nFlush Result : %@", loggingEntry, resultString]; +} + +- (void)flushTimerFired:(id)arg +{ + [FBSDKAppEventsUtility ensureOnMainThread]; + if (self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly && !self.disableTimer) { + [self flushForReason:FBSDKAppEventsFlushReasonTimer]; + } +} + +- (void)appSettingsFetchStateResetTimerFired:(id)arg +{ + _serverConfiguration = nil; +} + +- (void)applicationDidBecomeActive +{ + [FBSDKAppEventsUtility ensureOnMainThread]; + + [self checkPersistedEvents]; + + // Restore time spent data, indicating that we're not being called from "activateApp". + [FBSDKTimeSpentData restore:NO]; +} + +- (void)applicationMovingFromActiveStateOrTerminating +{ + // When moving from active state, we don't have time to wait for the result of a flush, so + // just persist events to storage, and we'll process them at the next activation. + FBSDKAppEventsState *copy = nil; + @synchronized (self) { + copy = [_appEventsState copy]; + _appEventsState = nil; + } + if (copy) { + [FBSDKAppEventsStateManager persistAppEventsData:copy]; + } + [FBSDKTimeSpentData suspend]; +} + +#pragma mark - Custom Audience + ++ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken +{ + accessToken = accessToken ?: [FBSDKAccessToken currentAccessToken]; + // Rules for how we use the attribution ID / advertiser ID for an 'custom_audience_third_party_id' Graph API request + // 1) if the OS tells us that the user has Limited Ad Tracking, then just don't send, and return a nil in the token. + // 2) if the app has set 'limitEventAndDataUsage', this effectively implies that app-initiated ad targeting shouldn't happen, + // so use that data here to return nil as well. + // 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter + // 4) otherwise, send back the udid parameter. + + if ([FBSDKAppEventsUtility advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed || [FBSDKSettings limitEventAndDataUsage]) { + return nil; + } + + NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken]; + NSString *udid = nil; + if (!accessToken) { + // We don't have a logged in user, so we need some form of udid representation. Prefer advertiser ID if + // available, and back off to attribution ID if not. Note that this function only makes sense to be + // called in the context of advertising. + udid = [FBSDKAppEventsUtility advertiserID]; + if (!udid) { + udid = [FBSDKAppEventsUtility attributionID]; + } + + if (!udid) { + // No udid, and no user token. No point in making the request. + return nil; + } + } + + NSDictionary *parameters = nil; + if (udid) { + parameters = @{ @"udid" : udid }; + } + + NSString *graphPath = [NSString stringWithFormat:@"%@/custom_audience_third_party_id", [[self singleton] appID]]; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + tokenString:tokenString + HTTPMethod:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + return request; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h new file mode 100644 index 0000000..8e65e5b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h @@ -0,0 +1,82 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class BFTask; + +// Check if Bolts.framework is available for import +#if __has_include() +// Import it if it's available +# import +#else +// Otherwise - redeclare BFAppLinkResolving protocol to resolve the problem of missing symbols +// Please note: Bolts.framework is still required for AppLink resolving to work, +// but this allows FBSDKCoreKit to weakly link Bolts.framework as well as this enables clang modulemaps to work. + +/*! + Implement this protocol to provide an alternate strategy for resolving + App Links that may include pre-fetching, caching, or querying for App Link + data from an index provided by a service provider. + */ +@protocol BFAppLinkResolving + +/*! + Asynchronously resolves App Link data for a given URL. + + @param url The URL to resolve into an App Link. + @returns A BFTask that will return a BFAppLink for the given URL. + */ +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url; + +@end + +#endif + +/*! + @class FBSDKAppLinkResolver + + @abstract + Provides an implementation of the BFAppLinkResolving protocol that uses the Facebook App Link + Index API to resolve App Links given a URL. It also provides an additional helper method that can resolve + multiple App Links in a single call. + + @discussion + Usage of this type requires a client token. See `[FBSDKSettings setClientToken:]` and linking + Bolts.framework + */ +@interface FBSDKAppLinkResolver : NSObject + +/*! + @abstract Asynchronously resolves App Link data for multiple URLs. + + @param urls An array of NSURLs to resolve into App Links. + @returns A BFTask that will return dictionary mapping input NSURLs to their + corresponding BFAppLink. + + @discussion + You should set the client token before making this call. See `[FBSDKSettings setClientToken:]` + */ +- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls; + +/*! + @abstract Allocates and initializes a new instance of FBSDKAppLinkResolver. + */ ++ (instancetype)resolver; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.m new file mode 100644 index 0000000..9ce2143 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.m @@ -0,0 +1,195 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppLinkResolver.h" + +#import + +#import +#import +#import +#import + +#import "FBSDKGraphRequest+Internal.h" +#import "FBSDKGraphRequestConnection.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings+Internal.h" +#import "FBSDKUtility.h" + +static NSString *const kURLKey = @"url"; +static NSString *const kIOSAppStoreIdKey = @"app_store_id"; +static NSString *const kIOSAppNameKey = @"app_name"; +static NSString *const kWebKey = @"web"; +static NSString *const kIOSKey = @"ios"; +static NSString *const kIPhoneKey = @"iphone"; +static NSString *const kIPadKey = @"ipad"; +static NSString *const kShouldFallbackKey = @"should_fallback"; +static NSString *const kAppLinksKey = @"app_links"; + +static void FBSDKAppLinkResolverBoltsClassFromString(Class *clazz, NSString *className) +{ + *clazz = NSClassFromString(className); + if (*clazz == nil) { + NSString *message = [NSString stringWithFormat:@"Unable to load class %@. Did you link Bolts.framework?", className]; + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:message + userInfo:nil]; + } +} + +@interface FBSDKAppLinkResolver () + +@property (nonatomic, strong) NSMutableDictionary *cachedLinks; +@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom; +@end + +@implementation FBSDKAppLinkResolver + +static Class g_BFTaskCompletionSourceClass; +static Class g_BFAppLinkTargetClass; +static Class g_BFAppLinkClass; +static Class g_BFTaskClass; + ++ (void)initialize +{ + if (self == [FBSDKAppLinkResolver class]) { + FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskCompletionSourceClass, @"BFTaskCompletionSource"); + FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkTargetClass, @"BFAppLinkTarget"); + FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkClass, @"BFAppLink"); + FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskClass, @"BFTask"); + } +} + +- (id)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom +{ + if (self = [super init]) { + self.cachedLinks = [NSMutableDictionary dictionary]; + self.userInterfaceIdiom = userInterfaceIdiom; + } + return self; +} + +- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls +{ + if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + logEntry:@"A user access token or clientToken is required to use FBAppLinkResolver"]; + } + NSMutableDictionary *appLinks = [NSMutableDictionary dictionary]; + NSMutableArray *toFind = [NSMutableArray array]; + NSMutableArray *toFindStrings = [NSMutableArray array]; + + @synchronized (self.cachedLinks) { + for (NSURL *url in urls) { + if (self.cachedLinks[url]) { + appLinks[url] = self.cachedLinks[url]; + } else { + [toFind addObject:url]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [toFindStrings addObject:[url.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; +#pragma clang diagnostic pop + } + } + } + if (toFind.count == 0) { + // All of the URLs have already been found. + return [g_BFTaskClass taskWithResult:appLinks]; + } + NSMutableArray *fields = [NSMutableArray arrayWithObject:kIOSKey]; + + NSString *idiomSpecificField = nil; + + switch (self.userInterfaceIdiom) { + case UIUserInterfaceIdiomPad: + idiomSpecificField = kIPadKey; + break; + case UIUserInterfaceIdiomPhone: + idiomSpecificField = kIPhoneKey; + break; + default: + break; + } + if (idiomSpecificField) { + [fields addObject:idiomSpecificField]; + } + NSString *path = [NSString stringWithFormat:@"?fields=%@.fields(%@)&ids=%@", + kAppLinksKey, + [fields componentsJoinedByString:@","], + [toFindStrings componentsJoinedByString:@","]]; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path + parameters:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + BFTaskCompletionSource *tcs = [g_BFTaskCompletionSourceClass taskCompletionSource]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (error) { + [tcs setError:error]; + return; + } + for (NSURL *url in toFind) { + id nestedObject = [[result objectForKey:url.absoluteString] objectForKey:kAppLinksKey]; + NSMutableArray *rawTargets = [NSMutableArray array]; + if (idiomSpecificField) { + [rawTargets addObjectsFromArray:[nestedObject objectForKey:idiomSpecificField]]; + } + [rawTargets addObjectsFromArray:[nestedObject objectForKey:kIOSKey]]; + + NSMutableArray *targets = [NSMutableArray arrayWithCapacity:rawTargets.count]; + for (id rawTarget in rawTargets) { + [targets addObject:[g_BFAppLinkTargetClass appLinkTargetWithURL:[NSURL URLWithString:[rawTarget objectForKey:kURLKey]] + appStoreId:[rawTarget objectForKey:kIOSAppStoreIdKey] + appName:[rawTarget objectForKey:kIOSAppNameKey]]]; + } + + id webTarget = [nestedObject objectForKey:kWebKey]; + NSString *webFallbackString = [webTarget objectForKey:kURLKey]; + NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url; + + NSNumber *shouldFallback = [webTarget objectForKey:kShouldFallbackKey]; + if (shouldFallback && !shouldFallback.boolValue) { + fallbackUrl = nil; + } + + BFAppLink *link = [g_BFAppLinkClass appLinkWithSourceURL:url + targets:targets + webURL:fallbackUrl]; + @synchronized (self.cachedLinks) { + self.cachedLinks[url] = link; + } + appLinks[url] = link; + } + [tcs setResult:appLinks]; + }]; + return tcs.task; +} + +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url +{ + // Implement in terms of appLinksFromURLsInBackground + BFTask *resolveTask = [self appLinksFromURLsInBackground:@[url]]; + return [resolveTask continueWithSuccessBlock:^id(BFTask *task) { + return task.result[url]; + }]; +} + ++ (id)resolver +{ + return [[self alloc] initWithUserInterfaceIdiom:UI_USER_INTERFACE_IDIOM()]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h new file mode 100644 index 0000000..216b71d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Describes the callback for fetchDeferredAppLink. + @param url the url representing the deferred App Link + @param error the error during the request, if any + + @discussion The url may also have a fb_click_time_utc query parameter that + represents when the click occurred that caused the deferred App Link to be created. + */ +typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error); + +/*! + @abstract Class containing App Links related utility methods. + */ +@interface FBSDKAppLinkUtility : NSObject + +/*! + @abstract + Call this method from the main thread to fetch deferred applink data if you use Mobile App + Engagement Ads (https://developers.facebook.com/docs/ads-for-apps/mobile-app-ads-engagement). + This may require a network round trip. If successful, the handler is invoked with the link + data (this will only return a valid URL once, and future calls will result in a nil URL + value in the callback). + + @param handler the handler to be invoked if there is deferred App Link data + + @discussion The handler may contain an NSError instance to capture any errors. In the + common case where there simply was no app link data, the NSError instance will be nil. + + This method should only be called from a location that occurs after any launching URL has + been processed (e.g., you should call this method from your application delegate's + applicationDidBecomeActive:). + */ ++ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.m new file mode 100644 index 0000000..83dc2c4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.m @@ -0,0 +1,80 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppLinkUtility.h" + +#import "FBSDKAppEventsUtility.h" +#import "FBSDKGraphRequest.h" +#import "FBSDKSettings.h" +#import "FBSDKUtility.h" + +static NSString *const FBSDKLastDeferredAppLink = @"com.facebook.sdk:lastDeferredAppLink%@"; +static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK"; + +@implementation FBSDKAppLinkUtility {} + ++ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler +{ + NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchDeferredAppLink: must be invoked from main thread."); + + NSString *appID = [FBSDKSettings appID]; + + // Deferred app links are only currently used for engagement ads, thus we consider the app to be an advertising one. + // If this is considered for organic, non-ads scenarios, we'll need to retrieve the FBAppEventsUtility.shouldAccessAdvertisingID + // before we make this call. + NSMutableDictionary *deferredAppLinkParameters = + [FBSDKAppEventsUtility activityParametersDictionaryForEvent:FBSDKDeferredAppLinkEvent + implicitEventsOnly:NO + shouldAccessAdvertisingID:YES]; + + FBSDKGraphRequest *deferredAppLinkRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appID, nil] + parameters:deferredAppLinkParameters + tokenString:nil + version:nil + HTTPMethod:@"POST"]; + + [deferredAppLinkRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, + id result, + NSError *error) { + NSURL *applinkURL = nil; + if (!error) { + NSString *appLinkString = result[@"applink_url"]; + if (appLinkString) { + applinkURL = [NSURL URLWithString:appLinkString]; + + NSString *createTimeUtc = result[@"click_time"]; + if (createTimeUtc) { + // append/translate the create_time_utc so it can be used by clients + NSString *modifiedURLString = [[applinkURL absoluteString] + stringByAppendingFormat:@"%@fb_click_time_utc=%@", + ([applinkURL query]) ? @"&" : @"?" , + createTimeUtc ]; + applinkURL = [NSURL URLWithString:modifiedURLString]; + } + } + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(applinkURL, error); + }); + } + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h new file mode 100644 index 0000000..857acd0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h @@ -0,0 +1,74 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @class FBSDKApplicationDelegate + + @abstract + The FBSDKApplicationDelegate is designed to post process the results from Facebook Login + or Facebook Dialogs (or any action that requires switching over to the native Facebook + app or Safari). + + @discussion + The methods in this class are designed to mirror those in UIApplicationDelegate, and you + should call them in the respective methods in your AppDelegate implementation. + */ +@interface FBSDKApplicationDelegate : NSObject + +/*! + @abstract Gets the singleton instance. + */ ++ (instancetype)sharedInstance; + +/*! + @abstract + Call this method from the [UIApplicationDelegate application:openURL:sourceApplication:annotation:] method + of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction + with the native Facebook app or Safari as part of SSO authorization flow or Facebook dialogs. + + @param application The application as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param url The URL as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param sourceApplication The sourceApplication as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @return YES if the url was intended for the Facebook SDK, NO if not. + */ +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation; + +/*! + @abstract + Call this method from the [UIApplicationDelegate application:didFinishLaunchingWithOptions:] method + of the AppDelegate for your app. It should be invoked for the proper use of the Facebook SDK. + + @param application The application as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + + @param launchOptions The launchOptions as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + + @return YES if the url was intended for the Facebook SDK, NO if not. + */ +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.m new file mode 100644 index 0000000..d3916a4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.m @@ -0,0 +1,430 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKApplicationDelegate.h" +#import "FBSDKApplicationDelegate+Internal.h" + +#import + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKBoltsMeasurementEventListener.h" +#import "FBSDKBridgeAPIRequest.h" +#import "FBSDKBridgeAPIResponse.h" +#import "FBSDKConstants.h" +#import "FBSDKContainerViewController.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKProfile+Internal.h" +#import "FBSDKServerConfiguration.h" +#import "FBSDKServerConfigurationManager.h" +#import "FBSDKSettings+Internal.h" +#import "FBSDKTimeSpentData.h" +#import "FBSDKUtility.h" + +NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification"; + +static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound"; + +@implementation FBSDKApplicationDelegate +{ + FBSDKBridgeAPIRequest *_pendingRequest; + FBSDKBridgeAPICallbackBlock _pendingRequestCompletionBlock; + id _pendingURLOpen; + BOOL _expectingBackground; + UIViewController *_safariViewController; +} + +#pragma mark - Class Methods + ++ (void)load +{ + // when the app becomes active by any means, kick off the initialization. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(initializeWithLaunchData:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +} + +// Initialize SDK listeners +// Don't call this function in any place else. It should only be called when the class is loaded. ++ (void)initializeWithLaunchData:(NSNotification *)note +{ + NSDictionary *launchData = note.userInfo; + // Register Listener for Bolts measurement events + [FBSDKBoltsMeasurementEventListener defaultListener]; + + // Set the SourceApplication for time spent data. This is not going to update the value if the app has already launched. + [FBSDKTimeSpentData setSourceApplication:launchData[UIApplicationLaunchOptionsSourceApplicationKey] + openURL:launchData[UIApplicationLaunchOptionsURLKey]]; + // Register on UIApplicationDidEnterBackgroundNotification events to reset source application data when app backgrounds. + [FBSDKTimeSpentData registerAutoResetSourceApplication]; + + // Remove the observer + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + ++ (instancetype)sharedInstance +{ + static FBSDKApplicationDelegate *_sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[self alloc] _init]; + }); + return _sharedInstance; +} + +#pragma mark - Object Lifecycle + +- (instancetype)_init +{ + if ((self = [super init]) != nil) { + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; + [defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; + } + return self; +} + +- (instancetype)init +{ + return nil; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - UIApplicationDelegate + +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation +{ + if (sourceApplication != nil && ![sourceApplication isKindOfClass:[NSString class]]) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Expected 'sourceApplication' to be NSString. Please verify you are passing in 'sourceApplication' from your app delegate (not the UIApplication* parameter). If your app delegate implements iOS 9's application:openURL:options:, you should pass in options[UIApplicationOpenURLOptionsSourceApplicationKey]. " + userInfo:nil]; + } + [FBSDKTimeSpentData setSourceApplication:sourceApplication openURL:url]; + // if they completed a SFVC flow, dimiss it. + [_safariViewController.presentingViewController dismissViewControllerAnimated:YES completion: nil]; + _safariViewController = nil; + + if (_pendingURLOpen) { + id pendingURLOpen = _pendingURLOpen; + + _pendingURLOpen = nil; + + if ([pendingURLOpen application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]) { + return YES; + } + } + if ([self _handleBridgeAPIResponseURL:url sourceApplication:sourceApplication]) { + return YES; + } + + [self _logIfAppLinkEvent:url]; + + return NO; +} + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + FBSDKProfile *cachedProfile = [FBSDKProfile fetchCachedProfile]; + [FBSDKProfile setCurrentProfile:cachedProfile]; + + FBSDKAccessToken *cachedToken = [[FBSDKSettings accessTokenCache] fetchAccessToken]; + [FBSDKAccessToken setCurrentAccessToken:cachedToken]; + + NSURL *launchedURL = launchOptions[UIApplicationLaunchOptionsURLKey]; + NSString *sourceApplication = launchOptions[UIApplicationLaunchOptionsSourceApplicationKey]; + + if (launchedURL && + sourceApplication) { + Class loginManagerClass = NSClassFromString(@"FBSDKLoginManager"); + if (loginManagerClass) { + id annotation = launchOptions[UIApplicationLaunchOptionsAnnotationKey]; + id loginManager = [[loginManagerClass alloc] init]; + return [loginManager application:application + openURL:launchedURL + sourceApplication:sourceApplication + annotation:annotation]; + } + } + return NO; +} + +- (void)applicationDidEnterBackground:(NSNotification *)notification +{ + _active = NO; + _expectingBackground = NO; +} + +- (void)applicationDidBecomeActive:(NSNotification *)notification +{ + // _expectingBackground can be YES if the caller started doing work (like login) + // within the app delegate's lifecycle like openURL, in which case there + // might have been a "didBecomeActive" event pending that we want to ignore. + if (!_expectingBackground && !_safariViewController) { + _active = YES; + [_pendingURLOpen applicationDidBecomeActive:[notification object]]; + + [self _cancelBridgeRequest]; + + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKApplicationDidBecomeActiveNotification object:self]; + } +} + +#pragma mark - SFSafariViewControllerDelegate + +// This means the user tapped "Done" which we should treat as a cancellation. +- (void)safariViewControllerDidFinish:(UIViewController *)safariViewController +{ + if (_pendingURLOpen) { + id pendingURLOpen = _pendingURLOpen; + + _pendingURLOpen = nil; + + [pendingURLOpen application:nil + openURL:nil + sourceApplication:nil + annotation:nil]; + + } + [self _cancelBridgeRequest]; + _safariViewController = nil; +} + +#pragma mark - FBSDKContainerViewControllerDelegate + +- (void)viewControllerDidDisappear:(FBSDKContainerViewController *)viewController animated:(BOOL)animated +{ + if (_safariViewController) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + logEntry:@"**ERROR**:\n The SFSafariViewController's parent view controller was dismissed.\n" + "This can happen if you are triggering login from a UIAlertController. Instead, make sure your top most view " + "controller will not be prematurely dismissed."]; + [self safariViewControllerDidFinish:_safariViewController]; + } +} + +#pragma mark - Internal Methods + +- (void)openBridgeAPIRequest:(FBSDKBridgeAPIRequest *)request + useSafariViewController:(BOOL)useSafariViewController + fromViewController:(UIViewController *)fromViewController + completionBlock:(FBSDKBridgeAPICallbackBlock)completionBlock +{ + if (!request) { + return; + } + NSError *error; + NSURL *requestURL = [request requestURL:&error]; + if (!requestURL) { + FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request error:error]; + completionBlock(response); + return; + } + _pendingRequest = request; + _pendingRequestCompletionBlock = [completionBlock copy]; + void (^handler)(BOOL) = ^(BOOL openedURL) { + if (!openedURL) { + _pendingRequest = nil; + _pendingRequestCompletionBlock = nil; + NSError *openedURLError; + if ([request.scheme hasPrefix:@"http"]) { + openedURLError = [FBSDKError errorWithCode:FBSDKBrowswerUnavailableErrorCode + message:@"the app switch failed because the browser is unavailable"]; + } else { + openedURLError = [FBSDKError errorWithCode:FBSDKAppVersionUnsupportedErrorCode + message:@"the app switch failed because the destination app is out of date"]; + } + FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request + error:openedURLError]; + completionBlock(response); + return; + } + }; + if (useSafariViewController) { + [self openURLWithSafariViewController:requestURL sender:nil fromViewController:fromViewController handler:handler]; + } else { + [self openURL:requestURL sender:nil handler:handler]; + } +} + +- (void)openURLWithSafariViewController:(NSURL *)url + sender:(id)sender + fromViewController:(UIViewController *)fromViewController + handler:(void(^)(BOOL))handler +{ + if (![url.scheme hasPrefix:@"http"]) { + [self openURL:url sender:sender handler:handler]; + return; + } + + _expectingBackground = NO; + _pendingURLOpen = sender; + + // trying to dynamically load SFSafariViewController class + // so for the cases when it is available we can send users through Safari View Controller flow + // in cases it is not available regular flow will be selected + Class SFSafariViewControllerClass = fbsdkdfl_SFSafariViewControllerClass(); + + if (SFSafariViewControllerClass) { + UIViewController *parent = fromViewController ?: [FBSDKInternalUtility topMostViewController]; + NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; + NSURLQueryItem *sfvcQueryItem = [[NSURLQueryItem alloc] initWithName:@"sfvc" value:@"1"]; + [components setQueryItems:[components.queryItems arrayByAddingObject:sfvcQueryItem]]; + url = components.URL; + FBSDKContainerViewController *container = [[FBSDKContainerViewController alloc] init]; + container.delegate = self; + if (parent.transitionCoordinator != nil) { + // Wait until the transition is finished before presenting SafariVC to avoid a blank screen. + [parent.transitionCoordinator animateAlongsideTransition:NULL completion:^(id context) { + // Note SFVC init must occur inside block to avoid blank screen. + _safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url]; + [_safariViewController performSelector:@selector(setDelegate:) withObject:self]; + [container displayChildController:_safariViewController]; + [parent presentViewController:container animated:YES completion:nil]; + }]; + } else { + _safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url]; + [_safariViewController performSelector:@selector(setDelegate:) withObject:self]; + [container displayChildController:_safariViewController]; + [parent presentViewController:container animated:YES completion:nil]; + } + + // Assuming Safari View Controller always opens + if (handler) { + handler(YES); + } + } else { + [self openURL:url sender:sender handler:handler]; + } +} + +- (void)openURL:(NSURL *)url sender:(id)sender handler:(void(^)(BOOL))handler +{ + _expectingBackground = YES; + _pendingURLOpen = sender; + dispatch_async(dispatch_get_main_queue(), ^{ + // Dispatch openURL calls to prevent hangs if we're inside the current app delegate's openURL flow already + BOOL opened = [[UIApplication sharedApplication] openURL:url]; + + if ([url.scheme hasPrefix:@"http"] && !opened) { + NSOperatingSystemVersion iOS8Version = { .majorVersion = 8, .minorVersion = 0, .patchVersion = 0 }; + if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) { + // Safari openURL calls can wrongly return NO on iOS 7 so manually overwrite that case to YES. + // Otherwise we would rather trust in the actual result of openURL + opened = YES; + } + } + if (handler) { + handler(opened); + } + }); +} + +#pragma mark - Helper Methods + +- (BOOL)_handleBridgeAPIResponseURL:(NSURL *)responseURL sourceApplication:(NSString *)sourceApplication +{ + FBSDKBridgeAPIRequest *request = _pendingRequest; + FBSDKBridgeAPICallbackBlock completionBlock = _pendingRequestCompletionBlock; + _pendingRequest = nil; + _pendingRequestCompletionBlock = NULL; + if (![responseURL.scheme isEqualToString:[FBSDKInternalUtility appURLScheme]]) { + return NO; + } + if (![responseURL.host isEqualToString:@"bridge"]) { + return NO; + } + if (!request) { + return NO; + } + if (!completionBlock) { + return YES; + } + NSError *error; + FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request + responseURL:responseURL + sourceApplication:sourceApplication + error:&error]; + if (response) { + completionBlock(response); + return YES; + } else if (error) { + completionBlock([FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request error:error]); + return YES; + } else { + return NO; + } +} + +- (void)_logIfAppLinkEvent:(NSURL *)url +{ + if (!url) { + return; + } + NSDictionary *params = [FBSDKUtility dictionaryWithQueryString:url.query]; + NSString *applinkDataString = params[@"al_applink_data"]; + if (!applinkDataString) { + return; + } + + NSDictionary * applinkData = [FBSDKInternalUtility objectForJSONString:applinkDataString error:NULL]; + if (!applinkData) { + return; + } + + NSURL *targetURL = [NSURL URLWithString:applinkData[@"target_url"]]; + NSMutableDictionary *logData = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:logData setObject:[targetURL absoluteString] forKey:@"targetURL"]; + [FBSDKInternalUtility dictionary:logData setObject:[targetURL host] forKey:@"targetURLHost"]; + + NSDictionary *refererData = applinkData[@"referer_data"]; + if (refererData) { + [FBSDKInternalUtility dictionary:logData setObject:refererData[@"target_url"] forKey:@"referralTargetURL"]; + [FBSDKInternalUtility dictionary:logData setObject:refererData[@"url"] forKey:@"referralURL"]; + [FBSDKInternalUtility dictionary:logData setObject:refererData[@"app_name"] forKey:@"referralAppName"]; + } + [FBSDKInternalUtility dictionary:logData setObject:[url absoluteString] forKey:@"inputURL"]; + [FBSDKInternalUtility dictionary:logData setObject:[url scheme] forKey:@"inputURLScheme"]; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppLinkInboundEvent + valueToSum:nil + parameters:logData + accessToken:nil]; +} + +- (void)_cancelBridgeRequest +{ + if (_pendingRequest && _pendingRequestCompletionBlock) { + _pendingRequestCompletionBlock([FBSDKBridgeAPIResponse bridgeAPIResponseCancelledWithRequest:_pendingRequest]); + } + _pendingRequest = nil; + _pendingRequestCompletionBlock = NULL; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h new file mode 100644 index 0000000..8132998 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract A base class for common SDK buttons. + */ +@interface FBSDKButton : UIButton + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.m new file mode 100644 index 0000000..48467b5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.m @@ -0,0 +1,430 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKButton.h" +#import "FBSDKButton+Subclass.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKAppEvents.h" +#import "FBSDKApplicationDelegate+Internal.h" +#import "FBSDKLogo.h" +#import "FBSDKMath.h" +#import "FBSDKUIUtility.h" +#import "FBSDKViewImpressionTracker.h" + +#define HEIGHT_TO_FONT_SIZE 0.47 +#define HEIGHT_TO_MARGIN 0.27 +#define HEIGHT_TO_PADDING 0.23 +#define HEIGHT_TO_TEXT_PADDING_CORRECTION 0.08 + +@implementation FBSDKButton +{ + BOOL _skipIntrinsicContentSizing; + BOOL _isExplicitlyDisabled; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + _skipIntrinsicContentSizing = YES; + [self configureButton]; + _skipIntrinsicContentSizing = NO; + } + return self; +} + +- (void)awakeFromNib +{ + [super awakeFromNib]; + _skipIntrinsicContentSizing = YES; + [self configureButton]; + _skipIntrinsicContentSizing = NO; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Properties + +- (void)setEnabled:(BOOL)enabled +{ + _isExplicitlyDisabled = !enabled; + [self checkImplicitlyDisabled]; +} + +#pragma mark - Layout + +- (CGRect)imageRectForContentRect:(CGRect)contentRect +{ + if ([self isHidden] || CGRectIsEmpty(self.bounds)) { + return CGRectZero; + } + CGRect imageRect = UIEdgeInsetsInsetRect(contentRect, self.imageEdgeInsets); + CGFloat margin = [self _marginForHeight:[self _heightForContentRect:contentRect]]; + imageRect = CGRectInset(imageRect, margin, margin); + imageRect.size.width = CGRectGetHeight(imageRect); + return imageRect; +} + +- (CGSize)intrinsicContentSize +{ + if (_skipIntrinsicContentSizing) { + return CGSizeZero; + } + _skipIntrinsicContentSizing = YES; + CGSize size = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; + _skipIntrinsicContentSizing = NO; + return size; +} + +- (void)layoutSubviews +{ + // automatic impression tracking if the button conforms to FBSDKButtonImpressionTracking + if ([self conformsToProtocol:@protocol(FBSDKButtonImpressionTracking)]) { + NSString *eventName = [(id)self impressionTrackingEventName]; + NSString *identifier = [(id)self impressionTrackingIdentifier]; + NSDictionary *parameters = [(id)self analyticsParameters]; + if (eventName && identifier) { + FBSDKViewImpressionTracker *impressionTracker = [FBSDKViewImpressionTracker impressionTrackerWithEventName:eventName]; + [impressionTracker logImpressionWithIdentifier:identifier parameters:parameters]; + } + } + [super layoutSubviews]; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + if ([self isHidden]) { + return CGSizeZero; + } + CGSize normalSize = [self sizeThatFits:size title:[self titleForState:UIControlStateNormal]]; + CGSize selectedSize = [self sizeThatFits:size title:[self titleForState:UIControlStateSelected]]; + return CGSizeMake(MAX(normalSize.width, selectedSize.width), MAX(normalSize.height, selectedSize.height)); +} + +- (void)sizeToFit +{ + CGRect bounds = self.bounds; + bounds.size = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; + self.bounds = bounds; +} + +- (CGRect)titleRectForContentRect:(CGRect)contentRect +{ + if ([self isHidden] || CGRectIsEmpty(self.bounds)) { + return CGRectZero; + } + CGRect imageRect = [self imageRectForContentRect:contentRect]; + CGFloat height = [self _heightForContentRect:contentRect]; + CGFloat padding = [self _paddingForHeight:height]; + CGFloat titleX = CGRectGetMaxX(imageRect) + padding; + CGRect titleRect = CGRectMake(titleX, 0.0, CGRectGetWidth(contentRect) - titleX, CGRectGetHeight(contentRect)); + + UIEdgeInsets titleEdgeInsets = UIEdgeInsetsZero; + if (!self.layer.needsLayout) { + UILabel *titleLabel = self.titleLabel; + if (titleLabel.textAlignment == NSTextAlignmentCenter) { + // if the text is centered, we need to adjust the frame for the titleLabel based on the size of the text in order + // to keep the text centered in the button without adding extra blank space to the right when unnecessary + // 1. the text fits centered within the button without colliding with the image (imagePaddingWidth) + // 2. the text would run into the image, so adjust the insets to effectively left align it (textPaddingWidth) + CGSize titleSize = FBSDKTextSize(titleLabel.text, + titleLabel.font, + titleRect.size, + titleLabel.lineBreakMode); + CGFloat titlePaddingWidth = (CGRectGetWidth(titleRect) - titleSize.width) / 2; + CGFloat imagePaddingWidth = (titleX - [self _marginForHeight:height]) / 2; + CGFloat inset = MIN(titlePaddingWidth, imagePaddingWidth); + titleEdgeInsets.left -= inset; + titleEdgeInsets.right += inset; + } + } + return UIEdgeInsetsInsetRect(titleRect, titleEdgeInsets); +} + +#pragma mark - Subclass Methods + +- (void)logTapEventWithEventName:(NSString *)eventName parameters:(NSDictionary *)parameters +{ + [FBSDKAppEvents logImplicitEvent:eventName + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; +} + +- (void)checkImplicitlyDisabled +{ + BOOL enabled = !_isExplicitlyDisabled && ![self isImplicitlyDisabled]; + BOOL currentEnabled = [self isEnabled]; + [super setEnabled:enabled]; + if (currentEnabled != enabled) { + [self invalidateIntrinsicContentSize]; + [self setNeedsLayout]; + } +} + +- (void)configureButton +{ + [self configureWithIcon:[[self class] defaultIcon] + title:nil + backgroundColor:[[self class] defaultBackgroundColor] + highlightedColor:[[self class] defaultHighlightedColor]]; +} + +- (void)configureWithIcon:(FBSDKIcon *)icon + title:(NSString *)title + backgroundColor:(UIColor *)backgroundColor + highlightedColor:(UIColor *)highlightedColor +{ + [self _configureWithIcon:icon + title:title + backgroundColor:backgroundColor + highlightedColor:highlightedColor + selectedTitle:nil + selectedIcon:nil + selectedColor:nil + selectedHighlightedColor:nil]; +} + +- (void)configureWithIcon:(FBSDKIcon *)icon + title:(NSString *)title + backgroundColor:(UIColor *)backgroundColor + highlightedColor:(UIColor *)highlightedColor + selectedTitle:(NSString *)selectedTitle + selectedIcon:(FBSDKIcon *)selectedIcon + selectedColor:(UIColor *)selectedColor + selectedHighlightedColor:(UIColor *)selectedHighlightedColor +{ + if (!selectedColor) { + selectedColor = [self defaultSelectedColor]; + } + if (!selectedHighlightedColor) { + selectedHighlightedColor = highlightedColor; + } + [self _configureWithIcon:icon + title:title + backgroundColor:backgroundColor + highlightedColor:highlightedColor + selectedTitle:selectedTitle + selectedIcon:selectedIcon + selectedColor:selectedColor + selectedHighlightedColor:selectedHighlightedColor]; +} + +- (UIColor *)defaultBackgroundColor +{ + return [UIColor colorWithRed:65.0/255.0 green:93.0/255.0 blue:174.0/255.0 alpha:1.0]; +} + +- (UIColor *)defaultDisabledColor +{ + return [UIColor colorWithRed:189.0/255.0 green:193.0/255.0 blue:201.0/255.0 alpha:1.0]; +} + +- (UIColor *)defaultHighlightedColor +{ + return [UIColor colorWithRed:47.0/255.0 green:71.0/255.0 blue:122.0/255.0 alpha:1.0]; +} + +- (FBSDKIcon *)defaultIcon +{ + return [[FBSDKLogo alloc] init]; +} + +- (UIColor *)defaultSelectedColor +{ + return [UIColor colorWithRed:124.0/255.0 green:143.0/255.0 blue:200.0/255.0 alpha:1.0]; +} + +- (BOOL)isImplicitlyDisabled +{ + return NO; +} + +- (CGSize)sizeThatFits:(CGSize)size title:(NSString *)title +{ + UIFont *font = self.titleLabel.font; + CGFloat height = [self _heightForFont:font]; + + UIEdgeInsets contentEdgeInsets = self.contentEdgeInsets; + + CGSize constrainedContentSize = FBSDKEdgeInsetsInsetSize(size, contentEdgeInsets); + + CGSize titleSize = FBSDKTextSize(title, font, constrainedContentSize, self.titleLabel.lineBreakMode); + + CGFloat padding = [self _paddingForHeight:height]; + CGFloat textPaddingCorrection = [self _textPaddingCorrectionForHeight:height]; + CGSize contentSize = CGSizeMake(height + padding + titleSize.width - textPaddingCorrection, height); + return FBSDKEdgeInsetsOutsetSize(contentSize, contentEdgeInsets); +} + +#pragma mark - Helper Methods + +- (void)_applicationDidBecomeActiveNotification:(NSNotification *)notification +{ + [self checkImplicitlyDisabled]; +} + +- (UIImage *)_backgroundImageWithColor:(UIColor *)color cornerRadius:(CGFloat)cornerRadius scale:(CGFloat)scale +{ + CGFloat size = 1.0 + 2 * cornerRadius; + UIGraphicsBeginImageContextWithOptions(CGSizeMake(size, size), NO, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetFillColorWithColor(context, color.CGColor); + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, NULL, cornerRadius + 1.0, 0.0); + CGPathAddArcToPoint(path, NULL, size, 0.0, size, cornerRadius, cornerRadius); + CGPathAddLineToPoint(path, NULL, size, cornerRadius + 1.0); + CGPathAddArcToPoint(path, NULL, size, size, cornerRadius + 1.0, size, cornerRadius); + CGPathAddLineToPoint(path, NULL, cornerRadius, size); + CGPathAddArcToPoint(path, NULL, 0.0, size, 0.0, cornerRadius + 1.0, cornerRadius); + CGPathAddLineToPoint(path, NULL, 0.0, cornerRadius); + CGPathAddArcToPoint(path, NULL, 0.0, 0.0, cornerRadius, 0.0, cornerRadius); + CGPathCloseSubpath(path); + CGContextAddPath(context, path); + CGPathRelease(path); + CGContextFillPath(context); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return [image stretchableImageWithLeftCapWidth:cornerRadius topCapHeight:cornerRadius]; +} + +- (void)_configureWithIcon:(FBSDKIcon *)icon + title:(NSString *)title + backgroundColor:(UIColor *)backgroundColor + highlightedColor:(UIColor *)highlightedColor + selectedTitle:(NSString *)selectedTitle + selectedIcon:(FBSDKIcon *)selectedIcon + selectedColor:(UIColor *)selectedColor + selectedHighlightedColor:(UIColor *)selectedHighlightedColor +{ + [self checkImplicitlyDisabled]; + + if (!icon) { + icon = [self defaultIcon]; + } + if (!backgroundColor) { + backgroundColor = [self defaultBackgroundColor]; + } + if (!highlightedColor) { + highlightedColor = [self defaultHighlightedColor]; + } + + self.adjustsImageWhenDisabled = NO; + self.adjustsImageWhenHighlighted = NO; + self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; + self.contentVerticalAlignment = UIControlContentVerticalAlignmentFill; + self.tintColor = [UIColor whiteColor]; + + BOOL forceSizeToFit = CGRectIsEmpty(self.bounds); + + CGFloat scale = [UIScreen mainScreen].scale; + UIImage *backgroundImage; + + backgroundImage = [self _backgroundImageWithColor:backgroundColor cornerRadius:3.0 scale:scale]; + [self setBackgroundImage:backgroundImage forState:UIControlStateNormal]; + + backgroundImage = [self _backgroundImageWithColor:highlightedColor cornerRadius:3.0 scale:scale]; + [self setBackgroundImage:backgroundImage forState:UIControlStateHighlighted]; + + backgroundImage = [self _backgroundImageWithColor:[self defaultDisabledColor] cornerRadius:3.0 scale:scale]; + [self setBackgroundImage:backgroundImage forState:UIControlStateDisabled]; + + if (selectedColor) { + backgroundImage = [self _backgroundImageWithColor:selectedColor cornerRadius:3.0 scale:scale]; + [self setBackgroundImage:backgroundImage forState:UIControlStateSelected]; + } + + if (selectedHighlightedColor) { + backgroundImage = [self _backgroundImageWithColor:selectedHighlightedColor cornerRadius:3.0 scale:scale]; + [self setBackgroundImage:backgroundImage forState:UIControlStateSelected | UIControlStateHighlighted]; + } + + [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + + [self setTitle:title forState:UIControlStateNormal]; + if (selectedTitle) { + [self setTitle:selectedTitle forState:UIControlStateSelected]; + [self setTitle:selectedTitle forState:UIControlStateSelected | UIControlStateHighlighted]; + } + + UILabel *titleLabel = self.titleLabel; + titleLabel.lineBreakMode = NSLineBreakByClipping; + UIFont *font = [UIFont boldSystemFontOfSize:14.0]; + titleLabel.font = font; + + CGSize imageSize = CGSizeMake(font.pointSize, font.pointSize); + UIImage *image = [icon imageWithSize:imageSize]; + image = [image resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeStretch]; + [self setImage:image forState:UIControlStateNormal]; + + if (selectedIcon) { + UIImage *selectedImage = [selectedIcon imageWithSize:imageSize]; + selectedImage = [selectedImage resizableImageWithCapInsets:UIEdgeInsetsZero + resizingMode:UIImageResizingModeStretch]; + [self setImage:selectedImage forState:UIControlStateSelected]; + [self setImage:selectedImage forState:UIControlStateSelected | UIControlStateHighlighted]; + } + + if (forceSizeToFit) { + [self sizeToFit]; + } + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_applicationDidBecomeActiveNotification:) + name:FBSDKApplicationDidBecomeActiveNotification + object:[FBSDKApplicationDelegate sharedInstance]]; +} + +- (CGFloat)_fontSizeForHeight:(CGFloat)height +{ + return floorf(height * HEIGHT_TO_FONT_SIZE); +} + +- (CGFloat)_heightForContentRect:(CGRect)contentRect +{ + UIEdgeInsets contentEdgeInsets = self.contentEdgeInsets; + return contentEdgeInsets.top + CGRectGetHeight(contentRect) + contentEdgeInsets.bottom; +} + +- (CGFloat)_heightForFont:(UIFont *)font +{ + return floorf(font.pointSize / (1 - 2 * HEIGHT_TO_MARGIN)); +} + +- (CGFloat)_marginForHeight:(CGFloat)height +{ + return floorf(height * HEIGHT_TO_MARGIN); +} + +- (CGFloat)_paddingForHeight:(CGFloat)height +{ + return roundf(height * HEIGHT_TO_PADDING) - [self _textPaddingCorrectionForHeight:height]; +} + +- (CGFloat)_textPaddingCorrectionForHeight:(CGFloat)height +{ + return floorf(height * HEIGHT_TO_TEXT_PADDING_CORRECTION); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h new file mode 100644 index 0000000..5f53161 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h @@ -0,0 +1,210 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKCoreKit. + @discussion Error codes from the SDK in the range 0-99 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKErrorCode) + @abstract Error codes for FBSDKErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKReservedErrorCode = 0, + + /*! + @abstract The error code for errors from invalid encryption on incoming encryption URLs. + */ + FBSDKEncryptionErrorCode, + + /*! + @abstract The error code for errors from invalid arguments to SDK methods. + */ + FBSDKInvalidArgumentErrorCode, + + /*! + @abstract The error code for unknown errors. + */ + FBSDKUnknownErrorCode, + + /*! + @abstract A request failed due to a network error. Use NSUnderlyingErrorKey to retrieve + the error object from the NSURLConnection for more information. + */ + FBSDKNetworkErrorCode, + + /*! + @abstract The error code for errors encounted during an App Events flush. + */ + FBSDKAppEventsFlushErrorCode, + + /*! + @abstract An endpoint that returns a binary response was used with FBSDKGraphRequestConnection. + @discussion Endpoints that return image/jpg, etc. should be accessed using NSURLRequest + */ + FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode, + + /*! + @abstract The operation failed because the server returned an unexpected response. + @discussion You can get this error if you are not using the most recent SDK, or you are accessing a version of the + Graph API incompatible with the current SDK. + */ + FBSDKGraphRequestProtocolMismatchErrorCode, + + /*! + @abstract The Graph API returned an error. + @discussion See below for useful userInfo keys (beginning with FBSDKGraphRequestError*) + */ + FBSDKGraphRequestGraphAPIErrorCode, + + /*! + @abstract The specified dialog configuration is not available. + @discussion This error may signify that the configuration for the dialogs has not yet been downloaded from the server + or that the dialog is unavailable. Subsequent attempts to use the dialog may succeed as the configuration is loaded. + */ + FBSDKDialogUnavailableErrorCode, + + /*! + @abstract Indicates an operation failed because a required access token was not found. + */ + FBSDKAccessTokenRequiredErrorCode, + + /*! + @abstract Indicates an app switch (typically for a dialog) failed because the destination app is out of date. + */ + FBSDKAppVersionUnsupportedErrorCode, + + /*! + @abstract Indicates an app switch to the browser (typically for a dialog) failed. + */ + FBSDKBrowswerUnavailableErrorCode, +}; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory) + @abstract Describes the category of Facebook error. See `FBSDKGraphRequestErrorCategoryKey`. + */ +typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory) +{ + /*! The default error category that is not known to be recoverable. Check `FBSDKLocalizedErrorDescriptionKey` for a user facing message. */ + FBSDKGraphRequestErrorCategoryOther = 0, + /*! Indicates the error is temporary (such as server throttling). While a recoveryAttempter will be provided with the error instance, the attempt is guaranteed to succeed so you can simply retry the operation if you do not want to present an alert. */ + FBSDKGraphRequestErrorCategoryTransient = 1, + /*! Indicates the error can be recovered (such as requiring a login). A recoveryAttempter will be provided with the error instance that can take UI action. */ + FBSDKGraphRequestErrorCategoryRecoverable = 2 +}; + +/* + @methodgroup error userInfo keys + */ + +/*! + @abstract The userInfo key for the invalid collection for errors with FBSDKInvalidArgumentErrorCode. + @discussion If the invalid argument is a collection, the collection can be found with this key and the individual + invalid item can be found with FBSDKErrorArgumentValueKey. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentCollectionKey; + +/*! + @abstract The userInfo key for the invalid argument name for errors with FBSDKInvalidArgumentErrorCode. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentNameKey; + +/*! + @abstract The userInfo key for the invalid argument value for errors with FBSDKInvalidArgumentErrorCode. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentValueKey; + +/*! + @abstract The userInfo key for the message for developers in NSErrors that originate from the SDK. + @discussion The developer message will not be localized and is not intended to be presented within the app. + */ +FBSDK_EXTERN NSString *const FBSDKErrorDeveloperMessageKey; + +/*! + @abstract The userInfo key describing a localized description that can be presented to the user. + */ +FBSDK_EXTERN NSString *const FBSDKErrorLocalizedDescriptionKey; + +/*! + @abstract The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`. + */ +FBSDK_EXTERN NSString *const FBSDKErrorLocalizedTitleKey; + +/* + @methodgroup FBSDKGraphRequest error userInfo keys + */ + +/*! + @abstract The userInfo key describing the error category, for error recovery purposes. + @discussion See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorCategoryKey; + +/* + @abstract The userInfo key for the Graph API error code. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorCode; + +/* + @abstract The userInfo key for the Graph API error subcode. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorSubcode; + +/* + @abstract The userInfo key for the HTTP status code. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey; + +/* + @abstract The userInfo key for the raw JSON response. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey; + +/*! + @abstract a formal protocol very similar to the informal protocol NSErrorRecoveryAttempting + */ +@protocol FBSDKErrorRecoveryAttempting + +/*! + @abstract attempt the recovery + @param error the error + @param recoveryOptionIndex the selected option index + @param delegate the delegate + @param didRecoverSelector the callback selector, see discussion. + @param contextInfo context info to pass back to callback selector, see discussion. + @discussion + Given that an error alert has been presented document-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and send the selected message to the specified delegate. The option index is an index into the error's array of localized recovery options. The method selected by didRecoverSelector must have the same signature as: + + - (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo; + + The value passed for didRecover must be YES if error recovery was completely successful, NO otherwise. + */ +- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.m new file mode 100644 index 0000000..f3a6ee5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.m @@ -0,0 +1,34 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKConstants.h" + +NSString *const FBSDKErrorDomain = @"com.facebook.sdk.core"; + +NSString *const FBSDKErrorArgumentCollectionKey = @"com.facebook.sdk:FBSDKErrorArgumentCollectionKey"; +NSString *const FBSDKErrorArgumentNameKey = @"com.facebook.sdk:FBSDKErrorArgumentNameKey"; +NSString *const FBSDKErrorArgumentValueKey = @"com.facebook.sdk:FBSDKErrorArgumentValueKey"; +NSString *const FBSDKErrorDeveloperMessageKey = @"com.facebook.sdk:FBSDKErrorDeveloperMessageKey"; +NSString *const FBSDKErrorLocalizedDescriptionKey = @"com.facebook.sdk:FBSDKErrorLocalizedDescriptionKey"; +NSString *const FBSDKErrorLocalizedTitleKey = @"com.facebook.sdk:FBSDKErrorLocalizedErrorTitleKey"; + +NSString *const FBSDKGraphRequestErrorCategoryKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey"; +NSString *const FBSDKGraphRequestErrorGraphErrorCode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode"; +NSString *const FBSDKGraphRequestErrorGraphErrorSubcode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode"; +NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey"; +NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey = @"com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey"; diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h new file mode 100644 index 0000000..f4ad767 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Extension protocol for NSCopying that adds the copy method, which is implemented on NSObject. + @discussion NSObject implicitly conforms to this protocol. + */ +@protocol FBSDKCopying + +/*! + @abstract Implemented by NSObject as a convenience to copyWithZone:. + @return A copy of the receiver. + */ +- (id)copy; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h new file mode 100644 index 0000000..3b78900 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h @@ -0,0 +1,38 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#define FBSDK_VERSION_STRING @"4.7.0" +#define FBSDK_TARGET_PLATFORM_VERSION @"v2.5" diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h new file mode 100644 index 0000000..d2b0313 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h @@ -0,0 +1,97 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKConstants.h" + +@class FBSDKGraphErrorRecoveryProcessor; +@class FBSDKGraphRequest; + +/*! + @abstract Defines a delegate for `FBSDKGraphErrorRecoveryProcessor`. + */ +@protocol FBSDKGraphErrorRecoveryProcessorDelegate + +/*! + @abstract Indicates the error recovery has been attempted. + @param processor the processor instance. + @param didRecover YES if the recovery was successful. + @param error the error that that was attempted to be recovered from. + */ +- (void)processorDidAttemptRecovery:(FBSDKGraphErrorRecoveryProcessor *)processor didRecover:(BOOL)didRecover error:(NSError *)error; + +@optional +/*! + @abstract Indicates the processor is about to process the error. + @param processor the processor instance. + @param error the error is about to be processed. + @discussion return NO if the processor should not process the error. For example, + if you want to prevent alerts of localized messages but otherwise perform retries and recoveries, + you could return NO for errors where userInfo[FBSDKGraphRequestErrorCategoryKey] equal to FBSDKGraphRequestErrorCategoryOther + */ +- (BOOL)processorWillProcessError:(FBSDKGraphErrorRecoveryProcessor *)processor error:(NSError *)error; + +@end + +/*! + @abstract Defines a type that can process Facebook NSErrors with best practices. + @discussion Facebook NSErrors can contain FBSDKErrorRecoveryAttempting instances to recover from errors, or + localized messages to present to the user. This class will process the instances as follows: + + 1. If the error is temporary as indicated by FBSDKGraphRequestErrorCategoryKey, assume the recovery succeeded and + notify the delegate. + 2. If a FBSDKErrorRecoveryAttempting instance is available, display an alert (dispatched to main thread) + with the recovery options and call the instance's [ attemptRecoveryFromError:optionIndex:...]. + 3. If a FBSDKErrorRecoveryAttempting is not available, check the userInfo for FBSDKLocalizedErrorDescriptionKey + and present that in an alert (dispatched to main thread). + + By default, FBSDKGraphRequests use this type to process errors and retry the request upon a successful + recovery. + + Note that Facebook recovery attempters can present UI or even cause app switches (such as to login). Any such + work is dispatched to the main thread (therefore your request handlers may then run on the main thread). + + Login recovery requires FBSDKLoginKit. Login will use FBSDKLoginBehaviorNative and will prompt the user + for all permissions last granted. If any are declined on the new request, the recovery is not successful but + the `[FBSDKAccessToken currentAccessToken]` might still have been updated. + . + */ +@interface FBSDKGraphErrorRecoveryProcessor : NSObject + +/*! + @abstract Gets the delegate. Note this is a strong reference, and is nil'ed out after recovery is complete. + */ +@property (nonatomic, strong, readonly) iddelegate; + +/*! + @abstract Attempts to process the error, return YES if the error can be processed. + @param error the error to process. + @param request the relateed request that may be reissued. + @param delegate the delegate that will be retained until recovery is complete. + */ +- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id) delegate; + +/*! + @abstract The callback for FBSDKErrorRecoveryAttempting + @param didRecover if the recovery succeeded + @param contextInfo unused + */ +- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.m new file mode 100644 index 0000000..4caed96 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.m @@ -0,0 +1,155 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKErrorRecoveryAttempter.h" + +@interface FBSDKGraphErrorRecoveryProcessor() +{ + FBSDKErrorRecoveryAttempter *_recoveryAttempter; + NSError *_error; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + UIAlertView *_alertView; +#pragma clang diagnostic pop +} + +@property (nonatomic, strong, readwrite) iddelegate; + +@end + +@implementation FBSDKGraphErrorRecoveryProcessor + +- (void)dealloc +{ + _alertView.delegate = nil; +} + +- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id) delegate +{ + self.delegate = delegate; + if ([self.delegate respondsToSelector:@selector(processorWillProcessError:error:)]) { + if (![self.delegate processorWillProcessError:self error:error]) { + return NO; + } + } + + FBSDKGraphRequestErrorCategory errorCategory = [error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue]; + switch (errorCategory) { + case FBSDKGraphRequestErrorCategoryTransient : + [self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil]; + self.delegate = nil; + return YES; + case FBSDKGraphRequestErrorCategoryRecoverable : + if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) { + _recoveryAttempter = error.recoveryAttempter; + BOOL isLoginRecoveryAttempter = [_recoveryAttempter isKindOfClass:NSClassFromString(@"_FBSDKLoginRecoveryAttempter")]; + + // Set up a block to do the typical recovery work so that we can chain it for ios auth special cases. + // the block returns YES if recovery UI is started (meaning we wait for the alertviewdelegate to resume control flow). + BOOL (^standardRecoveryWork)(void) = ^BOOL{ + NSArray *recoveryOptionsTitles = error.userInfo[NSLocalizedRecoveryOptionsErrorKey]; + if (recoveryOptionsTitles.count > 0 && _recoveryAttempter) { + NSString *recoverySuggestion = error.userInfo[NSLocalizedRecoverySuggestionErrorKey]; + _error = error; + dispatch_async(dispatch_get_main_queue(), ^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + _alertView = [[UIAlertView alloc] initWithTitle:nil + message:recoverySuggestion + delegate:self + cancelButtonTitle:nil + otherButtonTitles:nil]; +#pragma clang diagnostic pop + for (NSString *option in recoveryOptionsTitles) { + [_alertView addButtonWithTitle:option]; + } + [_alertView show]; + }); + return YES; + } + return NO; + }; + + if ([request.tokenString isEqualToString:[[FBSDKSystemAccountStoreAdapter sharedInstance] accessTokenString]] && + isLoginRecoveryAttempter) { + // special system auth case: if user has granted permissions we can simply renew. On a successful + // renew, treat this as immediately recovered without the standard alert prompty. + // (for example, this can repair expired tokens seamlessly) + [[FBSDKSystemAccountStoreAdapter sharedInstance] + renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (result == ACAccountCredentialRenewResultRenewed) { + [self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil]; + self.delegate = nil; + } else if (!standardRecoveryWork()) { + [self.delegate processorDidAttemptRecovery:self didRecover:NO error:_error]; + }; + }); + }]; + // short-circuit YES so that the renew callback resumes the control flow. + return YES; + } + + return standardRecoveryWork(); + } + return NO; + case FBSDKGraphRequestErrorCategoryOther : + if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) { + NSString *message = error.userInfo[FBSDKErrorLocalizedDescriptionKey]; + NSString *title = error.userInfo[FBSDKErrorLocalizedTitleKey]; + if (message) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSString *localizedOK = + NSLocalizedStringWithDefaultValue(@"ErrorRecovery.Alert.OK", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"OK", + @"The title of the label to dismiss the alert when presenting user facing error messages"); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[[UIAlertView alloc] initWithTitle:title + message:message + delegate:nil + cancelButtonTitle:localizedOK + otherButtonTitles:nil] show]; +#pragma clang diagnostic pop + }); + } + } + return NO; + } + return NO; +} + +#pragma mark - UIAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + [_recoveryAttempter attemptRecoveryFromError:_error optionIndex:buttonIndex delegate:self didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:) contextInfo:nil]; + _alertView.delegate = nil; + _alertView = nil; +} + +#pragma mark - FBSDKErrorRecoveryAttempting "delegate" + +- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo +{ + [self.delegate processorDidAttemptRecovery:self didRecover:didRecover error:_error]; + self.delegate = nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h new file mode 100644 index 0000000..5ae03e2 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h @@ -0,0 +1,120 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@class FBSDKAccessToken; + +/*! + @abstract Represents a request to the Facebook Graph API. + + @discussion `FBSDKGraphRequest` encapsulates the components of a request (the + Graph API path, the parameters, error recovery behavior) and should be + used in conjunction with `FBSDKGraphRequestConnection` to issue the request. + + Nearly all Graph APIs require an access token. Unless specified, the + `[FBSDKAccessToken currentAccessToken]` is used. Therefore, most requests + will require login first (see `FBSDKLoginManager` in FBSDKLoginKit.framework). + + A `- start` method is provided for convenience for single requests. + + By default, FBSDKGraphRequest will attempt to recover any errors returned from + Facebook. You can disable this via `disableErrorRecovery:`. + @see FBSDKGraphErrorRecoveryProcessor + */ +@interface FBSDKGraphRequest : NSObject + +/*! + @abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters; + +/*! + @abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + @param HTTPMethod the optional HTTP method. nil defaults to @"GET". + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + HTTPMethod:(NSString *)HTTPMethod; + +/*! + @abstract Initializes a new instance. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + @param tokenString the token string to use. Specifying nil will cause no token to be used. + @param version the optional Graph API version (e.g., @"v2.0"). nil defaults to FBSDK_TARGET_PLATFORM_VERSION. + @param HTTPMethod the optional HTTP method (e.g., @"POST"). nil defaults to @"GET". + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + tokenString:(NSString *)tokenString + version:(NSString *)version + HTTPMethod:(NSString *)HTTPMethod +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract The request parameters. + */ +@property (nonatomic, strong, readonly) NSMutableDictionary *parameters; + +/*! + @abstract The access token string used by the request. + */ +@property (nonatomic, copy, readonly) NSString *tokenString; + +/*! + @abstract The Graph API endpoint to use for the request, for example "me". + */ +@property (nonatomic, copy, readonly) NSString *graphPath; + +/*! + @abstract The HTTPMethod to use for the request, for example "GET" or "POST". + */ +@property (nonatomic, copy, readonly) NSString *HTTPMethod; + +/*! + @abstract The Graph API version to use (e.g., "v2.0") + */ +@property (nonatomic, copy, readonly) NSString *version; + +/*! + @abstract If set, disables the automatic error recovery mechanism. + @param disable whether to disable the automatic error recovery mechanism + @discussion By default, non-batched FBSDKGraphRequest instances will automatically try to recover + from errors by constructing a `FBSDKGraphErrorRecoveryProcessor` instance that + re-issues the request on successful recoveries. The re-issued request will call the same + handler as the receiver but may occur with a different `FBSDKGraphRequestConnection` instance. + + This will override [FBSDKSettings setGraphErrorRecoveryDisabled:]. + */ +- (void)setGraphErrorRecoveryDisabled:(BOOL)disable; + +/*! + @abstract Starts a connection to the Graph API. + @param handler The handler block to call when the request completes. + */ +- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.m new file mode 100644 index 0000000..050a676 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.m @@ -0,0 +1,204 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequest+Internal.h" + +#import + +#import "FBSDKAccessToken.h" +#import "FBSDKCoreKit.h" +#import "FBSDKGraphRequestConnection.h" +#import "FBSDKGraphRequestDataAttachment.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings+Internal.h" + +// constants +static NSString *const kGetHTTPMethod = @"GET"; + +@interface FBSDKGraphRequest() +@property (nonatomic, assign) FBSDKGraphRequestFlags flags; +@end + +@implementation FBSDKGraphRequest + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters { + return [self initWithGraphPath:graphPath + parameters:parameters + flags:FBSDKGraphRequestFlagNone]; +} + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + HTTPMethod:(NSString *)HTTPMethod { + return [self initWithGraphPath:graphPath + parameters:parameters + tokenString:[FBSDKAccessToken currentAccessToken].tokenString + version:nil + HTTPMethod:HTTPMethod]; +} + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + flags:(FBSDKGraphRequestFlags)flags { + return [self initWithGraphPath:graphPath + parameters:parameters + tokenString:[FBSDKAccessToken currentAccessToken].tokenString + HTTPMethod:nil + flags:flags]; +} + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + tokenString:(NSString *)tokenString + HTTPMethod:(NSString *)HTTPMethod + flags:(FBSDKGraphRequestFlags)flags { + if ((self = [self initWithGraphPath:graphPath + parameters:parameters + tokenString:tokenString + version:FBSDK_TARGET_PLATFORM_VERSION + HTTPMethod:HTTPMethod])) { + self.flags |= flags; + } + return self; +} + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + tokenString:(NSString *)tokenString + version:(NSString *)version + HTTPMethod:(NSString *)HTTPMethod { + if ((self = [super init])) { + _tokenString = [tokenString copy]; + _version = version ? [version copy] : FBSDK_TARGET_PLATFORM_VERSION; + _graphPath = [graphPath copy]; + _HTTPMethod = HTTPMethod ? [HTTPMethod copy] : kGetHTTPMethod; + _parameters = [[NSMutableDictionary alloc] initWithDictionary:parameters]; + if ([FBSDKSettings isGraphErrorRecoveryDisabled]) { + _flags = FBSDKGraphRequestFlagDisableErrorRecovery; + } + } + return self; +} + +- (BOOL)isGraphErrorRecoveryDisabled +{ + return (self.flags & FBSDKGraphRequestFlagDisableErrorRecovery); +} + +- (void)setGraphErrorRecoveryDisabled:(BOOL)disable +{ + if (disable) { + self.flags |= FBSDKGraphRequestFlagDisableErrorRecovery; + } else { + self.flags &= ~FBSDKGraphRequestFlagDisableErrorRecovery; + } +} + +- (BOOL)hasAttachments +{ + __block BOOL hasAttachments = NO; + [self.parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([FBSDKGraphRequest isAttachment:obj]) { + hasAttachments = YES; + *stop = YES; + } + }]; + return hasAttachments; +} + ++ (BOOL)isAttachment:(id)item +{ + return ([item isKindOfClass:[UIImage class]] || + [item isKindOfClass:[NSData class]] || + [item isKindOfClass:[FBSDKGraphRequestDataAttachment class]]); +} + + ++ (NSString *)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params { + return [self serializeURL:baseUrl params:params httpMethod:kGetHTTPMethod]; +} + ++ (NSString *)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params + httpMethod:(NSString *)httpMethod { + params = [self preprocessParams: params]; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSURL *parsedURL = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; +#pragma clang pop + NSString *queryPrefix = parsedURL.query ? @"&" : @"?"; + + NSString *query = [FBSDKInternalUtility queryStringWithDictionary:params error:NULL invalidObjectHandler:^id(id object, BOOL *stop) { + if ([self isAttachment:object]) { + if ([httpMethod isEqualToString:kGetHTTPMethod]) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"can not use GET to upload a file"]; + } + return nil; + } + return object; + }]; + return [NSString stringWithFormat:@"%@%@%@", baseUrl, queryPrefix, query]; +} + ++ (NSDictionary *)preprocessParams:(NSDictionary *)params +{ + NSString *debugValue = [FBSDKSettings graphAPIDebugParamValue]; + if (debugValue) { + NSMutableDictionary *mutableParams = [NSMutableDictionary dictionaryWithDictionary:params]; + [mutableParams setObject:debugValue forKey:@"debug"]; + return mutableParams; + } + + return params; +} + +- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler +{ + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [connection addRequest:self completionHandler:handler]; + [connection start]; + return connection; +} + +#pragma mark - Debugging helpers + +- (NSString *)description +{ + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@: %p", + NSStringFromClass([self class]), + self]; + if (self.graphPath) { + [result appendFormat:@", graphPath: %@", self.graphPath]; + } + if (self.HTTPMethod) { + [result appendFormat:@", HTTPMethod: %@", self.HTTPMethod]; + } + [result appendFormat:@", parameters: %@>", [self.parameters description]]; + return result; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h new file mode 100644 index 0000000..79ffb3f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h @@ -0,0 +1,325 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@class FBSDKGraphRequest; +@class FBSDKGraphRequestConnection; + +/*! + @typedef FBSDKGraphRequestHandler + + @abstract + A block that is passed to addRequest to register for a callback with the results of that + request once the connection completes. + + @discussion + Pass a block of this type when calling addRequest. This will be called once + the request completes. The call occurs on the UI thread. + + @param connection The `FBSDKGraphRequestConnection` that sent the request. + + @param result The result of the request. This is a translation of + JSON data to `NSDictionary` and `NSArray` objects. This + is nil if there was an error. + + @param error The `NSError` representing any error that occurred. + + */ +typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection, + id result, + NSError *error); + +/*! + @protocol + + @abstract + The `FBSDKGraphRequestConnectionDelegate` protocol defines the methods used to receive network + activity progress information from a . + */ +@protocol FBSDKGraphRequestConnectionDelegate + +@optional + +/*! + @method + + @abstract + Tells the delegate the request connection will begin loading + + @discussion + If the is created using one of the convenience factory methods prefixed with + start, the object returned from the convenience method has already begun loading and this method + will not be called when the delegate is set. + + @param connection The request connection that is starting a network request + */ +- (void)requestConnectionWillBeginLoading:(FBSDKGraphRequestConnection *)connection; + +/*! + @method + + @abstract + Tells the delegate the request connection finished loading + + @discussion + If the request connection completes without a network error occuring then this method is called. + Invocation of this method does not indicate success of every made, only that the + request connection has no further activity. Use the error argument passed to the FBSDKGraphRequestHandler + block to determine success or failure of each . + + This method is invoked after the completion handler for each . + + @param connection The request connection that successfully completed a network request + */ +- (void)requestConnectionDidFinishLoading:(FBSDKGraphRequestConnection *)connection; + +/*! + @method + + @abstract + Tells the delegate the request connection failed with an error + + @discussion + If the request connection fails with a network error then this method is called. The `error` + argument specifies why the network connection failed. The `NSError` object passed to the + FBSDKGraphRequestHandler block may contain additional information. + + @param connection The request connection that successfully completed a network request + @param error The `NSError` representing the network error that occurred, if any. May be nil + in some circumstances. Consult the `NSError` for the for reliable + failure information. + */ +- (void)requestConnection:(FBSDKGraphRequestConnection *)connection + didFailWithError:(NSError *)error; + +/*! + @method + + @abstract + Tells the delegate how much data has been sent and is planned to send to the remote host + + @discussion + The byte count arguments refer to the aggregated objects, not a particular . + + Like `NSURLConnection`, the values may change in unexpected ways if data needs to be resent. + + @param connection The request connection transmitting data to a remote host + @param bytesWritten The number of bytes sent in the last transmission + @param totalBytesWritten The total number of bytes sent to the remote host + @param totalBytesExpectedToWrite The total number of bytes expected to send to the remote host + */ +- (void)requestConnection:(FBSDKGraphRequestConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; + +@end + +/*! + @class FBSDKGraphRequestConnection + + @abstract + The `FBSDKGraphRequestConnection` represents a single connection to Facebook to service a request. + + @discussion + The request settings are encapsulated in a reusable object. The + `FBSDKGraphRequestConnection` object encapsulates the concerns of a single communication + e.g. starting a connection, canceling a connection, or batching requests. + + */ +@interface FBSDKGraphRequestConnection : NSObject + +/*! + @abstract + The delegate object that receives updates. + */ +@property (nonatomic, assign) id delegate; + +/*! + @abstract Gets or sets the timeout interval to wait for a response before giving up. + */ +@property (nonatomic) NSTimeInterval timeout; + +/*! + @abstract + The raw response that was returned from the server. (readonly) + + @discussion + This property can be used to inspect HTTP headers that were returned from + the server. + + The property is nil until the request completes. If there was a response + then this property will be non-nil during the FBSDKGraphRequestHandler callback. + */ +@property (nonatomic, retain, readonly) NSHTTPURLResponse *URLResponse; + +/*! + @methodgroup Class methods + */ + +/*! + @method + + @abstract + This method sets the default timeout on all FBSDKGraphRequestConnection instances. Defaults to 60 seconds. + + @param defaultConnectionTimeout The timeout interval. + */ ++ (void)setDefaultConnectionTimeout:(NSTimeInterval)defaultConnectionTimeout; + +/*! + @methodgroup Adding requests + */ + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + @param handler A handler to call back when the round-trip completes or times out. + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler; + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + + @param handler A handler to call back when the round-trip completes or times out. + The handler will be invoked on the main thread. + + @param name An optional name for this request. This can be used to feed + the results of one request to the input of another in the same + `FBSDKGraphRequestConnection` as described in + [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ). + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. This request can be named + to allow for using the request's response in a subsequent request. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchEntryName:(NSString *)name; + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + + @param handler A handler to call back when the round-trip completes or times out. + + @param batchParameters The optional dictionary of parameters to include for this request + as described in [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ). + Examples include "depends_on", "name", or "omit_response_on_success". + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. This request can be named + to allow for using the request's response in a subsequent request. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters; + +/*! + @methodgroup Instance methods + */ + +/*! + @method + + @abstract + Signals that a connection should be logically terminated as the + application is no longer interested in a response. + + @discussion + Synchronously calls any handlers indicating the request was cancelled. Cancel + does not guarantee that the request-related processing will cease. It + does promise that all handlers will complete before the cancel returns. A call to + cancel prior to a start implies a cancellation of all requests associated + with the connection. + */ +- (void)cancel; + +/*! + @method + + @abstract + This method starts a connection with the server and is capable of handling all of the + requests that were added to the connection. + + @discussion By default, a connection is scheduled on the current thread in the default mode when it is created. + See `setDelegateQueue:` for other options. + + This method cannot be called twice for an `FBSDKGraphRequestConnection` instance. + */ +- (void)start; + +/*! + @abstract Determines the operation queue that is used to call methods on the connection's delegate. + @param queue The operation queue to use when calling delegate methods. + @discussion By default, a connection is scheduled on the current thread in the default mode when it is created. + You cannot reschedule a connection after it has started. + + This is very similar to `[NSURLConnection setDelegateQueue:]`. + */ +- (void)setDelegateQueue:(NSOperationQueue *)queue; + +/*! + @method + + @abstract + Overrides the default version for a batch request + + @discussion + The SDK automatically prepends a version part, such as "v2.0" to API paths in order to simplify API versioning + for applications. If you want to override the version part while using batch requests on the connection, call + this method to set the version for the batch request. + + @param version This is a string in the form @"v2.0" which will be used for the version part of an API path + */ +- (void)overrideVersionPartWith:(NSString *)version; + +@end + +/*! + @abstract The key in the result dictionary for requests to old versions of the Graph API + whose response is not a JSON object. + + @discussion When a request returns a non-JSON response (such as a "true" literal), that response + will be wrapped into a dictionary using this const as the key. This only applies for very few Graph API + prior to v2.1. + */ +FBSDK_EXTERN NSString *const FBSDKNonJSONResponseProperty; diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.m new file mode 100644 index 0000000..3b86c36 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.m @@ -0,0 +1,1011 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequestConnection+Internal.h" + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKConstants.h" +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKError.h" +#import "FBSDKErrorConfiguration.h" +#import "FBSDKGraphErrorRecoveryProcessor.h" +#import "FBSDKGraphRequest+Internal.h" +#import "FBSDKGraphRequestBody.h" +#import "FBSDKGraphRequestDataAttachment.h" +#import "FBSDKGraphRequestMetadata.h" +#import "FBSDKGraphRequestPiggybackManager.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings+Internal.h" +#import "FBSDKURLConnection.h" + +NSString *const FBSDKNonJSONResponseProperty = @"FACEBOOK_NON_JSON_RESULT"; + +// URL construction constants +static NSString *const kGraphURLPrefix = @"graph."; +static NSString *const kGraphVideoURLPrefix = @"graph-video."; + +static NSString *const kBatchKey = @"batch"; +static NSString *const kBatchMethodKey = @"method"; +static NSString *const kBatchRelativeURLKey = @"relative_url"; +static NSString *const kBatchAttachmentKey = @"attached_files"; +static NSString *const kBatchFileNamePrefix = @"file"; +static NSString *const kBatchEntryName = @"name"; + +static NSString *const kAccessTokenKey = @"access_token"; +static NSString *const kSDK = @"ios"; +static NSString *const kUserAgentBase = @"FBiOSSDK"; + +static NSString *const kBatchRestMethodBaseURL = @"method/"; + +static NSTimeInterval g_defaultTimeout = 60.0; + +static FBSDKErrorConfiguration *g_errorConfiguration; + +// ---------------------------------------------------------------------------- +// FBSDKGraphRequestConnectionState + +typedef NS_ENUM(NSUInteger, FBSDKGraphRequestConnectionState) +{ + kStateCreated, + kStateSerialized, + kStateStarted, + kStateCompleted, + kStateCancelled, +}; + +// ---------------------------------------------------------------------------- +// Private properties and methods + +@interface FBSDKGraphRequestConnection () + +@property (nonatomic, retain) FBSDKURLConnection *connection; +@property (nonatomic, retain) NSMutableArray *requests; +@property (nonatomic) FBSDKGraphRequestConnectionState state; +@property (nonatomic, retain) FBSDKLogger *logger; +@property (nonatomic) unsigned long requestStartTime; + +@end + +// ---------------------------------------------------------------------------- +// FBSDKGraphRequestConnection + +@implementation FBSDKGraphRequestConnection +{ + NSString *_overrideVersionPart; + FBSDKGraphRequestMetadata *_recoveringRequestMetadata; + FBSDKGraphErrorRecoveryProcessor *_errorRecoveryProcessor; + NSUInteger _expectingResults; + NSOperationQueue *_delegateQueue; +} + +- (instancetype)init +{ + if ((self = [super init])) { + _requests = [[NSMutableArray alloc] init]; + _timeout = g_defaultTimeout; + _state = kStateCreated; + _logger = [[FBSDKLogger alloc] initWithLoggingBehavior:FBSDKLoggingBehaviorNetworkRequests]; + } + return self; +} + +- (void)dealloc +{ + _connection.delegate = nil; + [_connection cancel]; +} + +#pragma mark - Public + ++ (void)setDefaultConnectionTimeout:(NSTimeInterval)defaultTimeout +{ + if (defaultTimeout >= 0) { + g_defaultTimeout = defaultTimeout; + } +} + +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler +{ + [self addRequest:request completionHandler:handler batchEntryName:nil]; +} + +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchEntryName:(NSString *)name +{ + NSDictionary *batchParams = (name)? @{kBatchEntryName : name } : nil; + [self addRequest:request completionHandler:handler batchParameters:batchParams]; +} + +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters +{ + if (self.state != kStateCreated) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Cannot add requests once started or if a URLRequest is set" + userInfo:nil]; + } + FBSDKGraphRequestMetadata *metadata = [[FBSDKGraphRequestMetadata alloc] initWithRequest:request + completionHandler:handler + batchParameters:batchParameters]; + + [self.requests addObject:metadata]; +} + +- (void)cancel +{ + self.state = kStateCancelled; + [self.connection cancel]; + self.connection = nil; +} + +- (void)overrideVersionPartWith:(NSString *)version +{ + if (![_overrideVersionPart isEqualToString:version]) { + _overrideVersionPart = [version copy]; + } +} + +- (void)start +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + g_errorConfiguration = [[FBSDKErrorConfiguration alloc] initWithDictionary:nil]; + }); + //optimistically check for updated server configuration; + g_errorConfiguration = [FBSDKServerConfigurationManager cachedServerConfiguration].errorConfiguration ?: g_errorConfiguration; + + if (self.state != kStateCreated && self.state != kStateSerialized) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"FBSDKGraphRequestConnection cannot be started again."]; + return; + } + [FBSDKGraphRequestPiggybackManager addPiggybackRequests:self]; + NSMutableURLRequest *request = [self requestWithBatch:self.requests timeout:_timeout]; + + self.state = kStateStarted; + + [self logRequest:request bodyLength:0 bodyLogger:nil attachmentLogger:nil]; + _requestStartTime = [FBSDKInternalUtility currentTimeInMilliseconds]; + + FBSDKURLConnectionHandler handler = + ^(FBSDKURLConnection *connection, + NSError *error, + NSURLResponse *response, + NSData *responseData) { + [self completeFBSDKURLConnectionWithResponse:response + data:responseData + networkError:error]; + }; + + FBSDKURLConnection *connection = [[FBSDKURLConnection alloc] initWithRequest:request + completionHandler:handler]; + if (_delegateQueue) { + [connection setDelegateQueue:_delegateQueue]; + } + connection.delegate = self; + self.connection = connection; + [connection start]; + + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(requestConnectionWillBeginLoading:)]) { + if (_delegateQueue) { + [_delegateQueue addOperationWithBlock:^{ + [delegate requestConnectionWillBeginLoading:self]; + }]; + } else { + [delegate requestConnectionWillBeginLoading:self]; + } + } +} + +- (void)setDelegateQueue:(NSOperationQueue *)queue +{ + _delegateQueue = queue; +} + +#pragma mark - Private methods (request generation) + +// +// Adds request data to a batch in a format expected by the JsonWriter. +// Binary attachments are referenced by name in JSON and added to the +// attachments dictionary. +// +- (void)addRequest:(FBSDKGraphRequestMetadata *)metadata + toBatch:(NSMutableArray *)batch + attachments:(NSMutableDictionary *)attachments + batchToken:(NSString *)batchToken +{ + NSMutableDictionary *requestElement = [[NSMutableDictionary alloc] init]; + + if (metadata.batchParameters) { + [requestElement addEntriesFromDictionary:metadata.batchParameters]; + } + + if (batchToken) { + metadata.request.parameters[kAccessTokenKey] = batchToken; + [self registerTokenToOmitFromLog:batchToken]; + } + + NSString *urlString = [self urlStringForSingleRequest:metadata.request forBatch:YES]; + requestElement[kBatchRelativeURLKey] = urlString; + requestElement[kBatchMethodKey] = metadata.request.HTTPMethod; + + NSMutableArray *attachmentNames = [NSMutableArray array]; + + [metadata.request.parameters enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + if ([FBSDKGraphRequest isAttachment:value]) { + NSString *name = [NSString stringWithFormat:@"%@%lu", + kBatchFileNamePrefix, + (unsigned long)[attachments count]]; + [attachmentNames addObject:name]; + attachments[name] = value; + } + }]; + + if ([attachmentNames count]) { + requestElement[kBatchAttachmentKey] = [attachmentNames componentsJoinedByString:@","]; + } + + [batch addObject:requestElement]; +} + +- (void)appendAttachments:(NSDictionary *)attachments + toBody:(FBSDKGraphRequestBody *)body + addFormData:(BOOL)addFormData + logger:(FBSDKLogger *)logger +{ + [attachments enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + value = [FBSDKInternalUtility convertRequestValue:value]; + if ([value isKindOfClass:[NSString class]]) { + if (addFormData) { + [body appendWithKey:key formValue:(NSString *)value logger:logger]; + } + } else if ([value isKindOfClass:[UIImage class]]) { + [body appendWithKey:key imageValue:(UIImage *)value logger:logger]; + } else if ([value isKindOfClass:[NSData class]]) { + [body appendWithKey:key dataValue:(NSData *)value logger:logger]; + } else if ([value isKindOfClass:[FBSDKGraphRequestDataAttachment class]]) { + [body appendWithKey:key dataAttachmentValue:(FBSDKGraphRequestDataAttachment *)value logger:logger]; + } else { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors formatString:@"Unsupported FBSDKGraphRequest attachment:%@, skipping.", value]; + } + }]; +} + +// +// Serializes all requests in the batch to JSON and appends the result to +// body. Also names all attachments that need to go as separate blocks in +// the body of the request. +// +// All the requests are serialized into JSON, with any binary attachments +// named and referenced by name in the JSON. +// +- (void)appendJSONRequests:(NSArray *)requests + toBody:(FBSDKGraphRequestBody *)body + andNameAttachments:(NSMutableDictionary *)attachments + logger:(FBSDKLogger *)logger +{ + NSMutableArray *batch = [[NSMutableArray alloc] init]; + NSString *batchToken = nil; + for (FBSDKGraphRequestMetadata *metadata in requests) { + NSString *individualToken = [self accessTokenWithRequest:metadata.request]; + BOOL isClientToken = [FBSDKSettings clientToken] && [individualToken hasSuffix:[FBSDKSettings clientToken]]; + if (!batchToken && + !isClientToken) { + batchToken = individualToken; + } + [self addRequest:metadata + toBatch:batch + attachments:attachments + batchToken:[batchToken isEqualToString:individualToken] ? nil : individualToken]; + } + + NSString *jsonBatch = [FBSDKInternalUtility JSONStringForObject:batch error:NULL invalidObjectHandler:NULL]; + + [body appendWithKey:kBatchKey formValue:jsonBatch logger:logger]; + if (batchToken) { + [body appendWithKey:kAccessTokenKey formValue:batchToken logger:logger]; + } +} + +- (BOOL)_shouldWarnOnMissingFieldsParam:(FBSDKGraphRequest *)request +{ + NSString *minVersion = @"2.4"; + NSString *version = request.version; + if (!version) { + return YES; + } + if ([version hasPrefix:@"v"]) { + version = [version substringFromIndex:1]; + } + + NSComparisonResult result = [version compare:minVersion options:NSNumericSearch]; + + // if current version is the same as minVersion, or if the current version is > minVersion + return (result == NSOrderedSame) || (result == NSOrderedDescending); +} + +// Validate that all GET requests after v2.4 have a "fields" param +- (void)_validateFieldsParamForGetRequests:(NSArray *)requests +{ + for (FBSDKGraphRequestMetadata *metadata in requests) { + FBSDKGraphRequest *request = metadata.request; + if ([request.HTTPMethod.uppercaseString isEqualToString:@"GET"] && + [self _shouldWarnOnMissingFieldsParam:request] && + !request.parameters[@"fields"] && + [request.graphPath rangeOfString:@"fields="].location == NSNotFound) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"starting with Graph API v2.4, GET requests for /%@ should contain an explicit \"fields\" parameter", request.graphPath]; + } + } +} + +// +// Generates a NSURLRequest based on the contents of self.requests, and sets +// options on the request. Chooses between URL-based request for a single +// request and JSON-based request for batches. +// +- (NSMutableURLRequest *)requestWithBatch:(NSArray *)requests + timeout:(NSTimeInterval)timeout +{ + FBSDKGraphRequestBody *body = [[FBSDKGraphRequestBody alloc] init]; + FBSDKLogger *bodyLogger = [[FBSDKLogger alloc] initWithLoggingBehavior:_logger.loggingBehavior]; + FBSDKLogger *attachmentLogger = [[FBSDKLogger alloc] initWithLoggingBehavior:_logger.loggingBehavior]; + + NSMutableURLRequest *request; + + if (requests.count == 0) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"FBSDKGraphRequestConnection: Must have at least one request or urlRequest not specified." + userInfo:nil] + raise]; + + } + + [self _validateFieldsParamForGetRequests:requests]; + + if ([requests count] == 1) { + FBSDKGraphRequestMetadata *metadata = [requests objectAtIndex:0]; + NSURL *url = [NSURL URLWithString:[self urlStringForSingleRequest:metadata.request forBatch:NO]]; + request = [NSMutableURLRequest requestWithURL:url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:timeout]; + + // HTTP methods are case-sensitive; be helpful in case someone provided a mixed case one. + NSString *httpMethod = [metadata.request.HTTPMethod uppercaseString]; + [request setHTTPMethod:httpMethod]; + [self appendAttachments:metadata.request.parameters + toBody:body + addFormData:[httpMethod isEqualToString:@"POST"] + logger:attachmentLogger]; + } else { + // Find the session with an app ID and use that as the batch_app_id. If we can't + // find one, try to load it from the plist. As a last resort, pass 0. + NSString *batchAppID = [FBSDKSettings appID]; + if (!batchAppID || batchAppID.length == 0) { + // The Graph API batch method requires either an access token or batch_app_id. + // If we can't determine an App ID to use for the batch, we can't issue it. + [[NSException exceptionWithName:NSInternalInconsistencyException + reason:@"FBSDKGraphRequestConnection: [FBSDKSettings appID] must be specified for batch requests" + userInfo:nil] + raise]; + } + + [body appendWithKey:@"batch_app_id" formValue:batchAppID logger:bodyLogger]; + + NSMutableDictionary *attachments = [[NSMutableDictionary alloc] init]; + + [self appendJSONRequests:requests + toBody:body + andNameAttachments:attachments + logger:bodyLogger]; + + [self appendAttachments:attachments + toBody:body + addFormData:NO + logger:attachmentLogger]; + + NSURL *url = [FBSDKInternalUtility facebookURLWithHostPrefix:kGraphURLPrefix path:nil queryParameters:nil defaultVersion:_overrideVersionPart error:NULL]; + request = [NSMutableURLRequest requestWithURL:url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:timeout]; + [request setHTTPMethod:@"POST"]; + } + + [request setHTTPBody:[body data]]; + NSUInteger bodyLength = [[body data] length] / 1024; + + [request setValue:[FBSDKGraphRequestConnection userAgent] forHTTPHeaderField:@"User-Agent"]; + [request setValue:[FBSDKGraphRequestBody mimeContentType] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPShouldHandleCookies:NO]; + + [self logRequest:request bodyLength:bodyLength bodyLogger:bodyLogger attachmentLogger:attachmentLogger]; + + return request; +} + +// +// Generates a URL for a batch containing only a single request, +// and names all attachments that need to go in the body of the +// request. +// +// The URL contains all parameters that are not body attachments, +// including the session key if present. +// +// Attachments are named and referenced by name in the URL. +// +- (NSString *)urlStringForSingleRequest:(FBSDKGraphRequest *)request forBatch:(BOOL)forBatch +{ + request.parameters[@"format"] = @"json"; + request.parameters[@"sdk"] = kSDK; + request.parameters[@"include_headers"] = @"false"; + + NSString *baseURL; + if (forBatch) { + baseURL = request.graphPath; + } else { + NSString *token = [self accessTokenWithRequest:request]; + if (token) { + [request.parameters setValue:token forKey:kAccessTokenKey]; + [self registerTokenToOmitFromLog:token]; + } + + NSString *prefix = kGraphURLPrefix; + // We special case a graph post to /videos and send it to graph-video.facebook.com + // We only do this for non batch post requests + NSString *graphPath = [request.graphPath lowercaseString]; + if ([[request.HTTPMethod uppercaseString] isEqualToString:@"POST"] && + [graphPath hasSuffix:@"/videos"]) { + graphPath = [graphPath stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]]; + NSArray *components = [graphPath componentsSeparatedByString:@"/"]; + if ([components count] == 2) { + prefix = kGraphVideoURLPrefix; + } + } + + baseURL = [[FBSDKInternalUtility facebookURLWithHostPrefix:prefix path:request.graphPath queryParameters:nil defaultVersion:request.version error:NULL] absoluteString]; + } + + NSString *url = [FBSDKGraphRequest serializeURL:baseURL + params:request.parameters + httpMethod:request.HTTPMethod]; + return url; +} + +#pragma mark - Private methods (response parsing) + +- (void)completeFBSDKURLConnectionWithResponse:(NSURLResponse *)response + data:(NSData *)data + networkError:(NSError *)error +{ + if (self.state != kStateCancelled) { + NSAssert(self.state == kStateStarted, + @"Unexpected state %lu in completeWithResponse", + (unsigned long)self.state); + self.state = kStateCompleted; + } + + NSArray *results = nil; + _URLResponse = (NSHTTPURLResponse *)response; + if (response) { + NSAssert([response isKindOfClass:[NSHTTPURLResponse class]], + @"Expected NSHTTPURLResponse, got %@", + response); + + NSInteger statusCode = _URLResponse.statusCode; + + if (!error && [response.MIMEType hasPrefix:@"image"]) { + error = [FBSDKError errorWithCode:FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode + message:@"Response is a non-text MIME type; endpoints that return images and other " + @"binary data should be fetched using NSURLRequest and NSURLConnection"]; + } else { + results = [self parseJSONResponse:data + error:&error + statusCode:statusCode]; + } + } else if (!error) { + error = [FBSDKError errorWithCode:FBSDKUnknownErrorCode + message:@"Missing NSURLResponse"]; + } + + if (!error) { + if ([self.requests count] != [results count]) { + error = [FBSDKError errorWithCode:FBSDKGraphRequestProtocolMismatchErrorCode + message:@"Unexpected number of results returned from server."]; + } else { + [_logger appendFormat:@"Response <#%lu>\nDuration: %lu msec\nSize: %lu kB\nResponse Body:\n%@\n\n", + (unsigned long)[_logger loggerSerialNumber], + [FBSDKInternalUtility currentTimeInMilliseconds] - _requestStartTime, + (unsigned long)[data length], + results]; + } + } + + if (error) { + [_logger appendFormat:@"Response <#%lu> :\n%@\n%@\n", + (unsigned long)[_logger loggerSerialNumber], + [error localizedDescription], + [error userInfo]]; + } + [_logger emitToNSLog]; + + [self completeWithResults:results networkError:error]; + + self.connection = nil; +} + +// +// If there is one request, the JSON is the response. +// If there are multiple requests, the JSON has an array of dictionaries whose +// body property is the response. +// [{ "code":200, +// "body":"JSON-response-as-a-string" }, +// { "code":200, +// "body":"JSON-response-as-a-string" }] +// +// In both cases, this function returns an NSArray containing the results. +// The NSArray looks just like the multiple request case except the body +// value is converted from a string to parsed JSON. +// +- (NSArray *)parseJSONResponse:(NSData *)data + error:(NSError **)error + statusCode:(NSInteger)statusCode; +{ + // Graph API can return "true" or "false", which is not valid JSON. + // Translate that before asking JSON parser to look at it. + NSString *responseUTF8 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSMutableArray *results = [[NSMutableArray alloc] init];; + id response = [self parseJSONOrOtherwise:responseUTF8 error:error]; + + if (responseUTF8 == nil) { + NSString *base64Data = [data length] != 0 ? [data base64EncodedStringWithOptions:0] : @""; + if (base64Data != nil) { + [FBSDKAppEvents logImplicitEvent:@"fb_response_invalid_utf8" + valueToSum:nil + parameters:nil + accessToken:nil]; + } + } + + NSDictionary *responseError = nil; + if (!response) { + if ((error != NULL) && (*error == nil)) { + *error = [self errorWithCode:FBSDKUnknownErrorCode + statusCode:statusCode + parsedJSONResponse:nil + innerError:nil + message:@"The server returned an unexpected response."]; + } + } else if ([self.requests count] == 1) { + // response is the entry, so put it in a dictionary under "body" and add + // that to array of responses. + [results addObject:@{ + @"code":@(statusCode), + @"body":response + }]; + } else if ([response isKindOfClass:[NSArray class]]) { + // response is the array of responses, but the body element of each needs + // to be decoded from JSON. + for (id item in response) { + // Don't let errors parsing one response stop us from parsing another. + NSError *batchResultError = nil; + if (![item isKindOfClass:[NSDictionary class]]) { + [results addObject:item]; + } else { + NSMutableDictionary *result = [((NSDictionary *)item) mutableCopy]; + if (result[@"body"]) { + result[@"body"] = [self parseJSONOrOtherwise:result[@"body"] error:&batchResultError]; + } + [results addObject:result]; + } + if (batchResultError) { + // We'll report back the last error we saw. + *error = batchResultError; + } + } + } else if ([response isKindOfClass:[NSDictionary class]] && + (responseError = [FBSDKTypeUtility dictionaryValue:response[@"error"]]) != nil && + [responseError[@"type"] isEqualToString:@"OAuthException"]) { + // if there was one request then return the only result. if there were multiple requests + // but only one error then the server rejected the batch access token + NSDictionary *result = @{ + @"code":@(statusCode), + @"body":response + }; + + for (NSUInteger resultIndex = 0, resultCount = self.requests.count; resultIndex < resultCount; ++resultIndex) { + [results addObject:result]; + } + } else if (error != NULL) { + *error = [self errorWithCode:FBSDKGraphRequestProtocolMismatchErrorCode + statusCode:statusCode + parsedJSONResponse:results + innerError:nil + message:nil]; + } + + return results; +} + +- (id)parseJSONOrOtherwise:(NSString *)utf8 + error:(NSError **)error +{ + id parsed = nil; + if (!(*error)) { + parsed = [FBSDKInternalUtility objectForJSONString:utf8 error:error]; + // if we fail parse we attemp a reparse of a modified input to support results in the form "foo=bar", "true", etc. + // which is shouldn't be necessary since Graph API v2.1. + if (*error) { + // we round-trip our hand-wired response through the parser in order to remain + // consistent with the rest of the output of this function (note, if perf turns out + // to be a problem -- unlikely -- we can return the following dictionary outright) + NSDictionary *original = @{ FBSDKNonJSONResponseProperty : utf8 }; + NSString *jsonrep = [FBSDKInternalUtility JSONStringForObject:original error:NULL invalidObjectHandler:NULL]; + NSError *reparseError = nil; + parsed = [FBSDKInternalUtility objectForJSONString:jsonrep error:&reparseError]; + if (!reparseError) { + *error = nil; + } + } + } + return parsed; +} + +- (void)completeWithResults:(NSArray *)results + networkError:(NSError *)networkError +{ + NSUInteger count = [self.requests count]; + _expectingResults = count; + NSUInteger disabledRecoveryCount = 0; + for (FBSDKGraphRequestMetadata *metadata in self.requests) { + if ([metadata.request isGraphErrorRecoveryDisabled]) { + disabledRecoveryCount++; + } + } + BOOL isSingleRequestToRecover = (count - disabledRecoveryCount == 1); + + [self.requests enumerateObjectsUsingBlock:^(FBSDKGraphRequestMetadata *metadata, NSUInteger i, BOOL *stop) { + id result = networkError ? nil : [results objectAtIndex:i]; + NSError *resultError = networkError ?: [self errorFromResult:result request:metadata.request]; + + id body = nil; + if (!resultError && [result isKindOfClass:[NSDictionary class]]) { + NSDictionary *resultDictionary = [FBSDKTypeUtility dictionaryValue:result]; + body = [FBSDKTypeUtility dictionaryValue:resultDictionary[@"body"]]; + } + + if (resultError && ![metadata.request isGraphErrorRecoveryDisabled] && isSingleRequestToRecover) { + _recoveringRequestMetadata = metadata; + _errorRecoveryProcessor = [[FBSDKGraphErrorRecoveryProcessor alloc] init]; + if ([_errorRecoveryProcessor processError:resultError request:metadata.request delegate:self]) { + return; + } + } + + [self processResultBody:body error:resultError metadata:metadata canNotifyDelegate:(networkError ? NO : YES)]; + }]; + + if (networkError) { + if ([_delegate respondsToSelector:@selector(requestConnection:didFailWithError:)]) { + [_delegate requestConnection:self didFailWithError:networkError]; + } + } +} + +- (void)processResultBody:(NSDictionary *)body error:(NSError *)error metadata:(FBSDKGraphRequestMetadata *)metadata canNotifyDelegate:(BOOL)canNotifyDelegate +{ + void (^clearToken)(void) = ^{ + if (!(metadata.request.flags & FBSDKGraphRequestFlagDoNotInvalidateTokenOnError)) { + [FBSDKAccessToken setCurrentAccessToken:nil]; + } + }; + void (^finishAndInvokeCompletionHandler)(void) = ^{ + NSDictionary *graphDebugDict = [body objectForKey:@"__debug__"]; + if ([graphDebugDict isKindOfClass:[NSDictionary class]]) { + [self processResultDebugDictionary: graphDebugDict]; + } + [metadata invokeCompletionHandlerForConnection:self withResults:body error:error]; + + if (--_expectingResults == 0) { + if (canNotifyDelegate && [_delegate respondsToSelector:@selector(requestConnectionDidFinishLoading:)]) { + [_delegate requestConnectionDidFinishLoading:self]; + } + } + }; + + FBSDKSystemAccountStoreAdapter *adapter = [FBSDKSystemAccountStoreAdapter sharedInstance]; + NSString *metadataTokenString = metadata.request.tokenString; + NSString *currentTokenString = [FBSDKAccessToken currentAccessToken].tokenString; + NSString *accountStoreTokenString = adapter.accessTokenString; + BOOL isAccountStoreLogin = [metadataTokenString isEqualToString:accountStoreTokenString]; + + if ([metadataTokenString isEqualToString:currentTokenString] || isAccountStoreLogin) { + NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue]; + NSInteger errorSubcode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorSubcode] integerValue]; + if (errorCode == 190 || errorCode == 102) { + if (isAccountStoreLogin) { + if (errorSubcode == 460) { + // For iOS6, when the password is changed on the server, the system account store + // will continue to issue the old token until the user has changed the + // password AND _THEN_ a renew call is made. To prevent opening + // with an old token which would immediately be closed, we tell our adapter + // that we want to force a blocking renew until success. + adapter.forceBlockingRenew = YES; + } else { + [adapter renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) { + NSOperationQueue *queue = _delegateQueue ?: [NSOperationQueue mainQueue]; + [queue addOperationWithBlock:^{ + clearToken(); + finishAndInvokeCompletionHandler(); + }]; + }]; + return; + } + } + clearToken(); + } else if (errorCode >= 200 && errorCode < 300) { + // permission error + [adapter renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) { + NSOperationQueue *queue = _delegateQueue ?: [NSOperationQueue mainQueue]; + [queue addOperationWithBlock:finishAndInvokeCompletionHandler]; + }]; + return; + } + } + // this is already on the queue since we are currently in the NSURLConnection callback. + finishAndInvokeCompletionHandler(); +} + +- (void)processResultDebugDictionary:(NSDictionary *)dict +{ + NSArray *messages = [FBSDKTypeUtility arrayValue:dict[@"messages"]]; + if (![messages count]) { + return; + } + + [messages enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSDictionary *messageDict = [FBSDKTypeUtility dictionaryValue:obj]; + NSString *message = [FBSDKTypeUtility stringValue:messageDict[@"message"]]; + NSString *type = [FBSDKTypeUtility stringValue:messageDict[@"type"]]; + NSString *link = [FBSDKTypeUtility stringValue:messageDict[@"link"]]; + if (!message || !type) { + return; + } + + NSString *loggingBehavior = FBSDKLoggingBehaviorGraphAPIDebugInfo; + if ([type isEqualToString:@"warning"]) { + loggingBehavior = FBSDKLoggingBehaviorGraphAPIDebugWarning; + } + if (link) { + message = [message stringByAppendingFormat:@" Link: %@", link]; + } + + [FBSDKLogger singleShotLogEntry:loggingBehavior logEntry:message]; + }]; + +} + +- (NSError *)errorFromResult:(id)result request:(FBSDKGraphRequest *)request +{ + if ([result isKindOfClass:[NSDictionary class]]) { + NSDictionary *errorDictionary = [FBSDKTypeUtility dictionaryValue:result[@"body"]][@"error"]; + + if (errorDictionary) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"code"] forKey:FBSDKGraphRequestErrorGraphErrorCode]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_subcode"] forKey:FBSDKGraphRequestErrorGraphErrorSubcode]; + //"message" is preferred over error_msg or error_reason. + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_msg"] forKey:FBSDKErrorDeveloperMessageKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_reason"] forKey:FBSDKErrorDeveloperMessageKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"message"] forKey:FBSDKErrorDeveloperMessageKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_user_title"] forKey:FBSDKErrorLocalizedTitleKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_user_msg"] forKey:FBSDKErrorLocalizedDescriptionKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_user_msg"] forKey:NSLocalizedDescriptionKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:result[@"code"] forKey:FBSDKGraphRequestErrorHTTPStatusCodeKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:result forKey:FBSDKGraphRequestErrorParsedJSONResponseKey]; + + FBSDKErrorRecoveryConfiguration *recoveryConfiguration = [g_errorConfiguration + recoveryConfigurationForCode:[userInfo[FBSDKGraphRequestErrorGraphErrorCode] stringValue] + subcode:[userInfo[FBSDKGraphRequestErrorGraphErrorSubcode] stringValue] + request:request]; + if ([errorDictionary[@"is_transient"] boolValue]) { + userInfo[FBSDKGraphRequestErrorCategoryKey] = @(FBSDKGraphRequestErrorCategoryTransient); + } else { + [FBSDKInternalUtility dictionary:userInfo setObject:@(recoveryConfiguration.errorCategory) forKey:FBSDKGraphRequestErrorCategoryKey]; + } + [FBSDKInternalUtility dictionary:userInfo setObject:recoveryConfiguration.localizedRecoveryDescription forKey:NSLocalizedRecoverySuggestionErrorKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:recoveryConfiguration.localizedRecoveryOptionDescriptions forKey:NSLocalizedRecoveryOptionsErrorKey]; + FBSDKErrorRecoveryAttempter *attempter = [FBSDKErrorRecoveryAttempter recoveryAttempterFromConfiguration:recoveryConfiguration]; + [FBSDKInternalUtility dictionary:userInfo setObject:attempter forKey:NSRecoveryAttempterErrorKey]; + + return [FBSDKError errorWithCode:FBSDKGraphRequestGraphAPIErrorCode + userInfo:userInfo + message:nil + underlyingError:nil]; + } + } + + return nil; +} + +- (NSError *)errorWithCode:(FBSDKErrorCode)code + statusCode:(NSInteger)statusCode + parsedJSONResponse:(id)response + innerError:(NSError *)innerError + message:(NSString *)message { + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] = @(statusCode); + + if (response) { + userInfo[FBSDKGraphRequestErrorParsedJSONResponseKey] = response; + } + + if (innerError) { + userInfo[FBSDKGraphRequestErrorParsedJSONResponseKey] = innerError; + } + + if (message) { + userInfo[FBSDKErrorDeveloperMessageKey] = message; + } + + NSError *error = [[NSError alloc] + initWithDomain:FBSDKErrorDomain + code:code + userInfo:userInfo]; + + return error; +} + +#pragma mark - Private methods (miscellaneous) + +- (void)logRequest:(NSMutableURLRequest *)request + bodyLength:(NSUInteger)bodyLength + bodyLogger:(FBSDKLogger *)bodyLogger + attachmentLogger:(FBSDKLogger *)attachmentLogger +{ + if (_logger.isActive) { + [_logger appendFormat:@"Request <#%lu>:\n", (unsigned long)_logger.loggerSerialNumber]; + [_logger appendKey:@"URL" value:[[request URL] absoluteString]]; + [_logger appendKey:@"Method" value:[request HTTPMethod]]; + [_logger appendKey:@"UserAgent" value:[request valueForHTTPHeaderField:@"User-Agent"]]; + [_logger appendKey:@"MIME" value:[request valueForHTTPHeaderField:@"Content-Type"]]; + + if (bodyLength != 0) { + [_logger appendKey:@"Body Size" value:[NSString stringWithFormat:@"%lu kB", (unsigned long)bodyLength / 1024]]; + } + + if (bodyLogger != nil) { + [_logger appendKey:@"Body (w/o attachments)" value:bodyLogger.contents]; + } + + if (attachmentLogger != nil) { + [_logger appendKey:@"Attachments" value:attachmentLogger.contents]; + } + + [_logger appendString:@"\n"]; + + [_logger emitToNSLog]; + } +} + +- (NSString *)accessTokenWithRequest:(FBSDKGraphRequest *)request +{ + NSString *token = request.tokenString ?: request.parameters[kAccessTokenKey]; + if (!token && !(request.flags & FBSDKGraphRequestFlagSkipClientToken) && [FBSDKSettings clientToken].length > 0) { + return [NSString stringWithFormat:@"%@|%@", [FBSDKSettings appID], [FBSDKSettings clientToken]]; + } + return token; +} + +- (void)registerTokenToOmitFromLog:(NSString *)token +{ + if (![[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorAccessTokens]) { + [FBSDKLogger registerStringToReplace:token replaceWith:@"ACCESS_TOKEN_REMOVED"]; + } +} + ++ (NSString *)userAgent +{ + static NSString *agent = nil; + + if (!agent) { + agent = [NSString stringWithFormat:@"%@.%@", kUserAgentBase, FBSDK_VERSION_STRING]; + } + if ([FBSDKSettings userAgentSuffix]) { + return [NSString stringWithFormat:@"%@/%@", agent, [FBSDKSettings userAgentSuffix]]; + } + return agent; +} + +- (void)setConnection:(FBSDKURLConnection *)connection +{ + if (_connection != connection) { + _connection.delegate = nil; + _connection = connection; + } +} + +#pragma mark - FBSDKURLConnectionDelegate + +- (void)facebookURLConnection:(FBSDKURLConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { + id delegate = [self delegate]; + + if ([delegate respondsToSelector:@selector(requestConnection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)]) { + [delegate requestConnection:self + didSendBodyData:bytesWritten + totalBytesWritten:totalBytesWritten + totalBytesExpectedToWrite:totalBytesExpectedToWrite]; + } +} + +#pragma mark - FBSDKGraphErrorRecoveryProcessorDelegate + +- (void)processorDidAttemptRecovery:(FBSDKGraphErrorRecoveryProcessor *)processor didRecover:(BOOL)didRecover error:(NSError *)error +{ + if (didRecover) { + FBSDKGraphRequest *originalRequest = _recoveringRequestMetadata.request; + FBSDKGraphRequest *retryRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:originalRequest.graphPath + parameters:originalRequest.parameters + tokenString:[FBSDKAccessToken currentAccessToken].tokenString + version:originalRequest.version + HTTPMethod:originalRequest.HTTPMethod]; + // prevent further attempts at recovery (i.e., additional retries). + [retryRequest setGraphErrorRecoveryDisabled:YES]; + FBSDKGraphRequestMetadata *retryMetadata = [[FBSDKGraphRequestMetadata alloc] initWithRequest:retryRequest completionHandler:_recoveringRequestMetadata.completionHandler batchParameters:_recoveringRequestMetadata.batchParameters]; + [retryRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *retriedError) { + [self processResultBody:result error:retriedError metadata:retryMetadata canNotifyDelegate:YES]; + _errorRecoveryProcessor = nil; + _recoveringRequestMetadata = nil; + }]; + } else { + [self processResultBody:nil error:error metadata:_recoveringRequestMetadata canNotifyDelegate:YES]; + _errorRecoveryProcessor = nil; + _recoveringRequestMetadata = nil; + } +} + +#pragma mark - Debugging helpers + +- (NSString *)description +{ + NSMutableString *result = [NSMutableString stringWithFormat:@"<%@: %p, %lu request(s): (\n", + NSStringFromClass([self class]), + self, + (unsigned long)self.requests.count]; + BOOL comma = NO; + for (FBSDKGraphRequestMetadata *metadata in self.requests) { + FBSDKGraphRequest *request = metadata.request; + if (comma) { + [result appendString:@",\n"]; + } + [result appendString:[request description]]; + comma = YES; + } + [result appendString:@"\n)>"]; + return result; + +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h new file mode 100644 index 0000000..c179e29 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract A container class for data attachments so that additional metadata can be provided about the attachment. + */ +@interface FBSDKGraphRequestDataAttachment : NSObject + +/*! + @abstract Initializes the receiver with the attachment data and metadata. + @param data The attachment data (retained, not copied) + @param filename The filename for the attachment + @param contentType The content type for the attachment + */ +- (instancetype)initWithData:(NSData *)data + filename:(NSString *)filename + contentType:(NSString *)contentType +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract The content type for the attachment. + */ +@property (nonatomic, copy, readonly) NSString *contentType; + +/*! + @abstract The attachment data. + */ +@property (nonatomic, strong, readonly) NSData *data; + +/*! + @abstract The filename for the attachment. + */ +@property (nonatomic, copy, readonly) NSString *filename; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.m new file mode 100644 index 0000000..d5ec04d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.m @@ -0,0 +1,41 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequestDataAttachment.h" + +#import "FBSDKMacros.h" + +@implementation FBSDKGraphRequestDataAttachment + +- (instancetype)initWithData:(NSData *)data filename:(NSString *)filename contentType:(NSString *)contentType +{ + if ((self = [super init])) { + _data = data; + _filename = [filename copy]; + _contentType = [contentType copy]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithData:filename:contentType:); + return [self initWithData:nil filename:nil contentType:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h new file mode 100644 index 0000000..fd2e2ff --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#ifdef __cplusplus +#define FBSDK_EXTERN extern "C" __attribute__((visibility ("default"))) +#else +#define FBSDK_EXTERN extern __attribute__((visibility ("default"))) +#endif + +#define FBSDK_STATIC_INLINE static inline + +#define FBSDK_NO_DESIGNATED_INITIALIZER() \ +@throw [NSException exceptionWithName:NSInvalidArgumentException \ + reason:[NSString stringWithFormat:@"unrecognized selector sent to instance %p", self] \ + userInfo:nil] + +#define FBSDK_NOT_DESIGNATED_INITIALIZER(DESIGNATED_INITIALIZER) \ +@throw [NSException exceptionWithName:NSInvalidArgumentException \ + reason:[NSString stringWithFormat:@"Please use the designated initializer [%p %@]", \ + self, \ + NSStringFromSelector(@selector(DESIGNATED_INITIALIZER))] \ + userInfo:nil] diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h new file mode 100644 index 0000000..621fac9 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract Extension protocol for NSMutableCopying that adds the mutableCopy method, which is implemented on NSObject. + @discussion NSObject implicitly conforms to this protocol. + */ +@protocol FBSDKMutableCopying + +/*! + @abstract Implemented by NSObject as a convenience to mutableCopyWithZone:. + @return A mutable copy of the receiver. + */ +- (id)mutableCopy; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h new file mode 100644 index 0000000..11da3d9 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h @@ -0,0 +1,148 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMacros.h" +#import "FBSDKProfilePictureView.h" + +/*! + @abstract Notification indicating that the `currentProfile` has changed. + @discussion the userInfo dictionary of the notification will contain keys + `FBSDKProfileChangeOldKey` and + `FBSDKProfileChangeNewKey`. + */ +FBSDK_EXTERN NSString *const FBSDKProfileDidChangeNotification; + +/* @abstract key in notification's userInfo object for getting the old profile. + @discussion If there was no old profile, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKProfileChangeOldKey; + +/* @abstract key in notification's userInfo object for getting the new profile. + @discussion If there is no new profile, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey; + +/*! + @abstract Represents an immutable Facebook profile + @discussion This class provides a global "currentProfile" instance to more easily + add social context to your application. When the profile changes, a notification is + posted so that you can update relevant parts of your UI and is persisted to NSUserDefaults. + + Typically, you will want to call `enableUpdatesOnAccessTokenChange:YES` so that + it automatically observes changes to the `[FBSDKAccessToken currentAccessToken]`. + + You can use this class to build your own `FBSDKProfilePictureView` or in place of typical requests to "/me". + */ +@interface FBSDKProfile : NSObject + +/*! + @abstract initializes a new instance. + @param userID the user ID + @param firstName the user's first name + @param middleName the user's middle name + @param lastName the user's last name + @param name the user's complete name + @param linkURL the link for this profile + @param refreshDate the optional date this profile was fetched. Defaults to [NSDate date]. + */ +- (instancetype)initWithUserID:(NSString *)userID + firstName:(NSString *)firstName + middleName:(NSString *)middleName + lastName:(NSString *)lastName + name:(NSString *)name + linkURL:(NSURL *)linkURL + refreshDate:(NSDate *)refreshDate NS_DESIGNATED_INITIALIZER; +/*! + @abstract The user id + */ +@property (nonatomic, readonly) NSString *userID; +/*! + @abstract The user's first name + */ +@property (nonatomic, readonly) NSString *firstName; +/*! + @abstract The user's middle name + */ +@property (nonatomic, readonly) NSString *middleName; +/*! + @abstract The user's last name + */ +@property (nonatomic, readonly) NSString *lastName; +/*! + @abstract The user's complete name + */ +@property (nonatomic, readonly) NSString *name; +/*! + @abstract A URL to the user's profile. + @discussion Consider using Bolts and `FBSDKAppLinkResolver` to resolve this + to an app link to link directly to the user's profile in the Facebook app. + */ +@property (nonatomic, readonly) NSURL *linkURL; + +/*! + @abstract The last time the profile data was fetched. + */ +@property (nonatomic, readonly) NSDate *refreshDate; + +/*! + @abstract Gets the current FBSDKProfile instance. + */ ++ (FBSDKProfile *)currentProfile; + +/*! + @abstract Sets the current instance and posts the appropriate notification if the profile parameter is different + than the receiver. + @param profile the profile to set + @discussion This persists the profile to NSUserDefaults. + */ ++ (void)setCurrentProfile:(FBSDKProfile *)profile; + +/*! + @abstract Indicates if `currentProfile` will automatically observe `FBSDKAccessTokenDidChangeNotification` notifications + @param enable YES is observing + @discussion If observing, this class will issue a graph request for public profile data when the current token's userID + differs from the current profile. You can observe `FBSDKProfileDidChangeNotification` for when the profile is updated. + + Note that if `[FBSDKAccessToken currentAccessToken]` is unset, the `currentProfile` instance remains. It's also possible + for `currentProfile` to return nil until the data is fetched. + */ ++ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable; + +/*! + @abstract A convenience method for returning a complete `NSURL` for retrieving the user's profile image. + @param mode The picture mode + @param size The height and width. This will be rounded to integer precision. + */ +- (NSURL *)imageURLForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size; + +/*! + @abstract A convenience method for returning a Graph API path for retrieving the user's profile image. + @deprecated use `imageURLForPictureMode:size:` instead + @discussion You can pass this to a `FBSDKGraphRequest` instance to download the image. + @param mode The picture mode + @param size The height and width. This will be rounded to integer precision. + */ +- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size +__attribute__ ((deprecated("use imageURLForPictureMode:size: instead"))); + +/*! + @abstract Returns YES if the profile is equivalent to the receiver. + @param profile the profile to compare to. + */ +- (BOOL)isEqualToProfile:(FBSDKProfile *)profile; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.m new file mode 100644 index 0000000..b57b253 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.m @@ -0,0 +1,268 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKProfile+Internal.h" + +#import "FBSDKCoreKit+Internal.h" + +NSString *const FBSDKProfileDidChangeNotification = @"com.facebook.sdk.FBSDKProfile.FBSDKProfileDidChangeNotification";; +NSString *const FBSDKProfileChangeOldKey = @"FBSDKProfileOld"; +NSString *const FBSDKProfileChangeNewKey = @"FBSDKProfileNew"; +static NSString *const FBSDKProfileUserDefaultsKey = @"com.facebook.sdk.FBSDKProfile.currentProfile"; +static FBSDKProfile *g_currentProfile; + +#define FBSDKPROFILE_USERID_KEY @"userID" +#define FBSDKPROFILE_FIRSTNAME_KEY @"firstName" +#define FBSDKPROFILE_MIDDLENAME_KEY @"middleName" +#define FBSDKPROFILE_LASTNAME_KEY @"lastName" +#define FBSDKPROFILE_NAME_KEY @"name" +#define FBSDKPROFILE_LINKURL_KEY @"linkURL" +#define FBSDKPROFILE_REFRESHDATE_KEY @"refreshDate" + +// Once a day +#define FBSDKPROFILE_STALE_IN_SECONDS (60 * 60 * 24) + +@implementation FBSDKProfile + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithUserID:(NSString *)userID + firstName:(NSString *)firstName + middleName:(NSString *)middleName + lastName:(NSString *)lastName + name:(NSString *)name + linkURL:(NSURL *)linkURL + refreshDate:(NSDate *)refreshDate +{ + if ((self = [super init])) { + _userID = [userID copy]; + _firstName = [firstName copy]; + _middleName = [middleName copy]; + _lastName = [lastName copy]; + _name = [name copy]; + _linkURL = [linkURL copy]; + _refreshDate = [refreshDate copy] ?: [NSDate date]; + } + return self; +} + ++ (FBSDKProfile *)currentProfile +{ + return g_currentProfile; +} + ++ (void)setCurrentProfile:(FBSDKProfile *)profile +{ + if (profile != g_currentProfile && ![profile isEqualToProfile:g_currentProfile]) { + [[self class] cacheProfile:profile]; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + + [FBSDKInternalUtility dictionary:userInfo setObject:profile forKey:FBSDKProfileChangeNewKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:g_currentProfile forKey:FBSDKProfileChangeOldKey]; + g_currentProfile = profile; + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKProfileDidChangeNotification + object:[self class] + userInfo:userInfo]; + } +} + +- (NSURL *)imageURLForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSString *path = [self imagePathForPictureMode:FBSDKProfilePictureModeNormal size:size]; +#pragma clang diagnostic pop + return [FBSDKInternalUtility facebookURLWithHostPrefix:@"graph" + path:path + queryParameters:nil + error:NULL]; +} + +- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size +{ + NSString *type; + switch (mode) { + case FBSDKProfilePictureModeNormal: type = @"normal"; break; + case FBSDKProfilePictureModeSquare: type = @"square"; break; + } + return [NSString stringWithFormat:@"%@/picture?type=%@&width=%d&height=%d", + _userID, + type, + (int) roundf(size.width), + (int) roundf(size.height)]; +} + ++ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable +{ + if (enable) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(observeChangeAccessTokenChange:) + name:FBSDKAccessTokenDidChangeNotification + object:nil]; + } else { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } +} + +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + //immutable + return self; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [self.userID hash], + [self.firstName hash], + [self.middleName hash], + [self.lastName hash], + [self.name hash], + [self.linkURL hash], + [self.refreshDate hash] + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKProfile class]]){ + return NO; + } + return [self isEqualToProfile:object]; +} + +- (BOOL)isEqualToProfile:(FBSDKProfile *)profile +{ + return ([_userID isEqualToString:profile.userID] && + [_firstName isEqualToString:profile.firstName] && + [_middleName isEqualToString:profile.middleName] && + [_lastName isEqualToString:profile.lastName] && + [_name isEqualToString:profile.name] && + [_linkURL isEqual:profile.linkURL] && + [_refreshDate isEqualToDate:profile.refreshDate]); +} +#pragma mark NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_USERID_KEY]; + NSString *firstName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_FIRSTNAME_KEY]; + NSString *middleName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_MIDDLENAME_KEY]; + NSString *lastName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_LASTNAME_KEY]; + NSString *name = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_NAME_KEY]; + NSURL *linkURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDKPROFILE_LINKURL_KEY]; + NSDate *refreshDate = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDKPROFILE_REFRESHDATE_KEY]; + return [self initWithUserID:userID + firstName:firstName + middleName:middleName + lastName:lastName + name:name + linkURL:linkURL + refreshDate:refreshDate]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:self.userID forKey:FBSDKPROFILE_USERID_KEY]; + [encoder encodeObject:self.firstName forKey:FBSDKPROFILE_FIRSTNAME_KEY]; + [encoder encodeObject:self.middleName forKey:FBSDKPROFILE_MIDDLENAME_KEY]; + [encoder encodeObject:self.lastName forKey:FBSDKPROFILE_LASTNAME_KEY]; + [encoder encodeObject:self.name forKey:FBSDKPROFILE_NAME_KEY]; + [encoder encodeObject:self.linkURL forKey:FBSDKPROFILE_LINKURL_KEY]; + [encoder encodeObject:self.refreshDate forKey:FBSDKPROFILE_REFRESHDATE_KEY]; +} + +#pragma mark - Private + ++ (void)observeChangeAccessTokenChange:(NSNotification *)notification +{ + FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey]; + static FBSDKGraphRequestConnection *executingRequestConnection = nil; + + BOOL isStale = [[NSDate date] timeIntervalSinceDate:g_currentProfile.refreshDate] > FBSDKPROFILE_STALE_IN_SECONDS; + if (token && + (isStale || ![g_currentProfile.userID isEqualToString:token.userID])) { + FBSDKProfile *expectedCurrentProfile = g_currentProfile; + + NSString *graphPath = @"me?fields=id,first_name,middle_name,last_name,name,link"; + [executingRequestConnection cancel]; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + executingRequestConnection = [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (expectedCurrentProfile != g_currentProfile) { + // current profile has already changed since request was started. Let's not overwrite. + return; + } + FBSDKProfile *profile = nil; + if (!error) { + profile = [[FBSDKProfile alloc] initWithUserID:result[@"id"] + firstName:result[@"first_name"] + middleName:result[@"middle_name"] + lastName:result[@"last_name"] + name:result[@"name"] + linkURL:[NSURL URLWithString:result[@"link"]] + refreshDate:[NSDate date]]; + } + [[self class] setCurrentProfile:profile]; + }]; + } +} + +@end + +@implementation FBSDKProfile(Internal) + ++ (void)cacheProfile:(FBSDKProfile *) profile +{ + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + if (profile) { + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profile]; + [userDefaults setObject:data forKey:FBSDKProfileUserDefaultsKey]; + } else { + [userDefaults removeObjectForKey:FBSDKProfileUserDefaultsKey]; + } + [userDefaults synchronize]; +} + ++ (FBSDKProfile *)fetchCachedProfile +{ + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + NSData *data = [userDefaults objectForKey:FBSDKProfileUserDefaultsKey]; + return (data != nil) + ? [NSKeyedUnarchiver unarchiveObjectWithData:data] + : nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h new file mode 100644 index 0000000..f1f64cb --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h @@ -0,0 +1,59 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @typedef FBSDKProfilePictureMode enum + @abstract Defines the aspect ratio mode for the source image of the profile picture. + */ +typedef NS_ENUM(NSUInteger, FBSDKProfilePictureMode) +{ + /*! + @abstract A square cropped version of the image will be included in the view. + */ + FBSDKProfilePictureModeSquare, + /*! + @abstract The original picture's aspect ratio will be used for the source image in the view. + */ + FBSDKProfilePictureModeNormal, +}; + +/*! + @abstract A view to display a profile picture. + */ +@interface FBSDKProfilePictureView : UIView + +/*! + @abstract The mode for the receiver to determine the aspect ratio of the source image. + */ +@property (nonatomic, assign) FBSDKProfilePictureMode pictureMode; + +/*! + @abstract The profile ID to show the picture for. + */ +@property (nonatomic, copy) NSString *profileID; + +/*! + @abstract Explicitly marks the receiver as needing to update the image. + @discussion This method is called whenever any properties that affect the source image are modified, but this can also + be used to trigger a manual update of the image if it needs to be re-downloaded. + */ +- (void)setNeedsImageUpdate; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.m new file mode 100644 index 0000000..f107de3 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.m @@ -0,0 +1,368 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKProfilePictureView.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMaleSilhouetteIcon.h" +#import "FBSDKMath.h" +#import "FBSDKURLConnection.h" +#import "FBSDKUtility.h" + +@interface FBSDKProfilePictureViewState : NSObject + +- (instancetype)initWithProfileID:(NSString *)profileID + size:(CGSize)size + scale:(CGFloat)scale + pictureMode:(FBSDKProfilePictureMode)pictureMode + imageShouldFit:(BOOL)imageShouldFit; + +@property (nonatomic, assign, readonly) BOOL imageShouldFit; +@property (nonatomic, assign, readonly) FBSDKProfilePictureMode pictureMode; +@property (nonatomic, copy, readonly) NSString *profileID; +@property (nonatomic, assign, readonly) CGFloat scale; +@property (nonatomic, assign, readonly) CGSize size; + +- (BOOL)isEqualToState:(FBSDKProfilePictureViewState *)other; +- (BOOL)isValidForState:(FBSDKProfilePictureViewState *)other; + +@end + +@implementation FBSDKProfilePictureViewState + +- (instancetype)initWithProfileID:(NSString *)profileID + size:(CGSize)size + scale:(CGFloat)scale + pictureMode:(FBSDKProfilePictureMode)pictureMode + imageShouldFit:(BOOL)imageShouldFit +{ + if ((self = [super init])) { + _profileID = [profileID copy]; + _size = size; + _scale = scale; + _pictureMode = pictureMode; + _imageShouldFit = imageShouldFit; + } + return self; +} + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + (NSUInteger)_imageShouldFit, + (NSUInteger)_size.width, + (NSUInteger)_size.height, + (NSUInteger)_scale, + (NSUInteger)_pictureMode, + [_profileID hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (![object isKindOfClass:[FBSDKProfilePictureViewState class]]) { + return NO; + } + FBSDKProfilePictureViewState *other = (FBSDKProfilePictureViewState *)object; + return [self isEqualToState:other]; +} + +- (BOOL)isEqualToState:(FBSDKProfilePictureViewState *)other +{ + return ([self isValidForState:other] && + CGSizeEqualToSize(_size, other->_size) && + (_scale == other->_scale)); +} + +- (BOOL)isValidForState:(FBSDKProfilePictureViewState *)other +{ + return (other != nil && + (_imageShouldFit == other->_imageShouldFit) && + (_pictureMode == other->_pictureMode) && + [FBSDKInternalUtility object:_profileID isEqualToObject:other->_profileID]); +} + +@end + +@implementation FBSDKProfilePictureView +{ + BOOL _hasProfileImage; + UIImageView *_imageView; + FBSDKProfilePictureViewState *_lastState; + BOOL _needsImageUpdate; + BOOL _placeholderImageIsValid; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + [self _configureProfilePictureView]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) { + [self _configureProfilePictureView]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Properties + +- (void)setBounds:(CGRect)bounds +{ + CGRect currentBounds = self.bounds; + if (!CGRectEqualToRect(currentBounds, bounds)) { + [super setBounds:bounds]; + if (!CGSizeEqualToSize(currentBounds.size, bounds.size)) { + _placeholderImageIsValid = NO; + [self setNeedsImageUpdate]; + } + } +} + +- (UIViewContentMode)contentMode +{ + return _imageView.contentMode; +} + +- (void)setContentMode:(UIViewContentMode)contentMode +{ + if (_imageView.contentMode != contentMode) { + _imageView.contentMode = contentMode; + [super setContentMode:contentMode]; + [self setNeedsImageUpdate]; + } +} + +- (void)setMode:(FBSDKProfilePictureMode)pictureMode +{ + if (_pictureMode != pictureMode) { + _pictureMode = pictureMode; + [self setNeedsImageUpdate]; + } +} + +- (void)setProfileID:(NSString *)profileID +{ + if (![FBSDKInternalUtility object:_profileID isEqualToObject:profileID]) { + _profileID = [profileID copy]; + _placeholderImageIsValid = NO; + [self setNeedsImageUpdate]; + } +} + +#pragma mark - Public Methods + +- (void)setNeedsImageUpdate +{ + if (!_imageView || CGRectIsEmpty(self.bounds)) { + // we can't do anything with an empty view, so just bail out until we have a size + return; + } + + // ensure that we have an image. do this here so we can draw the placeholder image synchronously if we don't have one + if (!_placeholderImageIsValid && !_hasProfileImage) { + [self _setPlaceholderImage]; + } + + // debounce calls to needsImage against the main runloop + if (_needsImageUpdate) { + return; + } + _needsImageUpdate = YES; + __weak FBSDKProfilePictureView *weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf _needsImageUpdate]; + }); +} + +#pragma mark - Helper Methods + ++ (void)_downloadImageWithState:(FBSDKProfilePictureViewState *)state + completionBlock:(void(^)(NSData *data))completionBlock; +{ + NSURL *imageURL = [self _imageURLWithState:state]; + if (!imageURL) { + return; + } + FBSDKURLConnectionHandler completionHandler = ^(FBSDKURLConnection *connection, + NSError *error, + NSURLResponse *response, + NSData *responseData) { + if (!error && [responseData length]) { + completionBlock(responseData); + } + }; + NSURLRequest *request = [[NSURLRequest alloc] initWithURL:imageURL]; + [[[FBSDKURLConnection alloc] initWithRequest:request completionHandler:completionHandler] start]; +} + ++ (NSURL *)_imageURLWithState:(FBSDKProfilePictureViewState *)state +{ + FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken]; + if ([state.profileID isEqualToString:@"me"] && !accessToken) { + return nil; + } + NSString *path = [[NSString alloc] initWithFormat:@"/%@/picture", [FBSDKUtility URLEncode:state.profileID]]; + CGSize size = state.size; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + parameters[@"width"] = @(size.width); + parameters[@"height"] = @(size.height); + [FBSDKInternalUtility dictionary:parameters setObject:accessToken.tokenString forKey:@"access_token"]; + return [FBSDKInternalUtility facebookURLWithHostPrefix:@"graph" path:path queryParameters:parameters error:NULL]; +} + +- (void)_accessTokenDidChangeNotification:(NSNotification *)notification +{ + if (![_profileID isEqualToString:@"me"] || !notification.userInfo[FBSDKAccessTokenDidChangeUserID]) { + return; + } + _lastState = nil; + [self setNeedsImageUpdate]; +} + +- (void)_configureProfilePictureView +{ + _imageView = [[UIImageView alloc] initWithFrame:self.bounds]; + _imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self addSubview:_imageView]; + + _profileID = @"me"; + self.backgroundColor = [UIColor whiteColor]; + self.contentMode = UIViewContentModeScaleAspectFit; + self.userInteractionEnabled = NO; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_accessTokenDidChangeNotification:) + name:FBSDKAccessTokenDidChangeNotification + object:nil]; + + [self setNeedsImageUpdate]; +} + +- (BOOL)_imageShouldFit +{ + switch (self.contentMode) { + case UIViewContentModeBottom: + case UIViewContentModeBottomLeft: + case UIViewContentModeBottomRight: + case UIViewContentModeCenter: + case UIViewContentModeLeft: + case UIViewContentModeRedraw: + case UIViewContentModeRight: + case UIViewContentModeScaleAspectFit: + case UIViewContentModeTop: + case UIViewContentModeTopLeft: + case UIViewContentModeTopRight: + return YES; + case UIViewContentModeScaleAspectFill: + case UIViewContentModeScaleToFill: + return NO; + } +} + +- (CGSize)_imageSize:(BOOL)imageShouldFit scale:(CGFloat)scale +{ + // get the image size based on the contentMode and pictureMode + CGSize size = self.bounds.size; + switch (_pictureMode) { + case FBSDKProfilePictureModeSquare:{ + CGFloat imageSize; + if (imageShouldFit) { + imageSize = MIN(size.width, size.height); + } else { + imageSize = MAX(size.width, size.height); + } + size = CGSizeMake(imageSize, imageSize); + break; + } + case FBSDKProfilePictureModeNormal: + // use the bounds size + break; + } + + // adjust for the screen scale + size = CGSizeMake(size.width * scale, size.height * scale); + + return size; +} + +- (void)_needsImageUpdate +{ + _needsImageUpdate = NO; + + if (!_profileID) { + if (!_placeholderImageIsValid) { + [self _setPlaceholderImage]; + } + return; + } + + // if the current image is no longer representative of the current state, clear the current value out; otherwise, + // leave the current value until the new resolution image is downloaded + BOOL imageShouldFit = [self _imageShouldFit]; + UIScreen *screen = self.window.screen ?: [UIScreen mainScreen]; + CGFloat scale = [screen scale]; + CGSize imageSize = [self _imageSize:imageShouldFit scale:scale]; + FBSDKProfilePictureViewState *state = [[FBSDKProfilePictureViewState alloc] initWithProfileID:_profileID + size:imageSize + scale:scale + pictureMode:_pictureMode + imageShouldFit:imageShouldFit]; + if (![_lastState isValidForState:state]) { + [self _setPlaceholderImage]; + } + _lastState = state; + + __weak FBSDKProfilePictureView *weakSelf = self; + [[self class] _downloadImageWithState:state completionBlock:^(NSData *data) { + [weakSelf _updateImageWithData:data state:state]; + }]; +} + +- (void)_setPlaceholderImage +{ + UIColor *fillColor = [UIColor colorWithRed:157.0/255.0 green:177.0/255.0 blue:204.0/255.0 alpha:1.0]; + _imageView.image = [[[FBSDKMaleSilhouetteIcon alloc] initWithColor:fillColor] imageWithSize:_imageView.bounds.size]; + _placeholderImageIsValid = YES; + _hasProfileImage = NO; +} + +- (void)_updateImageWithData:(NSData *)data state:(FBSDKProfilePictureViewState *)state +{ + // make sure we haven't updated the state since we began fetching the image + if (![state isValidForState:_lastState]) { + return; + } + UIImage *image = [[UIImage alloc] initWithData:data scale:state.scale]; + _imageView.image = image; + _hasProfileImage = YES; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h new file mode 100644 index 0000000..edc0040 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h @@ -0,0 +1,209 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/* + * Constants defining logging behavior. Use with <[FBSDKSettings setLoggingBehavior]>. + */ + +/*! Include access token in logging. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAccessTokens; + +/*! Log performance characteristics */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics; + +/*! Log FBSDKAppEvents interactions */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAppEvents; + +/*! Log Informational occurrences */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorInformational; + +/*! Log cache errors. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorCacheErrors; + +/*! Log errors from SDK UI controls */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorUIControlErrors; + +/*! Log debug warnings from API response, i.e. when friends fields requested, but user_friends permission isn't granted. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning; + +/*! Log warnings from API response, i.e. when requested feature will be deprecated in next version of API. + Info is the lowest level of severity, using it will result in logging all previously mentioned levels. + */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo; + +/*! Log errors from SDK network requests */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorNetworkRequests; + +/*! Log errors likely to be preventable by the developer. This is in the default set of enabled logging behaviors. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorDeveloperErrors; + +@interface FBSDKSettings : NSObject + +/*! + @abstract Get the Facebook App ID used by the SDK. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookAppID). + */ ++ (NSString *)appID; + +/*! + @abstract Set the Facebook App ID to be used by the SDK. + @param appID The Facebook App ID to be used by the SDK. + */ ++ (void)setAppID:(NSString *)appID; + +/*! + @abstract Get the default url scheme suffix used for sessions. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookUrlSchemeSuffix). + */ ++ (NSString *)appURLSchemeSuffix; + +/*! + @abstract Set the app url scheme suffix used by the SDK. + @param appURLSchemeSuffix The url scheme suffix to be used by the SDK. + */ ++ (void)setAppURLSchemeSuffix:(NSString *)appURLSchemeSuffix; + +/*! + @abstract Retrieve the Client Token that has been set via [FBSDKSettings setClientToken]. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookClientToken). + */ ++ (NSString *)clientToken; + +/*! + @abstract Sets the Client Token for the Facebook App. + @discussion This is needed for certain API calls when made anonymously, without a user-based access token. + @param clientToken The Facebook App's "client token", which, for a given appid can be found in the Security + section of the Advanced tab of the Facebook App settings found at + */ ++ (void)setClientToken:(NSString *)clientToken; + +/*! + @abstract A convenient way to toggle error recovery for all FBSDKGraphRequest instances created after this is set. + @param disableGraphErrorRecovery YES or NO. + */ ++ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery; + +/*! + @abstract Get the Facebook Display Name used by the SDK. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookDisplayName). + */ ++ (NSString *)displayName; + +/*! + @abstract Set the default Facebook Display Name to be used by the SDK. + @discussion This should match the Display Name that has been set for the app with the corresponding Facebook App ID, + in the Facebook App Dashboard. + @param displayName The Facebook Display Name to be used by the SDK. + */ ++ (void)setDisplayName:(NSString *)displayName; + +/*! + @abstract Get the Facebook domain part. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookDomainPart). + */ ++ (NSString *)facebookDomainPart; + +/*! + @abstract Set the subpart of the Facebook domain. + @discussion This can be used to change the Facebook domain (e.g. @"beta") so that requests will be sent to + graph.beta.facebook.com + @param facebookDomainPart The domain part to be inserted into facebook.com. + */ ++ (void)setFacebookDomainPart:(NSString *)facebookDomainPart; + +/*! + @abstract The quality of JPEG images sent to Facebook from the SDK. + @discussion If not explicitly set, the default is 0.9. + @see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */ ++ (CGFloat)JPEGCompressionQuality; + +/*! + @abstract Set the quality of JPEG images sent to Facebook from the SDK. + @param JPEGCompressionQuality The quality for JPEG images, expressed as a value from 0.0 to 1.0. + @see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */ ++ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality; + +/*! + @abstract + Gets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches. + */ ++ (BOOL)limitEventAndDataUsage; + +/*! + @abstract + Sets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches. + + @param limitEventAndDataUsage The desired value. + */ ++ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage; + +/*! + @abstract Retrieve the current iOS SDK version. + */ ++ (NSString *)sdkVersion; + +/*! + @abstract Retrieve the current Facebook SDK logging behavior. + */ ++ (NSSet *)loggingBehavior; + +/*! + @abstract Set the current Facebook SDK logging behavior. This should consist of strings defined as + constants with FBSDKLoggingBehavior*. + + @param loggingBehavior A set of strings indicating what information should be logged. If nil is provided, the logging + behavior is reset to the default set of enabled behaviors. Set to an empty set in order to disable all logging. + + @discussion You can also define this via an array in your app plist with key "FacebookLoggingBehavior" or add and remove individual values via enableLoggingBehavior: or disableLogginBehavior: + */ ++ (void)setLoggingBehavior:(NSSet *)loggingBehavior; + +/*! + @abstract Enable a particular Facebook SDK logging behavior. + + @param loggingBehavior The LoggingBehavior to enable. This should be a string defined as a constant with FBSDKLoggingBehavior*. + */ ++ (void)enableLoggingBehavior:(NSString *)loggingBehavior; + +/*! + @abstract Disable a particular Facebook SDK logging behavior. + + @param loggingBehavior The LoggingBehavior to disable. This should be a string defined as a constant with FBSDKLoggingBehavior*. + */ ++ (void)disableLoggingBehavior:(NSString *)loggingBehavior; + +/*! + @abstract Set the user defaults key used by legacy token caches. + + @param tokenInformationKeyName the key used by legacy token caches. + + @discussion Use this only if you customized FBSessionTokenCachingStrategy in v3.x of + the Facebook SDK for iOS. +*/ ++ (void)setLegacyUserDefaultTokenInformationKeyName:(NSString *)tokenInformationKeyName; + +/*! + @abstract Get the user defaults key used by legacy token caches. +*/ ++ (NSString *)legacyUserDefaultTokenInformationKeyName; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.m new file mode 100644 index 0000000..8476827 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.m @@ -0,0 +1,223 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKSettings+Internal.h" + +#import "FBSDKCoreKit.h" + +#define FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(TYPE, PLIST_KEY, GETTER, SETTER, DEFAULT_VALUE) \ +static TYPE *g_##PLIST_KEY = nil; \ ++ (TYPE *)GETTER \ +{ \ + if (!g_##PLIST_KEY) { \ + g_##PLIST_KEY = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@#PLIST_KEY] copy] ?: DEFAULT_VALUE; \ + } \ + return g_##PLIST_KEY; \ +} \ ++ (void)SETTER:(TYPE *)value { \ + g_##PLIST_KEY = [value copy]; \ +} + +NSString *const FBSDKLoggingBehaviorAccessTokens = @"include_access_tokens"; +NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics = @"perf_characteristics"; +NSString *const FBSDKLoggingBehaviorAppEvents = @"app_events"; +NSString *const FBSDKLoggingBehaviorInformational = @"informational"; +NSString *const FBSDKLoggingBehaviorCacheErrors = @"cache_errors"; +NSString *const FBSDKLoggingBehaviorUIControlErrors = @"ui_control_errors"; +NSString *const FBSDKLoggingBehaviorDeveloperErrors = @"developer_errors"; +NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning = @"graph_api_debug_warning"; +NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo = @"graph_api_debug_info"; +NSString *const FBSDKLoggingBehaviorNetworkRequests = @"network_requests"; + +static FBSDKAccessTokenCache *g_tokenCache; +static NSMutableSet *g_loggingBehavior; +static NSString *g_legacyUserDefaultTokenInformationKeyName = @"FBAccessTokenInformationKey"; +static NSString *const FBSDKSettingsLimitEventAndDataUsage = @"com.facebook.sdk:FBSDKSettingsLimitEventAndDataUsage"; +static BOOL g_disableErrorRecovery; +static NSString *g_userAgentSuffix; + +@implementation FBSDKSettings + ++ (void)initialize +{ + if (self == [FBSDKSettings class]) { + g_tokenCache = [[FBSDKAccessTokenCache alloc] init]; + } +} + +#pragma mark - Plist Configuration Settings + +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookAppID, appID, setAppID, nil); +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookUrlSchemeSuffix, appURLSchemeSuffix, setAppURLSchemeSuffix, nil); +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookClientToken, clientToken, setClientToken, nil); +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookDisplayName, displayName, setDisplayName, nil); +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookDomainPart, facebookDomainPart, setFacebookDomainPart, nil); +FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookJpegCompressionQuality, _JPEGCompressionQualityNumber, _setJPEGCompressionQualityNumber, @(0.9)); + ++ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery { + g_disableErrorRecovery = disableGraphErrorRecovery; +} + ++ (BOOL)isGraphErrorRecoveryDisabled { + return g_disableErrorRecovery; +} + ++ (CGFloat)JPEGCompressionQuality +{ + return [[self _JPEGCompressionQualityNumber] floatValue]; +} + ++ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality +{ + [self _setJPEGCompressionQualityNumber:@(JPEGCompressionQuality)]; +} + ++ (BOOL)limitEventAndDataUsage +{ + NSNumber *storedValue = [[NSUserDefaults standardUserDefaults] objectForKey:FBSDKSettingsLimitEventAndDataUsage]; + if (storedValue == nil) { + return NO; + } + return storedValue.boolValue; +} + ++ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:@(limitEventAndDataUsage) forKey:FBSDKSettingsLimitEventAndDataUsage]; + [defaults synchronize]; +} + ++ (NSSet *)loggingBehavior +{ + if (!g_loggingBehavior) { + NSArray *bundleLoggingBehaviors = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FacebookLoggingBehavior"]; + if (bundleLoggingBehaviors) { + g_loggingBehavior = [[NSMutableSet alloc] initWithArray:bundleLoggingBehaviors]; + } else { + // Establish set of default enabled logging behaviors. You can completely disable logging by + // specifying an empty array for FacebookLoggingBehavior in your Info.plist. + g_loggingBehavior = [[NSMutableSet alloc] initWithObjects:FBSDKLoggingBehaviorDeveloperErrors, nil]; + } + } + return [g_loggingBehavior copy]; +} + ++ (void)setLoggingBehavior:(NSSet *)loggingBehavior +{ + if (![g_loggingBehavior isEqualToSet:loggingBehavior]) { + g_loggingBehavior = [loggingBehavior mutableCopy]; + + [self updateGraphAPIDebugBehavior]; + } +} + ++ (void)enableLoggingBehavior:(NSString *)loggingBehavior +{ + if (!g_loggingBehavior) { + [self loggingBehavior]; + } + [g_loggingBehavior addObject:loggingBehavior]; + [self updateGraphAPIDebugBehavior]; +} + ++ (void)disableLoggingBehavior:(NSString *)loggingBehavior +{ + if (!g_loggingBehavior) { + [self loggingBehavior]; + } + [g_loggingBehavior removeObject:loggingBehavior]; + [self updateGraphAPIDebugBehavior]; +} + ++ (void)setLegacyUserDefaultTokenInformationKeyName:(NSString *)tokenInformationKeyName +{ + if (![g_legacyUserDefaultTokenInformationKeyName isEqualToString:tokenInformationKeyName]) { + g_legacyUserDefaultTokenInformationKeyName = tokenInformationKeyName; + } +} + ++ (NSString *)legacyUserDefaultTokenInformationKeyName +{ + return g_legacyUserDefaultTokenInformationKeyName; +} + +#pragma mark - Readonly Configuration Settings + ++ (NSString *)sdkVersion +{ + return FBSDK_VERSION_STRING; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +#pragma mark - Internal + ++ (FBSDKAccessTokenCache *)accessTokenCache +{ + return g_tokenCache; +} + +- (void)setAccessTokenCache:(FBSDKAccessTokenCache *)cache +{ + if (g_tokenCache != cache) { + g_tokenCache = cache; + } +} + ++ (NSString *)userAgentSuffix +{ + return g_userAgentSuffix; +} + ++ (void)setUserAgentSuffix:(NSString *)suffix +{ + if (![g_userAgentSuffix isEqualToString:suffix]) { + g_userAgentSuffix = suffix; + } +} + +#pragma mark - Internal - Graph API Debug + ++ (void)updateGraphAPIDebugBehavior +{ + // Enable Warnings everytime Info is enabled + if ([g_loggingBehavior containsObject:FBSDKLoggingBehaviorGraphAPIDebugInfo] + && ![g_loggingBehavior containsObject:FBSDKLoggingBehaviorGraphAPIDebugWarning]) { + [g_loggingBehavior addObject:FBSDKLoggingBehaviorGraphAPIDebugWarning]; + } +} + ++ (NSString *)graphAPIDebugParamValue +{ + if ([[self loggingBehavior] containsObject:FBSDKLoggingBehaviorGraphAPIDebugInfo]) { + return @"info"; + } else if ([[self loggingBehavior] containsObject:FBSDKLoggingBehaviorGraphAPIDebugWarning]) { + return @"warning"; + } + + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h new file mode 100644 index 0000000..7d2e0ac --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h @@ -0,0 +1,102 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +/*! + @typedef + + @abstract Callback block for returning an array of FBSDKAccessToken instances (and possibly `NSNull` instances); or an error. + */ +typedef void (^FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)(NSArray *tokens, NSError *error) ; + +/*! + @typedef + + @abstract Callback block for removing a test user. + */ +typedef void (^FBSDKTestUsersManagerRemoveTestAccountHandler)(NSError *error) ; + + +/*! + @class FBSDKTestUsersManager + @abstract Provides methods for managing test accounts for testing Facebook integration. + + @discussion Facebook allows developers to create test accounts for testing their applications' + Facebook integration (see https://developers.facebook.com/docs/test_users/). This class + simplifies use of these accounts for writing tests. It is not designed for use in + production application code. + + This class will make Graph API calls on behalf of your app to manage test accounts and requires + an app id and app secret. You will typically use this class to write unit or integration tests. + Make sure you NEVER include your app secret in your production app. + */ +@interface FBSDKTestUsersManager : NSObject + +/*! + @abstract construct or return the shared instance + @param appID the Facebook app id + @param appSecret the Facebook app secret + */ ++ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret; + +/*! + @abstract retrieve FBSDKAccessToken instances for test accounts with the specific permissions. + @param arraysOfPermissions an array of permissions sets, such as @[ [NSSet setWithObject:@"email"], [NSSet setWithObject:@"user_birthday"]] + if you needed two test accounts with email and birthday permissions, respectively. You can pass in empty nested sets + if you need two arbitrary test accounts. For convenience, passing nil is treated as @[ [NSSet set] ] + for fetching a single test user. + @param createIfNotFound if YES, new test accounts are created if no test accounts existed that fit the permissions + requirement + @param handler the callback to invoke which will return an array of `FBAccessTokenData` instances or an `NSError`. + If param `createIfNotFound` is NO, the array may contain `[NSNull null]` instances. + + @discussion If you are requesting test accounts with differing number of permissions, try to order + `arrayOfPermissionsArrays` so that the most number of permissions come first to minimize creation of new + test accounts. + */ +- (void)requestTestAccountTokensWithArraysOfPermissions:(NSArray *)arraysOfPermissions + createIfNotFound:(BOOL)createIfNotFound + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler; + +/*! + @abstract add a test account with the specified permissions + @param permissions the set of permissions, e.g., [NSSet setWithObjects:@"email", @"user_friends"] + @param handler the callback handler + */ +- (void)addTestAccountWithPermissions:(NSSet *)permissions + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler; + +/*! + @abstract remove a test account for the given user id + @param userId the user id + @param handler the callback handler + */ +- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler; + +/*! + @abstract Make two test users friends with each other. + @param first the token of the first user + @param second the token of the second user + @param callback the callback handler + */ +- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.m new file mode 100644 index 0000000..71fb8df --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.m @@ -0,0 +1,328 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKTestUsersManager.h" + +#import "FBSDKCoreKit+Internal.h" + +static NSString *const kFBGraphAPITestUsersPathFormat = @"%@/accounts/test-users"; +static NSString *const kAccountsDictionaryTokenKey = @"access_token"; +static NSString *const kAccountsDictionaryPermissionsKey = @"permissions"; +static NSMutableDictionary *gInstancesDictionary; + +@interface FBSDKTestUsersManager() +- (instancetype)initWithAppID:(NSString *)appID appSecret:(NSString *)appSecret NS_DESIGNATED_INITIALIZER; +@end + +@implementation FBSDKTestUsersManager +{ + NSString *_appID; + NSString *_appSecret; + // dictionary with format like: + // { user_id : { kAccountsDictionaryTokenKey : "token", + // kAccountsDictionaryPermissionsKey : [ permissions ] } + NSMutableDictionary *_accounts; +} + +- (instancetype)initWithAppID:(NSString *)appID appSecret:(NSString *)appSecret { + if ((self = [super init])) { + _appID = [appID copy]; + _appSecret = [appSecret copy]; + _accounts = [NSMutableDictionary dictionary]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAppID:appSecret:); + return [self initWithAppID:nil appSecret:nil]; +} + ++ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gInstancesDictionary = [NSMutableDictionary dictionary]; + }); + + NSString *instanceKey = [NSString stringWithFormat:@"%@|%@", appID, appSecret]; + if (!gInstancesDictionary[instanceKey]) { + gInstancesDictionary[instanceKey] = [[FBSDKTestUsersManager alloc] initWithAppID:appID appSecret:appSecret]; + } + return gInstancesDictionary[instanceKey]; +} + +- (void)requestTestAccountTokensWithArraysOfPermissions:(NSArray *)arraysOfPermissions + createIfNotFound:(BOOL)createIfNotFound + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler { + arraysOfPermissions = arraysOfPermissions ?: @[[NSSet set]]; + + // wrap work in a block so that we can chain it to after a fetch of existing accounts if we need to. + void (^helper)(NSError *) = ^(NSError *error){ + if (error) { + if (handler) { + handler(nil, error); + } + return; + } + NSMutableArray *tokenDatum = [NSMutableArray arrayWithCapacity:arraysOfPermissions.count]; + NSMutableSet *collectedUserIds = [NSMutableSet setWithCapacity:arraysOfPermissions.count]; + __block BOOL canInvokeHandler = YES; + __weak id weakSelf = self; + [arraysOfPermissions enumerateObjectsUsingBlock:^(NSSet *desiredPermissions, NSUInteger idx, BOOL *stop) { + NSArray* userIdAndTokenPair = [self userIdAndTokenOfExistingAccountWithPermissions:desiredPermissions skip:collectedUserIds]; + if (!userIdAndTokenPair) { + if (createIfNotFound) { + [self addTestAccountWithPermissions:desiredPermissions + completionHandler:^(NSArray *tokens, NSError *addError) { + if (addError) { + if (handler) { + handler(nil, addError); + } + } else { + [weakSelf requestTestAccountTokensWithArraysOfPermissions:arraysOfPermissions + createIfNotFound:createIfNotFound + completionHandler:handler]; + } + }]; + // stop the enumeration (ane flag so that callback to addTestAccount* will resolve our handler now). + canInvokeHandler = NO; + *stop = YES; + return; + } else { + [tokenDatum addObject:[NSNull null]]; + } + } else { + NSString *userId = userIdAndTokenPair[0]; + NSString *tokenString = userIdAndTokenPair[1]; + [collectedUserIds addObject:userId]; + [tokenDatum addObject:[self tokenDataForTokenString:tokenString + permissions:desiredPermissions + userId:userId]]; + } + }]; + + if (canInvokeHandler && handler) { + handler(tokenDatum, nil); + } + }; + if (_accounts.count == 0) { + [self fetchExistingTestAccountsWithAfterCursor:nil handler:helper]; + } else { + helper(NULL); + } +} + +- (void)addTestAccountWithPermissions:(NSSet *)permissions + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler { + NSDictionary *params = @{ + @"installed" : @"true", + @"permissions" : [[permissions allObjects] componentsJoinedByString:@","], + @"access_token" : self.appAccessToken + }; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:kFBGraphAPITestUsersPathFormat, _appID] + parameters:params + tokenString:[self appAccessToken] + version:nil + HTTPMethod:@"POST"]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (error) { + if (handler) { + handler(nil, error); + } + } else { + NSMutableDictionary *accountData = [NSMutableDictionary dictionaryWithCapacity:2]; + accountData[kAccountsDictionaryPermissionsKey] = [NSSet setWithSet:permissions]; + accountData[kAccountsDictionaryTokenKey] = result[@"access_token"]; + _accounts[result[@"id"]] = accountData; + + if (handler) { + FBSDKAccessToken *token = [self tokenDataForTokenString:accountData[kAccountsDictionaryTokenKey] + permissions:permissions + userId:result[@"id"]]; + handler(@[token], nil); + } + } + }]; +} + +- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback +{ + __block int expectedCount = 2; + void (^complete)(NSError *) = ^(NSError *error) { + // ignore if they're already friends or pending request + if ([error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 522 || + [error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 520) { + error = nil; + } + if (--expectedCount == 0 || error) { + callback(error); + } + }; + FBSDKGraphRequest *one = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/friends/%@", first.userID, second.userID] + parameters:nil + tokenString:first.tokenString + version:nil + HTTPMethod:@"POST"]; + FBSDKGraphRequest *two = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/friends/%@", second.userID, first.userID] + parameters:nil + tokenString:second.tokenString + version:nil + HTTPMethod:@"POST"]; + FBSDKGraphRequestConnection *conn = [[FBSDKGraphRequestConnection alloc] init]; + [conn addRequest:one completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + complete(error); + } batchEntryName:@"first"]; + [conn addRequest:two completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + complete(error); + } batchParameters:@{ @"depends_on" : @"first"} ]; + [conn start]; +} + +- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler { + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:userId + parameters:nil + tokenString:self.appAccessToken + version:nil + HTTPMethod:@"DELETE"]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (handler) { + handler(error); + } + }]; +} + +#pragma mark - private methods +- (FBSDKAccessToken *)tokenDataForTokenString:(NSString *)tokenString permissions:(NSSet *)permissions userId:(NSString *)userId{ + return [[FBSDKAccessToken alloc] initWithTokenString:tokenString + permissions:[permissions allObjects] + declinedPermissions:nil + appID:_appID + userID:userId + expirationDate:nil + refreshDate:nil]; +} + +- (NSArray *)userIdAndTokenOfExistingAccountWithPermissions:(NSSet *)permissions skip:(NSSet *)setToSkip { + __block NSString *userId = nil; + __block NSString *token = nil; + + [_accounts enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *accountData, BOOL *stop) { + if ([setToSkip containsObject:key]) { + return; + } + NSSet *accountPermissions = accountData[kAccountsDictionaryPermissionsKey]; + if ([permissions isSubsetOfSet:accountPermissions]) { + token = accountData[kAccountsDictionaryTokenKey]; + userId = key; + *stop = YES; + } + }]; + if (userId && token) { + return @[userId, token]; + } else { + return nil; + } +} + +- (NSString *)appAccessToken { + return [NSString stringWithFormat:@"%@|%@", _appID, _appSecret]; +} + +- (void)fetchExistingTestAccountsWithAfterCursor:(NSString *)after handler:(void(^)(NSError *error))handler { + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + FBSDKGraphRequest *requestForAccountIds = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:kFBGraphAPITestUsersPathFormat, _appID] + parameters:@{@"limit" : @"50", + @"after" : after ?: @"", + @"fields": @"" + } + tokenString:self.appAccessToken + version:nil + HTTPMethod:nil]; + __block NSString *afterCursor = nil; + __block NSInteger expectedTestAccounts = 0; + FBSDKGraphRequestConnection *permissionConnection = [[FBSDKGraphRequestConnection alloc] init]; + [connection addRequest:requestForAccountIds completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + if (error) { + if (handler) { + handler(error); + } + // on errors, clear out accounts since it may be in a bad state + [_accounts removeAllObjects]; + return; + } else { + for (NSDictionary *account in result[@"data"]) { + NSString *userId = account[@"id"]; + NSString *token = account[@"access_token"]; + if (userId && token) { + _accounts[userId] = [NSMutableDictionary dictionaryWithCapacity:2]; + _accounts[userId][kAccountsDictionaryTokenKey] = token; + expectedTestAccounts++; + [permissionConnection addRequest:[[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@?fields=permissions", userId] + parameters:nil + tokenString:self.appAccessToken + version:nil + HTTPMethod:nil] + completionHandler:^(FBSDKGraphRequestConnection *innerConnection2, id innerResult, NSError *innerError) { + if (_accounts.count == 0) { + // indicates an earlier error that was already passed to handler, so just short circuit. + return; + } + if (innerError) { + if (handler) { + handler(innerError); + } + [_accounts removeAllObjects]; + return; + } else { + NSMutableSet *grantedPermissions = [NSMutableSet set]; + NSArray *resultPermissionsDictionaries = innerResult[@"permissions"][@"data"]; + [resultPermissionsDictionaries enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) { + if ([obj[@"status"] isEqualToString:@"granted"]) { + [grantedPermissions addObject:obj[@"permission"]]; + } + }]; + _accounts[userId][kAccountsDictionaryPermissionsKey] = grantedPermissions; + } + expectedTestAccounts--; + if (!expectedTestAccounts) { + if (afterCursor) { + [self fetchExistingTestAccountsWithAfterCursor:afterCursor handler:handler]; + } else if (handler) { + handler(nil); + } + } + } + ]; + } + } + afterCursor = result[@"paging"][@"cursors"][@"after"]; + } + + if (expectedTestAccounts) { + // finished fetching ids and tokens, now kick off the request for all the permissions + [permissionConnection start]; + } else { + if (handler) { + handler(nil); + } + } + }]; + [connection start]; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h new file mode 100644 index 0000000..46c490b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Class to contain common utility methods. + */ +@interface FBSDKUtility : NSObject + +/*! + @abstract Parses a query string into a dictionary. + @param queryString The query string value. + @return A dictionary with the key/value pairs. + */ ++ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString; + +/*! + @abstract Constructs a query string from a dictionary. + @param dictionary The dictionary with key/value pairs for the query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @result Query string representation of the parameters. + */ ++ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Decodes a value from an URL. + @param value The value to decode. + @result The decoded value. + */ ++ (NSString *)URLDecode:(NSString *)value; + +/*! + @abstract Encodes a value for an URL. + @param value The value to encode. + @result The encoded value. + */ ++ (NSString *)URLEncode:(NSString *)value; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.m new file mode 100644 index 0000000..e140d16 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.m @@ -0,0 +1,90 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKUtility.h" + +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" + +@implementation FBSDKUtility + ++ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString +{ + NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; + NSArray *parts = [queryString componentsSeparatedByString:@"&"]; + + for (NSString *part in parts) { + if ([part length] == 0) { + continue; + } + + NSRange index = [part rangeOfString:@"="]; + NSString *key; + NSString *value; + + if (index.location == NSNotFound) { + key = part; + value = @""; + } else { + key = [part substringToIndex:index.location]; + value = [part substringFromIndex:index.location + index.length]; + } + + key = [self URLDecode:key]; + value = [self URLDecode:value]; + if (key && value) { + result[key] = value; + } + } + return result; +} + ++ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef +{ + return [FBSDKInternalUtility queryStringWithDictionary:dictionary error:errorRef invalidObjectHandler:NULL]; +} + ++ (NSString *)URLDecode:(NSString *)value +{ + value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +#pragma clang diagnostic pop + return value; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ++ (NSString *)URLEncode:(NSString *)value +{ + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, + (CFStringRef)value, + NULL, // characters to leave unescaped + CFSTR(":!*();@/&?+$,='"), + kCFStringEncodingUTF8); +} +#pragma clang diagnostic pop + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h new file mode 100644 index 0000000..1781a00 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h @@ -0,0 +1,158 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBSDKAppEventsUtility.h" + +@class FBSDKGraphRequest; + +// Internally known event names + +FBSDK_EXTERN NSString *const FBSDKAppEventNamePurchased; + +/*! Use to log that the share dialog was launched */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetLaunch; + +/*! Use to log that the share dialog was dismissed */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetDismiss; + +/*! Use to log that the permissions UI was launched */ +FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUILaunch; + +/*! Use to log that the permissions UI was dismissed */ +FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUIDismiss; + +/*! Use to log that the login view was used */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameLoginViewUsage; + +// Internally known event parameters + +/*! String parameter specifying the outcome of a dialog invocation */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogOutcome; + +/*! Parameter key used to specify which application launches this application. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterLaunchSource; + +/*! Use to log the result of a call to FBDialogs presentShareDialogWithParams: */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog; + +/*! Use to log the result of a call to FBDialogs presentShareDialogWithOpenGraphActionParams: */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG; + +/*! Use to log the result of a call to FBDialogs presentLikeDialogWithLikeParams: */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG; + +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG; + +/*! Use to log the start of an auth request that cannot be fulfilled by the token cache */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthStart; + +/*! Use to log the end of an auth request that was not fulfilled by the token cache */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthEnd; + +/*! Use to log the start of a specific auth method as part of an auth request */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodStart; + +/*! Use to log the end of the last tried auth method as part of an auth request */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd; + +/*! Use to log the timestamp for the transition to the Facebook native login dialog */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart; + +/*! Use to log the timestamp for the transition back to the app after the Facebook native login dialog */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd; + +/*! Use to log the e2e timestamp metrics for web login */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted; + +/*! Use to log the results of a share dialog */ +FBSDK_EXTERN NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult; + +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow; + +FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogMode; +FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogShareContentType; + +// Internally known event parameter values + +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Completed; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Failed; + +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeStatus; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypePhoto; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeVideo; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeUnknown; + + +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeAutomatic; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeBrowser; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeNative; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeShareSheet; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeWeb; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedBrowser; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedWeb; +FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeUnknown; + +FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogStartTime; +FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogEndTime; + +FBSDK_EXTERN NSString *const FBSDKAppEventsWebLoginE2E; + +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonImpression; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonImpression; + +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap; + +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlError; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlImpression; +FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable; + +FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogErrorMessage; + +@interface FBSDKAppEvents (Internal) + ++ (void)logImplicitEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken; + ++ (FBSDKAppEvents *)singleton; +- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h new file mode 100644 index 0000000..2de04b8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKAppEventsDeviceInfo : NSObject + ++ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.m new file mode 100644 index 0000000..152d01d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.m @@ -0,0 +1,252 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppEventsDeviceInfo.h" + +#import +#import + +#import +#import +#import +#import + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKUtility.h" + +#define FB_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0]) + +static const u_int FB_GROUP1_RECHECK_DURATION = 30 * 60; // seconds + +// Apple reports storage in binary gigabytes (1024^3) in their About menus, etc. +static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes + +@implementation FBSDKAppEventsDeviceInfo + +// Ephemeral data, may change during the lifetime of an app. We collect them in different +// 'group' frequencies - group1 may gets collected once every 30 minutes. + +// group1 +NSString *_carrierName; +NSString *_timeZoneAbbrev; +unsigned long long _remainingDiskSpaceGB; + +// Persistent data, but we maintain it to make rebuilding the device info as fast as possible. +NSString *_bundleIdentifier; +NSString *_longVersion; +NSString *_shortVersion; +NSString *_sysVersion; +NSString *_machine; +NSString *_language; +unsigned long long _totalDiskSpaceGB; +unsigned long long _coreCount; +CGFloat _width; +CGFloat _height; +CGFloat _density; + +// Other state +long _lastGroup1CheckTime; +BOOL _isEncodingDirty = YES; +NSString *_encodedDeviceInfo; +static FBSDKAppEventsDeviceInfo *g_singleton; + +#pragma mark - Public Methods + ++ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary +{ + dictionary[@"extinfo"] = [g_singleton encodedDeviceInfo]; +} + +#pragma mark - Internal Methods + ++ (void)initialize +{ + if (self == [FBSDKAppEventsDeviceInfo class]) { + g_singleton = [[FBSDKAppEventsDeviceInfo alloc] init]; + [g_singleton _collectPersistentData]; + } +} + +- (NSString *)encodedDeviceInfo +{ + @synchronized (self) { + + BOOL isGroup1Expired = [self _isGroup1Expired]; + BOOL isEncodingExpired = isGroup1Expired; // Can || other groups in if we add them + + // As long as group1 hasn't expired, we can just return the last generated value + if (_encodedDeviceInfo && !isEncodingExpired) { + return _encodedDeviceInfo; + } + + if (isGroup1Expired) { + [self _collectGroup1Data]; + } + + if (_isEncodingDirty) { + self.encodedDeviceInfo = [self _generateEncoding]; + _isEncodingDirty = NO; + } + + return _encodedDeviceInfo; + } +} + +- (void)setEncodedDeviceInfo:(NSString *)encodedDeviceInfo +{ + @synchronized (self) { + if (![_encodedDeviceInfo isEqualToString:encodedDeviceInfo]) { + _encodedDeviceInfo = [encodedDeviceInfo copy]; + } + } +} + +// This data need only be collected once. +- (void)_collectPersistentData +{ + // Bundle stuff + NSBundle *mainBundle = [NSBundle mainBundle]; + _bundleIdentifier = mainBundle.bundleIdentifier; + _longVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + _shortVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + + // Locale stuff + _language = [[NSLocale currentLocale] localeIdentifier]; + + // Device stuff + UIDevice *device = [UIDevice currentDevice]; + _sysVersion = device.systemVersion; + _coreCount = [FBSDKAppEventsDeviceInfo _coreCount]; + + UIScreen *sc = [UIScreen mainScreen]; + CGRect sr = sc.bounds; + _width = sr.size.width; + _height = sr.size.height; + _density = sc.scale; + + struct utsname systemInfo; + uname(&systemInfo); + _machine = @(systemInfo.machine); + + // Disk space stuff + float totalDiskSpace = [[FBSDKAppEventsDeviceInfo _getTotalDiskSpace] floatValue]; + _totalDiskSpaceGB = (unsigned long long)round(totalDiskSpace / FB_GIGABYTE); +} + +- (BOOL)_isGroup1Expired +{ + return ([FBSDKAppEventsUtility unixTimeNow] - _lastGroup1CheckTime) > FB_GROUP1_RECHECK_DURATION; +} + +// This data is collected only once every GROUP1_RECHECK_DURATION. +- (void)_collectGroup1Data +{ + // Carrier + NSString *newCarrierName = [FBSDKAppEventsDeviceInfo _getCarrier]; + if (![newCarrierName isEqualToString:_carrierName]) { + _carrierName = newCarrierName; + _isEncodingDirty = YES; + } + + // Time zone + NSString *newTimeZoneAbbrev = [[NSTimeZone systemTimeZone] abbreviation]; + if (![newTimeZoneAbbrev isEqualToString:_timeZoneAbbrev]) { + _timeZoneAbbrev = newTimeZoneAbbrev; + _isEncodingDirty = YES; + } + + // Remaining disk space + float remainingDiskSpace = [[FBSDKAppEventsDeviceInfo _getRemainingDiskSpace] floatValue]; + unsigned long long newRemainingDiskSpaceGB = (unsigned long long)round(remainingDiskSpace / FB_GIGABYTE); + if (_remainingDiskSpaceGB != newRemainingDiskSpaceGB) { + _remainingDiskSpaceGB = newRemainingDiskSpaceGB; + _isEncodingDirty = YES; + } + + _lastGroup1CheckTime = [FBSDKAppEventsUtility unixTimeNow]; +} + +- (NSString *)_generateEncoding +{ + // Keep a bit of precision on density as it's the most likely to become non-integer. + NSString *densityString = _density ? [NSString stringWithFormat:@"%.02f", _density] : @""; + + NSArray *arr = @[ + @"i2", // version - starts with 'i' for iOS, we'll use 'a' for Android + _bundleIdentifier ?: @"", + _longVersion ?: @"", + _shortVersion ?: @"", + _sysVersion ?: @"", + _machine ?: @"", + _language ?: @"", + _timeZoneAbbrev ?: @"", + _carrierName ?: @"", + _width ? @((unsigned long)_width) : @"", + _height ? @((unsigned long)_height) : @"", + densityString, + @(_coreCount) ?: @"", + @(_totalDiskSpaceGB) ?: @"", + @(_remainingDiskSpaceGB) ?: @"", + ]; + + return [FBSDKInternalUtility JSONStringForObject:arr error:NULL invalidObjectHandler:NULL]; +} + +#pragma mark - Helper Methods + ++ (NSNumber *)_getTotalDiskSpace +{ + NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory() + error:nil]; + return [attrs objectForKey:NSFileSystemSize]; +} + ++ (NSNumber *)_getRemainingDiskSpace +{ + NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory() + error:nil]; + return [attrs objectForKey:NSFileSystemFreeSize]; +} + ++ (uint)_coreCount +{ + return [FBSDKAppEventsDeviceInfo _readSysCtlUInt:CTL_HW type:HW_AVAILCPU]; +} + ++ (uint)_readSysCtlUInt:(int)ctl type:(int)type +{ + int mib[2] = {ctl, type}; + uint value; + size_t size = sizeof value; + if (0 != sysctl(mib, FB_ARRAY_COUNT(mib), &value, &size, NULL, 0)) { + return 0; + } + return value; +} + ++ (NSString *)_getCarrier +{ + // Dynamically load class for this so calling app doesn't need to link framework in. + CTTelephonyNetworkInfo *networkInfo = [[fbsdkdfl_CTTelephonyNetworkInfoClass() alloc] init]; + CTCarrier *carrier = [networkInfo subscriberCellularProvider]; + return [carrier carrierName] ?: @"NoCarrier"; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h new file mode 100644 index 0000000..af45788 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h @@ -0,0 +1,38 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +// this type is not thread safe. +@interface FBSDKAppEventsState : NSObject + +@property (readonly, copy) NSArray *events; +@property (readonly, assign) NSUInteger numSkipped; +@property (readonly, copy) NSString *tokenString; +@property (readonly, copy) NSString *appID; + +- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID NS_DESIGNATED_INITIALIZER; + +- (void)addEvent:(NSDictionary *)eventDictionary isImplicit:(BOOL)isImplicit; +- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState; +- (BOOL)areAllEventsImplicit; +- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState; +- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID; +- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.m new file mode 100644 index 0000000..3498e50 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.m @@ -0,0 +1,161 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppEventsState.h" + +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" + +#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit" + +#define FBSDK_APPEVENTSSTATE_MAX_EVENTS 1000 + +#define FBSDK_APPEVENTSSTATE_APPID_KEY @"appID" +#define FBSDK_APPEVENTSSTATE_EVENTS_KEY @"events" +#define FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY @"numSkipped" +#define FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY @"tokenString" + +@implementation FBSDKAppEventsState +{ + NSMutableArray *_mutableEvents; + BOOL _containsExplicitEvent; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithToken:appID:); + return [self initWithToken:nil appID:nil]; +} + +- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID +{ + if ((self = [super init])) { + _tokenString = [tokenString copy]; + _appID = [appID copy]; + _mutableEvents = [NSMutableArray array]; + } + return self; +} + +- (instancetype)copyWithZone:(NSZone *)zone +{ + FBSDKAppEventsState *copy = [[FBSDKAppEventsState allocWithZone:zone] initWithToken:_tokenString appID:_appID]; + if (copy) { + [copy->_mutableEvents addObjectsFromArray:_mutableEvents]; + copy->_numSkipped = _numSkipped; + copy->_containsExplicitEvent = _containsExplicitEvent; + } + return copy; +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_APPID_KEY]; + NSString *tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY]; + NSArray *events = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY]; + NSUInteger numSkipped = [[decoder decodeObjectOfClass:[NSNumber class] forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY] unsignedIntegerValue]; + + if ((self = [self initWithToken:tokenString appID:appID])) { + _mutableEvents = [NSMutableArray arrayWithArray:events]; + _numSkipped = numSkipped; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_appID forKey:FBSDK_APPEVENTSSTATE_APPID_KEY]; + [encoder encodeObject:_tokenString forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY]; + [encoder encodeObject:@(_numSkipped) forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY]; + [encoder encodeObject:_mutableEvents forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY]; +} + +#pragma mark - Implementation + +- (NSArray *)events +{ + return [_mutableEvents copy]; +} + +- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState +{ + NSArray *toAdd = appEventsState->_mutableEvents; + NSInteger excess = _mutableEvents.count + toAdd.count - FBSDK_APPEVENTSSTATE_MAX_EVENTS; + if (excess > 0) { + NSInteger range = FBSDK_APPEVENTSSTATE_MAX_EVENTS - _mutableEvents.count; + toAdd = [toAdd subarrayWithRange:NSMakeRange(0, range)]; + _numSkipped += excess; + } + + [_mutableEvents addObjectsFromArray:toAdd]; +} + +- (void)addEvent:(NSDictionary *)eventDictionary + isImplicit:(BOOL)isImplicit { + if (_mutableEvents.count >= FBSDK_APPEVENTSSTATE_MAX_EVENTS) { + _numSkipped++; + } else { + if (!isImplicit) { + _containsExplicitEvent = YES; + } + [_mutableEvents addObject:@{ + @"event" : eventDictionary, + FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY : @(isImplicit) + }]; + } +} + +- (BOOL)areAllEventsImplicit +{ + return !_containsExplicitEvent; +} + +- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState +{ + return ([self isCompatibleWithTokenString:appEventsState.tokenString appID:appEventsState.appID]); +} + +- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID +{ + // token strings can be nil (e.g., no user token) but appIDs should not. + BOOL tokenCompatible = ([self.tokenString isEqualToString:tokenString] || + (self.tokenString == nil && tokenString == nil)); + return (tokenCompatible && + [self.appID isEqualToString:appID]); +} + +- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents +{ + NSMutableArray *events = [[NSMutableArray alloc] initWithCapacity:_mutableEvents.count]; + for (NSDictionary *eventAndImplicitFlag in _mutableEvents) { + if (!includeImplicitEvents && [eventAndImplicitFlag[FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) { + continue; + } + [events addObject:eventAndImplicitFlag[@"event"]]; + } + + return [FBSDKInternalUtility JSONStringForObject:events error:NULL invalidObjectHandler:NULL]; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h new file mode 100644 index 0000000..4c17a4c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h @@ -0,0 +1,34 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAppEventsState; + +@interface FBSDKAppEventsStateManager : NSObject + ++ (void)clearPersistedAppEventsStates; + +// reads all saved event states, appends the param, and writes them all. ++ (void)persistAppEventsData:(FBSDKAppEventsState *)appEventsState; + +// returns the array of saved app event states and deletes them. ++ (NSArray *)retrievePersistedAppEventsStates; + + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.m new file mode 100644 index 0000000..596d7a6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.m @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppEventsStateManager.h" + +#import + +#import "FBSDKAppEventsState.h" +#import "FBSDKAppEventsUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + +// A quick optimization to allow returning empty array if we know there are no persisted events. +static BOOL g_canSkipDiskCheck = NO; + +@implementation FBSDKAppEventsStateManager + ++ (void)clearPersistedAppEventsStates +{ + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + logEntry:@"FBSDKAppEvents Persist: Clearing"]; + [[NSFileManager defaultManager] removeItemAtPath:[[self class] filePath] + error:NULL]; + g_canSkipDiskCheck = YES; +} + ++ (void)persistAppEventsData:(FBSDKAppEventsState *)appEventsState +{ + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKAppEvents Persist: Writing %lu events", (unsigned long)appEventsState.events.count]; + + if (!appEventsState.events.count) { + return; + } + NSMutableArray *existingEvents = [NSMutableArray arrayWithArray:[[self class] retrievePersistedAppEventsStates]]; + [existingEvents addObject:appEventsState]; + + [NSKeyedArchiver archiveRootObject:existingEvents toFile:[[self class] filePath]]; + g_canSkipDiskCheck = NO; +} + ++ (NSArray *)retrievePersistedAppEventsStates +{ + NSMutableArray *eventsStates = [NSMutableArray array]; + if (!g_canSkipDiskCheck) { + [eventsStates addObjectsFromArray:[NSKeyedUnarchiver unarchiveObjectWithFile:[[self class] filePath]]]; + + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKAppEvents Persist: Read %lu event states. First state has %lu events", + (unsigned long)eventsStates.count, + (unsigned long)(eventsStates.count > 0 ? ((FBSDKAppEventsState *)eventsStates[0]).events.count : 0)]; + [[self class] clearPersistedAppEventsStates]; + } + return eventsStates; +} + +#pragma mark - Private Helpers + ++ (NSString *)filePath +{ + return [FBSDKAppEventsUtility persistenceFilePath:@"com-facebook-sdk-AppEventsPersistedEvents.json"]; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h new file mode 100644 index 0000000..7503217 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h @@ -0,0 +1,57 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +typedef NS_ENUM(NSUInteger, FBSDKAdvertisingTrackingStatus) +{ + FBSDKAdvertisingTrackingAllowed, + FBSDKAdvertisingTrackingDisallowed, + FBSDKAdvertisingTrackingUnspecified +}; + +typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason) +{ + FBSDKAppEventsFlushReasonExplicit, + FBSDKAppEventsFlushReasonTimer, + FBSDKAppEventsFlushReasonSessionChange, + FBSDKAppEventsFlushReasonPersistedEvents, + FBSDKAppEventsFlushReasonEventThreshold, + FBSDKAppEventsFlushReasonEagerlyFlushingEvent +}; + +@interface FBSDKAppEventsUtility : NSObject + ++ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory + implicitEventsOnly:(BOOL)implicitEventsOnly + shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID; ++ (NSString *)advertiserID; ++ (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus; ++ (NSString *)attributionID; ++ (void)ensureOnMainThread; ++ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason; ++ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError; ++ (void)logAndNotify:(NSString *)msg; ++ (NSString *)persistenceFilePath:(NSString *)filename; ++ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token; ++ (long)unixTimeNow; ++ (BOOL)validateIdentifier:(NSString *)identifier; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.m new file mode 100644 index 0000000..07562e1 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.m @@ -0,0 +1,305 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppEventsUtility.h" + +#import + +#import "FBSDKAccessToken.h" +#import "FBSDKAppEvents.h" +#import "FBSDKAppEventsDeviceInfo.h" +#import "FBSDKConstants.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" +#import "FBSDKTimeSpentData.h" + +#define FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME @"com-facebook-sdk-PersistedAnonymousID.json" +#define FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY @"anon_id" +#define FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH 40 + +@implementation FBSDKAppEventsUtility + ++ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory + implicitEventsOnly:(BOOL)implicitEventsOnly + shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + parameters[@"event"] = eventCategory; + + NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below. + [FBSDKInternalUtility dictionary:parameters setObject:attributionID forKey:@"attribution"]; + + if (!implicitEventsOnly && shouldAccessAdvertisingID) { + NSString *advertiserID = [[self class] advertiserID]; + [FBSDKInternalUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"]; + } + + parameters[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY] = [self anonymousID]; + + FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus]; + if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) { + BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed); + parameters[@"advertiser_tracking_enabled"] = [@(allowed) stringValue]; + } + + parameters[@"application_tracking_enabled"] = [@(!FBSDKSettings.limitEventAndDataUsage) stringValue]; + + [FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters]; + + static dispatch_once_t fetchBundleOnce; + static NSMutableArray *urlSchemes; + + dispatch_once(&fetchBundleOnce, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + urlSchemes = [[NSMutableArray alloc] init]; + for (NSDictionary *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) { + NSArray *schemesForType = [fields objectForKey:@"CFBundleURLSchemes"]; + if (schemesForType) { + [urlSchemes addObjectsFromArray:schemesForType]; + } + } + }); + + if (urlSchemes.count > 0) { + [parameters setObject:[FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL] + forKey:@"url_schemes"]; + } + + return parameters; +} + ++ (NSString *)advertiserID +{ + NSString *result = nil; + + Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass(); + if ([ASIdentifierManagerClass class]) { + ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager]; + result = [[manager advertisingIdentifier] UUIDString]; + } + + return result; +} + ++ (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus +{ + static dispatch_once_t fetchAdvertisingTrackingStatusOnce; + static FBSDKAdvertisingTrackingStatus status; + + dispatch_once(&fetchAdvertisingTrackingStatusOnce, ^{ + status = FBSDKAdvertisingTrackingUnspecified; + Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass(); + if ([ASIdentifierManagerClass class]) { + ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager]; + if (manager) { + status = [manager isAdvertisingTrackingEnabled] ? FBSDKAdvertisingTrackingAllowed : FBSDKAdvertisingTrackingDisallowed; + } + } + }); + + return status; +} + ++ (NSString *)anonymousID +{ + // Grab previously written anonymous ID and, if none have been generated, create and + // persist a new one which will remain associated with this app. + NSString *result = [[self class] retrievePersistedAnonymousID]; + if (!result) { + // Generate a new anonymous ID. Create as a UUID, but then prepend the fairly + // arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which + // will only contain hex. + result = [NSString stringWithFormat:@"XZ%@", [[NSUUID UUID] UUIDString]]; + + [self persistAnonymousID:result]; + } + return result; +} + ++ (NSString *)attributionID +{ + return [[UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO] string]; +} + +// for tests only. ++ (void)clearLibraryFiles +{ + [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME] + error:NULL]; + [[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDKTimeSpentFilename] + error:NULL]; +} + ++ (void)ensureOnMainThread +{ + FBSDKConditionalLog([NSThread isMainThread], FBSDKLoggingBehaviorInformational, @"*** This method expected to be called on the main thread."); +} + ++ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason +{ + NSString *result = @"Unknown"; + switch (flushReason) { + case FBSDKAppEventsFlushReasonExplicit: + result = @"Explicit"; + break; + case FBSDKAppEventsFlushReasonTimer: + result = @"Timer"; + break; + case FBSDKAppEventsFlushReasonSessionChange: + result = @"SessionChange"; + break; + case FBSDKAppEventsFlushReasonPersistedEvents: + result = @"PersistedEvents"; + break; + case FBSDKAppEventsFlushReasonEventThreshold: + result = @"EventCountThreshold"; + break; + case FBSDKAppEventsFlushReasonEagerlyFlushingEvent: + result = @"EagerlyFlushingEvent"; + break; + } + return result; +} + ++ (void)logAndNotify:(NSString *)msg +{ + [[self class] logAndNotify:msg allowLogAsDeveloperError:YES]; +} + ++ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError +{ + NSString *behaviorToLog = FBSDKLoggingBehaviorAppEvents; + if (allowLogAsDeveloperError) { + if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorDeveloperErrors]) { + // Rather than log twice, prefer 'DeveloperErrors' if it's set over AppEvents. + behaviorToLog = FBSDKLoggingBehaviorDeveloperErrors; + } + } + + [FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg]; + NSError *error = [FBSDKError errorWithCode:FBSDKAppEventsFlushErrorCode message:msg]; + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error]; +} + ++ (BOOL)regexValidateIdentifier:(NSString *)identifier +{ + static NSRegularExpression *regex; + static dispatch_once_t onceToken; + static NSMutableSet *cachedIdentifiers; + dispatch_once(&onceToken, ^{ + NSString *regexString = @"^[0-9a-zA-Z_]+[0-9a-zA-Z _-]*$"; + regex = [NSRegularExpression regularExpressionWithPattern:regexString + options:0 + error:NULL]; + cachedIdentifiers = [[NSMutableSet alloc] init]; + }); + + @synchronized(self) { + if (![cachedIdentifiers containsObject:identifier]) { + NSUInteger numMatches = [regex numberOfMatchesInString:identifier options:0 range:NSMakeRange(0, identifier.length)]; + if (numMatches > 0) { + [cachedIdentifiers addObject:identifier]; + } else { + return NO; + } + } + } + + return YES; +} + ++ (BOOL)validateIdentifier:(NSString *)identifier +{ + if (identifier == nil || identifier.length == 0 || identifier.length > FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH || ![[self class] regexValidateIdentifier:identifier]) { + [[self class] logAndNotify:[NSString stringWithFormat:@"Invalid identifier: '%@'. Must be between 1 and %d characters, and must be contain only alphanumerics, _, - or spaces, starting with alphanumeric or _.", + identifier, FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH]]; + return NO; + } + + return YES; +} + ++ (void)persistAnonymousID:(NSString *)anonymousID +{ + [[self class] ensureOnMainThread]; + NSDictionary *data = @{ FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY : anonymousID }; + NSString *content = [FBSDKInternalUtility JSONStringForObject:data error:NULL invalidObjectHandler:NULL]; + + [content writeToFile:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME] + atomically:YES + encoding:NSASCIIStringEncoding + error:nil]; +} + ++ (NSString *)persistenceFilePath:(NSString *)filename +{ + NSSearchPathDirectory directory = NSLibraryDirectory; + NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES); + NSString *docDirectory = [paths objectAtIndex:0]; + return [docDirectory stringByAppendingPathComponent:filename]; +} + ++ (NSString *)retrievePersistedAnonymousID +{ + [[self class] ensureOnMainThread]; + NSString *file = [[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]; + NSString *content = [[NSString alloc] initWithContentsOfFile:file + encoding:NSASCIIStringEncoding + error:nil]; + NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL]; + return [results objectForKey:FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY]; +} + +// Given a candidate token (which may be nil), find the real token to string to use. +// Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session. ++ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token +{ + if (!token) { + token = [FBSDKAccessToken currentAccessToken]; + } + + NSString *appID = [FBSDKAppEvents loggingOverrideAppID] ?: token.appID ?: [FBSDKSettings appID]; + NSString *tokenString = token.tokenString; + if (!tokenString || ![appID isEqualToString:token.appID]) { + // If there's an logging override app id present, then we don't want to use the client token since the client token + // is intended to match up with the primary app id (and AppEvents doesn't require a client token). + NSString *clientTokenString = [FBSDKSettings clientToken]; + if (clientTokenString && appID && [appID isEqualToString:token.appID]){ + tokenString = [NSString stringWithFormat:@"%@|%@", appID, clientTokenString]; + } else if (appID) { + tokenString = nil; + } + } + return tokenString; +} + ++ (long)unixTimeNow +{ + return (long)round([[NSDate date] timeIntervalSince1970]); +} + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.h new file mode 100644 index 0000000..a5f7a77 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +// Class to encapsulate implicit logging of purchase events +@interface FBSDKPaymentObserver : NSObject ++ (void)startObservingTransactions; ++ (void)stopObservingTransactions; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.m new file mode 100644 index 0000000..73ef436 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.m @@ -0,0 +1,281 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKPaymentObserver.h" + +#import + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + +static NSString *const FBSDKAppEventParameterImplicitlyLoggedPurchase = @"_implicitlyLoggedPurchaseEvent"; +static NSString *const FBSDKAppEventNamePurchaseFailed = @"fb_mobile_purchase_failed"; +static NSString *const FBSDKAppEventParameterNameProductTitle = @"fb_content_title"; +static NSString *const FBSDKAppEventParameterNameTransactionID = @"fb_transaction_id"; +static int const FBSDKMaxParameterValueLength = 100; +static NSMutableArray *g_pendingRequestors; + +@interface FBSDKPaymentProductRequestor : NSObject + +@property (nonatomic, retain) SKPaymentTransaction *transaction; + +- (instancetype)initWithTransaction:(SKPaymentTransaction*)transaction; +- (void)resolveProducts; + +@end + +@interface FBSDKPaymentObserver() +@end + +@implementation FBSDKPaymentObserver +{ + BOOL _observingTransactions; +} + ++ (void)startObservingTransactions +{ + [[self singleton] startObservingTransactions]; +} + ++ (void)stopObservingTransactions +{ + [[self singleton] stopObservingTransactions]; +} + +// +// Internal methods +// + ++ (FBSDKPaymentObserver *)singleton +{ + static dispatch_once_t pred; + static FBSDKPaymentObserver *shared = nil; + + dispatch_once(&pred, ^{ + shared = [[FBSDKPaymentObserver alloc] init]; + }); + return shared; +} + +- (instancetype) init +{ + self = [super init]; + if (self) { + _observingTransactions = NO; + } + return self; +} + +- (void)startObservingTransactions +{ + @synchronized (self) { + if (!_observingTransactions) { + [(SKPaymentQueue *)[fbsdkdfl_SKPaymentQueueClass() defaultQueue] addTransactionObserver:self]; + _observingTransactions = YES; + } + } +} + +- (void)stopObservingTransactions +{ + @synchronized (self) { + if (_observingTransactions) { + [(SKPaymentQueue *)[fbsdkdfl_SKPaymentQueueClass() defaultQueue] removeTransactionObserver:self]; + _observingTransactions = NO; + } + } +} + +- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions +{ + for (SKPaymentTransaction *transaction in transactions) { + switch (transaction.transactionState) { + case SKPaymentTransactionStatePurchasing: + case SKPaymentTransactionStatePurchased: + case SKPaymentTransactionStateFailed: + [self handleTransaction:transaction]; + break; + case SKPaymentTransactionStateDeferred: + case SKPaymentTransactionStateRestored: + break; + } + } +} + +- (void)handleTransaction:(SKPaymentTransaction *)transaction +{ + FBSDKPaymentProductRequestor *productRequest = [[FBSDKPaymentProductRequestor alloc] initWithTransaction:transaction]; + [productRequest resolveProducts]; +} + +@end + +@interface FBSDKPaymentProductRequestor() +@property (nonatomic, retain) SKProductsRequest *productRequest; +@end + +@implementation FBSDKPaymentProductRequestor + ++ (void)initialize +{ + if ([self class] == [FBSDKPaymentProductRequestor class]) { + g_pendingRequestors = [[NSMutableArray alloc] init]; + } +} + +- (instancetype)initWithTransaction:(SKPaymentTransaction*)transaction +{ + self = [super init]; + if (self) { + _transaction = transaction; + } + return self; +} + +- (void)setProductRequest:(SKProductsRequest *)productRequest +{ + if (productRequest != _productRequest) { + if (_productRequest) { + _productRequest.delegate = nil; + } + _productRequest = productRequest; + } +} + +- (void)resolveProducts +{ + NSString *productId = self.transaction.payment.productIdentifier; + NSSet *productIdentifiers = [NSSet setWithObjects:productId, nil]; + self.productRequest = [[fbsdkdfl_SKProductsRequestClass() alloc] initWithProductIdentifiers:productIdentifiers]; + self.productRequest.delegate = self; + @synchronized(g_pendingRequestors) { + [g_pendingRequestors addObject:self]; + } + [self.productRequest start]; +} + +- (NSString *)getTruncatedString:(NSString *)inputString +{ + if (!inputString) { + return @""; + } + + return [inputString length] <= FBSDKMaxParameterValueLength ? inputString : [inputString substringToIndex:FBSDKMaxParameterValueLength]; +} + +- (void)logTransactionEvent:(SKProduct *)product +{ + NSString *eventName = nil; + NSString *transactionID = nil; + switch (self.transaction.transactionState) { + case SKPaymentTransactionStatePurchasing: + eventName = FBSDKAppEventNameInitiatedCheckout; + break; + case SKPaymentTransactionStatePurchased: + eventName = FBSDKAppEventNamePurchased; + transactionID = self.transaction.transactionIdentifier; + break; + case SKPaymentTransactionStateFailed: + eventName = FBSDKAppEventNamePurchaseFailed; + break; + case SKPaymentTransactionStateDeferred: + case SKPaymentTransactionStateRestored: + return; + } + if (!eventName) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKPaymentObserver logTransactionEvent: event name cannot be nil"]; + return; + } + + SKPayment *payment = self.transaction.payment; + NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary: @{ + FBSDKAppEventParameterNameContentID: payment.productIdentifier ?: @"", + FBSDKAppEventParameterNameNumItems: @(payment.quantity), + }]; + double totalAmount = 0; + if (product) { + totalAmount = payment.quantity * product.price.doubleValue; + [eventParameters addEntriesFromDictionary: @{ + FBSDKAppEventParameterNameCurrency: [product.priceLocale objectForKey:NSLocaleCurrencyCode], + FBSDKAppEventParameterNameNumItems: @(payment.quantity), + FBSDKAppEventParameterNameProductTitle: [self getTruncatedString:product.localizedTitle], + FBSDKAppEventParameterNameDescription: [self getTruncatedString:product.localizedDescription], + }]; + if (transactionID) { + [eventParameters setObject:transactionID forKey:FBSDKAppEventParameterNameTransactionID]; + } + } + + [self logImplicitPurchaseEvent:eventName + valueToSum:totalAmount + parameters:eventParameters]; +} + +- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response +{ + NSArray* products = response.products; + NSArray* invalidProductIdentifiers = response.invalidProductIdentifiers; + if (products.count + invalidProductIdentifiers.count != 1) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKPaymentObserver: Expect to resolve one product per request"]; + } + SKProduct *product = nil; + if (products.count) { + product = products[0]; + } + [self logTransactionEvent:product]; +} + +- (void)requestDidFinish:(SKRequest *)request +{ + [self cleanUp]; +} + +- (void)request:(SKRequest *)request didFailWithError:(NSError *)error +{ + [self logTransactionEvent:nil]; + [self cleanUp]; +} + +- (void)cleanUp +{ + @synchronized(g_pendingRequestors) { + [g_pendingRequestors removeObject:self]; + } +} + +- (void)logImplicitPurchaseEvent:(NSString *)eventName + valueToSum:(double)valueToSum + parameters:(NSDictionary *)parameters { + NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:parameters]; + [eventParameters setObject:@"1" forKey:FBSDKAppEventParameterImplicitlyLoggedPurchase]; + [FBSDKAppEvents logEvent:eventName + valueToSum:valueToSum + parameters:parameters]; + + // Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events + // are relatively rare and relatively high value and worth getting across on wire right away. + if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) { + [[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.h new file mode 100644 index 0000000..12f2f3a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +FBSDK_EXTERN NSString *const FBSDKTimeSpentFilename; + +// Class to encapsulate persisting of time spent data collected by [FBSDKAppEvents activateApp]. The activate app App Event is +// logged when restore: is called with sufficient time since the last deactivation. +@interface FBSDKTimeSpentData : NSObject + ++ (void)suspend; ++ (void)restore:(BOOL)calledFromActivateApp; + ++ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url; ++ (void)setSourceApplication:(NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink; ++ (void)registerAutoResetSourceApplication; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.m new file mode 100644 index 0000000..cfa33c2 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.m @@ -0,0 +1,305 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKTimeSpentData.h" + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKAppEventsUtility.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + + +// Filename and keys for session length +NSString *const FBSDKTimeSpentFilename = @"com-facebook-sdk-AppEventsTimeSpent.json"; +static NSString *const FBSDKTimeSpentPersistKeySessionSecondsSpent = @"secondsSpentInCurrentSession"; +static NSString *const FBSDKTimeSpentPersistKeySessionNumInterruptions = @"numInterruptions"; +static NSString *const FBSDKTimeSpentPersistKeyLastSuspendTime = @"lastSuspendTime"; + +static NSString *const FBSDKAppEventNameActivatedApp = @"fb_mobile_activate_app"; +static NSString *const FBSDKAppEventNameDeactivatedApp = @"fb_mobile_deactivate_app"; +static NSString *const FBSDKAppEventParameterNameSessionInterruptions = @"fb_mobile_app_interruptions"; +static NSString *const FBSDKAppEventParameterNameTimeBetweenSessions = @"fb_mobile_time_between_sessions"; + +static const int NUM_SECONDS_IDLE_TO_BE_NEW_SESSION = 60; +static const int SECS_PER_MIN = 60; +static const int SECS_PER_HOUR = 60 * SECS_PER_MIN; +static const int SECS_PER_DAY = 24 * SECS_PER_HOUR; + +static NSString *g_sourceApplication; +static BOOL g_isOpenedFromAppLink; + +// Will be translated and displayed in App Insights. Need to maintain same number and value of quanta on the server. +static const long INACTIVE_SECONDS_QUANTA[] = +{ + 5 * SECS_PER_MIN, + 15 * SECS_PER_MIN, + 30 * SECS_PER_MIN, + 1 * SECS_PER_HOUR, + 6 * SECS_PER_HOUR, + 12 * SECS_PER_HOUR, + 1 * SECS_PER_DAY, + 2 * SECS_PER_DAY, + 3 * SECS_PER_DAY, + 7 * SECS_PER_DAY, + 14 * SECS_PER_DAY, + 21 * SECS_PER_DAY, + 28 * SECS_PER_DAY, + 60 * SECS_PER_DAY, + 90 * SECS_PER_DAY, + 120 * SECS_PER_DAY, + 150 * SECS_PER_DAY, + 180 * SECS_PER_DAY, + 365 * SECS_PER_DAY, + LONG_MAX, // keep as LONG_MAX to guarantee loop will terminate +}; + +/** + * This class encapsulates the notion of an app 'session' - the length of time that the user has + * spent in the app that can be considered a single usage of the app. Apps may be frequently interrupted + * do to other device activity, like a text message, so this class allows those interruptions to be smoothed + * out and the time actually spent in the app excluding this interruption time to be accumulated. Also, + * once a certain amount of time has gone by where the app is not in the foreground, we consider the + * session to be complete, and a new session beginning. When this occurs, we log an 'activate app' event + * with the duration of the previous session as the 'value' of this event, along with the number of + * interruptions from that previous session as an event parameter. + */ +@interface FBSDKTimeSpentData() + +@property (nonatomic) NSInteger numSecondsIdleToBeNewSession; + +@end + +@implementation FBSDKTimeSpentData +{ + BOOL _isCurrentlyLoaded; + BOOL _shouldLogActivateEvent; + BOOL _shouldLogDeactivateEvent; + long _secondsSpentInCurrentSession; + long _timeSinceLastSuspend; + int _numInterruptionsInCurrentSession; + long _lastRestoreTime; +} + +// +// Public methods +// + ++ (void)suspend +{ + [self.singleton instanceSuspend]; +} + ++ (void)restore:(BOOL)calledFromActivateApp +{ + [self.singleton instanceRestore:calledFromActivateApp]; +} + +// +// Internal methods +// + +- (instancetype)init +{ + if ((self = [super init])) { + _numSecondsIdleToBeNewSession = NUM_SECONDS_IDLE_TO_BE_NEW_SESSION; + } + return self; +} + ++ (FBSDKTimeSpentData *)singleton +{ + static dispatch_once_t pred; + static FBSDKTimeSpentData *shared = nil; + + dispatch_once(&pred, ^{ + shared = [[FBSDKTimeSpentData alloc] init]; + }); + return shared; +} + +// Calculate and persist time spent data for this instance of the app activation. +- (void)instanceSuspend +{ + + [FBSDKAppEventsUtility ensureOnMainThread]; + if (!_isCurrentlyLoaded) { + FBSDKConditionalLog(YES, FBSDKLoggingBehaviorInformational, @"[FBSDKTimeSpentData suspend] invoked without corresponding restore"); + return; + } + + long now = [FBSDKAppEventsUtility unixTimeNow]; + long timeSinceRestore = now - _lastRestoreTime; + + // Can happen if the clock on the device is changed + if (timeSinceRestore < 0) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"Clock skew detected"]; + timeSinceRestore = 0; + } + + _secondsSpentInCurrentSession += timeSinceRestore; + + NSDictionary *timeSpentData = + @{ + FBSDKTimeSpentPersistKeySessionSecondsSpent : @(_secondsSpentInCurrentSession), + FBSDKTimeSpentPersistKeySessionNumInterruptions : @(_numInterruptionsInCurrentSession), + FBSDKTimeSpentPersistKeyLastSuspendTime : @(now) + }; + + NSString *content = [FBSDKInternalUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL]; + + [content writeToFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename] + atomically:YES + encoding:NSASCIIStringEncoding + error:nil]; + + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKTimeSpentData Persist: %@", content]; + + _isCurrentlyLoaded = NO; +} + + +// Called during activation - either through an explicit 'activateApp' call or implicitly when the app is foregrounded. +// In both cases, we restore the persisted event data. In the case of the activateApp, we log an 'app activated' +// event if there's been enough time between the last deactivation and now. +- (void)instanceRestore:(BOOL)calledFromActivateApp +{ + + [FBSDKAppEventsUtility ensureOnMainThread]; + + // It's possible to call this multiple times during the time the app is in the foreground. If this is the case, + // just restore persisted data the first time. + if (!_isCurrentlyLoaded) { + + NSString *content = + [[NSString alloc] initWithContentsOfFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename] + usedEncoding:nil + error:nil]; + + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents + formatString:@"FBSDKTimeSpentData Restore: %@", content]; + + long now = [FBSDKAppEventsUtility unixTimeNow]; + if (!content) { + + // Nothing persisted, so this is the first launch. + _secondsSpentInCurrentSession = 0; + _numInterruptionsInCurrentSession = 0; + + // We want to log the app activation event on the first launch, but not the deactivate event + _shouldLogActivateEvent = YES; + _shouldLogDeactivateEvent = NO; + + } else { + + NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL]; + + long lastActiveTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue]; + + _timeSinceLastSuspend = now - lastActiveTime; + _secondsSpentInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionSecondsSpent] intValue]; + _numInterruptionsInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionNumInterruptions] intValue]; + _shouldLogActivateEvent = (_timeSinceLastSuspend > _numSecondsIdleToBeNewSession); + + // Other than the first launch, we always log the last session's deactivate with this session's activate. + _shouldLogDeactivateEvent = _shouldLogActivateEvent; + + if (!_shouldLogDeactivateEvent) { + // If we're not logging, then the time we spent deactivated is considered another interruption. But cap it + // so errant or test uses doesn't blow out the cardinality on the backend processing + _numInterruptionsInCurrentSession = MIN(_numInterruptionsInCurrentSession + 1, 200); + } + + } + + _lastRestoreTime = now; + _isCurrentlyLoaded = YES; + + if (calledFromActivateApp) { + + if (_shouldLogActivateEvent) { + [FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp + parameters:@{ + FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication] + }]; + } + + if (_shouldLogDeactivateEvent) { + + int quantaIndex = 0; + while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) { + quantaIndex++; + } + + [FBSDKAppEvents logEvent:FBSDKAppEventNameDeactivatedApp + valueToSum:_secondsSpentInCurrentSession + parameters: + @{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession), + FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex], + FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication], + } + ]; + + // We've logged the session stats, now reset. + _secondsSpentInCurrentSession = 0; + _numInterruptionsInCurrentSession = 0; + } + } + } +} + ++ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url +{ + [self setSourceApplication:sourceApplication + isFromAppLink:[FBSDKInternalUtility dictionaryFromFBURL:url][@"al_applink_data"] != nil]; +} + ++ (void)setSourceApplication:(NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink +{ + g_isOpenedFromAppLink = isFromAppLink; + g_sourceApplication = sourceApplication; +} + ++ (NSString *)getSourceApplication +{ + NSString *openType = @"Unclassified"; + if (g_isOpenedFromAppLink) { + openType = @"AppLink"; + } + return (g_sourceApplication ? + [NSString stringWithFormat:@"%@(%@)", openType, g_sourceApplication] + : openType); +} + ++ (void)resetSourceApplication +{ + g_sourceApplication = nil; + g_isOpenedFromAppLink = NO; +} + ++ (void)registerAutoResetSourceApplication +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(resetSourceApplication) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h new file mode 100644 index 0000000..c42431b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKBoltsMeasurementEventListener : NSObject ++ (FBSDKBoltsMeasurementEventListener *)defaultListener; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.m new file mode 100644 index 0000000..415e029 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.m @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBoltsMeasurementEventListener.h" + +#import "FBSDKAppEvents+Internal.h" +#import "FBSDKTimeSpentData.h" + +static NSString *const BoltsMeasurementEventNotificationName = @"com.parse.bolts.measurement_event"; +static NSString *const BoltsMeasurementEventName = @"event_name"; +static NSString *const BoltsMeasurementEventArgs = @"event_args"; +static NSString *const BoltsMeasurementEventPrefix = @"bf_"; + +@implementation FBSDKBoltsMeasurementEventListener + ++ (instancetype)defaultListener +{ + static dispatch_once_t dispatchOnceLocker = 0; + static FBSDKBoltsMeasurementEventListener *defaultListener = nil; + dispatch_once(&dispatchOnceLocker, ^{ + defaultListener = [[self alloc] init]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:defaultListener + selector:@selector(logFBAppEventForNotification:) + name:BoltsMeasurementEventNotificationName + object:nil]; + }); + return defaultListener; +} + +- (void)logFBAppEventForNotification:(NSNotification *)note +{ + // when catch al_nav_in event, we set source application for FBAppEvents. + if ([note.userInfo[BoltsMeasurementEventName] isEqualToString:@"al_nav_in"]) { + NSString *sourceApplication = note.userInfo[BoltsMeasurementEventArgs][@"sourceApplication"]; + if (sourceApplication) { + [FBSDKTimeSpentData setSourceApplication:sourceApplication isFromAppLink:YES]; + } + } + NSDictionary *eventArgs = note.userInfo[BoltsMeasurementEventArgs]; + NSMutableDictionary *logData = [[NSMutableDictionary alloc] init]; + for(NSString *key in eventArgs.allKeys) { + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9a-zA-Z _-]" options:0 error:&error]; + NSString *safeKey = [regex stringByReplacingMatchesInString:key + options:0 + range:NSMakeRange(0, [key length]) + withTemplate:@"-"]; + safeKey = [safeKey stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -"]]; + logData[safeKey] = eventArgs[key]; + } + [FBSDKAppEvents logImplicitEvent:[BoltsMeasurementEventPrefix stringByAppendingString:note.userInfo[BoltsMeasurementEventName]] + valueToSum:nil + parameters:logData + accessToken:nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h new file mode 100644 index 0000000..f358917 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKBase64 : NSObject + +/*! + @abstract Decodes a base-64 encoded string. + @param string The base-64 encoded string. + @return NSData containing the decoded bytes. + */ ++ (NSData *)decodeAsData:(NSString *)string; + +/*! + @abstract Decodes a base-64 encoded string into a string. + @param string The base-64 encoded string. + @return NSString with the decoded UTF-8 value. + */ ++ (NSString *)decodeAsString:(NSString *)string; + +/*! + @abstract Encodes data into a string. + @param data The data to be encoded. + @return The base-64 encoded string. + */ ++ (NSString *)encodeData:(NSData *)data; + +/*! + @abstract Encodes string into a base-64 representation. + @param string The string to be encoded. + @return The base-64 encoded string. + */ ++ (NSString *)encodeString:(NSString *)string; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.m new file mode 100644 index 0000000..c509d2e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.m @@ -0,0 +1,133 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBase64.h" + +#import "FBSDKMacros.h" + +@implementation FBSDKBase64 +{ + BOOL _optionsEnabled; +} + +static FBSDKBase64 *_decoder; +static FBSDKBase64 *_encoder; + +#pragma mark - Class Methods + ++ (void)initialize +{ + if (self == [FBSDKBase64 class]) { + BOOL optionsEnabled; + optionsEnabled = [NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]; + _decoder = [[FBSDKBase64 alloc] initWithOptionsEnabled:optionsEnabled]; + optionsEnabled = [NSData instancesRespondToSelector:@selector(base64EncodedStringWithOptions:)]; + _encoder = [[FBSDKBase64 alloc] initWithOptionsEnabled:optionsEnabled]; + } +} + ++ (NSData *)decodeAsData:(NSString *)string +{ + return [_decoder decodeAsData:string]; +} + ++ (NSString *)decodeAsString:(NSString *)string +{ + return [_decoder decodeAsString:string]; +} + ++ (NSString *)encodeData:(NSData *)data +{ + return [_encoder encodeData:data]; +} + ++ (NSString *)encodeString:(NSString *)string +{ + return [_encoder encodeString:string]; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithOptionsEnabled:); + return nil; +} + +- (instancetype)initWithOptionsEnabled:(BOOL)optionsEnabled +{ + if ((self = [super init])) { + _optionsEnabled = optionsEnabled; + } + return self; +} + +#pragma mark - Implementation Methods + +- (NSData *)decodeAsData:(NSString *)string +{ + if (!string) { + return nil; + } + // This padding will be appended before stripping unknown characters, so if there are unknown characters of count % 4 + // it will not be able to decode. Since we assume valid base64 data, we will take this as is. + int needPadding = string.length % 4; + if (needPadding > 0) { + needPadding = 4 - needPadding; + string = [string stringByPaddingToLength:string.length+needPadding withString:@"=" startingAtIndex:0]; + } + if (_optionsEnabled) { + return [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [[NSData alloc] initWithBase64Encoding:string]; +#pragma clang diagnostic pop + } +} + +- (NSString *)decodeAsString:(NSString *)string +{ + NSData *data = [self decodeAsData:string]; + if (!data) { + return nil; + } + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + +- (NSString *)encodeData:(NSData *)data +{ + if (!data) { + return nil; + } + if (_optionsEnabled) { + return [data base64EncodedStringWithOptions:0]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [data base64Encoding]; +#pragma clang diagnostic pop + } +} + +- (NSString *)encodeString:(NSString *)string +{ + return [self encodeData:[string dataUsingEncoding:NSUTF8StringEncoding]]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h new file mode 100644 index 0000000..7d488e7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKBridgeAPIRequest.h" + +@interface FBSDKBridgeAPICrypto : NSObject + ++ (void)addCipherKeyToQueryParameters:(NSMutableDictionary *)queryParameters; ++ (NSDictionary *)decryptResponseForRequest:(FBSDKBridgeAPIRequest *)request + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef; ++ (void)reset; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.m new file mode 100644 index 0000000..29d2eb4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.m @@ -0,0 +1,139 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPICrypto.h" + +#import "FBSDKBridgeAPIProtocol.h" +#import "FBSDKConstants.h" +#import "FBSDKCrypto.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" +#import "FBSDKUtility.h" + +static NSString *const FBSDKBridgeAPICryptoCipherKey = @"cipher"; +static NSString *const FBSDKBridgeAPICryptoCipherKeyKey = @"cipher_key"; +static NSString *g_cipherKey = nil; + +@implementation FBSDKBridgeAPICrypto + +#pragma mark - Class Methods + ++ (void)addCipherKeyToQueryParameters:(NSMutableDictionary *)queryParameters +{ + [FBSDKInternalUtility dictionary:queryParameters setObject:[self _cipherKey] forKey:FBSDKBridgeAPICryptoCipherKeyKey]; +} + ++ (NSDictionary *)decryptResponseForRequest:(FBSDKBridgeAPIRequest *)request + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef +{ + if (errorRef != NULL) { + *errorRef = nil; + } + NSString *cipher = queryParameters[FBSDKBridgeAPICryptoCipherKey]; + if (!cipher) { + return queryParameters ?: @{}; + } + NSString *version = queryParameters[FBSDKBridgeAPIVersionKey]; + NSString *cipherKey = [self _cipherKey]; + if (!version || !cipherKey) { + if (errorRef != NULL) { + NSDictionary *userInfo = @{ + FBSDKErrorArgumentValueKey: queryParameters, + }; + *errorRef = [FBSDKError errorWithCode:FBSDKEncryptionErrorCode + userInfo:userInfo + message:@"Error decrypting incoming query parameters." + underlyingError:nil]; + } + return nil; + } + NSArray *additionalSignedDataArray = @[ + [[NSBundle mainBundle] bundleIdentifier], + [FBSDKSettings appID] ?: @"", + @"bridge", + request.methodName ?: @"", + version, + ]; + NSString *additionalSignedDataString = [additionalSignedDataArray componentsJoinedByString:@":"]; + NSData *additionalSignedData = [additionalSignedDataString dataUsingEncoding:NSUTF8StringEncoding]; + FBSDKCrypto *crypto = [[FBSDKCrypto alloc] initWithMasterKey:cipherKey]; + NSData *decryptedData = [crypto decrypt:cipher additionalSignedData:additionalSignedData]; + if (!decryptedData) { + if (errorRef != NULL) { + NSDictionary *userInfo = @{ + FBSDKErrorArgumentValueKey: @{ + @"cipher": cipher, + @"bundleIdentifier": additionalSignedDataArray[0], + @"appID": additionalSignedDataArray[1], + @"host": additionalSignedDataArray[2], + @"methodName": additionalSignedDataArray[3], + @"version": additionalSignedDataArray[4], + }, + }; + *errorRef = [FBSDKError errorWithCode:FBSDKEncryptionErrorCode + userInfo:userInfo + message:@"Error decrypting incoming query parameters." + underlyingError:nil]; + } + return nil; + } + NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]; + NSDictionary *decryptedDictionary = [FBSDKUtility dictionaryWithQueryString:decryptedString]; + NSMutableDictionary *decryptedQueryParameters = [[NSMutableDictionary alloc] initWithDictionary:decryptedDictionary]; + decryptedQueryParameters[FBSDKBridgeAPIVersionKey] = version; + return [decryptedQueryParameters copy]; +} + ++ (void)reset +{ + [self _resetCipherKey]; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +#pragma mark - Helper Methods + ++ (NSString *)_cipherKey +{ + if (g_cipherKey) { + return g_cipherKey; + } + g_cipherKey = [[[NSUserDefaults standardUserDefaults] stringForKey:FBSDKBridgeAPICryptoCipherKeyKey] copy]; + if (g_cipherKey) { + return g_cipherKey; + } + return [self _resetCipherKey]; +} + ++ (NSString *)_resetCipherKey +{ + g_cipherKey = [[FBSDKCrypto makeMasterKey] copy]; + [[NSUserDefaults standardUserDefaults] setObject:g_cipherKey forKey:FBSDKBridgeAPICryptoCipherKeyKey]; + return g_cipherKey; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h new file mode 100644 index 0000000..679577c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIProtocolType.h" + +@class FBSDKBridgeAPIRequest; + +FBSDK_EXTERN NSString *const FBSDKBridgeAPIAppIDKey; +FBSDK_EXTERN NSString *const FBSDKBridgeAPISchemeSuffixKey; +FBSDK_EXTERN NSString *const FBSDKBridgeAPIVersionKey; + +@protocol FBSDKBridgeAPIProtocol + +- (NSURL *)requestURLWithActionID:(NSString *)actionID + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + error:(NSError *__autoreleasing *)errorRef; +- (NSDictionary *)responseParametersForActionID:(NSString *)actionID + queryParameters:(NSDictionary *)queryParameters + cancelled:(BOOL *)cancelledRef + error:(NSError *__autoreleasing *)errorRef; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h new file mode 100644 index 0000000..b04e359 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +typedef NS_ENUM(NSUInteger, FBSDKBridgeAPIProtocolType) +{ + FBSDKBridgeAPIProtocolTypeNative, + FBSDKBridgeAPIProtocolTypeWeb, +}; diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h new file mode 100644 index 0000000..4455e22 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIProtocol.h" +#import "FBSDKBridgeAPIRequest.h" + +@interface FBSDKBridgeAPIRequest () + +- (instancetype)initWithProtocol:(id)protocol + protocolType:(FBSDKBridgeAPIProtocolType)protocolType + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + userInfo:(NSDictionary *)userInfo +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, strong, readonly) id protocol; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h new file mode 100644 index 0000000..01af30c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIProtocolType.h" + +@interface FBSDKBridgeAPIRequest : NSObject + ++ (instancetype)bridgeAPIRequestWithProtocolType:(FBSDKBridgeAPIProtocolType)protocolType + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + userInfo:(NSDictionary *)userInfo; + +@property (nonatomic, copy, readonly) NSString *actionID; +@property (nonatomic, copy, readonly) NSString *methodName; +@property (nonatomic, copy, readonly) NSString *methodVersion; +@property (nonatomic, copy, readonly) NSDictionary *parameters; +@property (nonatomic, assign, readonly) FBSDKBridgeAPIProtocolType protocolType; +@property (nonatomic, copy, readonly) NSString *scheme; +@property (nonatomic, copy, readonly) NSDictionary *userInfo; + +- (NSURL *)requestURL:(NSError *__autoreleasing *)errorRef; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.m new file mode 100644 index 0000000..23a3712 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.m @@ -0,0 +1,166 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIRequest.h" +#import "FBSDKBridgeAPIRequest+Private.h" + +#import "FBSDKBridgeAPICrypto.h" +#import "FBSDKBridgeAPIProtocolNativeV1.h" +#import "FBSDKBridgeAPIProtocolWebV1.h" +#import "FBSDKBridgeAPIProtocolWebV2.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" +#import "FBSDKUtility.h" + +NSString *const FBSDKBridgeAPIAppIDKey = @"app_id"; +NSString *const FBSDKBridgeAPISchemeSuffixKey = @"scheme_suffix"; +NSString *const FBSDKBridgeAPIVersionKey = @"version"; + +@implementation FBSDKBridgeAPIRequest + +#pragma mark - Class Methods + ++ (instancetype)bridgeAPIRequestWithProtocolType:(FBSDKBridgeAPIProtocolType)protocolType + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + userInfo:(NSDictionary *)userInfo +{ + return [[self alloc] initWithProtocol:[self _protocolForType:protocolType scheme:scheme] + protocolType:protocolType + scheme:scheme + methodName:methodName + methodVersion:methodVersion + parameters:parameters + userInfo:userInfo]; +} + ++ (NSDictionary *)protocolMap +{ + static NSDictionary *_protocolMap; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _protocolMap = @{ + @(FBSDKBridgeAPIProtocolTypeNative): @{ + FBSDK_CANOPENURL_FACEBOOK:[[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:@"fbapi20130214"], + FBSDK_CANOPENURL_MESSENGER:[[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:@"fb-messenger-api20140430"] + }, + @(FBSDKBridgeAPIProtocolTypeWeb): @{ + @"https": [[FBSDKBridgeAPIProtocolWebV1 alloc] init], + @"web": [[FBSDKBridgeAPIProtocolWebV2 alloc] init] + }, + }; + }); + return _protocolMap; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithProtocol:(id)protocol + protocolType:(FBSDKBridgeAPIProtocolType)protocolType + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + userInfo:(NSDictionary *)userInfo +{ + if (!protocol) { + return nil; + } + if ((self = [super init])) { + _protocol = protocol; + _protocolType = protocolType; + _scheme = [scheme copy]; + _methodName = [methodName copy]; + _methodVersion = [methodVersion copy]; + _parameters = [parameters copy]; + _userInfo = [userInfo copy]; + + _actionID = [[NSUUID UUID] UUIDString]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithProtocol:protocolType:scheme:methodName:methodVersion:parameters:userInfo:); + return [self initWithProtocol:nil + protocolType:FBSDKBridgeAPIProtocolTypeWeb + scheme:nil + methodName:nil + methodVersion:nil + parameters:nil + userInfo:nil]; +} + +#pragma mark - Public Methods + +- (NSURL *)requestURL:(NSError *__autoreleasing *)errorRef +{ + NSURL *requestURL = [_protocol requestURLWithActionID:self.actionID + scheme:self.scheme + methodName:self.methodName + methodVersion:self.methodVersion + parameters:self.parameters + error:errorRef]; + if (!requestURL) { + return nil; + } + + [FBSDKInternalUtility validateURLSchemes]; + + NSDictionary *requestQueryParameters = [FBSDKUtility dictionaryWithQueryString:requestURL.query]; + NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] initWithDictionary:requestQueryParameters]; + [FBSDKBridgeAPICrypto addCipherKeyToQueryParameters:queryParameters]; + [FBSDKInternalUtility dictionary:queryParameters setObject:[FBSDKSettings appID] forKey:FBSDKBridgeAPIAppIDKey]; + [FBSDKInternalUtility dictionary:queryParameters + setObject:[FBSDKSettings appURLSchemeSuffix] + forKey:FBSDKBridgeAPISchemeSuffixKey]; + requestURL = [FBSDKInternalUtility URLWithScheme:requestURL.scheme + host:requestURL.host + path:requestURL.path + queryParameters:queryParameters + error:errorRef]; + return requestURL; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + ++ (id)_protocolForType:(FBSDKBridgeAPIProtocolType)type scheme:(NSString *)scheme +{ + id protocol = [self protocolMap][@(type)][scheme]; + if (type == FBSDKBridgeAPIProtocolTypeWeb) { + return protocol; + } + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = scheme; + components.path = @"/"; + if ([[UIApplication sharedApplication] canOpenURL:components.URL]) { + return protocol; + } + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h new file mode 100644 index 0000000..3da24d3 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIRequest.h" + +@interface FBSDKBridgeAPIResponse : NSObject + ++ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request error:(NSError *)error; ++ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request + responseURL:(NSURL *)responseURL + sourceApplication:(NSString *)sourceApplication + error:(NSError *__autoreleasing *)errorRef; ++ (instancetype)bridgeAPIResponseCancelledWithRequest:(FBSDKBridgeAPIRequest *)request; + +@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled; +@property (nonatomic, copy, readonly) NSError *error; +@property (nonatomic, copy, readonly) FBSDKBridgeAPIRequest *request; +@property (nonatomic, copy, readonly) NSDictionary *responseParameters; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.m new file mode 100644 index 0000000..2254c95 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.m @@ -0,0 +1,135 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIResponse.h" + +#import "FBSDKBridgeAPICrypto.h" +#import "FBSDKBridgeAPIProtocol.h" +#import "FBSDKBridgeAPIProtocolType.h" +#import "FBSDKBridgeAPIRequest+Private.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" +#import "FBSDKTypeUtility.h" +#import "FBSDKUtility.h" + +@interface FBSDKBridgeAPIResponse () +- (instancetype)initWithRequest:(FBSDKBridgeAPIRequest *)request + responseParameters:(NSDictionary *)responseParameters + cancelled:(BOOL)cancelled + error:(NSError *)error +NS_DESIGNATED_INITIALIZER; +@end + +@implementation FBSDKBridgeAPIResponse + +#pragma mark - Class Methods + ++ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request error:(NSError *)error +{ + return [[self alloc] initWithRequest:request + responseParameters:nil + cancelled:NO + error:error]; +} + ++ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request + responseURL:(NSURL *)responseURL + sourceApplication:(NSString *)sourceApplication + error:(NSError *__autoreleasing *)errorRef +{ + FBSDKBridgeAPIProtocolType protocolType = request.protocolType; + switch (protocolType) { + case FBSDKBridgeAPIProtocolTypeNative:{ + if (![FBSDKInternalUtility isFacebookBundleIdentifier:sourceApplication]) { + [FBSDKBridgeAPICrypto reset]; + return nil; + } + break; + } + case FBSDKBridgeAPIProtocolTypeWeb:{ + if (![FBSDKInternalUtility isSafariBundleIdentifier:sourceApplication]) { + [FBSDKBridgeAPICrypto reset]; + return nil; + } + break; + } + } + NSDictionary *queryParameters = [FBSDKUtility dictionaryWithQueryString:responseURL.query]; + queryParameters = [FBSDKBridgeAPICrypto decryptResponseForRequest:request + queryParameters:queryParameters + error:errorRef]; + if (!queryParameters) { + return nil; + } + id protocol = request.protocol; + BOOL cancelled; + NSError *error; + NSDictionary *responseParameters = [protocol responseParametersForActionID:request.actionID + queryParameters:queryParameters + cancelled:&cancelled + error:&error]; + if (errorRef != NULL) { + *errorRef = error; + } + if (!responseParameters) { + return nil; + } + return [[self alloc] initWithRequest:request + responseParameters:responseParameters + cancelled:cancelled + error:error]; +} + ++ (instancetype)bridgeAPIResponseCancelledWithRequest:(FBSDKBridgeAPIRequest *)request +{ + return [[self alloc] initWithRequest:request + responseParameters:nil + cancelled:YES + error:nil]; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithRequest:(FBSDKBridgeAPIRequest *)request + responseParameters:(NSDictionary *)responseParameters + cancelled:(BOOL)cancelled + error:(NSError *)error +{ + if ((self = [super init])) { + _request = [request copy]; + _responseParameters = [responseParameters copy]; + _cancelled = cancelled; + _error = [error copy]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithRequest:responseParameters:cancelled:error:); + return [self initWithRequest:nil responseParameters:nil cancelled:NO error:nil]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKURLOpening.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKURLOpening.h new file mode 100644 index 0000000..83c355a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKURLOpening.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@protocol FBSDKURLOpening + +// Implementations should make sure they can handle nil parameters +// which is possible in SafariViewController. +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation; + +- (void)applicationDidBecomeActive:(UIApplication *)application; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h new file mode 100644 index 0000000..8fd34bd --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h @@ -0,0 +1,70 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIProtocol.h" + +typedef struct +{ + __unsafe_unretained NSString *bridgeArgs; + __unsafe_unretained NSString *methodArgs; + __unsafe_unretained NSString *methodVersion; +} FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct FBSDKBridgeAPIProtocolNativeV1OutputKeys; + +typedef struct +{ + __unsafe_unretained NSString *actionID; + __unsafe_unretained NSString *appIcon; + __unsafe_unretained NSString *appName; + __unsafe_unretained NSString *sdkVersion; +} FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys; + +typedef struct +{ + __unsafe_unretained NSString *bridgeArgs; + __unsafe_unretained NSString *methodResults; +} FBSDKBridgeAPIProtocolNativeV1InputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1InputKeysStruct FBSDKBridgeAPIProtocolNativeV1InputKeys; + +typedef struct +{ + __unsafe_unretained NSString *actionID; + __unsafe_unretained NSString *error; +} FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys; + +@interface FBSDKBridgeAPIProtocolNativeV1 : NSObject + +- (instancetype)initWithAppScheme:(NSString *)appScheme; +- (instancetype)initWithAppScheme:(NSString *)appScheme + pasteboard:(UIPasteboard *)pasteboard + dataLengthThreshold:(NSUInteger)dataLengthThreshold + includeAppIcon:(BOOL)includeAppIcon +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, copy, readonly) NSString *appScheme; +@property (nonatomic, assign, readonly) NSUInteger dataLengthThreshold; +@property (nonatomic, assign, readonly) BOOL includeAppIcon; +@property (nonatomic, strong, readonly) UIPasteboard *pasteboard; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.m new file mode 100644 index 0000000..50e5b97 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.m @@ -0,0 +1,338 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIProtocolNativeV1.h" + +#import + +#import + +#import "FBSDKApplicationDelegate+Internal.h" +#import "FBSDKBase64.h" +#import "FBSDKBridgeAPIRequest.h" +#import "FBSDKConstants.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKSettings.h" +#import "FBSDKTypeUtility.h" + +#define FBSDKBridgeAPIProtocolNativeV1BridgeMaxBase64DataLengthThreshold (1024 * 16) + +const FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct FBSDKBridgeAPIProtocolNativeV1OutputKeys = +{ + .bridgeArgs = @"bridge_args", + .methodArgs = @"method_args", + .methodVersion = @"version", +}; + +const FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys = +{ + .actionID = @"action_id", + .appIcon = @"app_icon", + .appName = @"app_name", + .sdkVersion = @"sdk_version", +}; + +const FBSDKBridgeAPIProtocolNativeV1InputKeysStruct FBSDKBridgeAPIProtocolNativeV1InputKeys = +{ + .bridgeArgs = @"bridge_args", + .methodResults = @"method_results", +}; + +const FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys = +{ + .actionID = @"action_id", + .error = @"error", +}; + +static const struct +{ + __unsafe_unretained NSString *isBase64; + __unsafe_unretained NSString *isPasteboard; + __unsafe_unretained NSString *tag; + __unsafe_unretained NSString *value; +} FBSDKBridgeAPIProtocolNativeV1DataKeys = +{ + .isBase64 = @"isBase64", + .isPasteboard = @"isPasteboard", + .tag = @"tag", + .value = @"fbAppBridgeType_jsonReadyValue", +}; + +static NSString *const FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey = @"com.facebook.Facebook.FBAppBridgeType"; + +static const struct +{ + __unsafe_unretained NSString *data; + __unsafe_unretained NSString *image; +} FBSDKBridgeAPIProtocolNativeV1DataTypeTags = +{ + .data = @"data", + // we serialize jpegs but use png for backward compatibility - it is any image format that UIImage can handle + .image = @"png", +}; + +static const struct +{ + __unsafe_unretained NSString *code; + __unsafe_unretained NSString *domain; + __unsafe_unretained NSString *userInfo; +} FBSDKBridgeAPIProtocolNativeV1ErrorKeys = +{ + .code = @"code", + .domain = @"domain", + .userInfo = @"user_info", +}; + +@implementation FBSDKBridgeAPIProtocolNativeV1 + +#pragma mark - Object Lifecycle + +- (instancetype)initWithAppScheme:(NSString *)appScheme +{ + return [self initWithAppScheme:appScheme + pasteboard:[UIPasteboard generalPasteboard] + dataLengthThreshold:FBSDKBridgeAPIProtocolNativeV1BridgeMaxBase64DataLengthThreshold + includeAppIcon:YES]; +} + +- (instancetype)initWithAppScheme:(NSString *)appScheme + pasteboard:(UIPasteboard *)pasteboard + dataLengthThreshold:(NSUInteger)dataLengthThreshold + includeAppIcon:(BOOL)includeAppIcon +{ + if ((self = [super init])) { + _appScheme = [appScheme copy]; + _pasteboard = pasteboard; + _dataLengthThreshold = dataLengthThreshold; + _includeAppIcon = includeAppIcon; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAppScheme:); + return [self initWithAppScheme:nil]; +} + +#pragma mark - FBSDKBridgeAPIProtocol + +- (NSURL *)requestURLWithActionID:(NSString *)actionID + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + error:(NSError *__autoreleasing *)errorRef +{ + NSString *host = @"dialog"; + NSString *path = [@"/" stringByAppendingString:methodName]; + + NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:queryParameters setObject:methodVersion + forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.methodVersion]; + + if ([parameters count]) { + NSString *parametersString = [self _JSONStringForObject:parameters enablePasteboard:YES error:errorRef]; + if (!parametersString) { + return nil; + } + [FBSDKInternalUtility dictionary:queryParameters + setObject:parametersString + forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.methodArgs]; + } + + NSDictionary *bridgeParameters = [self _bridgeParametersWithActionID:actionID error:errorRef]; + if (!bridgeParameters) { + return nil; + } + NSString *bridgeParametersString = [self _JSONStringForObject:bridgeParameters enablePasteboard:NO error:errorRef]; + if (!bridgeParametersString) { + return nil; + } + [FBSDKInternalUtility dictionary:queryParameters + setObject:bridgeParametersString + forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.bridgeArgs]; + + + return [FBSDKInternalUtility URLWithScheme:self.appScheme + host:host + path:path + queryParameters:queryParameters + error:errorRef]; +} + +- (NSDictionary *)responseParametersForActionID:(NSString *)actionID + queryParameters:(NSDictionary *)queryParameters + cancelled:(BOOL *)cancelledRef + error:(NSError *__autoreleasing *)errorRef +{ + if (cancelledRef != NULL) { + *cancelledRef = NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + NSError *error; + NSString *bridgeParametersJSON = queryParameters[FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs]; + NSDictionary *bridgeParameters = [FBSDKInternalUtility objectForJSONString:bridgeParametersJSON error:&error]; + bridgeParameters = [FBSDKTypeUtility dictionaryValue:bridgeParameters]; + if (!bridgeParameters) { + if (error && (errorRef != NULL)) { + *errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs + value:bridgeParametersJSON + message:@"Invalid bridge_args." + underlyingError:error]; + } + return nil; + } + NSString *responseActionID = bridgeParameters[FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.actionID]; + responseActionID = [FBSDKTypeUtility stringValue:responseActionID]; + if (![responseActionID isEqualToString:actionID]) { + return nil; + } + NSDictionary *errorDictionary = bridgeParameters[FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.error]; + errorDictionary = [FBSDKTypeUtility dictionaryValue:errorDictionary]; + if (errorDictionary) { + error = [self _errorWithDictionary:errorDictionary]; + if (errorRef != NULL) { + *errorRef = error; + } + return nil; + } + NSString *resultParametersJSON = queryParameters[FBSDKBridgeAPIProtocolNativeV1InputKeys.methodResults]; + NSDictionary *resultParameters = [FBSDKInternalUtility objectForJSONString:resultParametersJSON error:&error]; + if (!resultParameters) { + if (errorRef != NULL) { + *errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDKBridgeAPIProtocolNativeV1InputKeys.methodResults + value:resultParametersJSON + message:@"Invalid method_results." + underlyingError:error]; + } + return nil; + } + if (cancelledRef != NULL) { + NSString *completionGesture = [FBSDKTypeUtility stringValue:resultParameters[@"completionGesture"]]; + *cancelledRef = [completionGesture isEqualToString:@"cancel"]; + } + return resultParameters; +} + +#pragma mark - Helper Methods + +- (UIImage *)_appIcon +{ + if (!_includeAppIcon) { + return nil; + } + NSArray *files = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIcons"] + [@"CFBundlePrimaryIcon"] + [@"CFBundleIconFiles"]; + if (![files count]) { + return nil; + } + return [UIImage imageNamed:files[0]]; +} + +- (NSDictionary *)_bridgeParametersWithActionID:(NSString *)actionID error:(NSError *__autoreleasing *)errorRef +{ + NSMutableDictionary *bridgeParameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:bridgeParameters setObject:actionID + forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.actionID]; + [FBSDKInternalUtility dictionary:bridgeParameters setObject:[self _appIcon] + forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.appIcon]; + [FBSDKInternalUtility dictionary:bridgeParameters setObject:[FBSDKSettings displayName] + forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.appName]; + [FBSDKInternalUtility dictionary:bridgeParameters setObject:[FBSDKSettings sdkVersion] + forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.sdkVersion]; + return bridgeParameters; +} + +- (NSError *)_errorWithDictionary:(NSDictionary *)dictionary +{ + if (!dictionary) { + return nil; + } + NSString *domain = [FBSDKTypeUtility stringValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.domain]] ?: + FBSDKErrorDomain; + NSInteger code = [FBSDKTypeUtility integerValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.code]] ?: + FBSDKUnknownErrorCode; + NSDictionary *userInfo = [FBSDKTypeUtility dictionaryValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.userInfo]]; + return [NSError errorWithDomain:domain code:code userInfo:userInfo]; +} + +- (NSString *)_JSONStringForObject:(id)object enablePasteboard:(BOOL)enablePasteboard error:(NSError **)errorRef +{ + __block BOOL didAddToPasteboard = NO; + return [FBSDKInternalUtility JSONStringForObject:object error:errorRef invalidObjectHandler:^id(id invalidObject, BOOL *stop) { + NSString *dataTag = FBSDKBridgeAPIProtocolNativeV1DataTypeTags.data; + if ([invalidObject isKindOfClass:[UIImage class]]) { + UIImage *image = (UIImage *)invalidObject; + // due to backward compatibility, we must send UIImage as NSData even though UIPasteboard can handle UIImage + invalidObject = UIImageJPEGRepresentation(image, [FBSDKSettings JPEGCompressionQuality]); + dataTag = FBSDKBridgeAPIProtocolNativeV1DataTypeTags.image; + } + if ([invalidObject isKindOfClass:[NSData class]]) { + NSData *data = (NSData *)invalidObject; + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + if (didAddToPasteboard || !enablePasteboard || !_pasteboard || (data.length < _dataLengthThreshold)) { + dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.isBase64] = @YES; + dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.tag] = dataTag; + [FBSDKInternalUtility dictionary:dictionary + setObject:[FBSDKBase64 encodeData:data] + forKey:FBSDKBridgeAPIProtocolNativeV1DataKeys.value]; + } else { + dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.isPasteboard] = @YES; + dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.tag] = dataTag; + dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.value] = _pasteboard.name; + [_pasteboard setData:data forPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey]; + // this version of the protocol only supports a single item on the pasteboard, so if when we add an item, make + // sure we don't add another item + didAddToPasteboard = YES; + // if we are adding this to the general pasteboard, then we want to remove it when we are done with the share. + // the Facebook app will not clear the value with this version of the protocol, so we should do it when the app + // becomes active again + NSString *pasteboardName = _pasteboard.name; + if ([pasteboardName isEqualToString:UIPasteboardNameGeneral] || + [pasteboardName isEqualToString:UIPasteboardNameFind]) { + [[self class] clearData:data fromPasteboardOnApplicationDidBecomeActive:_pasteboard]; + } + } + return dictionary; + } else if ([invalidObject isKindOfClass:[NSURL class]]) { + return [(NSURL *)invalidObject absoluteString]; + } + return invalidObject; + }]; +} + ++ (void)clearData:(NSData *)data fromPasteboardOnApplicationDidBecomeActive:(UIPasteboard *)pasteboard +{ + void(^notificationBlock)(NSNotification *) = ^(NSNotification *note){ + NSData *pasteboardData = [pasteboard dataForPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey]; + if ([data isEqualToData:pasteboardData]) { + [pasteboard setData:[NSData data] forPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey]; + } + }; + [[NSNotificationCenter defaultCenter] addObserverForName:FBSDKApplicationDidBecomeActiveNotification + object:[FBSDKApplicationDelegate sharedInstance] + queue:nil + usingBlock:notificationBlock]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h new file mode 100644 index 0000000..c7b28f4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKBridgeAPIProtocol.h" + +@interface FBSDKBridgeAPIProtocolWebV1 : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.m new file mode 100644 index 0000000..ebe8710 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.m @@ -0,0 +1,116 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIProtocolWebV1.h" + +#import + +#import "FBSDKBase64.h" +#import "FBSDKBridgeAPIRequest.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" +#import "FBSDKTypeUtility.h" + +#define FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY @"action_id" +#define FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY @"bridge_args" + +@implementation FBSDKBridgeAPIProtocolWebV1 + +#pragma mark - FBSDKBridgeAPIProtocol + +- (NSURL *)requestURLWithActionID:(NSString *)actionID + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + error:(NSError *__autoreleasing *)errorRef +{ + NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] initWithDictionary:parameters]; + queryParameters[@"display"] = @"touch"; + NSString *bridgeArgs = [FBSDKInternalUtility JSONStringForObject:@{ FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY: actionID } + error:NULL + invalidObjectHandler:NULL]; + NSDictionary *redirectQueryParameters = @{ FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY: bridgeArgs }; + NSURL *redirectURL = [FBSDKInternalUtility appURLWithHost:@"bridge" + path:methodName + queryParameters:redirectQueryParameters + error:NULL]; + [FBSDKInternalUtility dictionary:queryParameters setObject:redirectURL forKey:@"redirect_uri"]; + [queryParameters addEntriesFromDictionary:parameters]; + return [FBSDKInternalUtility facebookURLWithHostPrefix:@"m" + path:[@"/dialog/" stringByAppendingString:methodName] + queryParameters:queryParameters + error:NULL]; +} + +- (NSDictionary *)responseParametersForActionID:(NSString *)actionID + queryParameters:(NSDictionary *)queryParameters + cancelled:(BOOL *)cancelledRef + error:(NSError *__autoreleasing *)errorRef +{ + if (errorRef != NULL) { + *errorRef = nil; + } + NSInteger errorCode = [FBSDKTypeUtility integerValue:queryParameters[@"error_code"]]; + switch (errorCode) { + case 0:{ + // good to go, handle the other codes and bail + break; + } + case 4201:{ + return @{ + @"completionGesture": @"cancel", + }; + break; + } + default:{ + if (errorRef != NULL) { + *errorRef = [FBSDKError errorWithCode:errorCode + message:[FBSDKTypeUtility stringValue:queryParameters[@"error_message"]]]; + } + return nil; + break; + } + } + + NSError *error; + NSString *bridgeParametersJSON = [FBSDKTypeUtility stringValue:queryParameters[FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY]]; + NSDictionary *bridgeParameters = [FBSDKInternalUtility objectForJSONString:bridgeParametersJSON error:&error]; + if (!bridgeParameters) { + if (error && (errorRef != NULL)) { + *errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY + value:bridgeParametersJSON + message:nil + underlyingError:error]; + } + return nil; + } + NSString *responseActionID = bridgeParameters[FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY]; + responseActionID = [FBSDKTypeUtility stringValue:responseActionID]; + if (![responseActionID isEqualToString:actionID]) { + return nil; + } + NSMutableDictionary *resultParameters = [queryParameters mutableCopy]; + [resultParameters removeObjectForKey:FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY]; + resultParameters[@"didComplete"] = @YES; + return resultParameters; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h new file mode 100644 index 0000000..3d7e340 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKBridgeAPIProtocol.h" + +@interface FBSDKBridgeAPIProtocolWebV2 : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.m new file mode 100644 index 0000000..414543d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.m @@ -0,0 +1,130 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKBridgeAPIProtocolWebV2.h" + +#import "FBSDKBridgeAPIProtocolNativeV1.h" +#import "FBSDKDialogConfiguration.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKServerConfiguration.h" +#import "FBSDKServerConfigurationManager.h" +#import "FBSDKUtility.h" + +@implementation FBSDKBridgeAPIProtocolWebV2 +{ + FBSDKBridgeAPIProtocolNativeV1 *_nativeProtocol; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _nativeProtocol = [[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:nil + pasteboard:nil + dataLengthThreshold:0 + includeAppIcon:NO]; + } + return self; +} + +#pragma mark - FBSDKBridgeAPIProtocol + +- (NSURL *)_redirectURLWithActionID:(NSString *)actionID methodName:(NSString *)methodName error:(NSError **)errorRef +{ + NSDictionary *queryParameters = nil; + if (actionID) { + NSDictionary *bridgeArgs = @{ FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.actionID: actionID }; + NSString *bridgeArgsString = [FBSDKInternalUtility JSONStringForObject:bridgeArgs + error:NULL + invalidObjectHandler:NULL]; + queryParameters = @{ FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs: bridgeArgsString }; + } + return [FBSDKInternalUtility appURLWithHost:@"bridge" path:methodName queryParameters:queryParameters error:errorRef]; +} + +- (NSURL *)_requestURLForDialogConfiguration:(FBSDKDialogConfiguration *)dialogConfiguration error:(NSError **)errorRef +{ + NSURL *requestURL = dialogConfiguration.URL; + if (!requestURL.scheme) { + requestURL = [FBSDKInternalUtility facebookURLWithHostPrefix:@"m" + path:requestURL.path + queryParameters:nil + defaultVersion:@"" + error:errorRef]; + } + return requestURL; +} + +- (NSURL *)requestURLWithActionID:(NSString *)actionID + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + error:(NSError *__autoreleasing *)errorRef +{ + FBSDKServerConfiguration *serverConfiguration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + FBSDKDialogConfiguration *dialogConfiguration = [serverConfiguration dialogConfigurationForDialogName:methodName]; + if (!dialogConfiguration) { + if (errorRef != NULL) { + *errorRef = [FBSDKError errorWithCode:FBSDKDialogUnavailableErrorCode message:nil]; + } + return nil; + } + + NSURL *requestURL = [_nativeProtocol requestURLWithActionID:actionID + scheme:scheme + methodName:methodName + methodVersion:methodVersion + parameters:parameters error:errorRef]; + if (!requestURL) { + return nil; + } + + NSMutableDictionary *queryParameters = [[FBSDKUtility dictionaryWithQueryString:requestURL.query] mutableCopy]; + queryParameters[@"ios_bundle_id"] = [[NSBundle mainBundle] bundleIdentifier]; + NSURL *redirectURL = [self _redirectURLWithActionID:nil methodName:methodName error:errorRef]; + if (!redirectURL) { + return nil; + } + queryParameters[@"redirect_url"] = redirectURL; + + requestURL = [self _requestURLForDialogConfiguration:dialogConfiguration error:errorRef]; + if (!requestURL) { + return nil; + } + return [FBSDKInternalUtility URLWithScheme:requestURL.scheme + host:requestURL.host + path:requestURL.path + queryParameters:queryParameters + error:errorRef]; +} + +- (NSDictionary *)responseParametersForActionID:(NSString *)actionID + queryParameters:(NSDictionary *)queryParameters + cancelled:(BOOL *)cancelledRef + error:(NSError *__autoreleasing *)errorRef +{ + return [_nativeProtocol responseParametersForActionID:actionID + queryParameters:queryParameters + cancelled:cancelledRef + error:errorRef]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.h new file mode 100644 index 0000000..6fd6170 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.h @@ -0,0 +1,63 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKCrypto : NSObject + +/*! + @abstract Generate numOfBytes random data. + @discussion This calls the system-provided function SecRandomCopyBytes, based on /dev/random. + */ ++ (NSData *)randomBytes:(NSUInteger)numOfBytes; + +/** + * Generate numOfBytes random data, base64-encoded. + * This calls the system-provided function SecRandomCopyBytes, based on /dev/random. + */ ++ (NSString *)randomString:(NSUInteger)numOfBytes; + +/*! + @abstract Generate a fresh master key using SecRandomCopyBytes, the result is encoded in base64/. + */ ++ (NSString *)makeMasterKey; + +/*! + @abstract Initialize with a base64-encoded master key. + @discussion This key and the current derivation function will be used to generate the encryption key and the mac key. + */ +- (instancetype)initWithMasterKey:(NSString *)masterKey; + +/*! + @abstract Initialize with base64-encoded encryption key and mac key. + */ +- (instancetype)initWithEncryptionKey:(NSString *)encryptionKey macKey:(NSString *)macKey; + +/*! + @abstract Encrypt plainText and return the base64 encoded result. + @discussion MAC computation involves additionalDataToSign. + */ +- (NSString *)encrypt:(NSData *)plainText additionalDataToSign:(NSData *)additionalDataToSign; + +/*! + @abstract Decrypt base64EncodedCipherText. + @discussion MAC computation involves additionalSignedData. + */ +- (NSData *)decrypt:(NSString *)base64EncodedCipherText additionalSignedData:(NSData *)additionalSignedData; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.m new file mode 100644 index 0000000..9c2a66a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.m @@ -0,0 +1,287 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCrypto.h" + +#import +#import +#import + +#import "FBSDKBase64.h" +#import "FBSDKDynamicFrameworkLoader.h" + +static const uint8_t kFBSDK_CRYPTO_CURRENT_VERSION = 1; +static const uint8_t kFBSDK_CRYPTO_CURRENT_MASTER_KEY_LENGTH = 16; + +FBSDK_STATIC_INLINE void FBSDKCryptoWriteIntBigEndian(uint8_t *buffer, uint32_t value) +{ + buffer[3] = (uint8_t)(value & 0xff); + buffer[2] = (uint8_t)((value >> 8) & 0xff); + buffer[1] = (uint8_t)((value >> 16) & 0xff); + buffer[0] = (uint8_t)((value >> 24) & 0xff); +} + +FBSDK_STATIC_INLINE void FBSDKCryptoBlankData(NSData *data) +{ + if (!data) { + return; + } + bzero((void *) [data bytes], [data length]); +} + +// Note: the following simple derivation function is NOT suitable for passwords or weak keys +FBSDK_STATIC_INLINE NSData *FBSDKCryptoMakeSubKey(uint8_t *key, size_t len, uint32_t idx) +{ + if (!key || len < 10) { + return nil; + } + + size_t macBufferLength = 4; + uint8_t macBuffer[4]; + FBSDKCryptoWriteIntBigEndian(macBuffer, idx); + + uint8_t *result = malloc(CC_SHA256_DIGEST_LENGTH); + if (!result) { + return nil; + } + + CCHmac(kCCHmacAlgSHA256, key, len, macBuffer, macBufferLength, result); + + return [NSData dataWithBytesNoCopy:result length:CC_SHA256_DIGEST_LENGTH]; +} + +@implementation FBSDKCrypto +{ + NSData *_encryptionKeyData; + NSData *_macKeyData; +} + +#pragma mark - Class Methods + ++ (NSString *)makeMasterKey +{ + NSData *masterKeyData = [FBSDKCrypto randomBytes:kFBSDK_CRYPTO_CURRENT_MASTER_KEY_LENGTH + 1]; + + // force the first byte to be the crypto version + uint8_t *first = (uint8_t *) [masterKeyData bytes]; + *first = kFBSDK_CRYPTO_CURRENT_VERSION; + + NSString *masterKey = [FBSDKBase64 encodeData:masterKeyData]; + FBSDKCryptoBlankData(masterKeyData); + return masterKey; +} + ++ (NSData *)randomBytes:(NSUInteger)numOfBytes +{ + uint8_t *buffer = malloc(numOfBytes); + int result = fbsdkdfl_SecRandomCopyBytes([FBSDKDynamicFrameworkLoader loadkSecRandomDefault], numOfBytes, buffer); + if (result != 0) { + free(buffer); + return nil; + } + return [NSData dataWithBytesNoCopy:buffer length:numOfBytes]; +} + ++ (NSString *)randomString:(NSUInteger)numOfBytes +{ + NSData *randomStringData = [FBSDKCrypto randomBytes:numOfBytes]; + NSString *randomString = [FBSDKBase64 encodeData:randomStringData]; + FBSDKCryptoBlankData(randomStringData); + return randomString; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithMasterKey:(NSString *)masterKey +{ + if ((self = [super init])) { + NSData *masterKeyData = [FBSDKBase64 decodeAsData:masterKey]; + NSUInteger len = [masterKeyData length]; + uint8_t *first = (uint8_t *) [masterKeyData bytes]; + + if (len == 0 || first == nil || *first != kFBSDK_CRYPTO_CURRENT_VERSION) { + // only one version supported at the moment + return nil; + } + + _encryptionKeyData = FBSDKCryptoMakeSubKey(first+1, len-1, 1); + _macKeyData = FBSDKCryptoMakeSubKey(first+1, len-1, 2); + FBSDKCryptoBlankData(masterKeyData); + return self; + } else { + return nil; + } +} + +- (instancetype)initWithEncryptionKey:(NSString *)encryptionKey macKey:(NSString *)macKey +{ + if ((self = [super init])) { + _macKeyData = [FBSDKBase64 decodeAsData:macKey]; + _encryptionKeyData = [FBSDKBase64 decodeAsData:encryptionKey]; + } + return self; +} + +- (void)dealloc +{ + FBSDKCryptoBlankData(_encryptionKeyData); + FBSDKCryptoBlankData(_macKeyData); +} + +#pragma mark - Public Methods + +/** + * return base64_encode([VERSION 1 byte] + [MAC 32 bytes] + [IV 16 bytes] + [AES256(Padded Data, multiples of 16)] + */ +- (NSString *)encrypt:(NSData *)plainText additionalDataToSign:(NSData *)additionalDataToSign +{ + NSAssert(plainText.length <= INT_MAX, @""); + int plainTextLength = (int)plainText.length; + + uint8_t numPaddingBytes = kCCBlockSizeAES128 - (plainText.length % kCCBlockSizeAES128); // Pad 1 .. 16 bytes + int cipherDataLength = plainTextLength + numPaddingBytes; + size_t bufferSize = 1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128 + cipherDataLength; + int offsetMAC = 1; + int offsetIV = offsetMAC + CC_SHA256_DIGEST_LENGTH; + int offsetCipherData = offsetIV + kCCBlockSizeAES128; + + uint8_t *buffer = calloc(bufferSize, sizeof(uint8_t)); + buffer[0] = kFBSDK_CRYPTO_CURRENT_VERSION; // First byte is the version number + NSData *IV = [[self class] randomBytes:kCCBlockSizeAES128]; + memcpy(buffer + offsetIV, IV.bytes, IV.length); + + memcpy(buffer + offsetCipherData, plainText.bytes, plainTextLength); // Copy input in + fbsdkdfl_SecRandomCopyBytes([FBSDKDynamicFrameworkLoader loadkSecRandomDefault], + numPaddingBytes, + buffer + offsetCipherData + plainTextLength); // Random pad + buffer[offsetCipherData + cipherDataLength - 1] = numPaddingBytes; // Record the number of padded bytes at the end + + size_t numOutputBytes = 0; + CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0, + _encryptionKeyData.bytes, kCCKeySizeAES256, + IV.bytes, + buffer + offsetCipherData, cipherDataLength, + buffer + offsetCipherData, cipherDataLength, + &numOutputBytes); + + NSData *mac = [self _macForIV:IV + cipherData:[NSData dataWithBytesNoCopy:buffer + offsetCipherData length:cipherDataLength freeWhenDone:NO] + additionalDataToSign:additionalDataToSign]; + memcpy(buffer + offsetMAC, mac.bytes, CC_SHA256_DIGEST_LENGTH); + + if (cryptStatus == kCCSuccess) { + return [FBSDKBase64 encodeData:[NSData dataWithBytesNoCopy:buffer length:bufferSize]]; + } + free(buffer); + return nil; +} + +- (NSData *)decrypt:(NSString *)base64EncodedCipherText additionalSignedData:(NSData *)additionalSignedData +{ + NSData *cipherText = [FBSDKBase64 decodeAsData:base64EncodedCipherText]; + NSAssert(cipherText.length <= INT_MAX, @""); + int cipherTextLength = (int)cipherText.length; + + if (!cipherText || cipherTextLength < 1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128) { + return nil; + } + int cipherDataLength = cipherTextLength - (1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128); + if (cipherDataLength % kCCBlockSizeAES128 != 0) { + return nil; + } + uint8_t *buffer = (uint8_t *)cipherText.bytes; + + int offsetMAC = 1; + int offsetIV = offsetMAC + CC_SHA256_DIGEST_LENGTH; + int offsetCipherData = offsetIV + kCCBlockSizeAES128; + + if (buffer[0] != kFBSDK_CRYPTO_CURRENT_VERSION) { + return nil; // Version does not match + } + + NSData *IV = [NSData dataWithBytesNoCopy:buffer + offsetIV length:kCCBlockSizeAES128 freeWhenDone:NO]; + NSData *cipherData = [NSData dataWithBytesNoCopy:buffer + offsetCipherData length:cipherDataLength freeWhenDone:NO]; + NSData *mac = [self _macForIV:IV cipherData:cipherData additionalDataToSign:additionalSignedData]; + NSData *macFromStream = [NSData dataWithBytesNoCopy:buffer + offsetMAC length:CC_SHA256_DIGEST_LENGTH freeWhenDone:NO]; + if (![mac isEqualToData:macFromStream]) { + return nil; // MAC does not match + } + + + uint8_t *outputBuffer = malloc(cipherDataLength); + size_t numOutputBytes = 0; + CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, + _encryptionKeyData.bytes, kCCKeySizeAES256, + IV.bytes, + buffer + offsetCipherData, cipherDataLength, + outputBuffer, cipherDataLength, + &numOutputBytes); + if (cryptStatus == kCCSuccess) { + int numPaddingBytes = outputBuffer[cipherDataLength - 1]; + if (!(numPaddingBytes >= 1 && numPaddingBytes <= kCCBlockSizeAES128)) { + numPaddingBytes = 0; + } + return [NSData dataWithBytesNoCopy:outputBuffer length:cipherDataLength - numPaddingBytes]; + } + free(outputBuffer); + return nil; +} + +#pragma mark - Helper Methods + +/** + * + * [IV 16 bytes] . [length of ciphertext 4 bytes] . [ciphertext] . [length of additionalDataToSign, 4 bytes] . [additionalDataToSign]) + * length is written in big-endian + */ +- (NSData *)_macForIV:(NSData *)IV cipherData:(NSData *)cipherData additionalDataToSign:(NSData *)additionalDataToSign +{ + NSAssert(cipherData.length <= INT_MAX, @""); + int cipherDataLength = (int)cipherData.length; + + NSAssert(additionalDataToSign.length <= INT_MAX, @""); + int additionalDataToSignLength = (int)additionalDataToSign.length; + + size_t macBufferLength = kCCBlockSizeAES128 + 4 + cipherData.length + 4 + additionalDataToSign.length; + uint8_t *macBuffer = malloc(macBufferLength); + int offsetIV = 0; + int offsetCipherTextLength = offsetIV + kCCBlockSizeAES128; + int offsetCipherText = offsetCipherTextLength + 4; + + int offsetAdditionalDataLength = offsetCipherText + cipherDataLength; + int offsetAdditionalData = offsetAdditionalDataLength + 4; + + // [IV 16 bytes] + memcpy(macBuffer + offsetIV, IV.bytes, kCCBlockSizeAES128); + // [length of ciphertext 4 bytes] + FBSDKCryptoWriteIntBigEndian(macBuffer + offsetCipherTextLength, cipherDataLength); + // [ciphertext] + memcpy(macBuffer + offsetCipherText, cipherData.bytes, cipherDataLength); + // [length of additionalDataToSign, 4 bytes] + FBSDKCryptoWriteIntBigEndian(macBuffer + offsetAdditionalDataLength, additionalDataToSignLength); + memcpy(macBuffer + offsetAdditionalData, additionalDataToSign.bytes, additionalDataToSignLength); + + uint8_t *result = malloc(CC_SHA256_DIGEST_LENGTH); + + CCHmac(kCCHmacAlgSHA256, _macKeyData.bytes, _macKeyData.length, macBuffer, macBufferLength, result); + free(macBuffer); + + return [NSData dataWithBytesNoCopy:result length:CC_SHA256_DIGEST_LENGTH]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.h new file mode 100644 index 0000000..40715b2 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.h @@ -0,0 +1,34 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@class FBSDKErrorRecoveryConfiguration; + +@interface FBSDKErrorRecoveryAttempter : NSObject + +// can return nil if configuration is not supported. ++ (instancetype)recoveryAttempterFromConfiguration:(FBSDKErrorRecoveryConfiguration *)configuration; + +@end + +@interface FBSDKErrorRecoveryAttempter (Protected) +- (void)completeRecovery:(BOOL)didRecover delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.m new file mode 100644 index 0000000..78b5e87 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.m @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKErrorRecoveryAttempter.h" + +#import "_FBSDKTemporaryErrorRecoveryAttempter.h" +#import "FBSDKErrorRecoveryConfiguration.h" + +@implementation FBSDKErrorRecoveryAttempter + ++ (instancetype)recoveryAttempterFromConfiguration:(FBSDKErrorRecoveryConfiguration *)configuration +{ + if (configuration.errorCategory == FBSDKGraphRequestErrorCategoryTransient) { + return [[_FBSDKTemporaryErrorRecoveryAttempter alloc] init]; + } else if (configuration.errorCategory == FBSDKGraphRequestErrorCategoryOther) { + return nil; + } + if ([configuration.recoveryActionName isEqualToString:@"login"]) { + Class loginRecoveryAttmpterClass = NSClassFromString(@"_FBSDKLoginRecoveryAttempter"); + if (loginRecoveryAttmpterClass) { + return [[loginRecoveryAttmpterClass alloc] init]; + } + } + return nil; +} + +- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo +{ + // should be implemented by subclasses. +} +@end + +@implementation FBSDKErrorRecoveryAttempter(Protected) + +- (void)completeRecovery:(BOOL)didRecover delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo +{ + void (*callback)(id, SEL, BOOL, void *) = (void *)[delegate methodForSelector:didRecoverSelector]; + (*callback)(delegate, didRecoverSelector, didRecover, contextInfo); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h new file mode 100644 index 0000000..21ad040 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKErrorRecoveryAttempter.h" + +@interface _FBSDKTemporaryErrorRecoveryAttempter : FBSDKErrorRecoveryAttempter + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.m new file mode 100644 index 0000000..bb555aa --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.m @@ -0,0 +1,28 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "_FBSDKTemporaryErrorRecoveryAttempter.h" + +@implementation _FBSDKTemporaryErrorRecoveryAttempter + +- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo +{ + [super completeRecovery:YES delegate:delegate didRecoverSelector:didRecoverSelector contextInfo:contextInfo]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h new file mode 100644 index 0000000..479d79a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +#import "BridgeAPI/FBSDKBridgeAPIRequest.h" +#import "BridgeAPI/FBSDKBridgeAPIResponse.h" +#import "BridgeAPI/FBSDKURLOpening.h" +#import "FBSDKContainerViewController.h" + +FBSDK_EXTERN NSString *const FBSDKApplicationDidBecomeActiveNotification; + +@class FBSDKApplicationCall; + +typedef void(^FBSDKBridgeAPICallbackBlock)(FBSDKBridgeAPIResponse *response); + +@interface FBSDKApplicationDelegate () + +- (void)openBridgeAPIRequest:(FBSDKBridgeAPIRequest *)request + useSafariViewController:(BOOL)useSafariViewController + fromViewController:(UIViewController *)fromViewController + completionBlock:(FBSDKBridgeAPICallbackBlock)completionBlock; + +- (void)openURLWithSafariViewController:(NSURL *)url + sender:(id)sender + fromViewController:(UIViewController *)fromViewController + handler:(void(^)(BOOL))handler; + +- (void)openURL:(NSURL *)url sender:(id)sender handler:(void(^)(BOOL))handler; + +@property (nonatomic, readonly, getter=isActive) BOOL active; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h new file mode 100644 index 0000000..2c05575 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKAudioResourceLoader : NSObject + ++ (instancetype)sharedLoader; + +- (BOOL)loadSound:(NSError **)error; +- (void)playSound; + +@end + +@interface FBSDKAudioResourceLoader (Subclass) + ++ (NSString *)name; ++ (NSUInteger)version; ++ (NSData *)data; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.m new file mode 100644 index 0000000..c7efb3f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.m @@ -0,0 +1,151 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAudioResourceLoader.h" + +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + +@implementation FBSDKAudioResourceLoader +{ + NSFileManager *_fileManager; + NSURL *_fileURL; + SystemSoundID _systemSoundID; +} + +#pragma mark - Class Methods + ++ (instancetype)sharedLoader +{ + static NSMutableDictionary *_loaderCache = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _loaderCache = [[NSMutableDictionary alloc] init]; + }); + + NSString *name = [self name]; + FBSDKAudioResourceLoader *loader; + @synchronized(_loaderCache) { + loader = _loaderCache[name]; + if (!loader) { + loader = [[self alloc] init]; + NSError *error = nil; + if ([loader loadSound:&error]) { + _loaderCache[name] = loader; + } else { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"%@ error: %@", self, error]; + } + } + } + + return loader; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _fileManager = [[NSFileManager alloc] init]; + } + return self; +} + +- (void)dealloc +{ + fbsdkdfl_AudioServicesDisposeSystemSoundID(_systemSoundID); +} + +#pragma mark - Public API + +- (BOOL)loadSound:(NSError **)errorRef +{ + NSURL *fileURL = [self _fileURL:errorRef]; + + if (![_fileManager fileExistsAtPath:[fileURL path]]) { + NSData *data = [[self class] data]; + if (![data writeToURL:fileURL options:NSDataWritingAtomic error:errorRef]) { + return NO; + } + } + + OSStatus status = fbsdkdfl_AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &_systemSoundID); + return (status == kAudioServicesNoError); +} + +- (void)playSound +{ + if ((_systemSoundID == 0) && ![self loadSound:NULL]) { + return; + } + fbsdkdfl_AudioServicesPlaySystemSound(_systemSoundID); +} + +#pragma mark - Helper Methods + +- (NSURL *)_fileURL:(NSError **)errorRef +{ + if (_fileURL) { + return _fileURL; + } + + NSURL *baseURL = [_fileManager URLForDirectory:NSCachesDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:YES + error:errorRef]; + if (!baseURL) { + return nil; + } + + NSURL *directoryURL = [baseURL URLByAppendingPathComponent:@"fb_audio" isDirectory:YES]; + NSURL *versionURL = [directoryURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%lu", (unsigned long)[[self class] version]] + isDirectory:YES]; + if (![_fileManager createDirectoryAtURL:versionURL withIntermediateDirectories:YES attributes:nil error:errorRef]) { + return nil; + } + + _fileURL = [[versionURL URLByAppendingPathComponent:[[self class] name]] copy]; + + return _fileURL; +} + +@end + +@implementation FBSDKAudioResourceLoader (Subclass) + +#pragma mark - Subclass Methods + ++ (NSString *)name +{ + return nil; +} + ++ (NSUInteger)version +{ + return 0; +} + ++ (NSData *)data +{ + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h new file mode 100644 index 0000000..5feed4f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKContainerViewController; + +@protocol FBSDKContainerViewControllerDelegate + +- (void)viewControllerDidDisappear:(FBSDKContainerViewController *)viewController animated:(BOOL)animated; + +@end + +@interface FBSDKContainerViewController : UIViewController + +@property (nonatomic, weak) id delegate; + +- (void)displayChildController:(UIViewController *)childController; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.m new file mode 100644 index 0000000..e1c2e6d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.m @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKContainerViewController.h" + +@implementation FBSDKContainerViewController + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + if ([self.delegate respondsToSelector:@selector(viewControllerDidDisappear:animated:)]) { + [self.delegate viewControllerDidDisappear:self animated:animated]; + } +} + +- (void)displayChildController:(UIViewController *)childController +{ + [self addChildViewController:childController]; + UIView *view = self.view; + UIView *childView = childController.view; + childView.translatesAutoresizingMaskIntoConstraints = NO; + childView.frame = view.frame; + [view addSubview:childView]; + + [view addConstraints: + @[ + [NSLayoutConstraint constraintWithItem:childView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:view + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:0.0], + + [NSLayoutConstraint constraintWithItem:childView + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:view + attribute:NSLayoutAttributeBottom + multiplier:1.0 + constant:0.0], + + [NSLayoutConstraint constraintWithItem:childView + attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:view + attribute:NSLayoutAttributeLeading + multiplier:1.0 + constant:0.0], + + [NSLayoutConstraint constraintWithItem:childView + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:view + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:0.0], + ]]; + + [childController didMoveToParentViewController:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h new file mode 100644 index 0000000..1d1ce6b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h @@ -0,0 +1,68 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "AppEvents/FBSDKAppEvents+Internal.h" +#import "AppEvents/FBSDKAppEventsState.h" +#import "AppEvents/FBSDKAppEventsStateManager.h" +#import "AppEvents/FBSDKAppEventsUtility.h" +#import "AppEvents/FBSDKTimeSpentData.h" +#import "Base64/FBSDKBase64.h" +#import "BridgeAPI/FBSDKBridgeAPIProtocol.h" +#import "BridgeAPI/FBSDKBridgeAPIProtocolType.h" +#import "BridgeAPI/FBSDKBridgeAPIRequest.h" +#import "BridgeAPI/FBSDKBridgeAPIResponse.h" +#import "BridgeAPI/FBSDKURLOpening.h" +#import "Cryptography/FBSDKCrypto.h" +#import "ErrorRecovery/FBSDKErrorRecoveryAttempter.h" +#import "FBSDKApplicationDelegate+Internal.h" +#import "FBSDKAudioResourceLoader.h" +#import "FBSDKContainerViewController.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKError.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKMath.h" +#import "FBSDKMonotonicTime.h" +#import "FBSDKSystemAccountStoreAdapter.h" +#import "FBSDKTriStateBOOL.h" +#import "FBSDKTypeUtility.h" +#import "Network/FBSDKGraphRequest+Internal.h" +#import "Network/FBSDKGraphRequestConnection+Internal.h" +#import "Network/FBSDKGraphRequestMetadata.h" +#import "ServerConfiguration/FBSDKDialogConfiguration.h" +#import "ServerConfiguration/FBSDKServerConfiguration+Internal.h" +#import "ServerConfiguration/FBSDKServerConfiguration.h" +#import "ServerConfiguration/FBSDKServerConfigurationManager+Internal.h" +#import "ServerConfiguration/FBSDKServerConfigurationManager.h" +#import "TokenCaching/FBSDKAccessTokenCache.h" +#import "TokenCaching/FBSDKAccessTokenCaching.h" +#import "TokenCaching/FBSDKKeychainStore.h" +#import "TokenCaching/FBSDKKeychainStoreViaBundleID.h" +#import "UI/FBSDKButton+Subclass.h" +#import "UI/FBSDKCloseIcon.h" +#import "UI/FBSDKColor.h" +#import "UI/FBSDKIcon.h" +#import "UI/FBSDKLogo.h" +#import "UI/FBSDKMaleSilhouetteIcon.h" +#import "UI/FBSDKUIUtility.h" +#import "UI/FBSDKViewImpressionTracker.h" +#import "WebDialog/FBSDKWebDialog.h" diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.h new file mode 100644 index 0000000..196d626 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.h @@ -0,0 +1,236 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +#import + +/*! + @class FBSDKDynamicFrameworkLoader + + @abstract + This class provides a way to load constants and methods from Apple Frameworks in a dynamic + fashion. It allows the SDK to be just dragged into a project without having to specify additional + frameworks to link against. It is an internal class and not to be used by 3rd party developers. + + As new types are needed, they should be added and strongly typed. + */ +@interface FBSDKDynamicFrameworkLoader : NSObject + +#pragma mark - Security Constants + +/*! + @abstract + Load the kSecRandomDefault value from the Security Framework + + @return The kSecRandomDefault value or nil. + */ ++ (SecRandomRef)loadkSecRandomDefault; + +/*! + @abstract + Load the kSecAttrAccessible value from the Security Framework + + @return The kSecAttrAccessible value or nil. + */ ++ (CFTypeRef)loadkSecAttrAccessible; + +/*! + @abstract + Load the kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly value from the Security Framework + + @return The kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly value or nil. + */ ++ (CFTypeRef)loadkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + +/*! + @abstract + Load the kSecAttrAccount value from the Security Framework + + @return The kSecAttrAccount value or nil. + */ ++ (CFTypeRef)loadkSecAttrAccount; + +/*! + @abstract + Load the kSecAttrService value from the Security Framework + + @return The kSecAttrService value or nil. + */ ++ (CFTypeRef)loadkSecAttrService; + +/*! + @abstract + Load the kSecAttrGeneric value from the Security Framework + + @return The kSecAttrGeneric value or nil. + */ ++ (CFTypeRef)loadkSecAttrGeneric; + +/*! + @abstract + Load the kSecValueData value from the Security Framework + + @return The kSecValueData value or nil. + */ ++ (CFTypeRef)loadkSecValueData; + +/*! + @abstract + Load the kSecClassGenericPassword value from the Security Framework + + @return The kSecClassGenericPassword value or nil. + */ ++ (CFTypeRef)loadkSecClassGenericPassword; + +/*! + @abstract + Load the kSecAttrAccessGroup value from the Security Framework + + @return The kSecAttrAccessGroup value or nil. + */ ++ (CFTypeRef)loadkSecAttrAccessGroup; + +/*! + @abstract + Load the kSecMatchLimitOne value from the Security Framework + + @return The kSecMatchLimitOne value or nil. + */ ++ (CFTypeRef)loadkSecMatchLimitOne; + +/*! + @abstract + Load the kSecMatchLimit value from the Security Framework + + @return The kSecMatchLimit value or nil. + */ ++ (CFTypeRef)loadkSecMatchLimit; + +/*! + @abstract + Load the kSecReturnData value from the Security Framework + + @return The kSecReturnData value or nil. + */ ++ (CFTypeRef)loadkSecReturnData; + +/*! + @abstract + Load the kSecClass value from the Security Framework + + @return The kSecClass value or nil. + */ ++ (CFTypeRef)loadkSecClass; + +@end + +#pragma mark - Security APIs + +// These are local wrappers around the corresponding methods in Security/SecRandom.h +FBSDK_EXTERN int fbsdkdfl_SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes); + +// These are local wrappers around Keychain API +FBSDK_EXTERN OSStatus fbsdkdfl_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate); +FBSDK_EXTERN OSStatus fbsdkdfl_SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result); +FBSDK_EXTERN OSStatus fbsdkdfl_SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result); +FBSDK_EXTERN OSStatus fbsdkdfl_SecItemDelete(CFDictionaryRef query); + +#pragma mark - sqlite3 APIs + +// These are local wrappers around the corresponding sqlite3 method from /usr/include/sqlite3.h +FBSDK_EXTERN SQLITE_API const char *fbsdkdfl_sqlite3_errmsg(sqlite3 *db); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_reset(sqlite3_stmt *pStmt); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_finalize(sqlite3_stmt *pStmt); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_close(sqlite3 *db); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_double(sqlite3_stmt *stmt, int index, double value); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_int(sqlite3_stmt *stmt, int index, int value); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_text(sqlite3_stmt *stmt, int index, const char *value, int n, void(*callback)(void *)); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_step(sqlite3_stmt *stmt); +FBSDK_EXTERN SQLITE_API double fbsdkdfl_sqlite3_column_double(sqlite3_stmt *stmt, int iCol); +FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_column_int(sqlite3_stmt *stmt, int iCol); +FBSDK_EXTERN SQLITE_API const unsigned char *fbsdkdfl_sqlite3_column_text(sqlite3_stmt *stmt, int iCol); + +#pragma mark - Social Constants + +FBSDK_EXTERN NSString *fbsdkdfl_SLServiceTypeFacebook(void); + +#pragma mark - Social Classes + +FBSDK_EXTERN Class fbsdkdfl_SLComposeViewControllerClass(void); + +#pragma mark - QuartzCore Classes + +FBSDK_EXTERN Class fbsdkdfl_CATransactionClass(void); + +#pragma mark - QuartzCore APIs + +// These are local wrappers around the corresponding transform methods from QuartzCore.framework/CATransform3D.h +FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz); +FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz); +FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DConcat (CATransform3D a, CATransform3D b); + +FBSDK_EXTERN const CATransform3D fbsdkdfl_CATransform3DIdentity; + +#pragma mark - AudioToolbox APIs + +// These are local wrappers around the corresponding methods in AudioToolbox/AudioToolbox.h +FBSDK_EXTERN OSStatus fbsdkdfl_AudioServicesCreateSystemSoundID(CFURLRef inFileURL, SystemSoundID *outSystemSoundID); +FBSDK_EXTERN OSStatus fbsdkdfl_AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID); +FBSDK_EXTERN void fbsdkdfl_AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID); + +#pragma mark - AdSupport Classes + +FBSDK_EXTERN Class fbsdkdfl_ASIdentifierManagerClass(void); + +#pragma mark - SafariServices Classes + +FBSDK_EXTERN Class fbsdkdfl_SFSafariViewControllerClass(void); + +#pragma mark - Accounts Constants + +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAppIdKey(void); +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceEveryone(void); +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceFriends(void); +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceKey(void); +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceOnlyMe(void); +FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookPermissionsKey(void); + +#pragma mark - Accounts Classes + +FBSDK_EXTERN Class fbsdkdfl_ACAccountStoreClass(void); + +#pragma mark - StoreKit classes + +FBSDK_EXTERN Class fbsdkdfl_SKPaymentQueueClass(void); +FBSDK_EXTERN Class fbsdkdfl_SKProductsRequestClass(void); + +#pragma mark - AssetsLibrary Classes + +FBSDK_EXTERN Class fbsdkdfl_ALAssetsLibraryClass(void); + +#pragma mark - CoreTelephony Classes + +FBSDK_EXTERN Class fbsdkdfl_CTTelephonyNetworkInfoClass(void); diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.m new file mode 100644 index 0000000..1f01dfc --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.m @@ -0,0 +1,556 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKDynamicFrameworkLoader.h" + +#import + +#import +#import +#import + +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + +static NSString *const g_frameworkPathTemplate = @"/System/Library/Frameworks/%@.framework/%@"; +static NSString *const g_sqlitePath = @"/usr/lib/libsqlite3.dylib"; + +#pragma mark - Library and Symbol Loading + +struct FBSDKDFLLoadSymbolContext +{ + void *(*library)(void); // function to retrieve the library handle (it's a function instead of void * so it can be staticlly bound) + const char *name; // name of the symbol to retrieve + void **address; // [out] address of the symbol in the process address space +}; + +// Retrieves the handle for a library for framework. The paths for each are constructed +// differently so the loading function passed to dispatch_once() calls this. +static void *fbsdkdfl_load_library_once(const char *path) +{ + void *handle = dlopen(path, RTLD_LAZY); + if (handle) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorInformational formatString:@"Dynamically loaded library at %s", path]; + } else { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorInformational formatString:@"Failed to load library at %s", path]; + } + return handle; +} + +// Constructs the path for a system framework with the given name and returns the handle for dlsym +static void *fbsdkdfl_load_framework_once(NSString *framework) +{ + NSString *path = [NSString stringWithFormat:g_frameworkPathTemplate, framework, framework]; + return fbsdkdfl_load_library_once([path fileSystemRepresentation]); +} + +// Implements the callback for dispatch_once() that loads the handle for specified framework name +#define _fbsdkdfl_load_framework_once_impl_(FRAMEWORK) \ + static void fbsdkdfl_load_##FRAMEWORK##_once(void *context) { \ + *(void **)context = fbsdkdfl_load_framework_once(@#FRAMEWORK); \ + } + +// Implements the framework/library retrieval function for the given name. +// It calls the loading function once and caches the handle in a local static variable +#define _fbsdkdfl_handle_get_impl_(LIBRARY) \ + static void *fbsdkdfl_handle_get_##LIBRARY(void) { \ + static void *LIBRARY##_handle; \ + static dispatch_once_t LIBRARY##_once; \ + dispatch_once_f(&LIBRARY##_once, &LIBRARY##_handle, &fbsdkdfl_load_##LIBRARY##_once); \ + return LIBRARY##_handle;\ + } + +// Callback from dispatch_once() to load a specific symbol +static void fbsdkdfl_load_symbol_once(void *context) +{ + struct FBSDKDFLLoadSymbolContext *ctx = context; + *ctx->address = dlsym(ctx->library(), ctx->name); +} + +// The boilerplate code for loading a symbol from a given library once and caching it in a static local +#define _fbsdkdfl_symbol_get(LIBRARY, PREFIX, SYMBOL, TYPE, VARIABLE_NAME) \ + static TYPE VARIABLE_NAME; \ + static dispatch_once_t SYMBOL##_once; \ + static struct FBSDKDFLLoadSymbolContext ctx = { .library = &fbsdkdfl_handle_get_##LIBRARY, .name = PREFIX #SYMBOL, .address = (void **)&VARIABLE_NAME }; \ + dispatch_once_f(&SYMBOL##_once, &ctx, &fbsdkdfl_load_symbol_once) + +#define _fbsdkdfl_symbol_get_c(LIBRARY, SYMBOL) _fbsdkdfl_symbol_get(LIBRARY, "OBJC_CLASS_$_", SYMBOL, Class, c) // convenience symbol retrieval macro for getting an Objective-C class symbol and storing it in the local static c +#define _fbsdkdfl_symbol_get_f(LIBRARY, SYMBOL) _fbsdkdfl_symbol_get(LIBRARY, "", SYMBOL, SYMBOL##_type, f) // convenience symbol retrieval macro for getting a function pointer and storing it in the local static f +#define _fbsdkdfl_symbol_get_k(LIBRARY, SYMBOL, TYPE) _fbsdkdfl_symbol_get(LIBRARY, "", SYMBOL, TYPE, k) // convenience symbol retrieval macro for getting a pointer to a named variable and storing it in the local static k + +// convenience macro for verifying a pointer to a named variable was successfully loaded and returns the value +#define _fbsdkdfl_return_k(FRAMEWORK, SYMBOL) \ + NSCAssert(k != NULL, @"Failed to load constant %@ in the %@ framework", @#SYMBOL, @#FRAMEWORK); \ + return *k + +// convenience macro for getting a pointer to a named NSString, verifying it loaded correctly, and returning it +#define _fbsdkdfl_get_and_return_NSString(LIBRARY, SYMBOL) \ + _fbsdkdfl_symbol_get_k(LIBRARY, SYMBOL, NSString **); \ + NSCAssert([*k isKindOfClass:[NSString class]], @"Loaded symbol %@ is not of type NSString *", @#SYMBOL); \ + _fbsdkdfl_return_k(LIBRARY, SYMBOL) + +#pragma mark - Security Framework + +_fbsdkdfl_load_framework_once_impl_(Security) +_fbsdkdfl_handle_get_impl_(Security) + +#pragma mark - Security Constants + +@implementation FBSDKDynamicFrameworkLoader + +#define _fbsdkdfl_Security_get_k(SYMBOL) _fbsdkdfl_symbol_get_k(Security, SYMBOL, CFTypeRef *) + +#define _fbsdkdfl_Security_get_and_return_k(SYMBOL) \ + _fbsdkdfl_Security_get_k(SYMBOL); \ + _fbsdkdfl_return_k(Security, SYMBOL) + ++ (SecRandomRef)loadkSecRandomDefault +{ + _fbsdkdfl_symbol_get_k(Security, kSecRandomDefault, SecRandomRef *); + _fbsdkdfl_return_k(Security, kSecRandomDefault); +} + ++ (CFTypeRef)loadkSecAttrAccessible +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrAccessible); +} + ++ (CFTypeRef)loadkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly); +} + ++ (CFTypeRef)loadkSecAttrAccount +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrAccount); +} + ++ (CFTypeRef)loadkSecAttrService +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrService); +} + ++ (CFTypeRef)loadkSecAttrGeneric +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrGeneric); +} + ++ (CFTypeRef)loadkSecValueData +{ + _fbsdkdfl_Security_get_and_return_k(kSecValueData); +} + ++ (CFTypeRef)loadkSecClassGenericPassword +{ + _fbsdkdfl_Security_get_and_return_k(kSecClassGenericPassword); +} + ++ (CFTypeRef)loadkSecAttrAccessGroup +{ + _fbsdkdfl_Security_get_and_return_k(kSecAttrAccessGroup); +} + ++ (CFTypeRef)loadkSecMatchLimitOne +{ + _fbsdkdfl_Security_get_and_return_k(kSecMatchLimitOne); +} + ++ (CFTypeRef)loadkSecMatchLimit +{ + _fbsdkdfl_Security_get_and_return_k(kSecMatchLimit); +} + ++ (CFTypeRef)loadkSecReturnData +{ + _fbsdkdfl_Security_get_and_return_k(kSecReturnData); +} + ++ (CFTypeRef)loadkSecClass +{ + _fbsdkdfl_Security_get_and_return_k(kSecClass); +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end + +#pragma mark - Security APIs + +#define _fbsdkdfl_Security_get_f(SYMBOL) _fbsdkdfl_symbol_get_f(Security, SYMBOL) + +typedef int (*SecRandomCopyBytes_type)(SecRandomRef, size_t, uint8_t *); +typedef OSStatus (*SecItemUpdate_type)(CFDictionaryRef, CFDictionaryRef); +typedef OSStatus (*SecItemAdd_type)(CFDictionaryRef, CFTypeRef); +typedef OSStatus (*SecItemCopyMatching_type)(CFDictionaryRef, CFTypeRef); +typedef OSStatus (*SecItemDelete_type)(CFDictionaryRef); + +int fbsdkdfl_SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) +{ + _fbsdkdfl_Security_get_f(SecRandomCopyBytes); + return f(rnd, count, bytes); +} + +OSStatus fbsdkdfl_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) +{ + _fbsdkdfl_Security_get_f(SecItemUpdate); + return f(query, attributesToUpdate); +} + +OSStatus fbsdkdfl_SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) +{ + _fbsdkdfl_Security_get_f(SecItemAdd); + return f(attributes, result); +} + +OSStatus fbsdkdfl_SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) +{ + _fbsdkdfl_Security_get_f(SecItemCopyMatching); + return f(query, result); +} + +OSStatus fbsdkdfl_SecItemDelete(CFDictionaryRef query) +{ + _fbsdkdfl_Security_get_f(SecItemDelete); + return f(query); +} + +#pragma mark - sqlite3 APIs + +// sqlite3 is a dynamic library (not a framework) so its path is constructed differently +// than the way employed by the framework macros. +static void fbsdkdfl_load_sqlite3_once(void *context) +{ + *(void **)context = fbsdkdfl_load_library_once([g_sqlitePath fileSystemRepresentation]); +} +_fbsdkdfl_handle_get_impl_(sqlite3) + +#define _fbsdkdfl_sqlite3_get_f(SYMBOL) _fbsdkdfl_symbol_get_f(sqlite3, SYMBOL) + +typedef SQLITE_API const char *(*sqlite3_errmsg_type)(sqlite3 *); +typedef SQLITE_API int (*sqlite3_prepare_v2_type)(sqlite3 *, const char *, int, sqlite3_stmt **, const char **); +typedef SQLITE_API int (*sqlite3_reset_type)(sqlite3_stmt *); +typedef SQLITE_API int (*sqlite3_finalize_type)(sqlite3_stmt *); +typedef SQLITE_API int (*sqlite3_open_v2_type)(const char *, sqlite3 **, int, const char *); +typedef SQLITE_API int (*sqlite3_exec_type)(sqlite3 *, const char *, int (*)(void *, int, char **, char **), void *, char **); +typedef SQLITE_API int (*sqlite3_close_type)(sqlite3 *); +typedef SQLITE_API int (*sqlite3_bind_double_type)(sqlite3_stmt *, int, double); +typedef SQLITE_API int (*sqlite3_bind_int_type)(sqlite3_stmt *, int, int); +typedef SQLITE_API int (*sqlite3_bind_text_type)(sqlite3_stmt *, int, const char *, int, void(*)(void *)); +typedef SQLITE_API int (*sqlite3_step_type)(sqlite3_stmt *); +typedef SQLITE_API double (*sqlite3_column_double_type)(sqlite3_stmt *, int); +typedef SQLITE_API int (*sqlite3_column_int_type)(sqlite3_stmt *, int); +typedef SQLITE_API const unsigned char *(*sqlite3_column_text_type)(sqlite3_stmt *, int); + +SQLITE_API const char *fbsdkdfl_sqlite3_errmsg(sqlite3 *db) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_errmsg); + return f(db); +} + +SQLITE_API int fbsdkdfl_sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_prepare_v2); + return f(db, zSql, nByte, ppStmt, pzTail); +} + +SQLITE_API int fbsdkdfl_sqlite3_reset(sqlite3_stmt *pStmt) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_reset); + return f(pStmt); +} + +SQLITE_API int fbsdkdfl_sqlite3_finalize(sqlite3_stmt *pStmt) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_finalize); + return f(pStmt); +} + +SQLITE_API int fbsdkdfl_sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_open_v2); + return f(filename, ppDb, flags, zVfs); +} + +SQLITE_API int fbsdkdfl_sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_exec); + return f(db, sql, callback, arg, errmsg); +} + +SQLITE_API int fbsdkdfl_sqlite3_close(sqlite3 *db) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_close); + return f(db); +} + +SQLITE_API int fbsdkdfl_sqlite3_bind_double(sqlite3_stmt *stmt, int index , double value) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_bind_double); + return f(stmt, index, value); +} + +SQLITE_API int fbsdkdfl_sqlite3_bind_int(sqlite3_stmt *stmt, int index, int value) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_bind_int); + return f(stmt, index, value); +} + +SQLITE_API int fbsdkdfl_sqlite3_bind_text(sqlite3_stmt *stmt, int index, const char *value, int n, void(*callback)(void *)) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_bind_text); + return f(stmt, index, value, n, callback); +} + +SQLITE_API int fbsdkdfl_sqlite3_step(sqlite3_stmt *stmt) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_step); + return f(stmt); +} + +SQLITE_API double fbsdkdfl_sqlite3_column_double(sqlite3_stmt *stmt, int iCol) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_column_double); + return f(stmt, iCol); +} + +SQLITE_API int fbsdkdfl_sqlite3_column_int(sqlite3_stmt *stmt, int iCol) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_column_int); + return f(stmt, iCol); +} + +SQLITE_API const unsigned char *fbsdkdfl_sqlite3_column_text(sqlite3_stmt *stmt, int iCol) +{ + _fbsdkdfl_sqlite3_get_f(sqlite3_column_text); + return f(stmt, iCol); +} + +#pragma mark - Social Constants + +_fbsdkdfl_load_framework_once_impl_(Social) +_fbsdkdfl_handle_get_impl_(Social) + +#define _fbsdkdfl_Social_get_and_return_constant(SYMBOL) _fbsdkdfl_get_and_return_NSString(Social, SYMBOL) + +NSString *fbsdkdfl_SLServiceTypeFacebook(void) +{ + _fbsdkdfl_Social_get_and_return_constant(SLServiceTypeFacebook); +} + +#pragma mark - Social Classes + +#define _fbsdkdfl_Social_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(Social, SYMBOL) + +Class fbsdkdfl_SLComposeViewControllerClass(void) +{ + _fbsdkdfl_Social_get_c(SLComposeViewController); + return c; +} + +#pragma mark - QuartzCore Classes + +_fbsdkdfl_load_framework_once_impl_(QuartzCore) +_fbsdkdfl_handle_get_impl_(QuartzCore) + +#define _fbsdkdfl_QuartzCore_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(QuartzCore, SYMBOL); + +Class fbsdkdfl_CATransactionClass(void) +{ + _fbsdkdfl_QuartzCore_get_c(CATransaction); + return c; +} + +#pragma mark - QuartzCore APIs + +#define _fbsdkdfl_QuartzCore_get_f(SYMBOL) _fbsdkdfl_symbol_get_f(QuartzCore, SYMBOL) + +typedef CATransform3D (*CATransform3DMakeScale_type)(CGFloat, CGFloat, CGFloat); +typedef CATransform3D (*CATransform3DMakeTranslation_type)(CGFloat, CGFloat, CGFloat); +typedef CATransform3D (*CATransform3DConcat_type)(CATransform3D, CATransform3D); + +const CATransform3D fbsdkdfl_CATransform3DIdentity = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + +CATransform3D fbsdkdfl_CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) +{ + _fbsdkdfl_QuartzCore_get_f(CATransform3DMakeScale); + return f(sx, sy, sz); +} + +CATransform3D fbsdkdfl_CATransform3DMakeTranslation(CGFloat tx, CGFloat ty, CGFloat tz) +{ + _fbsdkdfl_QuartzCore_get_f(CATransform3DMakeTranslation); + return f(tx, ty, tz); +} + +CATransform3D fbsdkdfl_CATransform3DConcat(CATransform3D a, CATransform3D b) +{ + _fbsdkdfl_QuartzCore_get_f(CATransform3DConcat); + return f(a, b); +} + +#pragma mark - AudioToolbox APIs + +_fbsdkdfl_load_framework_once_impl_(AudioToolbox) +_fbsdkdfl_handle_get_impl_(AudioToolbox) + +#define _fbsdkdfl_AudioToolbox_get_f(SYMBOL) _fbsdkdfl_symbol_get_f(AudioToolbox, SYMBOL) + +typedef OSStatus (*AudioServicesCreateSystemSoundID_type)(CFURLRef, SystemSoundID *); +typedef OSStatus (*AudioServicesDisposeSystemSoundID_type)(SystemSoundID); +typedef void (*AudioServicesPlaySystemSound_type)(SystemSoundID); + +OSStatus fbsdkdfl_AudioServicesCreateSystemSoundID(CFURLRef inFileURL, SystemSoundID *outSystemSoundID) +{ + _fbsdkdfl_AudioToolbox_get_f(AudioServicesCreateSystemSoundID); + return f(inFileURL, outSystemSoundID); +} + +OSStatus fbsdkdfl_AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID) +{ + _fbsdkdfl_AudioToolbox_get_f(AudioServicesDisposeSystemSoundID); + return f(inSystemSoundID); +} + +void fbsdkdfl_AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID) +{ + _fbsdkdfl_AudioToolbox_get_f(AudioServicesPlaySystemSound); + return f(inSystemSoundID); +} + +#pragma mark - Ad Support Classes + +_fbsdkdfl_load_framework_once_impl_(AdSupport) +_fbsdkdfl_handle_get_impl_(AdSupport) + +#define _fbsdkdfl_AdSupport_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(AdSupport, SYMBOL); + +Class fbsdkdfl_ASIdentifierManagerClass(void) +{ + _fbsdkdfl_AdSupport_get_c(ASIdentifierManager); + return c; +} + +#pragma mark - Safari Services +_fbsdkdfl_load_framework_once_impl_(SafariServices) +_fbsdkdfl_handle_get_impl_(SafariServices) + +#define _fbsdkdfl_SafariServices_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(SafariServices, SYMBOL); + +Class fbsdkdfl_SFSafariViewControllerClass(void) +{ + _fbsdkdfl_SafariServices_get_c(SFSafariViewController); + return c; +} + +#pragma mark - Accounts Constants + +_fbsdkdfl_load_framework_once_impl_(Accounts) +_fbsdkdfl_handle_get_impl_(Accounts) + +#define _fbsdkdfl_Accounts_get_and_return_NSString(SYMBOL) _fbsdkdfl_get_and_return_NSString(Accounts, SYMBOL) + +NSString *fbsdkdfl_ACFacebookAppIdKey(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookAppIdKey); +} + +NSString *fbsdkdfl_ACFacebookAudienceEveryone(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookAudienceEveryone); +} + +NSString *fbsdkdfl_ACFacebookAudienceFriends(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookAudienceFriends); +} + +NSString *fbsdkdfl_ACFacebookAudienceKey(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookAudienceKey); +} + +NSString *fbsdkdfl_ACFacebookAudienceOnlyMe(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookAudienceOnlyMe); +} + +NSString *fbsdkdfl_ACFacebookPermissionsKey(void) +{ + _fbsdkdfl_Accounts_get_and_return_NSString(ACFacebookPermissionsKey); +} + +#pragma mark - Accounts Classes + +#define _fbsdkdfl_Accounts_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(Accounts, SYMBOL); + +Class fbsdkdfl_ACAccountStoreClass(void) +{ + _fbsdkdfl_Accounts_get_c(ACAccountStore); + return c; +} + +#pragma mark - StoreKit Classes + +_fbsdkdfl_load_framework_once_impl_(StoreKit) +_fbsdkdfl_handle_get_impl_(StoreKit) + +#define _fbsdkdfl_StoreKit_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(StoreKit, SYMBOL); + +Class fbsdkdfl_SKPaymentQueueClass(void) +{ + _fbsdkdfl_StoreKit_get_c(SKPaymentQueue); + return c; +} + +Class fbsdkdfl_SKProductsRequestClass(void) +{ + _fbsdkdfl_StoreKit_get_c(SKProductsRequest); + return c; +} + +#pragma mark - AssetsLibrary Classes + +_fbsdkdfl_load_framework_once_impl_(AssetsLibrary) +_fbsdkdfl_handle_get_impl_(AssetsLibrary) + +#define _fbsdkdfl_AssetsLibrary_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(AssetsLibrary, SYMBOL); + +Class fbsdkdfl_ALAssetsLibraryClass(void) +{ + _fbsdkdfl_AssetsLibrary_get_c(ALAssetsLibrary); + return c; +} + +#pragma mark - CoreTelephony Classes + +_fbsdkdfl_load_framework_once_impl_(CoreTelephony) +_fbsdkdfl_handle_get_impl_(CoreTelephony) + +#define _fbsdkdfl_CoreTelephonyLibrary_get_c(SYMBOL) _fbsdkdfl_symbol_get_c(CoreTelephony, SYMBOL); + +Class fbsdkdfl_CTTelephonyNetworkInfoClass(void) +{ + _fbsdkdfl_CoreTelephonyLibrary_get_c(CTTelephonyNetworkInfo); + return c; +} diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.h new file mode 100644 index 0000000..f37bd86 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKError : NSObject + ++ (NSString *)errorDomain; + ++ (BOOL)errorIsNetworkError:(NSError *)error; + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message; ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message underlyingError:(NSError *)underlyingError; ++ (NSError *)errorWithCode:(NSInteger)code + userInfo:(NSDictionary *)userInfo + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message; ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name + value:(id)value + message:(NSString *)message + underlyingError:(NSError *)underlyingError; ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message; ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name message:(NSString *)message; ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)unknownErrorWithMessage:(NSString *)message; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.m new file mode 100644 index 0000000..0a7b455 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.m @@ -0,0 +1,163 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKError.h" + +#import "FBSDKConstants.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKTypeUtility.h" + +@implementation FBSDKError + +#pragma mark - Class Methods + ++ (NSString *)errorDomain +{ + return FBSDKErrorDomain; +} + ++ (BOOL)errorIsNetworkError:(NSError *)error +{ + if (error == nil) { + return NO; + } + + NSError *innerError = error.userInfo[NSUnderlyingErrorKey]; + if ([self errorIsNetworkError:innerError]) { + return YES; + } + + switch (error.code) { + case NSURLErrorTimedOut: + case NSURLErrorCannotFindHost: + case NSURLErrorCannotConnectToHost: + case NSURLErrorNetworkConnectionLost: + case NSURLErrorDNSLookupFailed: + case NSURLErrorNotConnectedToInternet: + case NSURLErrorInternationalRoamingOff: + case NSURLErrorCallIsActive: + case NSURLErrorDataNotAllowed: + return YES; + default: + return NO; + } +} + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message +{ + return [self errorWithCode:code message:message underlyingError:nil]; +} + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message underlyingError:(NSError *)underlyingError +{ + return [self errorWithCode:code userInfo:nil message:message underlyingError:underlyingError]; +} + ++ (NSError *)errorWithCode:(NSInteger)code + userInfo:(NSDictionary *)userInfo + message:(NSString *)message + underlyingError:(NSError *)underlyingError +{ + NSMutableDictionary *fullUserInfo = [[NSMutableDictionary alloc] initWithDictionary:userInfo]; + [FBSDKInternalUtility dictionary:fullUserInfo setObject:message forKey:FBSDKErrorDeveloperMessageKey]; + [FBSDKInternalUtility dictionary:fullUserInfo setObject:underlyingError forKey:NSUnderlyingErrorKey]; + userInfo = ([fullUserInfo count] ? [fullUserInfo copy] : nil); + return [[NSError alloc] initWithDomain:[self errorDomain] code:code userInfo:userInfo]; +} + ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message +{ + return [self invalidArgumentErrorWithName:name value:value message:message underlyingError:nil]; +} + ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name + value:(id)value + message:(NSString *)message + underlyingError:(NSError *)underlyingError +{ + if (!message) { + message = [[NSString alloc] initWithFormat:@"Invalid value for %@: %@", name, value]; + } + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:userInfo setObject:name forKey:FBSDKErrorArgumentNameKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:value forKey:FBSDKErrorArgumentValueKey]; + return [self errorWithCode:FBSDKInvalidArgumentErrorCode + userInfo:userInfo + message:message + underlyingError:underlyingError]; +} + ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message +{ + return [self invalidCollectionErrorWithName:name collection:collection item:item message:message underlyingError:nil]; +} + ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message + underlyingError:(NSError *)underlyingError +{ + if (!message) { + message = [[NSString alloc] initWithFormat:@"Invalid item (%@) found in collection for %@: %@", item, name, collection]; + } + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:userInfo setObject:name forKey:FBSDKErrorArgumentNameKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:item forKey:FBSDKErrorArgumentValueKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:collection forKey:FBSDKErrorArgumentCollectionKey]; + return [self errorWithCode:FBSDKInvalidArgumentErrorCode + userInfo:userInfo + message:message + underlyingError:underlyingError]; +} + ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name message:(NSString *)message +{ + return [self requiredArgumentErrorWithName:name message:message underlyingError:nil]; +} + ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name + message:(NSString *)message + underlyingError:(NSError *)underlyingError +{ + if (!message) { + message = [[NSString alloc] initWithFormat:@"Value for %@ is required.", name]; + } + return [self invalidArgumentErrorWithName:name value:nil message:message underlyingError:underlyingError]; +} + ++ (NSError *)unknownErrorWithMessage:(NSString *)message +{ + return [self errorWithCode:FBSDKUnknownErrorCode + userInfo:nil + message:message + underlyingError:nil]; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.h new file mode 100644 index 0000000..71e4445 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.h @@ -0,0 +1,321 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#define FBSDK_CANOPENURL_FACEBOOK @"fbauth2" +#define FBSDK_CANOPENURL_MESSENGER @"fb-messenger-api" + +typedef NS_ENUM(int32_t, FBSDKUIKitVersion) +{ + FBSDKUIKitVersion_6_0 = 0x0944, + FBSDKUIKitVersion_6_1 = 0x094C, + FBSDKUIKitVersion_7_0 = 0x0B57, + FBSDKUIKitVersion_7_1 = 0x0B77, + FBSDKUIKitVersion_8_0 = 0x0CF6, +}; + +@interface FBSDKInternalUtility : NSObject + +/*! + @abstract Constructs the scheme for apps that come to the current app through the bridge. + */ ++ (NSString *)appURLScheme; + +/*! + @abstract Constructs an URL for the current app. + @param host The host for the URL. + @param path The path for the URL. + @param queryParameters The query parameters for the URL. This will be converted into a query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return The app URL. + */ ++ (NSURL *)appURLWithHost:(NSString *)host + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Parses an FB url's query params (and potentially fragment) into a dictionary. + @param url The FB url. + @return A dictionary with the key/value pairs. + */ ++ (NSDictionary *)dictionaryFromFBURL:(NSURL *)url; + +/*! + @abstract Adds an object to an array if it is not nil. + @param array The array to add the object to. + @param object The object to add to the array. + */ ++ (void)array:(NSMutableArray *)array addObject:(id)object; + +/*! + @abstract Returns bundle for returning localized strings + @discussion We assume a convention of a bundle named FBSDKStrings.bundle, otherwise we + return the main bundle. +*/ ++ (NSBundle *)bundleForStrings; + +/*! + @abstract Converts simple value types to the string equivelant for serializing to a request query or body. + @param value The value to be converted. + @return The value that may have been converted if able (otherwise the input param). + */ ++ (id)convertRequestValue:(id)value; + +/*! + @abstract Gets the milliseconds since the Unix Epoch. + @discussion Changes in the system clock will affect this value. + @return The number of milliseconds since the Unix Epoch. + */ ++ (unsigned long)currentTimeInMilliseconds; + +/*! + @abstract Sets an object for a key in a dictionary if it is not nil. + @param dictionary The dictionary to set the value for. + @param object The value to set after serializing to JSON. + @param key The key to set the value for. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return NO if an error occurred while serializing the object, otherwise YES. + */ ++ (BOOL)dictionary:(NSMutableDictionary *)dictionary +setJSONStringForObject:(id)object + forKey:(id)key + error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Sets an object for a key in a dictionary if it is not nil. + @param dictionary The dictionary to set the value for. + @param object The value to set. + @param key The key to set the value for. + */ ++ (void)dictionary:(NSMutableDictionary *)dictionary setObject:(id)object forKey:(id)key; + +/*! + @abstract Constructs a Facebook URL. + @param hostPrefix The prefix for the host, such as 'm', 'graph', etc. + @param path The path for the URL. This may or may not include a version. + @param queryParameters The query parameters for the URL. This will be converted into a query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return The Facebook URL. + */ ++ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Constructs a Facebook URL. + @param hostPrefix The prefix for the host, such as 'm', 'graph', etc. + @param path The path for the URL. This may or may not include a version. + @param queryParameters The query parameters for the URL. This will be converted into a query string. + @param defaultVersion A version to add to the URL if none is found in the path. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return The Facebook URL. + */ ++ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + defaultVersion:(NSString *)defaultVersion + error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Tests whether the supplied URL is a valid URL for opening in the browser. + @param URL The URL to test. + @return YES if the URL refers to an http or https resource, otherwise NO. + */ ++ (BOOL)isBrowserURL:(NSURL *)URL; + +/*! + @abstract Tests whether the supplied bundle identifier references a Facebook app. + @param bundleIdentifier The bundle identifier to test. + @return YES if the bundle identifier refers to a Facebook app, otherwise NO. + */ ++ (BOOL)isFacebookBundleIdentifier:(NSString *)bundleIdentifier; + +/*! + @abstract Tests whether the operating system is at least the specified version. + @param version The version to test against. + @return YES if the operating system is greater than or equal to the specified version, otherwise NO. + */ ++ (BOOL)isOSRunTimeVersionAtLeast:(NSOperatingSystemVersion)version; + +/*! + @abstract Tests whether the supplied bundle identifier references the Safari app. + @param bundleIdentifier The bundle identifier to test. + @return YES if the bundle identifier refers to the Safari app, otherwise NO. + */ ++ (BOOL)isSafariBundleIdentifier:(NSString *)bundleIdentifier; + +/*! + @abstract Tests whether the UIKit version that the current app was linked to is at least the specified version. + @param version The version to test against. + @return YES if the linked UIKit version is greater than or equal to the specified version, otherwise NO. + */ ++ (BOOL)isUIKitLinkTimeVersionAtLeast:(FBSDKUIKitVersion)version; + +/*! + @abstract Tests whether the UIKit version in the runtime is at least the specified version. + @param version The version to test against. + @return YES if the runtime UIKit version is greater than or equal to the specified version, otherwise NO. + */ ++ (BOOL)isUIKitRunTimeVersionAtLeast:(FBSDKUIKitVersion)version; + +/*! + @abstract Converts an object into a JSON string. + @param object The object to convert to JSON. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @param invalidObjectHandler Handles objects that are invalid, returning a replacement value or nil to ignore. + @return A JSON string or nil if the object cannot be converted to JSON. + */ ++ (NSString *)JSONStringForObject:(id)object + error:(NSError *__autoreleasing *)errorRef + invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler; + +/*! + @abstract Checks equality between 2 objects. + @discussion Checks for pointer equality, nils, isEqual:. + @param object The first object to compare. + @param other The second object to compare. + @result YES if the objects are equal, otherwise NO. + */ ++ (BOOL)object:(id)object isEqualToObject:(id)other; + +/*! + @abstract Converts a JSON string into an object + @param string The JSON string to convert. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return An NSDictionary, NSArray, NSString or NSNumber containing the object representation, or nil if the string + cannot be converted. + */ ++ (id)objectForJSONString:(NSString *)string error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract The version of the operating system on which the process is executing. + */ ++ (NSOperatingSystemVersion)operatingSystemVersion; + +/*! + @abstract Constructs a query string from a dictionary. + @param dictionary The dictionary with key/value pairs for the query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @param invalidObjectHandler Handles objects that are invalid, returning a replacement value or nil to ignore. + @result Query string representation of the parameters. + */ ++ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary + error:(NSError *__autoreleasing *)errorRef + invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler; + +/*! + @abstract Tests whether the orientation should be manually adjusted for views outside of the root view controller. + @discussion With the legacy layout the developer must worry about device orientation when working with views outside of + the window's root view controller and apply the correct rotation transform and/or swap a view's width and height + values. If the application was linked with UIKit on iOS 7 or earlier or the application is running on iOS 7 or earlier + then we need to use the legacy layout code. Otherwise if the application was linked with UIKit on iOS 8 or later and + the application is running on iOS 8 or later, UIKit handles all of the rotation complexity and the origin is always in + the top-left and no rotation transform is necessary. + @return YES if if the orientation must be manually adjusted, otherwise NO. + */ ++ (BOOL)shouldManuallyAdjustOrientation; + +/*! + @abstract Constructs an NSURL. + @param scheme The scheme for the URL. + @param host The host for the URL. + @param path The path for the URL. + @param queryParameters The query parameters for the URL. This will be converted into a query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return The URL. + */ ++ (NSURL *)URLWithScheme:(NSString *)scheme + host:(NSString *)host + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef; + +/*! + * @abstract Deletes all the cookies in the NSHTTPCookieStorage for Facebook web dialogs + */ ++ (void)deleteFacebookCookies; + +/*! + @abstract Extracts permissions from a response fetched from me/permissions + @param responseObject the response + @param grantedPermissions the set to add granted permissions to + @param declinedPermissions the set to add decliend permissions to. + */ ++ (void)extractPermissionsFromResponse:(NSDictionary *)responseObject + grantedPermissions:(NSMutableSet *)grantedPermissions + declinedPermissions:(NSMutableSet *)declinedPermissions; + +/*! + @abstract Registers a transient object so that it will not be deallocated until unregistered + @param object The transient object + */ ++ (void)registerTransientObject:(id)object; + +/*! + @abstract Unregisters a transient object that was previously registered with registerTransientObject: + @param object The transient object + */ ++ (void)unregisterTransientObject:(__weak id)object; + +/*! + @abstract validates that the app ID is non-nil, throws an NSException if nil. + */ ++ (void)validateAppID; + +/*! + @abstract validates that the right URL schemes are registered, throws an NSException if not. + */ ++ (void)validateURLSchemes; + +/*! + @abstract Attempts to find the first UIViewController in the view's responder chain. Returns nil if not found. + */ ++ (UIViewController *)viewControllerforView:(UIView*)view; + +/*! + @abstract returns true if the url scheme is registered in the CFBundleURLTypes + */ ++ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme; + +/*! + @abstract returns currently displayed top view controller. + */ ++ (UIViewController *)topMostViewController; + +#pragma mark - FB Apps Installed + ++ (BOOL)isFacebookAppInstalled; ++ (BOOL)isMessengerAppInstalled; ++ (void)checkRegisteredCanOpenURLScheme:(NSString *)urlScheme; ++ (BOOL)isRegisteredCanOpenURLScheme:(NSString *)urlScheme; + +#define FBSDKConditionalLog(condition, loggingBehavior, desc, ...) \ +{ \ + if (!(condition)) { \ + NSString *msg = [NSString stringWithFormat:(desc), ##__VA_ARGS__]; \ + [FBSDKLogger singleShotLogEntry:loggingBehavior logEntry:msg]; \ + } \ +} + +#define FB_BASE_URL @"facebook.com" + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m new file mode 100644 index 0000000..7f0db81 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m @@ -0,0 +1,666 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKInternalUtility.h" + +#import + +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKError.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" +#import "FBSDKUtility.h" + +typedef NS_ENUM(NSUInteger, FBSDKInternalUtilityVersionMask) +{ + FBSDKInternalUtilityMajorVersionMask = 0xFFFF0000, + //FBSDKInternalUtilityMinorVersionMask = 0x0000FF00, // unused + //FBSDKInternalUtilityPatchVersionMask = 0x000000FF, // unused +}; + +typedef NS_ENUM(NSUInteger, FBSDKInternalUtilityVersionShift) +{ + FBSDKInternalUtilityMajorVersionShift = 16, + //FBSDKInternalUtilityMinorVersionShift = 8, // unused + //FBSDKInternalUtilityPatchVersionShift = 0, // unused +}; + +@implementation FBSDKInternalUtility + +#pragma mark - Class Methods + ++ (NSString *)appURLScheme +{ + NSString *appID = ([FBSDKSettings appID] ?: @""); + NSString *suffix = ([FBSDKSettings appURLSchemeSuffix] ?: @""); + return [[NSString alloc] initWithFormat: @"fb%@%@", appID, suffix]; +} + ++ (NSURL *)appURLWithHost:(NSString *)host + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef +{ + return [self URLWithScheme:[self appURLScheme] + host:host + path:path + queryParameters:queryParameters + error:errorRef]; +} + ++ (NSDictionary *)dictionaryFromFBURL:(NSURL *)url +{ + // version 3.2.3 of the Facebook app encodes the parameters in the query but + // version 3.3 and above encode the parameters in the fragment; + // merge them together with fragment taking priority. + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + [params addEntriesFromDictionary:[FBSDKUtility dictionaryWithQueryString:url.query]]; + + // Only get the params from the fragment if it has authorize as the host + if ([url.host isEqualToString:@"authorize"]) { + [params addEntriesFromDictionary:[FBSDKUtility dictionaryWithQueryString:url.fragment]]; + } + return params; +} + ++ (void)array:(NSMutableArray *)array addObject:(id)object +{ + if (object) { + [array addObject:object]; + } +} + ++ (NSBundle *)bundleForStrings +{ + static NSBundle *bundle; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *stringsBundlePath = [[NSBundle mainBundle] pathForResource:@"FacebookSDKStrings" + ofType:@"bundle"]; + bundle = [NSBundle bundleWithPath:stringsBundlePath] ?: [NSBundle mainBundle]; + }); + return bundle; +} + ++ (id)convertRequestValue:(id)value +{ + if ([value isKindOfClass:[NSNumber class]]) { + value = [(NSNumber *)value stringValue]; + } else if ([value isKindOfClass:[NSURL class]]) { + value = [(NSURL *)value absoluteString]; + } + return value; +} + ++ (unsigned long)currentTimeInMilliseconds +{ + struct timeval time; + gettimeofday(&time, NULL); + return (time.tv_sec * 1000) + (time.tv_usec / 1000); +} + ++ (BOOL)dictionary:(NSMutableDictionary *)dictionary +setJSONStringForObject:(id)object + forKey:(id)key + error:(NSError *__autoreleasing *)errorRef +{ + if (!object || !key) { + return YES; + } + NSString *JSONString = [self JSONStringForObject:object error:errorRef invalidObjectHandler:NULL]; + if (!JSONString) { + return NO; + } + [self dictionary:dictionary setObject:JSONString forKey:key]; + return YES; +} + ++ (void)dictionary:(NSMutableDictionary *)dictionary setObject:(id)object forKey:(id)key +{ + if (object && key) { + [dictionary setObject:object forKey:key]; + } +} + ++ (void)extractPermissionsFromResponse:(NSDictionary *)responseObject + grantedPermissions:(NSMutableSet *)grantedPermissions + declinedPermissions:(NSMutableSet *)declinedPermissions +{ + NSArray *resultData = responseObject[@"data"]; + if (resultData.count > 0) { + for (NSDictionary *permissionsDictionary in resultData) { + NSString *permissionName = permissionsDictionary[@"permission"]; + NSString *status = permissionsDictionary[@"status"]; + + if ([status isEqualToString:@"granted"]) { + [grantedPermissions addObject:permissionName]; + } else if ([status isEqualToString:@"declined"]) { + [declinedPermissions addObject:permissionName]; + } + } + } +} + ++ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef +{ + return [self facebookURLWithHostPrefix:hostPrefix + path:path + queryParameters:queryParameters + defaultVersion:nil + error:errorRef]; +} + ++ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + defaultVersion:(NSString *)defaultVersion + error:(NSError *__autoreleasing *)errorRef +{ + if ([hostPrefix length] && ![hostPrefix hasSuffix:@"."]) { + hostPrefix = [hostPrefix stringByAppendingString:@"."]; + } + + NSString *host = @"facebook.com"; + NSString *domainPart = [FBSDKSettings facebookDomainPart]; + if ([domainPart length]) { + host = [[NSString alloc] initWithFormat:@"%@.%@", domainPart, host]; + } + host = [NSString stringWithFormat:@"%@%@", hostPrefix ?: @"", host ?: @""]; + + NSString *version = defaultVersion ?: FBSDK_TARGET_PLATFORM_VERSION; + if ([version length]) { + version = [@"/" stringByAppendingString:version]; + } + + if ([path length]) { + NSScanner *versionScanner = [[NSScanner alloc] initWithString:path]; + if ([versionScanner scanString:@"/v" intoString:NULL] && + [versionScanner scanInteger:NULL] && + [versionScanner scanString:@"." intoString:NULL] && + [versionScanner scanInteger:NULL]) { + version = nil; + } + if (![path hasPrefix:@"/"]) { + path = [@"/" stringByAppendingString:path]; + } + } + path = [[NSString alloc] initWithFormat:@"%@%@", version ?: @"", path ?: @""]; + + return [self URLWithScheme:@"https" + host:host + path:path + queryParameters:queryParameters + error:errorRef]; +} + ++ (BOOL)isBrowserURL:(NSURL *)URL +{ + NSString *scheme = [URL.scheme lowercaseString]; + return ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]); +} + ++ (BOOL)isFacebookBundleIdentifier:(NSString *)bundleIdentifier +{ + return ([bundleIdentifier hasPrefix:@"com.facebook."] || + [bundleIdentifier hasPrefix:@".com.facebook."]); +} + ++ (BOOL)isOSRunTimeVersionAtLeast:(NSOperatingSystemVersion)version +{ + return ([self _compareOperatingSystemVersion:[self operatingSystemVersion] toVersion:version] != NSOrderedAscending); +} + ++ (BOOL)isSafariBundleIdentifier:(NSString *)bundleIdentifier +{ + return ([bundleIdentifier isEqualToString:@"com.apple.mobilesafari"] || + [bundleIdentifier isEqualToString:@"com.apple.SafariViewService"]); +} + ++ (BOOL)isUIKitLinkTimeVersionAtLeast:(FBSDKUIKitVersion)version +{ + static int32_t linkTimeMajorVersion; + static dispatch_once_t getVersionOnce; + dispatch_once(&getVersionOnce, ^{ + int32_t linkTimeVersion = NSVersionOfLinkTimeLibrary("UIKit"); + linkTimeMajorVersion = ((MAX(linkTimeVersion, 0) & FBSDKInternalUtilityMajorVersionMask) >> FBSDKInternalUtilityMajorVersionShift); + }); + return (version <= linkTimeMajorVersion); +} + ++ (BOOL)isUIKitRunTimeVersionAtLeast:(FBSDKUIKitVersion)version +{ + static int32_t runTimeMajorVersion; + static dispatch_once_t getVersionOnce; + dispatch_once(&getVersionOnce, ^{ + int32_t runTimeVersion = NSVersionOfRunTimeLibrary("UIKit"); + runTimeMajorVersion = ((MAX(runTimeVersion, 0) & FBSDKInternalUtilityMajorVersionMask) >> FBSDKInternalUtilityMajorVersionShift); + }); + return (version <= runTimeMajorVersion); +} + ++ (NSString *)JSONStringForObject:(id)object + error:(NSError *__autoreleasing *)errorRef + invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler +{ + if (invalidObjectHandler || ![NSJSONSerialization isValidJSONObject:object]) { + object = [self _convertObjectToJSONObject:object invalidObjectHandler:invalidObjectHandler stop:NULL]; + if (![NSJSONSerialization isValidJSONObject:object]) { + if (errorRef != NULL) { + *errorRef = [FBSDKError invalidArgumentErrorWithName:@"object" + value:object + message:@"Invalid object for JSON serialization."]; + } + return nil; + } + } + NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:errorRef]; + if (!data) { + return nil; + } + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + ++ (BOOL)object:(id)object isEqualToObject:(id)other; +{ + if (object == other) { + return YES; + } + if (!object || !other) { + return NO; + } + return [object isEqual:other]; +} + ++ (id)objectForJSONString:(NSString *)string error:(NSError *__autoreleasing *)errorRef +{ + NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; + if (!data) { + if (errorRef != NULL) { + *errorRef = nil; + } + return nil; + } + return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:errorRef]; +} + ++ (NSOperatingSystemVersion)operatingSystemVersion +{ + static NSOperatingSystemVersion operatingSystemVersion = { + .majorVersion = 0, + .minorVersion = 0, + .patchVersion = 0, + }; + static dispatch_once_t getVersionOnce; + dispatch_once(&getVersionOnce, ^{ + if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { + operatingSystemVersion = [NSProcessInfo processInfo].operatingSystemVersion; + } else { + NSArray *components = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."]; + switch (components.count) { + default: + case 3: + operatingSystemVersion.patchVersion = [components[2] integerValue]; + // fall through + case 2: + operatingSystemVersion.minorVersion = [components[1] integerValue]; + // fall through + case 1: + operatingSystemVersion.majorVersion = [components[0] integerValue]; + break; + case 0: + operatingSystemVersion.majorVersion = ([self isUIKitLinkTimeVersionAtLeast:FBSDKUIKitVersion_7_0] ? 7 : 6); + break; + } + } + }); + return operatingSystemVersion; +} + ++ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary + error:(NSError *__autoreleasing *)errorRef + invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler +{ + NSMutableString *queryString = [[NSMutableString alloc] init]; + __block BOOL hasParameters = NO; + if (dictionary) { + NSMutableArray *keys = [[dictionary allKeys] mutableCopy]; + // remove non-string keys, as they are not valid + [keys filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [evaluatedObject isKindOfClass:[NSString class]]; + }]]; + // sort the keys so that the query string order is deterministic + [keys sortUsingSelector:@selector(compare:)]; + BOOL stop = NO; + for (NSString *key in keys) { + id value = [self convertRequestValue:dictionary[key]]; + if ([value isKindOfClass:[NSString class]]) { + value = [FBSDKUtility URLEncode:value]; + } + if (invalidObjectHandler && ![value isKindOfClass:[NSString class]]) { + value = invalidObjectHandler(value, &stop); + if (stop) { + break; + } + } + if (value) { + if (hasParameters) { + [queryString appendString:@"&"]; + } + [queryString appendFormat:@"%@=%@", key, value]; + hasParameters = YES; + } + } + } + if (errorRef != NULL) { + *errorRef = nil; + } + return ([queryString length] ? [queryString copy] : nil); +} + ++ (BOOL)shouldManuallyAdjustOrientation +{ + return (![self isUIKitLinkTimeVersionAtLeast:FBSDKUIKitVersion_8_0] || + ![self isUIKitRunTimeVersionAtLeast:FBSDKUIKitVersion_8_0]); +} + ++ (NSURL *)URLWithScheme:(NSString *)scheme + host:(NSString *)host + path:(NSString *)path + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef +{ + if (![path hasPrefix:@"/"]) { + path = [@"/" stringByAppendingString:path ?: @""]; + } + + NSString *queryString = nil; + if ([queryParameters count]) { + NSError *queryStringError; + queryString = [@"?" stringByAppendingString:[FBSDKUtility queryStringWithDictionary:queryParameters + error:&queryStringError]]; + if (!queryString) { + if (errorRef != NULL) { + *errorRef = [FBSDKError invalidArgumentErrorWithName:@"queryParameters" + value:queryParameters + message:nil + underlyingError:queryStringError]; + } + return nil; + } + } + + NSURL *URL = [[NSURL alloc] initWithString:[NSString stringWithFormat: + @"%@://%@%@%@", + scheme ?: @"", + host ?: @"", + path ?: @"", + queryString ?: @""]]; + if (errorRef != NULL) { + if (URL) { + *errorRef = nil; + } else { + *errorRef = [FBSDKError unknownErrorWithMessage:@"Unknown error building URL."]; + } + } + return URL; +} + ++ (void)deleteFacebookCookies +{ + NSHTTPCookieStorage *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray *facebookCookies = [cookies cookiesForURL:[self facebookURLWithHostPrefix:@"m." + path:@"/dialog/" + queryParameters:nil + error:NULL]]; + + for (NSHTTPCookie *cookie in facebookCookies) { + [cookies deleteCookie:cookie]; + } +} + +static NSMapTable *_transientObjects; + ++ (void)registerTransientObject:(id)object +{ + NSAssert([NSThread isMainThread], @"Must be called from the main thread!"); + if (!_transientObjects) { + _transientObjects = [[NSMapTable alloc] init]; + } + NSUInteger count = [(NSNumber *)[_transientObjects objectForKey:object] unsignedIntegerValue]; + [_transientObjects setObject:@(count + 1) forKey:object]; +} + ++ (void)unregisterTransientObject:(__weak id)object +{ + if (!object) { + return; + } + NSAssert([NSThread isMainThread], @"Must be called from the main thread!"); + NSUInteger count = [(NSNumber *)[_transientObjects objectForKey:object] unsignedIntegerValue]; + if (count == 1) { + [_transientObjects removeObjectForKey:object]; + } else if (count != 0) { + [_transientObjects setObject:@(count - 1) forKey:object]; + } else { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"unregisterTransientObject:%@ count is 0. This may indicate a bug in the FBSDK. Please" + " file a report to developers.facebook.com/bugs if you encounter any problems. Thanks!", [object class]]; + } +} + ++ (UIViewController *)viewControllerforView:(UIView*)view +{ + UIResponder *responder = view.nextResponder; + while (responder) { + if ([responder isKindOfClass:[UIViewController class]]) { + return (UIViewController *)responder; + } + responder = responder.nextResponder; + } + return nil; +} + +#pragma mark - FB Apps Installed + ++ (BOOL)isFacebookAppInstalled +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK]; + }); + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = FBSDK_CANOPENURL_FACEBOOK; + components.path = @"/"; + return [[UIApplication sharedApplication] + canOpenURL:components.URL]; +} + ++ (BOOL)isMessengerAppInstalled +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_MESSENGER]; + }); + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = FBSDK_CANOPENURL_MESSENGER; + components.path = @"/"; + return [[UIApplication sharedApplication] + canOpenURL:components.URL]; + +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +#pragma mark - Helper Methods + ++ (NSComparisonResult)_compareOperatingSystemVersion:(NSOperatingSystemVersion)version1 + toVersion:(NSOperatingSystemVersion)version2 +{ + if (version1.majorVersion < version2.majorVersion) { + return NSOrderedAscending; + } else if (version1.majorVersion > version2.majorVersion) { + return NSOrderedDescending; + } else if (version1.minorVersion < version2.minorVersion) { + return NSOrderedAscending; + } else if (version1.minorVersion > version2.minorVersion) { + return NSOrderedDescending; + } else if (version1.patchVersion < version2.patchVersion) { + return NSOrderedAscending; + } else if (version1.patchVersion > version2.patchVersion) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } +} + ++ (id)_convertObjectToJSONObject:(id)object + invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler + stop:(BOOL *)stopRef +{ + __block BOOL stop = NO; + if ([object isKindOfClass:[NSString class]] || [object isKindOfClass:[NSNumber class]]) { + // good to go, keep the object + } else if ([object isKindOfClass:[NSURL class]]) { + object = [(NSURL *)object absoluteString]; + } else if ([object isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + [(NSDictionary *)object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *dictionaryStop) { + [self dictionary:dictionary + setObject:[self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop] + forKey:[FBSDKTypeUtility stringValue:key]]; + if (stop) { + *dictionaryStop = YES; + } + }]; + object = dictionary; + } else if ([object isKindOfClass:[NSArray class]]) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + for (id obj in (NSArray *)object) { + id convertedObj = [self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop]; + [self array:array addObject:convertedObj]; + if (stop) { + break; + } + } + object = array; + } else { + object = invalidObjectHandler(object, stopRef); + } + if (stopRef != NULL) { + *stopRef = stop; + } + return object; +} + ++ (void)validateAppID +{ + if (![FBSDKSettings appID]) { + NSString *reason = @"App ID not found. Add a string value with your app ID for the key " + @"FacebookAppID to the Info.plist or call [FBSDKSettings setAppID:]."; + @throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil]; + } +} + ++ (void)validateURLSchemes +{ + [self validateAppID]; + NSString *defaultUrlScheme = [NSString stringWithFormat:@"fb%@%@", [FBSDKSettings appID], [FBSDKSettings appURLSchemeSuffix] ?: @""]; + if (![self isRegisteredURLScheme:defaultUrlScheme]) { + NSString *reason = [NSString stringWithFormat:@"%@ is not registered as a URL scheme. Please add it in your Info.plist", defaultUrlScheme]; + @throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil]; + } +} + + ++ (UIViewController *)topMostViewController +{ + UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; + while (topController.presentedViewController) { + topController = topController.presentedViewController; + } + return topController; +} + + ++ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme { + static dispatch_once_t fetchBundleOnce; + static NSArray *urlTypes = nil; + + dispatch_once(&fetchBundleOnce, ^{ + urlTypes = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleURLTypes"]; + }); + for (NSDictionary *urlType in urlTypes) { + NSArray *urlSchemes = [urlType valueForKey:@"CFBundleURLSchemes"]; + if ([urlSchemes containsObject:urlScheme]) { + return YES; + } + } + return NO; +} + ++ (void)checkRegisteredCanOpenURLScheme:(NSString *)urlScheme +{ + static dispatch_once_t initCheckedSchemesOnce; + static NSMutableSet *checkedSchemes = nil; + + dispatch_once(&initCheckedSchemesOnce, ^{ + checkedSchemes = [NSMutableSet set]; + }); + + @synchronized(self) { + if ([checkedSchemes containsObject:urlScheme]) { + return; + } else { + [checkedSchemes addObject:urlScheme]; + } + } + + if (![self isRegisteredCanOpenURLScheme:urlScheme]){ + NSString *reason = [NSString stringWithFormat:@"%@ is missing from your Info.plist under LSApplicationQueriesSchemes and is required for iOS 9.0", urlScheme]; +#ifdef __IPHONE_9_0 + @throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil]; +#else + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:reason]; +#endif + } +} + ++ (BOOL)isRegisteredCanOpenURLScheme:(NSString *)urlScheme +{ + static dispatch_once_t fetchBundleOnce; + static NSArray *schemes = nil; + + dispatch_once(&fetchBundleOnce, ^{ + schemes = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"LSApplicationQueriesSchemes"]; + }); + + return [schemes containsObject:urlScheme]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.h new file mode 100644 index 0000000..d00dea6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.h @@ -0,0 +1,88 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @class FBSDKLogger + + @abstract + Simple logging utility for conditionally logging strings and then emitting them + via NSLog(). + + @unsorted + */ +@interface FBSDKLogger : NSObject + +// Access current accumulated contents of the logger. +@property (copy, nonatomic) NSString *contents; + +// Each FBSDKLogger gets a unique serial number to allow the client to log these numbers and, for instance, correlation of Request/Response +@property (nonatomic, readonly) NSUInteger loggerSerialNumber; + +// The logging behavior of this logger. See the FB_LOG_BEHAVIOR* constants in FBSession.h +@property (copy, nonatomic, readonly) NSString *loggingBehavior; + +// Is the current logger instance active, based on its loggingBehavior? +@property (nonatomic, readonly) BOOL isActive; + +// +// Instance methods +// + +// Create with specified logging behavior +- (instancetype)initWithLoggingBehavior:(NSString *)loggingBehavior; + +// Append string, or key/value pair +- (void)appendString:(NSString *)string; +- (void)appendFormat:(NSString *)formatString, ... NS_FORMAT_FUNCTION(1,2); +- (void)appendKey:(NSString *)key value:(NSString *)value; + +// Emit log, clearing out the logger contents. +- (void)emitToNSLog; + +// +// Class methods +// + +// +// Return a globally unique serial number to be used for correlating multiple output from the same logger. +// ++ (NSUInteger)generateSerialNumber; + +// Simple helper to write a single log entry, based upon whether the behavior matches a specified on. ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + logEntry:(NSString *)logEntry; + ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + formatString:(NSString *)formatString, ... NS_FORMAT_FUNCTION(2,3); + ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + timestampTag:(NSObject *)timestampTag + formatString:(NSString *)formatString, ... NS_FORMAT_FUNCTION(3,4); + +// Register a timestamp label with the "current" time, to then be retrieved by singleShotLogEntry +// to include a duration. ++ (void)registerCurrentTime:(NSString *)loggingBehavior + withTag:(NSObject *)timestampTag; + +// When logging strings, replace all instances of 'replace' with instances of 'replaceWith'. ++ (void)registerStringToReplace:(NSString *)replace + replaceWith:(NSString *)replaceWith; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.m new file mode 100644 index 0000000..89e9197 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.m @@ -0,0 +1,219 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLogger.h" + +#import "FBSDKInternalUtility.h" +#import "FBSDKSettings+Internal.h" + +static NSUInteger g_serialNumberCounter = 1111; +static NSMutableDictionary *g_stringsToReplace = nil; +static NSMutableDictionary *g_startTimesWithTags = nil; + +@interface FBSDKLogger () + +@property (nonatomic, strong, readonly) NSMutableString *internalContents; + +@end + +@implementation FBSDKLogger + +// Lifetime + +- (instancetype)initWithLoggingBehavior:(NSString *)loggingBehavior +{ + if ((self = [super init])) { + _isActive = [[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]; + _loggingBehavior = loggingBehavior; + if (_isActive) { + _internalContents = [[NSMutableString alloc] init]; + _loggerSerialNumber = [FBSDKLogger generateSerialNumber]; + } + } + + return self; +} + +// Public properties + +- (NSString *)contents +{ + return _internalContents; +} + +- (void)setContents:(NSString *)contents +{ + if (_isActive) { + _internalContents = [NSMutableString stringWithString:contents]; + } +} + +// Public instance methods + +- (void)appendString:(NSString *)string +{ + if (_isActive) { + [_internalContents appendString:string]; + } +} + +- (void)appendFormat:(NSString *)formatString, ... +{ + if (_isActive) { + va_list vaArguments; + va_start(vaArguments, formatString); + NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments]; + va_end(vaArguments); + + [self appendString:logString]; + } +} + + +- (void)appendKey:(NSString *)key value:(NSString *)value +{ + if (_isActive && [value length]) { + [_internalContents appendFormat:@" %@:\t%@\n", key, value]; + } +} + +- (void)emitToNSLog +{ + if (_isActive) { + + for (NSString *key in [g_stringsToReplace keyEnumerator]) { + [_internalContents replaceOccurrencesOfString:key + withString:[g_stringsToReplace objectForKey:key] + options:NSLiteralSearch + range:NSMakeRange(0, _internalContents.length)]; + } + + // Xcode 4.4 hangs on extremely long NSLog output (http://openradar.appspot.com/11972490). Truncate if needed. + const int MAX_LOG_STRING_LENGTH = 10000; + NSString *logString = _internalContents; + if (_internalContents.length > MAX_LOG_STRING_LENGTH) { + logString = [NSString stringWithFormat:@"TRUNCATED: %@", [_internalContents substringToIndex:MAX_LOG_STRING_LENGTH]]; + } + NSLog(@"FBSDKLog: %@", logString); + + [_internalContents setString:@""]; + } +} + +// Public static methods + ++ (NSUInteger)generateSerialNumber +{ + return g_serialNumberCounter++; +} + ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + logEntry:(NSString *)logEntry { + if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) { + FBSDKLogger *logger = [[FBSDKLogger alloc] initWithLoggingBehavior:loggingBehavior]; + [logger appendString:logEntry]; + [logger emitToNSLog]; + } +} + ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + formatString:(NSString *)formatString, ... { + + if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) { + va_list vaArguments; + va_start(vaArguments, formatString); + NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments]; + va_end(vaArguments); + + [self singleShotLogEntry:loggingBehavior logEntry:logString]; + } +} + + ++ (void)singleShotLogEntry:(NSString *)loggingBehavior + timestampTag:(NSObject *)timestampTag + formatString:(NSString *)formatString, ... { + + if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) { + va_list vaArguments; + va_start(vaArguments, formatString); + NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments]; + va_end(vaArguments); + + // Start time of this "timestampTag" is stashed in the dictionary. + // Treat the incoming object tag simply as an address, since it's only used to identify during lifetime. If + // we send in as an object, the dictionary will try to copy it. + NSNumber *tagAsNumber = [NSNumber numberWithUnsignedLong:(unsigned long)(__bridge void *)timestampTag]; + NSNumber *startTimeNumber = [g_startTimesWithTags objectForKey:tagAsNumber]; + + // Only log if there's been an associated start time. + if (startTimeNumber) { + unsigned long elapsed = [FBSDKInternalUtility currentTimeInMilliseconds] - startTimeNumber.unsignedLongValue; + [g_startTimesWithTags removeObjectForKey:tagAsNumber]; // served its purpose, remove + + // Log string is appended with "%d msec", with nothing intervening. This gives the most control to the caller. + logString = [NSString stringWithFormat:@"%@%lu msec", logString, elapsed]; + + [self singleShotLogEntry:loggingBehavior logEntry:logString]; + } + } +} + ++ (void)registerCurrentTime:(NSString *)loggingBehavior + withTag:(NSObject *)timestampTag { + + if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) { + + if (!g_startTimesWithTags) { + g_startTimesWithTags = [[NSMutableDictionary alloc] init]; + } + + if (g_startTimesWithTags.count >= 1000) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry: + @"Unexpectedly large number of outstanding perf logging start times, something is likely wrong."]; + } + + unsigned long currTime = [FBSDKInternalUtility currentTimeInMilliseconds]; + + // Treat the incoming object tag simply as an address, since it's only used to identify during lifetime. If + // we send in as an object, the dictionary will try to copy it. + unsigned long tagAsNumber = (unsigned long)(__bridge void *)timestampTag; + [g_startTimesWithTags setObject:[NSNumber numberWithUnsignedLong:currTime] + forKey:[NSNumber numberWithUnsignedLong:tagAsNumber]]; + } +} + + ++ (void)registerStringToReplace:(NSString *)replace + replaceWith:(NSString *)replaceWith { + + // Strings sent in here never get cleaned up, but that's OK, don't ever expect too many. + + if ([[FBSDKSettings loggingBehavior] count] > 0) { // otherwise there's no logging. + + if (!g_stringsToReplace) { + g_stringsToReplace = [[NSMutableDictionary alloc] init]; + } + + [g_stringsToReplace setValue:replaceWith forKey:replace]; + } +} + + + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.h new file mode 100644 index 0000000..e3f9cd5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.h @@ -0,0 +1,38 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@interface FBSDKMath : NSObject + ++ (CGPoint)ceilForPoint:(CGPoint)value; ++ (CGSize)ceilForSize:(CGSize)value; ++ (CGPoint)floorForPoint:(CGPoint)value; ++ (CGSize)floorForSize:(CGSize)value; ++ (NSUInteger)hashWithCGFloat:(CGFloat)value; ++ (NSUInteger)hashWithCString:(const char *)value; ++ (NSUInteger)hashWithDouble:(double)value; ++ (NSUInteger)hashWithFloat:(float)value; ++ (NSUInteger)hashWithInteger:(NSUInteger)value; ++ (NSUInteger)hashWithInteger:(NSUInteger)value1 andInteger:(NSUInteger)value2; ++ (NSUInteger)hashWithIntegerArray:(NSUInteger *)values count:(NSUInteger)count; ++ (NSUInteger)hashWithLong:(unsigned long long)value; ++ (NSUInteger)hashWithPointer:(const void *)value; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.m new file mode 100644 index 0000000..6ac3fe5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.m @@ -0,0 +1,159 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// +// Based on Thomas Wang 32/64 bit mix hash +// http://www.concentric.net/~Ttwang/tech/inthash.htm +// + +#import "FBSDKMath.h" + +#import + +#import "FBSDKMacros.h" + +@implementation FBSDKMath + +#pragma mark - Class Methods + ++ (CGPoint)ceilForPoint:(CGPoint)value +{ + return CGPointMake(ceilf(value.x), ceilf(value.x)); +} + ++ (CGSize)ceilForSize:(CGSize)value +{ + return CGSizeMake(ceilf(value.width), ceilf(value.height)); +} + ++ (CGPoint)floorForPoint:(CGPoint)value +{ + return CGPointMake(floorf(value.x), floorf(value.y)); +} + ++ (CGSize)floorForSize:(CGSize)value +{ + return CGSizeMake(floorf(value.width), floorf(value.height)); +} + ++ (NSUInteger)hashWithCGFloat:(CGFloat)value +{ +#if CGFLOAT_IS_DOUBLE + return [self hashWithDouble:value]; +#else + return [self hashWithFloat:value]; +#endif +} + ++ (NSUInteger)hashWithCString:(const char *)value +{ + // FNV-1a hash. + NSUInteger hash = sizeof(NSUInteger) == 4 ? 2166136261U : 14695981039346656037U; + while (*value) { + hash ^= *value++; + hash *= sizeof(NSUInteger) == 4 ? 16777619 : 1099511628211; + } + return hash; +} + ++ (NSUInteger)hashWithDouble:(double)value +{ + assert(sizeof(double) == sizeof(uint64_t)); // Size of double must be 8 bytes + union { + double key; + uint64_t bits; + } u; + u.key = value; + return [self hashWithLong:u.bits]; +} + ++ (NSUInteger)hashWithFloat:(float)value +{ + assert(sizeof(float) == sizeof(uint32_t)); // Size of float must be 4 bytes + union { + float key; + uint32_t bits; + } u; + u.key = value; + return [self hashWithInteger:u.bits]; +} + ++ (NSUInteger)hashWithInteger:(NSUInteger)value +{ + return [self hashWithPointer:(void *)value]; +} + ++ (NSUInteger)hashWithInteger:(NSUInteger)value1 andInteger:(NSUInteger)value2 +{ + return [self hashWithLong:(((unsigned long long)value1) << 32 | value2)]; +} + ++ (NSUInteger)hashWithIntegerArray:(NSUInteger *)values count:(NSUInteger)count +{ + if (count == 0) { + return 0; + } + NSUInteger hash = values[0]; + for (NSUInteger i = 1; i < count; ++i) { + hash = [self hashWithInteger:hash andInteger:values[i]]; + } + return hash; +} + ++ (NSUInteger)hashWithLong:(unsigned long long)value +{ + value = (~value) + (value << 18); // key = (key << 18) - key - 1; + value ^= (value >> 31); + value *= 21; // key = (key + (key << 2)) + (key << 4); + value ^= (value >> 11); + value += (value << 6); + value ^= (value >> 22); + return (NSUInteger)value; +} + ++ (NSUInteger)hashWithPointer:(const void *)value +{ + NSUInteger hash = (NSUInteger)value; +#if !TARGET_RT_64_BIT + hash = ~hash + (hash << 15); // key = (key << 15) - key - 1; + hash ^= (hash >> 12); + hash += (hash << 2); + hash ^= (hash >> 4); + hash *= 2057; // key = (key + (key << 3)) + (key << 11); + hash ^= (hash >> 16); +#else + hash += ~hash + (hash << 21); // key = (key << 21) - key - 1; + hash ^= (hash >> 24); + hash = (hash + (hash << 3)) + (hash << 8); + hash ^= (hash >> 14); + hash = (hash + (hash << 2)) + (hash << 4); // key * 21 + hash ^= (hash >> 28); + hash += (hash << 31); +#endif + return hash; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.h new file mode 100644 index 0000000..b771602 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.h @@ -0,0 +1,67 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include + +typedef double FBSDKMonotonicTimeSeconds; +typedef uint64_t FBSDKMonotonicTimeMilliseconds; +typedef uint64_t FBSDKMonotonicTimeNanoseconds; +typedef uint64_t FBSDKMachAbsoluteTimeUnits; + +/** + * return current monotonic time in Milliseconds + * Millisecond precision, uint64_t value. + * Avoids float/double math operations, thus more efficient than FBSDKMonotonicTimeGetCurrentSeconds. + * Should be prefered over FBSDKMonotonicTimeGetCurrentSeconds in case millisecond + * precision is requred. + * IMPORTANT: this timer doesn't run while the device is sleeping. + */ +FBSDKMonotonicTimeMilliseconds FBSDKMonotonicTimeGetCurrentMilliseconds(void); + +/** + * return current monotonic time in Seconds + * Nanosecond precision, double value. + * Should be prefered over FBSDKMonotonicTimeGetCurrentMilliseconds in case + * nanosecond precision is requred. + * IMPORTANT: this timer doesn't run while the device is sleeping. + */ +FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeGetCurrentSeconds(void); + +/** + * return current monotonic time in NanoSeconds + * Nanosecond precision, uint64_t value. + * Useful when nanosecond precision is required but you want to avoid float/double math operations. + * IMPORTANT: this timer doesn't run while the device is sleeping. + */ +FBSDKMonotonicTimeNanoseconds FBSDKMonotonicTimeGetCurrentNanoseconds(void); + +/** + * return number of MachTimeUnits for given number of seconds + * this is useful when you want to use the really fast mach_absolute_time() function + * to calculate deltas between two points and then check it against a (precomputed) threshold. + * Nanosecond precision, uint64_t value. + */ +FBSDKMachAbsoluteTimeUnits FBSDKMonotonicTimeConvertSecondsToMachUnits(FBSDKMonotonicTimeSeconds seconds); + +/** + * return the number of seconds for a given amount of MachTimeUnits + * this is useful when you want to use the really fast mach_absolute_time() function, take + * deltas between time points, and when you're out of the timing critical section, use + * this function to compute how many seconds the delta works out to be. + */ +FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeConvertMachUnitsToSeconds(FBSDKMachAbsoluteTimeUnits machUnits); diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.m new file mode 100644 index 0000000..1a52c81 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.m @@ -0,0 +1,86 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include +#include +#include +#include + +#import "FBSDKMonotonicTime.h" + +/** + * PLEASE NOTE: FBSDKSDKMonotonicTimeTests work fine, but are disabled + * because they take several seconds. Please re-enable them to test + * any changes you're making here! + */ +static uint64_t _get_time_nanoseconds(void) +{ + static struct mach_timebase_info tb_info = {0}; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + int ret = mach_timebase_info(&tb_info); + assert(0 == ret); + }); + + return (mach_absolute_time() * tb_info.numer) / tb_info.denom; +} + +FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeGetCurrentSeconds(void) +{ + const uint64_t nowNanoSeconds = _get_time_nanoseconds(); + return (FBSDKMonotonicTimeSeconds)nowNanoSeconds / (FBSDKMonotonicTimeSeconds)1000000000.0; +} + +FBSDKMonotonicTimeMilliseconds FBSDKMonotonicTimeGetCurrentMilliseconds(void) +{ + const uint64_t nowNanoSeconds = _get_time_nanoseconds(); + return nowNanoSeconds / 1000000; +} + +FBSDKMonotonicTimeNanoseconds FBSDKMonotonicTimeGetCurrentNanoseconds(void) +{ + return _get_time_nanoseconds(); +} + +FBSDKMachAbsoluteTimeUnits FBSDKMonotonicTimeConvertSecondsToMachUnits(FBSDKMonotonicTimeSeconds seconds) +{ + static double ratio = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + struct mach_timebase_info tb_info = {0}; + int ret = mach_timebase_info(&tb_info); + assert(0 == ret); + ratio = ((double) tb_info.denom / (double)tb_info.numer) * 1000000000.0; + }); + + return seconds * ratio; +} + +FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeConvertMachUnitsToSeconds(FBSDKMachAbsoluteTimeUnits machUnits) +{ + static double ratio = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + struct mach_timebase_info tb_info = {0}; + int ret = mach_timebase_info(&tb_info); + assert(0 == ret); + ratio = ((double) tb_info.numer / (double)tb_info.denom) / 1000000000.0; + }); + + return ratio * (double)machUnits; +} diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKProfile+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKProfile+Internal.h new file mode 100644 index 0000000..d2298d5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKProfile+Internal.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKProfile.h" + +@interface FBSDKProfile(Internal) + ++ (void)cacheProfile:(FBSDKProfile *) profile; ++ (FBSDKProfile *)fetchCachedProfile; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSettings+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSettings+Internal.h new file mode 100644 index 0000000..2af3879 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSettings+Internal.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCache.h" +#import "FBSDKSettings.h" + +@interface FBSDKSettings(Internal) + ++ (FBSDKAccessTokenCache *)accessTokenCache; + +- (void)setAccessTokenCache; + ++ (NSString *)graphAPIDebugParamValue; + ++ (BOOL)isGraphErrorRecoveryDisabled; + +// used by Unity. ++ (NSString *)userAgentSuffix; ++ (void)setUserAgentSuffix:(NSString *)suffix; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.h new file mode 100644 index 0000000..00999f5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.h @@ -0,0 +1,82 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +typedef void (^FBSDKGraphRequestAccessToAccountsHandler)(NSString *oauthToken, NSError *accountStoreError); + +/* + @class + + @abstract Adapter around system account store APIs. Note this is only intended for internal + consumption. If publicized, consider moving declarations to an internal only header and + reconsider dispatching semantics. + */ +@interface FBSDKSystemAccountStoreAdapter : NSObject + +/* + @abstract + Requests access to the device's Facebook account for the given parameters. + @param permissions the permissions + @param defaultAudience the default audience + @param isReauthorize a flag describing if this is a reauth request + @param appID the app id + @param handler the handler that will be invoked on completion (dispatched to the main thread). the oauthToken is nil on failure. + */ +- (void)requestAccessToFacebookAccountStore:(NSSet *)permissions + defaultAudience:(NSString *)defaultAudience + isReauthorize:(BOOL)isReauthorize + appID:(NSString *)appID + handler:(FBSDKGraphRequestAccessToAccountsHandler)handler; + +/* + @abstract Sends a message to the device account store to renew the Facebook account credentials + + @param handler the handler that is invoked on completion + */ +- (void)renewSystemAuthorization:(void(^)(ACAccountCredentialRenewResult result, NSError *error))handler; + +/* + @abstracts gets the oauth token stored in the account store credential, if available. If not empty, + this implies user has granted access. + */ +- (NSString *)accessTokenString; + +/* + @abstract Gets the singleton instance. + */ ++ (FBSDKSystemAccountStoreAdapter *)sharedInstance; + +/* + @abstract Sets the singleton instance, typically only for unit tests + */ ++ (void)setSharedInstance:(FBSDKSystemAccountStoreAdapter *)instance; + +/* + @abstract Gets or sets the flag indicating if the next requestAccess call should block + on a renew call. + */ +@property (nonatomic, assign) BOOL forceBlockingRenew; + +/* + @abstract A convenience getter to the Facebook account type in the account store, if available. + */ +@property (strong, nonatomic, readonly) ACAccountType *accountType; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.m new file mode 100644 index 0000000..43f506a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.m @@ -0,0 +1,275 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKSystemAccountStoreAdapter.h" + +#import "FBSDKConstants.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKError.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings+Internal.h" + +@interface FBSDKSystemAccountStoreAdapter () + +@property (retain, nonatomic, readonly) ACAccountStore *accountStore; + +@end + +static NSString *const FBForceBlockingRenewKey = @"com.facebook.sdk:ForceBlockingRenewKey"; +static FBSDKSystemAccountStoreAdapter *_singletonInstance = nil; + +@implementation FBSDKSystemAccountStoreAdapter +{ + ACAccountStore *_accountStore; + ACAccountType *_accountType; +} + ++ (void)initialize +{ + if (self == [FBSDKSystemAccountStoreAdapter class]) { + _singletonInstance = [[self alloc] init]; + } +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _forceBlockingRenew = [[NSUserDefaults standardUserDefaults] boolForKey:FBForceBlockingRenewKey]; + } + return self; +} + +#pragma mark - Properties + +- (ACAccountStore *)accountStore +{ + if (_accountStore == nil) { + _accountStore = [[fbsdkdfl_ACAccountStoreClass() alloc] init]; + } + return _accountStore; +} + +- (ACAccountType *)accountType +{ + if (_accountType == nil) { + _accountType = [self.accountStore accountTypeWithAccountTypeIdentifier:@"com.apple.facebook"]; + } + return _accountType; +} + +- (void)setForceBlockingRenew:(BOOL)forceBlockingRenew +{ + if (_forceBlockingRenew != forceBlockingRenew) { + _forceBlockingRenew = forceBlockingRenew; + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setBool:forceBlockingRenew forKey:FBForceBlockingRenewKey]; + [userDefaults synchronize]; + } +} + ++ (FBSDKSystemAccountStoreAdapter *)sharedInstance +{ + return _singletonInstance; +} + ++ (void)setSharedInstance:(FBSDKSystemAccountStoreAdapter *)instance +{ + _singletonInstance = instance; +} + +- (NSString *)accessTokenString +{ + if (self.accountType && self.accountType.accessGranted) { + NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType]; + if (fbAccounts.count > 0) { + id account = [fbAccounts objectAtIndex:0]; + id credential = [account credential]; + + return [credential oauthToken]; + } + } + return nil; +} + +#pragma mark - Public properties and methods + +- (void)requestAccessToFacebookAccountStore:(NSSet *)permissions + defaultAudience:(NSString *)defaultAudience + isReauthorize:(BOOL)isReauthorize + appID:(NSString *)appID + handler:(FBSDKGraphRequestAccessToAccountsHandler)handler +{ + if (appID == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"appID cannot be nil" + userInfo:nil]; + } + + // no publish_* permissions are permitted with a nil audience + if (!defaultAudience && isReauthorize) { + for (NSString *p in permissions) { + if ([p hasPrefix:@"publish"]) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"FBSDKLoginManager: One or more publish permission was requested " + @"without specifying an audience; use FBSDKDefaultAudienceOnlyMe, " + @"FBSDKDefaultAudienceFriends, or FBSDKDefaultAudienceEveryone" + userInfo:nil] + raise]; + } + } + } + + // construct access options + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + appID, fbsdkdfl_ACFacebookAppIdKey(), + [permissions allObjects], fbsdkdfl_ACFacebookPermissionsKey(), + defaultAudience, fbsdkdfl_ACFacebookAudienceKey(), // must end on this key/value due to audience possibly being nil + nil]; + + if (self.forceBlockingRenew + && [self.accountStore accountsWithAccountType:self.accountType].count > 0) { + // If the force renew flag is set and an iOS FB account is still set, + // chain the requestAccessBlock to a successful renew result + [self renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *error) { + if (result == ACAccountCredentialRenewResultRenewed) { + self.forceBlockingRenew = NO; + [self requestAccessToFacebookAccountStore:options retrying:NO handler:handler]; + } else if (handler) { + // Otherwise, invoke the caller's handler back on the main thread with an + // error that will trigger the password change user message. + dispatch_async(dispatch_get_main_queue(), ^{ + handler(nil, error); + }); + } + }]; + } else { + // Otherwise go ahead and invoke normal request. + [self requestAccessToFacebookAccountStore:options retrying:NO handler:handler]; + } +} + +- (void)requestAccessToFacebookAccountStore:(NSDictionary *)options + retrying:(BOOL)retrying + handler:(FBSDKGraphRequestAccessToAccountsHandler)handler +{ + if (!self.accountType) { + if (handler) { + handler(nil, [FBSDKError errorWithCode:FBSDKUnknownErrorCode message:@"Invalid request to account store"]); + } + return; + } + // we will attempt an iOS integrated facebook login + [self.accountStore + requestAccessToAccountsWithType:self.accountType + options:options + completion:^(BOOL granted, NSError *error) { + if (!granted && + error.code == ACErrorPermissionDenied && + [error.description rangeOfString:@"remote_app_id does not match stored id"].location != NSNotFound) { + + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors formatString: + @"System authorization failed:'%@'. This may be caused by a mismatch between" + @" the bundle identifier and your app configuration on the server" + @" at developers.facebook.com/apps.", + error.localizedDescription]; + } + + // requestAccessToAccountsWithType:options:completion: completes on an + // arbitrary thread; let's process this back on our main thread + dispatch_async(dispatch_get_main_queue(), ^{ + NSError *accountStoreError = error; + NSString *oauthToken = nil; + id account = nil; + if (granted) { + NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType]; + if (fbAccounts.count > 0) { + account = [fbAccounts objectAtIndex:0]; + + id credential = [account credential]; + + oauthToken = [credential oauthToken]; + } + self.forceBlockingRenew = NO; + } + + if (!accountStoreError && !oauthToken) { + if (!retrying) { + // This can happen as a result of, e.g., restoring from iCloud to a different device. Try once to renew. + [self renewSystemAuthorization:^(ACAccountCredentialRenewResult renewResult, NSError *renewError) { + // Call block again, regardless of result -- either we'll get credentials or we'll fail with the + // exception below. We want to treat failure here the same regardless of whether it was before or after the refresh attempt. + [self requestAccessToFacebookAccountStore:options retrying:YES handler:handler]; + }]; + return; + } + // else call handler with nils. + } + handler(oauthToken, accountStoreError); + }); + }]; +} + +- (void)renewSystemAuthorization:(void(^)(ACAccountCredentialRenewResult, NSError *))handler +{ + // if the slider has been set to off, renew calls to iOS simply hang, so we must + // preemptively check for that condition. + if (self.accountStore && self.accountType && self.accountType.accessGranted) { + NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType]; + id account; + if (fbAccounts && [fbAccounts count] > 0 && + (account = [fbAccounts objectAtIndex:0])) { + + FBSDKAccessToken *currentToken = [FBSDKAccessToken currentAccessToken]; + if (![currentToken.tokenString isEqualToString:[self accessTokenString]]) { + currentToken = nil; + } + [self.accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { + if (error) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAccessTokens + logEntry:[NSString stringWithFormat:@"renewCredentialsForAccount result:%ld, error: %@", + (long)renewResult, + error]]; + } + if (renewResult == ACAccountCredentialRenewResultRenewed && + currentToken && + [currentToken isEqual:[FBSDKAccessToken currentAccessToken]]) { + // account store renewals can change the stored oauth token so we need to update the currentAccessToken + // so future comparisons to -[ accessTokenString] work correctly (e.g., error recovery). + FBSDKAccessToken *updatedToken = [[FBSDKAccessToken alloc] initWithTokenString:[self accessTokenString] + permissions:[currentToken.permissions allObjects] declinedPermissions:[currentToken.declinedPermissions allObjects] + appID:currentToken.appID + userID:currentToken.userID + expirationDate:[NSDate distantFuture] + refreshDate:[NSDate date]]; + [FBSDKAccessToken setCurrentAccessToken:updatedToken]; + } + if (handler) { + handler(renewResult, error); + } + }]; + return; + } + } + + if (handler) { + handler(ACAccountCredentialRenewResultFailed, nil); + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.h new file mode 100644 index 0000000..8fe3e9e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +typedef NS_ENUM(NSInteger, FBSDKTriStateBOOL) +{ + FBSDKTriStateBOOLValueUnknown = -1, + FBSDKTriStateBOOLValueNO = 0, + FBSDKTriStateBOOLValueYES = 1, +}; + +FBSDK_EXTERN FBSDKTriStateBOOL FBSDKTriStateBOOLFromBOOL(BOOL value); +FBSDK_EXTERN FBSDKTriStateBOOL FBSDKTriStateBOOLFromNSNumber(NSNumber *value); +FBSDK_EXTERN BOOL BOOLFromFBSDKTriStateBOOL(FBSDKTriStateBOOL value, BOOL defaultValue); diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.m new file mode 100644 index 0000000..c25d365 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.m @@ -0,0 +1,43 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKTriStateBOOL.h" + +FBSDKTriStateBOOL FBSDKTriStateBOOLFromBOOL(BOOL value) +{ + return value ? FBSDKTriStateBOOLValueYES : FBSDKTriStateBOOLValueNO; +} + +FBSDKTriStateBOOL FBSDKTriStateBOOLFromNSNumber(NSNumber *value) +{ + return ([value isKindOfClass:[NSNumber class]] ? + FBSDKTriStateBOOLFromBOOL([value boolValue]) : + FBSDKTriStateBOOLValueUnknown); +} + +BOOL BOOLFromFBSDKTriStateBOOL(FBSDKTriStateBOOL value, BOOL defaultValue) +{ + switch (value) { + case FBSDKTriStateBOOLValueYES: + return YES; + case FBSDKTriStateBOOLValueNO: + return NO; + case FBSDKTriStateBOOLValueUnknown: + return defaultValue; + } +} diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.h new file mode 100644 index 0000000..7daa2fc --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKTypeUtility : NSObject + ++ (NSArray *)arrayValue:(id)object; ++ (BOOL)boolValue:(id)object; ++ (NSDictionary *)dictionaryValue:(id)object; ++ (NSInteger)integerValue:(id)object; ++ (id)objectValue:(id)object; ++ (NSString *)stringValue:(id)object; ++ (NSUInteger)unsignedIntegerValue:(id)object; ++ (NSURL *)URLValue:(id)object; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.m new file mode 100644 index 0000000..84de948 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.m @@ -0,0 +1,120 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKTypeUtility.h" + +#import "FBSDKMacros.h" + +@implementation FBSDKTypeUtility + +#pragma mark - Class Methods + ++ (NSArray *)arrayValue:(id)object +{ + return (NSArray *)[self _objectValue:object ofClass:[NSArray class]]; +} + ++ (BOOL)boolValue:(id)object +{ + if ([object isKindOfClass:[NSNumber class]]) { + // @0 or @NO returns NO, otherwise YES + return [(NSNumber *)object boolValue]; + } else if ([object isKindOfClass:[NSString class]]) { + // Returns YES on encountering one of "Y", "y", "T", "t", or a digit 1-9, otherwise NO + return [(NSString *)object boolValue]; + } else { + return ([self objectValue:object] != nil); + } +} + ++ (NSDictionary *)dictionaryValue:(id)object +{ + return (NSDictionary *)[self _objectValue:object ofClass:[NSDictionary class]]; +} + ++ (NSInteger)integerValue:(id)object +{ + if ([object isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)object integerValue]; + } else if ([object isKindOfClass:[NSString class]]) { + return [(NSString *)object integerValue]; + } else { + return 0; + } +} + ++ (id)objectValue:(id)object +{ + return ([object isKindOfClass:[NSNull class]] ? nil : object); +} + ++ (NSString *)stringValue:(id)object +{ + if ([object isKindOfClass:[NSString class]]) { + return (NSString *)object; + } else if ([object isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)object stringValue]; + } else if ([object isKindOfClass:[NSURL class]]) { + return [(NSURL *)object absoluteString]; + } else { + return nil; + } +} + ++ (NSUInteger)unsignedIntegerValue:(id)object +{ + if ([object isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)object unsignedIntegerValue]; + } else { + // there is no direct support for strings containing unsigned values > NSIntegerMax - not worth writing ourselves + // right now, so just cap unsigned values at NSIntegerMax until we have a need for larger + NSInteger integerValue = [self integerValue:object]; + if (integerValue < 0) { + integerValue = 0; + } + return (NSUInteger)integerValue; + } +} + ++ (NSURL *)URLValue:(id)object +{ + if ([object isKindOfClass:[NSURL class]]) { + return (NSURL *)object; + } else if ([object isKindOfClass:[NSString class]]) { + return [[NSURL alloc] initWithString:(NSString *)object]; + } else { + return nil; + } +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +#pragma mark - Helper Methods + ++ (id)_objectValue:(id)object ofClass:(Class)expectedClass +{ + return ([object isKindOfClass:expectedClass] ? object : nil); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequest+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequest+Internal.h new file mode 100644 index 0000000..86fedc6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequest+Internal.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +typedef NS_OPTIONS(NSUInteger, FBSDKGraphRequestFlags) +{ + FBSDKGraphRequestFlagNone = 0, + // indicates this request should not use a client token as its token parameter + FBSDKGraphRequestFlagSkipClientToken = 1 << 1, + // indicates this request should not close the session if its response is an oauth error + FBSDKGraphRequestFlagDoNotInvalidateTokenOnError = 1 << 2, + // indicates this request should not perform error recovery + FBSDKGraphRequestFlagDisableErrorRecovery = 1 << 3, +}; +@interface FBSDKGraphRequest (Internal) + +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + flags:(FBSDKGraphRequestFlags)flags; +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + tokenString:(NSString *)tokenString + HTTPMethod:(NSString *)HTTPMethod + flags:(FBSDKGraphRequestFlags)flags; +// Generally, requests automatically issued by the SDK +// should not invalidate the token and should disableErrorRecovery +// so that we don't cause a sudden change in token state or trigger recovery +// out of context of any user action. +@property (nonatomic, assign) FBSDKGraphRequestFlags flags; + +- (BOOL)isGraphErrorRecoveryDisabled; +- (BOOL)hasAttachments; ++ (BOOL)isAttachment:(id)item; ++ (NSString *)serializeURL:(NSString *)baseUrl + params:(NSDictionary *)params + httpMethod:(NSString *)httpMethod; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h new file mode 100644 index 0000000..b61c782 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@class FBSDKGraphRequestDataAttachment; +@class FBSDKLogger; + +@interface FBSDKGraphRequestBody : NSObject + +@property (nonatomic, retain, readonly) NSData *data; + +- (void)appendWithKey:(NSString *)key + formValue:(NSString *)value + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + imageValue:(UIImage *)image + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + dataValue:(NSData *)data + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + dataAttachmentValue:(FBSDKGraphRequestDataAttachment *)dataAttachment + logger:(FBSDKLogger *)logger; + ++ (NSString *)mimeContentType; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.m new file mode 100644 index 0000000..5462576 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.m @@ -0,0 +1,131 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequestBody.h" + +#import "FBSDKGraphRequestDataAttachment.h" +#import "FBSDKLogger.h" +#import "FBSDKSettings.h" + +#define kStringBoundary @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f" +#define kNewline @"\r\n" + +@implementation FBSDKGraphRequestBody +{ + NSMutableData *_data; +} + +- (instancetype)init +{ + if ((self = [super init])) { + _data = [[NSMutableData alloc] init]; + } + + return self; +} + ++ (NSString *)mimeContentType +{ + return [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; +} + +- (void)appendUTF8:(NSString *)utf8 +{ + if (![_data length]) { + NSString *headerUTF8 = [NSString stringWithFormat:@"--%@%@", kStringBoundary, kNewline]; + NSData *headerData = [headerUTF8 dataUsingEncoding:NSUTF8StringEncoding]; + [_data appendData:headerData]; + } + NSData *data = [utf8 dataUsingEncoding:NSUTF8StringEncoding]; + [_data appendData:data]; +} + +- (void)appendWithKey:(NSString *)key + formValue:(NSString *)value + logger:(FBSDKLogger *)logger +{ + [self _appendWithKey:key filename:nil contentType:nil contentBlock:^{ + [self appendUTF8:value]; + }]; + [logger appendFormat:@"\n %@:\t%@", key, (NSString *)value]; +} + +- (void)appendWithKey:(NSString *)key + imageValue:(UIImage *)image + logger:(FBSDKLogger *)logger +{ + NSData *data = UIImageJPEGRepresentation(image, [FBSDKSettings JPEGCompressionQuality]); + [self _appendWithKey:key filename:key contentType:@"image/jpeg" contentBlock:^{ + [_data appendData:data]; + }]; + [logger appendFormat:@"\n %@:\t", key, (unsigned long)([data length] / 1024)]; +} + +- (void)appendWithKey:(NSString *)key + dataValue:(NSData *)data + logger:(FBSDKLogger *)logger +{ + [self _appendWithKey:key filename:key contentType:@"content/unknown" contentBlock:^{ + [_data appendData:data]; + }]; + [logger appendFormat:@"\n %@:\t", key, (unsigned long)([data length] / 1024)]; +} + +- (void)appendWithKey:(NSString *)key + dataAttachmentValue:(FBSDKGraphRequestDataAttachment *)dataAttachment + logger:(FBSDKLogger *)logger +{ + NSString *filename = dataAttachment.filename ?: key; + NSString *contentType = dataAttachment.contentType ?: @"content/unknown"; + NSData *data = dataAttachment.data; + [self _appendWithKey:key filename:filename contentType:contentType contentBlock:^{ + [_data appendData:data]; + }]; + [logger appendFormat:@"\n %@:\t", key, (unsigned long)([data length] / 1024)]; +} + +- (NSData *)data +{ + return [_data copy]; +} + +- (void)_appendWithKey:(NSString *)key + filename:(NSString *)filename + contentType:(NSString *)contentType + contentBlock:(void(^)(void))contentBlock +{ + NSMutableArray *disposition = [[NSMutableArray alloc] init]; + [disposition addObject:@"Content-Disposition: form-data"]; + if (key) { + [disposition addObject:[[NSString alloc] initWithFormat:@"name=\"%@\"", key]]; + } + if (filename) { + [disposition addObject:[[NSString alloc] initWithFormat:@"filename=\"%@\"", filename]]; + } + [self appendUTF8:[[NSString alloc] initWithFormat:@"%@%@", [disposition componentsJoinedByString:@"; "], kNewline]]; + if (contentType) { + [self appendUTF8:[[NSString alloc] initWithFormat:@"Content-Type: %@%@", contentType, kNewline]]; + } + [self appendUTF8:kNewline]; + if (contentBlock != NULL) { + contentBlock(); + } + [self appendUTF8:[[NSString alloc] initWithFormat:@"%@--%@%@", kNewline, kStringBoundary, kNewline]]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnection+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnection+Internal.h new file mode 100644 index 0000000..c63688c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnection+Internal.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKGraphRequestConnection(Internal) + +@property (nonatomic, readonly) NSMutableArray *requests; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h new file mode 100644 index 0000000..cd218c4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +// Internal only class to facilitate FBSDKGraphRequest processing, specifically +// associating FBSDKGraphRequest and FBSDKGraphRequestHandler instances and necessary +// data for retry processing. +@interface FBSDKGraphRequestMetadata : NSObject + +@property (nonatomic, retain) FBSDKGraphRequest *request; +@property (nonatomic, copy) FBSDKGraphRequestHandler completionHandler; +@property (nonatomic, copy) NSDictionary *batchParameters; + +- (instancetype)initWithRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters +NS_DESIGNATED_INITIALIZER; + +- (void)invokeCompletionHandlerForConnection:(FBSDKGraphRequestConnection *)connection + withResults:(id)results + error:(NSError *)error; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.m new file mode 100644 index 0000000..3b0ee78 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.m @@ -0,0 +1,62 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequestMetadata.h" + +#import "FBSDKGraphRequest.h" +#import "FBSDKMacros.h" + +@implementation FBSDKGraphRequestMetadata + +- (instancetype)initWithRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters { + + if ((self = [super init])) { + _request = request; + _batchParameters = [batchParameters copy]; + _completionHandler = [handler copy]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithRequest:completionHandler:batchParameters:); + return [self initWithRequest:nil completionHandler:NULL batchParameters:nil]; +} + +- (void)invokeCompletionHandlerForConnection:(FBSDKGraphRequestConnection *)connection + withResults:(id)results + error:(NSError *)error { + if (self.completionHandler) { + self.completionHandler(connection, results, error); + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, batchParameters: %@, completionHandler: %@, request: %@>", + NSStringFromClass([self class]), + self, + self.batchParameters, + self.completionHandler, + self.request.description]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.h new file mode 100644 index 0000000..567f8ec --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKGraphRequestPiggybackManager : NSObject + ++ (void)addPiggybackRequests:(FBSDKGraphRequestConnection *)connection; + ++ (void)addRefreshPiggyback:(FBSDKGraphRequestConnection *)connection permissionHandler:(FBSDKGraphRequestHandler)permissionHandler; + ++ (void)addRefreshPiggybackIfStale:(FBSDKGraphRequestConnection *)connection; + ++ (void)addServerConfigurationPiggyback:(FBSDKGraphRequestConnection *)connection; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m new file mode 100644 index 0000000..e0e4866 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m @@ -0,0 +1,140 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGraphRequestPiggybackManager.h" + +#import "FBSDKCoreKit+Internal.h" + +static int const FBSDKTokenRefreshThresholdSeconds = 24 * 60 * 60; // day +static int const FBSDKTokenRefreshRetrySeconds = 60 * 60; // hour + +@implementation FBSDKGraphRequestPiggybackManager + ++ (void)addPiggybackRequests:(FBSDKGraphRequestConnection *)connection +{ + if ([FBSDKSettings appID].length > 0) { + BOOL safeForPiggyback = YES; + for (FBSDKGraphRequestMetadata *metadata in connection.requests) { + if (![metadata.request.version isEqualToString:FBSDK_TARGET_PLATFORM_VERSION] || + [metadata.request hasAttachments]) { + safeForPiggyback = NO; + break; + } + } + if (safeForPiggyback) { + [[self class] addRefreshPiggybackIfStale:connection]; + [[self class] addServerConfigurationPiggyback:connection]; + } + } +} + ++ (void)addRefreshPiggyback:(FBSDKGraphRequestConnection *)connection permissionHandler:(FBSDKGraphRequestHandler)permissionHandler +{ + FBSDKAccessToken *expectedToken = [FBSDKAccessToken currentAccessToken]; + __block NSMutableSet *permissions = nil; + __block NSMutableSet *declinedPermissions = nil; + __block NSString *tokenString = nil; + __block NSNumber *expirationDateNumber = nil; + __block int expectingCallbacksCount = 2; + void (^expectingCallbackComplete)(void) = ^{ + if (--expectingCallbacksCount == 0) { + FBSDKAccessToken *currentToken = [FBSDKAccessToken currentAccessToken]; + NSDate *expirationDate = currentToken.expirationDate; + if (expirationDateNumber) { + expirationDate = ([expirationDateNumber doubleValue] > 0 ? + [NSDate dateWithTimeIntervalSince1970:[expirationDateNumber doubleValue]] : + [NSDate distantFuture]); + } + FBSDKAccessToken *refreshedToken = [[FBSDKAccessToken alloc] initWithTokenString:tokenString ?: currentToken.tokenString + permissions:[(permissions ?: currentToken.permissions) allObjects] + declinedPermissions:[(declinedPermissions ?: currentToken.declinedPermissions) allObjects] + appID:currentToken.appID + userID:currentToken.userID + expirationDate:expirationDate + refreshDate:[NSDate date]]; + if (expectedToken == currentToken) { + [FBSDKAccessToken setCurrentAccessToken:refreshedToken]; + } + } + }; + FBSDKGraphRequest *extendRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:@"oauth/access_token" + parameters:@{@"grant_type" : @"fb_extend_sso_token", + @"fields": @"" + } + flags:FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:extendRequest completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + tokenString = result[@"access_token"]; + expirationDateNumber = result[@"expires_at"]; + expectingCallbackComplete(); + }]; + FBSDKGraphRequest *permissionsRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me/permissions" + parameters:@{@"fields": @""} + flags:FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:permissionsRequest completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + if (!error) { + permissions = [NSMutableSet set]; + declinedPermissions = [NSMutableSet set]; + + [FBSDKInternalUtility extractPermissionsFromResponse:result + grantedPermissions:permissions + declinedPermissions:declinedPermissions]; + } + expectingCallbackComplete(); + if (permissionHandler) { + permissionHandler(innerConnection, result, error); + } + }]; +} + ++ (void)addRefreshPiggybackIfStale:(FBSDKGraphRequestConnection *)connection +{ + // don't piggy back more than once an hour as a cheap way of + // retrying in cases of errors and preventing duplicate refreshes. + // obviously this is not foolproof but is simple and sufficient. + static NSDate *lastRefreshTry; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lastRefreshTry = [NSDate distantPast]; + }); + + NSDate *now = [NSDate date]; + NSDate *tokenRefreshDate = [FBSDKAccessToken currentAccessToken].refreshDate; + if (tokenRefreshDate && + [now timeIntervalSinceDate:lastRefreshTry] > FBSDKTokenRefreshRetrySeconds && + [now timeIntervalSinceDate:tokenRefreshDate] > FBSDKTokenRefreshThresholdSeconds) { + [self addRefreshPiggyback:connection permissionHandler:NULL]; + lastRefreshTry = [NSDate date]; + } +} + ++ (void)addServerConfigurationPiggyback:(FBSDKGraphRequestConnection *)connection +{ + if (![[FBSDKServerConfigurationManager cachedServerConfiguration] isDefaults]) { + return; + } + NSString *appID = [FBSDKSettings appID]; + FBSDKGraphRequest *serverConfigurationRequest = [FBSDKServerConfigurationManager requestToLoadServerConfiguration:appID]; + [connection addRequest:serverConfigurationRequest + completionHandler:^(FBSDKGraphRequestConnection *conn, id result, NSError *error) { + [FBSDKServerConfigurationManager processLoadRequestResponse:result error:error appID:appID]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.h new file mode 100644 index 0000000..cbe80a0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.h @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKURLConnection; + +typedef void (^FBSDKURLConnectionHandler)(FBSDKURLConnection *connection, + NSError *error, + NSURLResponse *response, + NSData *responseData); + +@protocol FBSDKURLConnectionDelegate + +@optional + +- (void)facebookURLConnection:(FBSDKURLConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; + +@end + +@interface FBSDKURLConnection : NSObject + +- (FBSDKURLConnection *)initWithRequest:(NSURLRequest *)request + completionHandler:(FBSDKURLConnectionHandler)handler +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, assign) id delegate; + +- (void)cancel; +- (void)start; +- (void)setDelegateQueue:(NSOperationQueue *)queue; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.m new file mode 100644 index 0000000..613fb8b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.m @@ -0,0 +1,191 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKURLConnection.h" + +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKMacros.h" +#import "FBSDKSettings.h" + +@interface FBSDKURLConnection () + +@property (nonatomic, retain) NSURLConnection *connection; +@property (nonatomic, retain) NSMutableData *data; +@property (nonatomic, copy) FBSDKURLConnectionHandler handler; +@property (nonatomic, retain) NSURLResponse *response; +@property (nonatomic) unsigned long requestStartTime; +@property (nonatomic, readonly) NSUInteger loggerSerialNumber; + +@end + +@implementation FBSDKURLConnection + +#pragma mark - Lifecycle + +- (FBSDKURLConnection *)initWithRequest:(NSURLRequest *)request + completionHandler:(FBSDKURLConnectionHandler)handler { + if ((self = [super init])) { + _requestStartTime = [FBSDKInternalUtility currentTimeInMilliseconds]; + _loggerSerialNumber = [FBSDKLogger generateSerialNumber]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + _connection = [[NSURLConnection alloc] + initWithRequest:request + delegate:self + startImmediately:NO]; +#pragma clang diagnostic pop + _data = [[NSMutableData alloc] init]; + + _handler = [handler copy]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithRequest:completionHandler:); + return [self initWithRequest:nil completionHandler:NULL]; +} + +- (void)logAndInvokeHandler:(FBSDKURLConnectionHandler)handler + error:(NSError *)error { + if (error) { + NSString *logEntry = [NSString + stringWithFormat:@"FBSDKURLConnection <#%lu>:\n Error: '%@'\n%@\n", + (unsigned long)self.loggerSerialNumber, + [error localizedDescription], + [error userInfo]]; + + [self logMessage:logEntry]; + } + + [self invokeHandler:handler error:error response:nil responseData:nil]; +} + +- (void)logAndInvokeHandler:(FBSDKURLConnectionHandler)handler + response:(NSURLResponse *)response + responseData:(NSData *)responseData { + // Basic FBSDKURLConnection logging just prints out the URL. FBSDKGraphRequest logging provides more details. + NSString *mimeType = [response MIMEType]; + NSMutableString *mutableLogEntry = [NSMutableString stringWithFormat:@"FBSDKURLConnection <#%lu>:\n Duration: %lu msec\nResponse Size: %lu kB\n MIME type: %@\n", + (unsigned long)self.loggerSerialNumber, + [FBSDKInternalUtility currentTimeInMilliseconds] - self.requestStartTime, + (unsigned long)[responseData length] / 1024, + mimeType]; + + if ([mimeType isEqualToString:@"text/javascript"]) { + NSString *responseUTF8 = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; + [mutableLogEntry appendFormat:@" Response:\n%@\n\n", responseUTF8]; + } + + [self logMessage:mutableLogEntry]; + + [self invokeHandler:handler error:nil response:response responseData:responseData]; +} + +- (void)invokeHandler:(FBSDKURLConnectionHandler)handler + error:(NSError *)error + response:(NSURLResponse *)response + responseData:(NSData *)responseData { + if (handler != nil) { + handler(self, error, response, responseData); + } +} + +- (void)logMessage:(NSString *)message +{ + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorNetworkRequests formatString:@"%@", message]; +} + +- (void)cancel +{ + [self.connection cancel]; + self.handler = nil; +} + +- (void)connection:(NSURLConnection *)connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = response; + [self.data setLength:0]; +} + +- (void)connection:(NSURLResponse *)connection + didReceiveData:(NSData *)data { + [self.data appendData:data]; +} + +- (void)connection:(NSURLConnection *)connection + didFailWithError:(NSError *)error { + @try { + if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == kCFURLErrorSecureConnectionFailed) { + NSOperatingSystemVersion iOS9Version = { .majorVersion = 9, .minorVersion = 0, .patchVersion = 0 }; + if ([FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS9Version]) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + logEntry:@"WARNING: FBSDK secure network request failed. Please verify you have configured your " + "app for Application Transport Security compatibility described at https://developers.facebook.com/docs/ios/ios9"]; + } + } + [self logAndInvokeHandler:self.handler error:error]; + } @finally { + self.handler = nil; + } +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + @try { + [self logAndInvokeHandler:self.handler response:self.response responseData:self.data]; + } @finally { + self.handler = nil; + } +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse { + return request; +} + +- (void) connection:(NSURLConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + id delegate = self.delegate; + + if ([delegate respondsToSelector:@selector(facebookURLConnection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)]) { + [delegate facebookURLConnection:self + didSendBodyData:bytesWritten + totalBytesWritten:totalBytesWritten + totalBytesExpectedToWrite:totalBytesExpectedToWrite]; + } +} + +- (void)start +{ + [_connection start]; +} + +- (void)setDelegateQueue:(NSOperationQueue*)queue +{ + [_connection setDelegateQueue:queue]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.h new file mode 100644 index 0000000..8913cc0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.h @@ -0,0 +1,34 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@interface FBSDKDialogConfiguration : NSObject + +- (instancetype)initWithName:(NSString *)name + URL:(NSURL *)URL + appVersions:(NSArray *)appVersions +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, copy, readonly) NSArray *appVersions; +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, copy, readonly) NSURL *URL; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.m new file mode 100644 index 0000000..a8986c0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.m @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKDialogConfiguration.h" + +#import "FBSDKMacros.h" + +#define FBSDK_DIALOG_CONFIGURATION_APP_VERSIONS_KEY @"appVersions" +#define FBSDK_DIALOG_CONFIGURATION_NAME_KEY @"name" +#define FBSDK_DIALOG_CONFIGURATION_URL_KEY @"url" + +@implementation FBSDKDialogConfiguration + +#pragma mark - Object Lifecycle + +- (instancetype)initWithName:(NSString *)name URL:(NSURL *)URL appVersions:(NSArray *)appVersions +{ + if ((self = [super init])) { + _name = [name copy]; + _URL = [URL copy]; + _appVersions = [appVersions copy]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithName:URL:appVersions:); + return [self initWithName:nil URL:nil appVersions:nil]; +} + +#pragma mark NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *name = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_DIALOG_CONFIGURATION_NAME_KEY]; + NSURL *URL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_DIALOG_CONFIGURATION_URL_KEY]; + NSSet *appVersionsClasses = [NSSet setWithObjects:[NSArray class], [NSNumber class], nil]; + NSArray *appVersions = [decoder decodeObjectOfClasses:appVersionsClasses + forKey:FBSDK_DIALOG_CONFIGURATION_APP_VERSIONS_KEY]; + return [self initWithName:name URL:URL appVersions:appVersions]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_appVersions forKey:FBSDK_DIALOG_CONFIGURATION_APP_VERSIONS_KEY]; + [encoder encodeObject:_name forKey:FBSDK_DIALOG_CONFIGURATION_NAME_KEY]; + [encoder encodeObject:_URL forKey:FBSDK_DIALOG_CONFIGURATION_URL_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.h new file mode 100644 index 0000000..ae8bce7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKErrorRecoveryConfiguration.h" + +@class FBSDKGraphRequest; + +// maps codes and subcodes pairs to FBSDKErrorRecoveryConfiguration instances. +@interface FBSDKErrorConfiguration : NSObject + +// initialize from optional dictionary of existing configurations. If not supplied a fallback will be created. +- (instancetype)initWithDictionary:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER; + +// parses the array (supplied from app settings endpoint) +- (void)parseArray:(NSArray *)array; + +// NSString "code" instances support "*" wildcard semantics (nil is treated as "*" also) +// 'request' is optional, typically for identifying special graph request semantics (e.g., no recovery for client token) +- (FBSDKErrorRecoveryConfiguration *)recoveryConfigurationForCode:(NSString *)code subcode:(NSString *)subcode request:(FBSDKGraphRequest *)request; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.m new file mode 100644 index 0000000..81589c4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.m @@ -0,0 +1,176 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKErrorConfiguration.h" + +#import + +#import "FBSDKErrorRecoveryConfiguration.h" + +static NSString *const kErrorCategoryOther = @"other"; +static NSString *const kErrorCategoryTransient = @"transient"; +static NSString *const kErrorCategoryLogin = @"login"; + +#define FBSDKERRORCONFIGURATION_DICTIONARY_KEY @"configurationDictionary" + +@implementation FBSDKErrorConfiguration +{ + NSMutableDictionary *_configurationDictionary; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithDictionary:); + return [self initWithDictionary:nil]; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary +{ + if ((self = [super init])) { + if (dictionary) { + _configurationDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary]; + } else { + _configurationDictionary = [NSMutableDictionary dictionary]; + NSString *localizedOK = + NSLocalizedStringWithDefaultValue(@"ErrorRecovery.OK", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"OK", + @"The title of the label to start attempting error recovery"); + NSString *localizedCancel = + NSLocalizedStringWithDefaultValue(@"ErrorRecovery.Cancel", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Cancel", + @"The title of the label to decline attempting error recovery"); + NSString *localizedTransientSuggestion = + NSLocalizedStringWithDefaultValue(@"ErrorRecovery.Transient.Suggestion", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"The server is temporarily busy, please try again.", + @"The fallback message to display to retry transient errors"); + NSString *localizedLoginRecoverableSuggestion = + NSLocalizedStringWithDefaultValue(@"ErrorRecovery.Login.Suggestion", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Please log into this app again to reconnect your Facebook account.", + @"The fallback message to display to recover invalidated tokens"); + NSArray *fallbackArray = @[ + @{ @"name" : @"login", + @"items" : @[ @{ @"code" : @102 }, + @{ @"code" : @190 } ], + @"recovery_message" : localizedLoginRecoverableSuggestion, + @"recovery_options" : @[ localizedOK, localizedCancel] + }, + @{ @"name" : @"transient", + @"items" : @[ @{ @"code" : @1 }, + @{ @"code" : @2 }, + @{ @"code" : @4 }, + @{ @"code" : @9 }, + @{ @"code" : @17 }, + @{ @"code" : @341 } ], + @"recovery_message" : localizedTransientSuggestion, + @"recovery_options" : @[ localizedOK] + }, + ]; + [self parseArray:fallbackArray]; + } + } + return self; +} + +- (FBSDKErrorRecoveryConfiguration *)recoveryConfigurationForCode:(NSString *)code subcode:(NSString *)subcode request:(FBSDKGraphRequest *)request +{ + code = code ?: @"*"; + subcode = subcode ?: @"*"; + FBSDKErrorRecoveryConfiguration *configuration = (_configurationDictionary[code][subcode] ?: + _configurationDictionary[code][@"*"] ?: + _configurationDictionary[@"*"][subcode] ?: + _configurationDictionary[@"*"][@"*"]); + if (configuration.errorCategory == FBSDKGraphRequestErrorCategoryRecoverable && + [FBSDKSettings clientToken] && + [request.parameters[@"access_token"] hasSuffix:[FBSDKSettings clientToken]]) { + // do not attempt to recovery client tokens. + return nil; + } + return configuration; +} + +- (void)parseArray:(NSArray *)array +{ + for (NSDictionary *dictionary in array) { + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + FBSDKGraphRequestErrorCategory category; + NSString *action = dictionary[@"name"]; + if ([action isEqualToString:kErrorCategoryOther]) { + category = FBSDKGraphRequestErrorCategoryOther; + } else if ([action isEqualToString:kErrorCategoryTransient]) { + category = FBSDKGraphRequestErrorCategoryTransient; + } else { + category = FBSDKGraphRequestErrorCategoryRecoverable; + } + NSString *suggestion = dictionary[@"recovery_message"]; + NSArray *options = dictionary[@"recovery_options"]; + for (NSDictionary *codeSubcodesDictionary in dictionary[@"items"]) { + NSString *code = [codeSubcodesDictionary[@"code"] stringValue]; + + NSMutableDictionary *currentSubcodes = _configurationDictionary[code]; + if (!currentSubcodes) { + currentSubcodes = [NSMutableDictionary dictionary]; + _configurationDictionary[code] = currentSubcodes; + } + + NSArray *subcodes = codeSubcodesDictionary[@"subcodes"]; + if (subcodes.count > 0) { + for (NSNumber *subcodeNumber in subcodes) { + currentSubcodes[[subcodeNumber stringValue]] = [[FBSDKErrorRecoveryConfiguration alloc] + initWithRecoveryDescription:suggestion + optionDescriptions:options + category:category + recoveryActionName:action]; + } + } else { + currentSubcodes[@"*"] = [[FBSDKErrorRecoveryConfiguration alloc] + initWithRecoveryDescription:suggestion + optionDescriptions:options + category:category + recoveryActionName:action]; + } + } + }]; + } +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSDictionary *configurationDictionary = [decoder decodeObjectOfClass:[NSDictionary class] forKey:FBSDKERRORCONFIGURATION_DICTIONARY_KEY]; + return [self initWithDictionary:configurationDictionary]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_configurationDictionary forKey:FBSDKERRORCONFIGURATION_DICTIONARY_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h new file mode 100644 index 0000000..105618f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +//immutable +@interface FBSDKErrorRecoveryConfiguration : NSObject + +@property (nonatomic, readonly) NSString *localizedRecoveryDescription; +@property (nonatomic, readonly) NSArray *localizedRecoveryOptionDescriptions; +@property (nonatomic, readonly) FBSDKGraphRequestErrorCategory errorCategory; +@property (nonatomic, readonly) NSString *recoveryActionName; + +- (instancetype)initWithRecoveryDescription:(NSString *)description + optionDescriptions:(NSArray *)optionDescriptions + category:(FBSDKGraphRequestErrorCategory)category + recoveryActionName:(NSString *)recoveryActionName NS_DESIGNATED_INITIALIZER; +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.m new file mode 100644 index 0000000..3c0642d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.m @@ -0,0 +1,86 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKErrorRecoveryConfiguration.h" + +#define FBSDK_ERROR_RECOVERY_CONFIGURATION_DESCRIPTION_KEY @"description" +#define FBSDK_ERROR_RECOVERY_CONFIGURATION_OPTIONS_KEY @"options" +#define FBSDK_ERROR_RECOVERY_CONFIGURATION_CATEGORY_KEY @"category" +#define FBSDK_ERROR_RECOVERY_CONFIGURATION_ACTION_KEY @"action" + +@implementation FBSDKErrorRecoveryConfiguration + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithRecoveryDescription:optionDescriptions:category:recoveryActionName:); + return [self initWithRecoveryDescription:nil + optionDescriptions:nil + category:0 + recoveryActionName:nil]; +} + +- (instancetype)initWithRecoveryDescription:(NSString *)description + optionDescriptions:(NSArray *)optionDescriptions + category:(FBSDKGraphRequestErrorCategory)category + recoveryActionName:(NSString *)recoveryActionName { + if ((self = [super init])) { + _localizedRecoveryDescription = [description copy]; + _localizedRecoveryOptionDescriptions = [optionDescriptions copy]; + _errorCategory = category; + _recoveryActionName = [recoveryActionName copy]; + } + return self; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *description = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_DESCRIPTION_KEY]; + NSArray *options = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_OPTIONS_KEY]; + NSNumber *category = [decoder decodeObjectOfClass:[NSNumber class] forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_CATEGORY_KEY]; + NSString *action = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_ACTION_KEY]; + + return [self initWithRecoveryDescription:description + optionDescriptions:options + category:[category unsignedIntegerValue] + recoveryActionName:action]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_localizedRecoveryDescription forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_DESCRIPTION_KEY]; + [encoder encodeObject:_localizedRecoveryOptionDescriptions forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_OPTIONS_KEY]; + [encoder encodeObject:@(_errorCategory) forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_CATEGORY_KEY]; + [encoder encodeObject:_recoveryActionName forKey:FBSDK_ERROR_RECOVERY_CONFIGURATION_ACTION_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + //immutable + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration+Internal.h new file mode 100644 index 0000000..5096c03 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration+Internal.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +extern NSString *const FBSDKDialogConfigurationNameDefault; +extern NSString *const FBSDKDialogConfigurationNameSharing; + +extern NSString *const FBSDKDialogConfigurationFeatureUseNativeFlow; +extern NSString *const FBSDKDialogConfigurationFeatureUseSafariViewController; diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h new file mode 100644 index 0000000..9cd1825 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h @@ -0,0 +1,74 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKDialogConfiguration.h" +#import "FBSDKErrorConfiguration.h" + +// login kit +extern NSString *const FBSDKDialogConfigurationNameLogin; + +// share kit +extern NSString *const FBSDKDialogConfigurationNameAppInvite; +extern NSString *const FBSDKDialogConfigurationNameGameRequest; +extern NSString *const FBSDKDialogConfigurationNameGroup; +extern NSString *const FBSDKDialogConfigurationNameLike; +extern NSString *const FBSDKDialogConfigurationNameMessage; +extern NSString *const FBSDKDialogConfigurationNameShare; + +@interface FBSDKServerConfiguration : NSObject + +- (instancetype)initWithAppID:(NSString *)appID + appName:(NSString *)appName + loginTooltipEnabled:(BOOL)loginTooltipEnabled + loginTooltipText:(NSString *)loginTooltipText + defaultShareMode:(NSString *)defaultShareMode + advertisingIDEnabled:(BOOL)advertisingIDEnabled + implicitLoggingEnabled:(BOOL)implicitLoggingEnabled +implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled + systemAuthenticationEnabled:(BOOL)systemAuthenticationEnabled + nativeAuthFlowEnabled:(BOOL)nativeAuthFlowEnabled + dialogConfigurations:(NSDictionary *)dialogConfigurations + dialogFlows:(NSDictionary *)dialogFlows + timestamp:(NSDate *)timestamp + errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration + defaults:(BOOL)defaults +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, assign, readonly, getter=isAdvertisingIDEnabled) BOOL advertisingIDEnabled; +@property (nonatomic, copy, readonly) NSString *appID; +@property (nonatomic, copy, readonly) NSString *appName; +@property (nonatomic, assign, readonly, getter=isDefaults) BOOL defaults; +@property (nonatomic, copy, readonly) NSString *defaultShareMode; +@property (nonatomic, strong, readonly) FBSDKErrorConfiguration *errorConfiguration; +@property (nonatomic, assign, readonly, getter=isImplicitLoggingSupported) BOOL implicitLoggingEnabled; +@property (nonatomic, assign, readonly, getter=isImplicitPurchaseLoggingSupported) BOOL implicitPurchaseLoggingEnabled; +@property (nonatomic, assign, readonly, getter=isLoginTooltipEnabled) BOOL loginTooltipEnabled; +@property (nonatomic, assign, readonly, getter=isNativeAuthFlowEnabled) BOOL nativeAuthFlowEnabled; +@property (nonatomic, assign, readonly, getter=isSystemAuthenticationEnabled) BOOL systemAuthenticationEnabled; +@property (nonatomic, copy, readonly) NSString *loginTooltipText; +@property (nonatomic, copy, readonly) NSDate *timestamp; + +- (FBSDKDialogConfiguration *)dialogConfigurationForDialogName:(NSString *)dialogName; +- (BOOL)useNativeDialogForDialogName:(NSString *)dialogName; +- (BOOL)useSafariViewControllerForDialogName:(NSString *)dialogName; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.m new file mode 100644 index 0000000..5faac5b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.m @@ -0,0 +1,219 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKServerConfiguration.h" +#import "FBSDKServerConfiguration+Internal.h" + +#import "FBSDKInternalUtility.h" +#import "FBSDKMacros.h" + +#define FBSDK_SERVER_CONFIGURATION_ADVERTISING_ID_ENABLED_KEY @"advertisingIDEnabled" +#define FBSDK_SERVER_CONFIGURATION_APP_ID_KEY @"appID" +#define FBSDK_SERVER_CONFIGURATION_APP_NAME_KEY @"appName" +#define FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_KEY @"dialogConfigs" +#define FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_KEY @"dialogFlows" +#define FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGS_KEY @"errorConfigs" +#define FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_KEY @"implicitLoggingEnabled" +#define FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_KEY @"defaultShareMode" +#define FBSDK_SERVER_CONFIGURATION_IMPLICIT_PURCHASE_LOGGING_ENABLED_KEY @"implicitPurchaseLoggingEnabled" +#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_KEY @"loginTooltipEnabled" +#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_KEY @"loginTooltipText" +#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY @"systemAuthenticationEnabled" +#define FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY @"nativeAuthFlowEnabled" +#define FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY @"timestamp" + +#pragma mark - Dialog Names + +NSString *const FBSDKDialogConfigurationNameDefault = @"default"; + +NSString *const FBSDKDialogConfigurationNameLogin = @"login"; + +NSString *const FBSDKDialogConfigurationNameSharing = @"sharing"; + +NSString *const FBSDKDialogConfigurationNameAppInvite = @"app_invite"; +NSString *const FBSDKDialogConfigurationNameGameRequest = @"game_request"; +NSString *const FBSDKDialogConfigurationNameGroup = @"group"; +NSString *const FBSDKDialogConfigurationNameLike = @"like"; +NSString *const FBSDKDialogConfigurationNameMessage = @"message"; +NSString *const FBSDKDialogConfigurationNameShare = @"share"; + +NSString *const FBSDKDialogConfigurationFeatureUseNativeFlow = @"use_native_flow"; +NSString *const FBSDKDialogConfigurationFeatureUseSafariViewController = @"use_safari_vc"; + +@implementation FBSDKServerConfiguration +{ + NSDictionary *_dialogConfigurations; + NSDictionary *_dialogFlows; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithAppID:(NSString *)appID + appName:(NSString *)appName + loginTooltipEnabled:(BOOL)loginTooltipEnabled + loginTooltipText:(NSString *)loginTooltipText + defaultShareMode:(NSString*)defaultShareMode + advertisingIDEnabled:(BOOL)advertisingIDEnabled + implicitLoggingEnabled:(BOOL)implicitLoggingEnabled +implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled + systemAuthenticationEnabled:(BOOL)systemAuthenticationEnabled + nativeAuthFlowEnabled:(BOOL)nativeAuthFlowEnabled + dialogConfigurations:(NSDictionary *)dialogConfigurations + dialogFlows:(NSDictionary *)dialogFlows + timestamp:(NSDate *)timestamp + errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration + defaults:(BOOL)defaults +{ + if ((self = [super init])) { + _appID = [appID copy]; + _appName = [appName copy]; + _loginTooltipEnabled = loginTooltipEnabled; + _loginTooltipText = [loginTooltipText copy]; + _defaultShareMode = defaultShareMode; + _advertisingIDEnabled = advertisingIDEnabled; + _implicitLoggingEnabled = implicitLoggingEnabled; + _implicitPurchaseLoggingEnabled = implicitPurchaseLoggingEnabled; + _systemAuthenticationEnabled = systemAuthenticationEnabled; + _nativeAuthFlowEnabled = nativeAuthFlowEnabled; + _dialogConfigurations = [dialogConfigurations copy]; + _dialogFlows = [dialogFlows copy]; + _timestamp = [timestamp copy]; + _errorConfiguration = [errorConfiguration copy]; + _defaults = defaults; + } + return self; +} + +#pragma mark - Public Methods + +- (FBSDKDialogConfiguration *)dialogConfigurationForDialogName:(NSString *)dialogName +{ + return _dialogConfigurations[dialogName]; +} + +- (BOOL)useNativeDialogForDialogName:(NSString *)dialogName +{ + return [self _useFeatureWithKey:FBSDKDialogConfigurationFeatureUseNativeFlow dialogName:dialogName]; +} + +- (BOOL)useSafariViewControllerForDialogName:(NSString *)dialogName +{ + return [self _useFeatureWithKey:FBSDKDialogConfigurationFeatureUseSafariViewController dialogName:dialogName]; +} + +#pragma mark - Helper Methods + +- (BOOL)_useFeatureWithKey:(NSString *)key dialogName:(NSString *)dialogName +{ + if ([dialogName isEqualToString:FBSDKDialogConfigurationNameLogin]) { + return [(NSNumber *)(_dialogFlows[dialogName][key] ?: + _dialogFlows[FBSDKDialogConfigurationNameDefault][key]) boolValue]; + } else { + return [(NSNumber *)(_dialogFlows[dialogName][key] ?: + _dialogFlows[FBSDKDialogConfigurationNameSharing][key] ?: + _dialogFlows[FBSDKDialogConfigurationNameDefault][key]) boolValue]; + } +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SERVER_CONFIGURATION_APP_ID_KEY]; + NSString *appName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SERVER_CONFIGURATION_APP_NAME_KEY]; + BOOL loginTooltipEnabled = [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_KEY]; + NSString *loginTooltipText = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_KEY]; + NSString *defaultShareMode = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_KEY]; + BOOL advertisingIDEnabled = [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_ADVERTISING_ID_ENABLED_KEY]; + BOOL implicitLoggingEnabled = [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_KEY]; + BOOL implicitPurchaseLoggingEnabbled = + [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_IMPLICIT_PURCHASE_LOGGING_ENABLED_KEY]; + BOOL systemAuthenticationEnabled = + [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY]; + BOOL nativeAuthFlowEnabled = [decoder decodeBoolForKey:FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY]; + NSDate *timestamp = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY]; + NSSet *dialogConfigurationsClasses = [[NSSet alloc] initWithObjects: + [NSDictionary class], + [FBSDKDialogConfiguration class], + nil]; + NSDictionary *dialogConfigurations = [decoder decodeObjectOfClasses:dialogConfigurationsClasses + forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_KEY]; + NSSet *dialogFlowsClasses = [[NSSet alloc] initWithObjects: + [NSDictionary class], + [NSString class], + [NSNumber class], + nil]; + NSDictionary *dialogFlows = [decoder decodeObjectOfClasses:dialogFlowsClasses + forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_KEY]; + FBSDKErrorConfiguration *errorConfiguration = [decoder decodeObjectOfClass:[FBSDKErrorConfiguration class] forKey:FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGS_KEY]; + return [self initWithAppID:appID + appName:appName + loginTooltipEnabled:loginTooltipEnabled + loginTooltipText:loginTooltipText + defaultShareMode:defaultShareMode + advertisingIDEnabled:advertisingIDEnabled + implicitLoggingEnabled:implicitLoggingEnabled +implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabbled + systemAuthenticationEnabled:systemAuthenticationEnabled + nativeAuthFlowEnabled:nativeAuthFlowEnabled + dialogConfigurations:dialogConfigurations + dialogFlows:dialogFlows + timestamp:timestamp + errorConfiguration:errorConfiguration + defaults:NO]; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeBool:_advertisingIDEnabled forKey:FBSDK_SERVER_CONFIGURATION_ADVERTISING_ID_ENABLED_KEY]; + [encoder encodeObject:_appID forKey:FBSDK_SERVER_CONFIGURATION_APP_ID_KEY]; + [encoder encodeObject:_appName forKey:FBSDK_SERVER_CONFIGURATION_APP_NAME_KEY]; + [encoder encodeObject:_defaultShareMode forKey:FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_KEY]; + [encoder encodeObject:_dialogConfigurations forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_KEY]; + [encoder encodeObject:_dialogFlows forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_KEY]; + [encoder encodeObject:_errorConfiguration forKey:FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGS_KEY]; + [encoder encodeBool:_implicitLoggingEnabled forKey:FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_KEY]; + [encoder encodeBool:_implicitPurchaseLoggingEnabled + forKey:FBSDK_SERVER_CONFIGURATION_IMPLICIT_PURCHASE_LOGGING_ENABLED_KEY]; + [encoder encodeBool:_loginTooltipEnabled forKey:FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_KEY]; + [encoder encodeObject:_loginTooltipText forKey:FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_KEY]; + [encoder encodeBool:_nativeAuthFlowEnabled forKey:FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY]; + [encoder encodeBool:_systemAuthenticationEnabled forKey:FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY]; + [encoder encodeObject:_timestamp forKey:FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h new file mode 100644 index 0000000..1edec6f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKServerConfigurationManager.h" + +@class FBSDKGraphRequest; + +@interface FBSDKServerConfigurationManager () + ++ (void)processLoadRequestResponse:(id)result error:(NSError *)error appID:(NSString *)appID; + ++ (FBSDKGraphRequest *)requestToLoadServerConfiguration:(NSString *)appID; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.h new file mode 100644 index 0000000..ed79efb --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKServerConfiguration.h" + +typedef void(^FBSDKServerConfigurationManagerLoadBlock)(FBSDKServerConfiguration *serverConfiguration, NSError *error); + +@interface FBSDKServerConfigurationManager : NSObject + +/** + @abstract Returns the locally cached configuration. + @discussion The result will be valid for the appID from FBSDKSettings, but may be expired. A network request will be + initiated to update the configuration if a valid and unexpired configuration is not available. + */ ++ (FBSDKServerConfiguration *)cachedServerConfiguration; + +/** + @abstract Executes the completionBlock with a valid and current configuration when it is available. + @discussion This method will use a cached configuration if it is valid and not expired. + */ ++ (void)loadServerConfigurationWithCompletionBlock:(FBSDKServerConfigurationManagerLoadBlock)completionBlock; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.m new file mode 100644 index 0000000..116e235 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.m @@ -0,0 +1,357 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKServerConfigurationManager+Internal.h" + +#import "FBSDKGraphRequest+Internal.h" +#import "FBSDKGraphRequest.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKLogger.h" +#import "FBSDKServerConfiguration+Internal.h" +#import "FBSDKServerConfiguration.h" +#import "FBSDKSettings.h" +#import "FBSDKTypeUtility.h" + +// one hour +#define FBSDK_SERVER_CONFIGURATION_MANAGER_CACHE_TIMEOUT (60 * 60) + +#define FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY @"com.facebook.sdk:serverConfiguration%@" + +#define FBSDK_SERVER_CONFIGURATION_APP_EVENTS_FEATURES_FIELD @"app_events_feature_bitmask" +#define FBSDK_SERVER_CONFIGURATION_APP_NAME_FIELD @"name" +#define FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_FIELD @"default_share_mode" +#define FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_FIELD @"ios_dialog_configs" +#define FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_FIELD @"ios_sdk_dialog_flows" +#define FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGURATION_FIELD @"ios_sdk_error_categories" +#define FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_FIELD @"supports_implicit_sdk_logging" +#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_FIELD @"gdpv4_nux_enabled" +#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD @"gdpv4_nux_content" +#define FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD @"ios_supports_native_proxy_auth_flow" +#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD @"ios_supports_system_auth" + +@implementation FBSDKServerConfigurationManager + +static NSMutableArray *_completionBlocks; +static BOOL _loadingServerConfiguration; +static FBSDKServerConfiguration *_serverConfiguration; +static NSError *_serverConfigurationError; +static NSDate *_serverConfigurationErrorTimestamp; +static const NSTimeInterval kTimeout = 4.0; + +typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures) +{ + FBSDKServerConfigurationManagerAppEventsFeaturesNone = 0, + FBSDKServerConfigurationManagerAppEventsFeaturesAdvertisingIDEnabled = 1 << 0, + FBSDKServerConfigurationManagerAppEventsFeaturesImplicitPurchaseLoggingEnabled = 1 << 1, +}; + +#pragma mark - Public Class Methods + ++ (void)initialize +{ + if (self == [FBSDKServerConfigurationManager class]) { + _completionBlocks = [[NSMutableArray alloc] init]; + } +} + ++ (FBSDKServerConfiguration *)cachedServerConfiguration +{ + NSString *appID = [FBSDKSettings appID]; + @synchronized(self) { + // load the server configuration if we don't have it already + [self loadServerConfigurationWithCompletionBlock:NULL]; + + // use whatever configuration we have or the default + return _serverConfiguration ?: [self _defaultServerConfigurationForAppID:appID]; + } +} + ++ (void)loadServerConfigurationWithCompletionBlock:(FBSDKServerConfigurationManagerLoadBlock)completionBlock +{ + void (^loadBlock)(void) = NULL; + NSString *appID = [FBSDKSettings appID]; + @synchronized(self) { + // validate the cached configuration has the correct appID + if (_serverConfiguration && ![_serverConfiguration.appID isEqualToString:appID]) { + _serverConfiguration = nil; + _serverConfigurationError = nil; + _serverConfigurationErrorTimestamp = nil; + } + + // load the configuration from NSUserDefaults + if (!_serverConfiguration) { + // load the defaults + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *defaultsKey = [NSString stringWithFormat:FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY, appID]; + NSData *data = [defaults objectForKey:defaultsKey]; + if ([data isKindOfClass:[NSData class]]) { + // decode the configuration + FBSDKServerConfiguration *serverConfiguration = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + if ([serverConfiguration isKindOfClass:[FBSDKServerConfiguration class]]) { + // ensure that the configuration points to the current appID + if ([serverConfiguration.appID isEqualToString:appID]) { + _serverConfiguration = serverConfiguration; + } + } + } + } + + if ((_serverConfiguration && [self _serverConfigurationTimestampIsValid:_serverConfiguration.timestamp]) || + (_serverConfigurationErrorTimestamp && [self _serverConfigurationTimestampIsValid:_serverConfigurationErrorTimestamp])) { + // we have a valid server configuration, use that + loadBlock = [self _wrapperBlockForLoadBlock:completionBlock]; + } else { + // hold onto the completion block + [FBSDKInternalUtility array:_completionBlocks addObject:[completionBlock copy]]; + + // check if we are already loading + if (!_loadingServerConfiguration) { + // load the configuration from the network + _loadingServerConfiguration = YES; + FBSDKGraphRequest *request = [[self class] requestToLoadServerConfiguration:appID]; + + // start request with specified timeout instead of the default 180s + FBSDKGraphRequestConnection *requestConnection = [[FBSDKGraphRequestConnection alloc] init]; + requestConnection.timeout = kTimeout; + [requestConnection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + [self processLoadRequestResponse:result error:error appID:appID]; + }]; + [requestConnection start]; + } + } + } + + if (loadBlock != NULL) { + loadBlock(); + } +} + +#pragma mark - Internal Class Methods + ++ (void)processLoadRequestResponse:(id)result error:(NSError *)error appID:(NSString *)appID +{ + if (error) { + [self _didProcessConfigurationFromNetwork:nil appID:appID error:error]; + return; + } + + NSDictionary *resultDictionary = [FBSDKTypeUtility dictionaryValue:result]; + NSUInteger appEventsFeatures = [FBSDKTypeUtility unsignedIntegerValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_APP_EVENTS_FEATURES_FIELD]]; + BOOL advertisingIDEnabled = (appEventsFeatures & FBSDKServerConfigurationManagerAppEventsFeaturesAdvertisingIDEnabled); + BOOL implicitPurchaseLoggingEnabled = (appEventsFeatures & FBSDKServerConfigurationManagerAppEventsFeaturesImplicitPurchaseLoggingEnabled); + + NSString *appName = [FBSDKTypeUtility stringValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_APP_NAME_FIELD]]; + BOOL loginTooltipEnabled = [FBSDKTypeUtility boolValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_FIELD]]; + NSString *loginTooltipText = [FBSDKTypeUtility stringValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD]]; + NSString *defaultShareMode = [FBSDKTypeUtility stringValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_FIELD]]; + BOOL implicitLoggingEnabled = [FBSDKTypeUtility boolValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_FIELD]]; + BOOL systemAuthenticationEnabled = [FBSDKTypeUtility boolValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD]]; + BOOL nativeAuthFlowEnabled = [FBSDKTypeUtility boolValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD]]; + NSDictionary *dialogConfigurations = [FBSDKTypeUtility dictionaryValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_FIELD]]; + dialogConfigurations = [self _parseDialogConfigurations:dialogConfigurations]; + NSDictionary *dialogFlows = [FBSDKTypeUtility dictionaryValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_FIELD]]; + FBSDKErrorConfiguration *errorConfiguration = [[FBSDKErrorConfiguration alloc] initWithDictionary:nil]; + [errorConfiguration parseArray:resultDictionary[FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGURATION_FIELD]]; + FBSDKServerConfiguration *serverConfiguration = [[FBSDKServerConfiguration alloc] initWithAppID:appID + appName:appName + loginTooltipEnabled:loginTooltipEnabled + loginTooltipText:loginTooltipText + defaultShareMode:defaultShareMode + advertisingIDEnabled:advertisingIDEnabled + implicitLoggingEnabled:implicitLoggingEnabled + implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabled + systemAuthenticationEnabled:systemAuthenticationEnabled + nativeAuthFlowEnabled:nativeAuthFlowEnabled + dialogConfigurations:dialogConfigurations + dialogFlows:dialogFlows + timestamp:[NSDate date] + errorConfiguration:errorConfiguration + defaults:NO]; + [self _didProcessConfigurationFromNetwork:serverConfiguration appID:appID error:nil]; +} + ++ (FBSDKGraphRequest *)requestToLoadServerConfiguration:(NSString *)appID +{ + NSOperatingSystemVersion operatingSystemVersion = [FBSDKInternalUtility operatingSystemVersion]; + NSString *dialogFlowsField = [NSString stringWithFormat:@"%@.os_version(%ti.%ti.%ti)", + FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_FIELD, + operatingSystemVersion.majorVersion, + operatingSystemVersion.minorVersion, + operatingSystemVersion.patchVersion]; + NSArray *fields = @[FBSDK_SERVER_CONFIGURATION_APP_EVENTS_FEATURES_FIELD, + FBSDK_SERVER_CONFIGURATION_APP_NAME_FIELD, + FBSDK_SERVER_CONFIGURATION_DEFAULT_SHARE_MODE_FIELD, + FBSDK_SERVER_CONFIGURATION_DIALOG_CONFIGS_FIELD, + dialogFlowsField, + FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGURATION_FIELD, + FBSDK_SERVER_CONFIGURATION_IMPLICIT_LOGGING_ENABLED_FIELD, + FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_ENABLED_FIELD, + FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD, + FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD, + FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD, + ]; + NSDictionary *parameters = @{ @"fields": [fields componentsJoinedByString:@","] }; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:appID + parameters:parameters + tokenString:nil + HTTPMethod:nil + flags:FBSDKGraphRequestFlagSkipClientToken | FBSDKGraphRequestFlagDisableErrorRecovery]; + return request; +} + +#pragma mark - Helper Class Methods + ++ (FBSDKServerConfiguration *)_defaultServerConfigurationForAppID:(NSString *)appID +{ + // Use a default configuration while we do not have a configuration back from the server. This allows us to set + // the default values for any of the dialog sets or anything else in a centralized location while we are waiting for + // the server to respond. + static FBSDKServerConfiguration *_defaultServerConfiguration = nil; + if (![_defaultServerConfiguration.appID isEqualToString:appID]) { + // Bypass the native dialog flow for iOS 9+, as it produces a series of additional confirmation dialogs that lead to + // extra friction that is not desirable. + NSOperatingSystemVersion iOS9Version = { .majorVersion = 9, .minorVersion = 0, .patchVersion = 0 }; + BOOL useNativeFlow = ![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS9Version]; + // Also enable SFSafariViewController by default. + NSDictionary *dialogFlows = @{ + FBSDKDialogConfigurationNameDefault: @{ + FBSDKDialogConfigurationFeatureUseNativeFlow: @(useNativeFlow), + FBSDKDialogConfigurationFeatureUseSafariViewController: @YES, + }, + FBSDKDialogConfigurationNameMessage: @{ + FBSDKDialogConfigurationFeatureUseNativeFlow: @YES, + }, + }; + _defaultServerConfiguration = [[FBSDKServerConfiguration alloc] initWithAppID:appID + appName:nil + loginTooltipEnabled:NO + loginTooltipText:nil + defaultShareMode:nil + advertisingIDEnabled:NO + implicitLoggingEnabled:NO + implicitPurchaseLoggingEnabled:NO + systemAuthenticationEnabled:NO + nativeAuthFlowEnabled:NO + dialogConfigurations:nil + dialogFlows:dialogFlows + timestamp:nil + errorConfiguration:nil + defaults:YES]; + } + return _defaultServerConfiguration; +} + ++ (void)_didProcessConfigurationFromNetwork:(FBSDKServerConfiguration *)serverConfiguration + appID:(NSString *)appID + error:(NSError *)error +{ + NSMutableArray *completionBlocks = [[NSMutableArray alloc] init]; + @synchronized(self) { + if (error) { + // Only set the error if we don't have previously fetched app settings. + // (i.e., if we have app settings and a new call gets an error, we'll + // ignore the error and surface the last successfully fetched settings). + if (_serverConfiguration && [_serverConfiguration.appID isEqualToString:appID]) { + // We have older app settings but the refresh received an error. + // Log and ignore the error. + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorInformational + formatString:@"loadServerConfigurationWithCompletionBlock failed with %@", error]; + } else { + _serverConfiguration = nil; + } + _serverConfigurationError = error; + _serverConfigurationErrorTimestamp = [NSDate date]; + } else { + _serverConfiguration = serverConfiguration; + _serverConfigurationError = nil; + _serverConfigurationErrorTimestamp = nil; + } + + // update the cached copy in NSUserDefaults + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *defaultsKey = [NSString stringWithFormat:FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY, appID]; + if (serverConfiguration) { + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:serverConfiguration]; + [defaults setObject:data forKey:defaultsKey]; + } + + // wrap the completion blocks + for (FBSDKServerConfigurationManagerLoadBlock completionBlock in _completionBlocks) { + [completionBlocks addObject:[self _wrapperBlockForLoadBlock:completionBlock]]; + } + [_completionBlocks removeAllObjects]; + _loadingServerConfiguration = NO; + } + + // release the lock before calling out of this class + for (void (^completionBlock)(void) in completionBlocks) { + completionBlock(); + } +} + ++ (NSDictionary *)_parseDialogConfigurations:(NSDictionary *)dictionary +{ + NSMutableDictionary *dialogConfigurations = [[NSMutableDictionary alloc] init]; + NSArray *dialogConfigurationsArray = [FBSDKTypeUtility arrayValue:dictionary[@"data"]]; + for (id dialogConfiguration in dialogConfigurationsArray) { + NSDictionary *dialogConfigurationDictionary = [FBSDKTypeUtility dictionaryValue:dialogConfiguration]; + if (dialogConfigurationDictionary) { + NSString *name = [FBSDKTypeUtility stringValue:dialogConfigurationDictionary[@"name"]]; + if ([name length]) { + NSURL *URL = [FBSDKTypeUtility URLValue:dialogConfigurationDictionary[@"url"]]; + NSArray *appVersions = [FBSDKTypeUtility arrayValue:dialogConfigurationDictionary[@"versions"]]; + dialogConfigurations[name] = [[FBSDKDialogConfiguration alloc] initWithName:name + URL:URL + appVersions:appVersions]; + } + } + } + return dialogConfigurations; +} + ++ (BOOL)_serverConfigurationTimestampIsValid:(NSDate *)timestamp +{ + return ([[NSDate date] timeIntervalSinceDate:timestamp] < FBSDK_SERVER_CONFIGURATION_MANAGER_CACHE_TIMEOUT); +} + ++ (void(^)(void))_wrapperBlockForLoadBlock:(FBSDKServerConfigurationManagerLoadBlock)loadBlock +{ + if (loadBlock == NULL) { + return NULL; + } + + // create local vars to capture the current values from the ivars to allow this wrapper to be called outside of a lock + FBSDKServerConfiguration *serverConfiguration; + NSError *serverConfigurationError; + @synchronized(self) { + serverConfiguration = _serverConfiguration; + serverConfigurationError = _serverConfigurationError; + } + return ^{ + loadBlock(serverConfiguration, serverConfigurationError); + }; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h new file mode 100644 index 0000000..0d7a492 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h @@ -0,0 +1,27 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKAccessTokenCaching.h" + +@interface FBSDKAccessTokenCache : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.m new file mode 100644 index 0000000..aeb1103 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.m @@ -0,0 +1,82 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCache.h" + +#import "FBSDKAccessTokenCacheV3.h" +#import "FBSDKAccessTokenCacheV3_17.h" +#import "FBSDKAccessTokenCacheV3_21.h" +#import "FBSDKAccessTokenCacheV4.h" + +static BOOL g_tryDeprecatedCaches = YES; + +@implementation FBSDKAccessTokenCache + +- (FBSDKAccessToken*)fetchAccessToken +{ + FBSDKAccessToken *token = [[[FBSDKAccessTokenCacheV4 alloc] init] fetchAccessToken]; + if (token || !g_tryDeprecatedCaches) { + return token; + } + + g_tryDeprecatedCaches = NO; + NSArray *oldCacheClasses = [[self class] deprecatedCacheClasses]; + __block FBSDKAccessToken *oldToken = nil; + [oldCacheClasses enumerateObjectsUsingBlock:^(Class obj, NSUInteger idx, BOOL *stop) { + id cache = [[obj alloc] init]; + oldToken = [cache fetchAccessToken]; + if (oldToken) { + *stop = YES; + [cache clearCache]; + } + }]; + if (oldToken) { + [self cacheAccessToken:oldToken]; + } + return oldToken; +} + +- (void)cacheAccessToken:(FBSDKAccessToken *)token +{ + [[[FBSDKAccessTokenCacheV4 alloc] init] cacheAccessToken:token]; + if (g_tryDeprecatedCaches) { + g_tryDeprecatedCaches = NO; + NSArray *oldCacheClasses = [[self class] deprecatedCacheClasses]; + [oldCacheClasses enumerateObjectsUsingBlock:^(Class obj, NSUInteger idx, BOOL *stop) { + id cache = [[obj alloc] init]; + [cache clearCache]; + }]; + } +} + +- (void)clearCache +{ + [[[FBSDKAccessTokenCacheV4 alloc] init] clearCache]; +} + +// used by FBSDKAccessTokenCacheIntegrationTests ++ (void)resetV3CacheChecks +{ + g_tryDeprecatedCaches = YES; +} + ++ (NSArray *)deprecatedCacheClasses +{ + return @[ [FBSDKAccessTokenCacheV3_21 class], [FBSDKAccessTokenCacheV3_17 class], [FBSDKAccessTokenCacheV3 class]]; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h new file mode 100644 index 0000000..28134a0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKAccessTokenCaching.h" +#import "FBSDKMacros.h" + +FBSDK_EXTERN NSString *const FBSDKTokenInformationUUIDKey; + +@interface FBSDKAccessTokenCacheV3 : NSObject + ++ (FBSDKAccessToken *)accessTokenForV3Dictionary:(NSDictionary *)dictionary; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.m new file mode 100644 index 0000000..356a1a6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.m @@ -0,0 +1,79 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCacheV3.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKSettings.h" +#import "FBSDKTypeUtility.h" + +NSString *const FBSDKTokenInformationUUIDKey = @"com.facebook.sdk:TokenInformationUUIDKey"; + +#define FBSDK_TOKEN_INFORMATION_TOKEN_KEY @"com.facebook.sdk:TokenInformationTokenKey" +#define FBSDK_TOKEN_INFORMATION_EXPIRATION_DATE_KEY @"com.facebook.sdk:TokenInformationExpirationDateKey" +#define FBSDK_TOKEN_INFORMATION_USER_FBID_KEY @"com.facebook.sdk:TokenInformationUserFBIDKey" +#define FBSDK_TOKEN_INFORMATION_PERMISSIONS_KEY @"com.facebook.sdk:TokenInformationPermissionsKey" +#define FBSDK_TOKEN_INFORMATION_DECLINED_PERMISSIONS_KEY @"com.facebook.sdk:TokenInformationDeclinedPermissionsKey" +#define FBSDK_TOKEN_INFORMATION_APP_ID_KEY @"com.facebook.sdk:TokenInformationAppIDKey" +#define FBSDK_TOKEN_INFORMATION_REFRESH_DATE_KEY @"com.facebook.sdk:TokenInformationRefreshDateKey" + + +@implementation FBSDKAccessTokenCacheV3 + +- (FBSDKAccessToken *)fetchAccessToken +{ + // Check NSUserDefaults ( <= v3.16 ) + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *tokenDictionary = [defaults objectForKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName]]; + return [[self class] accessTokenForV3Dictionary:tokenDictionary]; +} + +- (void)clearCache +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName]]; + [defaults synchronize]; +} + +- (void)cacheAccessToken:(FBSDKAccessToken *)token +{ + //no-op. + NSAssert(NO, @"deprecated cache FBSDKAccessTokenCacheV3 should not be used to cache a token"); +} + ++ (FBSDKAccessToken *)accessTokenForV3Dictionary:(NSDictionary *)dictionary +{ + NSString *tokenString = [FBSDKTypeUtility stringValue:dictionary[FBSDK_TOKEN_INFORMATION_TOKEN_KEY]]; + if (tokenString.length > 0) { + NSDate *expirationDate = dictionary[FBSDK_TOKEN_INFORMATION_EXPIRATION_DATE_KEY]; + // Note we default to valid in cases where expiration date is missing. + BOOL isExpired = ([expirationDate compare:[NSDate date]] == NSOrderedAscending); + if (isExpired) { + return nil; + } + return [[FBSDKAccessToken alloc] initWithTokenString:tokenString + permissions:dictionary[FBSDK_TOKEN_INFORMATION_PERMISSIONS_KEY] + declinedPermissions:dictionary[FBSDK_TOKEN_INFORMATION_DECLINED_PERMISSIONS_KEY] + appID:dictionary[FBSDK_TOKEN_INFORMATION_APP_ID_KEY] + userID:dictionary[FBSDK_TOKEN_INFORMATION_USER_FBID_KEY] + expirationDate:expirationDate + refreshDate:dictionary[FBSDK_TOKEN_INFORMATION_REFRESH_DATE_KEY]]; + } + return nil; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h new file mode 100644 index 0000000..7f486f3 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKAccessTokenCaching.h" + +@interface FBSDKAccessTokenCacheV3_17 : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.m new file mode 100644 index 0000000..18626e5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.m @@ -0,0 +1,63 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCacheV3_17.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKAccessTokenCacheV3.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKKeychainStoreViaBundleID.h" +#import "FBSDKSettings.h" + +@implementation FBSDKAccessTokenCacheV3_17 +{ + FBSDKKeychainStoreViaBundleID *_keychainStore; +} + +- (instancetype)init +{ + if ((self = [super init])) { + _keychainStore = [[FBSDKKeychainStoreViaBundleID alloc] init]; + } + return self; +} +- (FBSDKAccessToken *)fetchAccessToken +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *uuidKey = [[FBSDKSettings legacyUserDefaultTokenInformationKeyName] stringByAppendingString:@"UUID"]; + NSString *uuid = [defaults objectForKey:uuidKey]; + NSDictionary *tokenDictionary = [_keychainStore dictionaryForKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName]]; + if (![tokenDictionary[FBSDKTokenInformationUUIDKey] isEqualToString:uuid]) { + [self clearCache]; + } + + return [FBSDKAccessTokenCacheV3 accessTokenForV3Dictionary:tokenDictionary]; +} + +- (void)clearCache +{ + [_keychainStore setDictionary:nil forKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName] accessibility:nil]; +} + +- (void)cacheAccessToken:(FBSDKAccessToken *)token +{ + //no-op. + NSAssert(NO, @"deprecated cache FBSDKAccessTokenCacheV3_17 should not be used to cache a token"); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h new file mode 100644 index 0000000..da1ac64 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKAccessTokenCaching.h" + +@interface FBSDKAccessTokenCacheV3_21 : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.m new file mode 100644 index 0000000..845138b --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.m @@ -0,0 +1,66 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCacheV3_21.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKAccessTokenCacheV3.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKKeychainStore.h" +#import "FBSDKSettings.h" + +@implementation FBSDKAccessTokenCacheV3_21 +{ + FBSDKKeychainStore *_keychainStore; +} + +- (instancetype)init +{ + if ((self = [super init])) { + NSString *keyChainServiceIdentifier = [NSString stringWithFormat:@"com.facebook.sdk.tokencache.%@", [[NSBundle mainBundle] bundleIdentifier]]; + _keychainStore = [[FBSDKKeychainStore alloc] initWithService:keyChainServiceIdentifier accessGroup:nil]; + } + return self; +} + +- (FBSDKAccessToken *)fetchAccessToken +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *uuidKey = [[FBSDKSettings legacyUserDefaultTokenInformationKeyName] stringByAppendingString:@"UUID"]; + NSString *uuid = [defaults objectForKey:uuidKey]; + NSDictionary *tokenDictionary = [_keychainStore dictionaryForKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName]]; + if (![tokenDictionary[FBSDKTokenInformationUUIDKey] isEqualToString:uuid]) { + [self clearCache]; + } + + return [FBSDKAccessTokenCacheV3 accessTokenForV3Dictionary:tokenDictionary]; +} + +- (void)clearCache +{ + [_keychainStore setDictionary:nil forKey:[FBSDKSettings legacyUserDefaultTokenInformationKeyName] accessibility:nil]; +} + +- (void)cacheAccessToken:(FBSDKAccessToken *)token +{ + //no-op. + NSAssert(NO, @"deprecated cache FBSDKAccessTokenCacheV3_21 should not be used to cache a token"); +} + + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h new file mode 100644 index 0000000..7fa7d7f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKAccessToken.h" +#import "FBSDKAccessTokenCaching.h" + +@interface FBSDKAccessTokenCacheV4 : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.m new file mode 100644 index 0000000..84d4151 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.m @@ -0,0 +1,97 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAccessTokenCacheV4.h" + +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKKeychainStore.h" + +static NSString *const kFBSDKAccessTokenUserDefaultsKey = @"com.facebook.sdk.v4.FBSDKAccessTokenInformationKey"; +static NSString *const kFBSDKAccessTokenUUIDKey = @"tokenUUID"; +static NSString *const kFBSDKAccessTokenEncodedKey = @"tokenEncoded"; + +@implementation FBSDKAccessTokenCacheV4 +{ + FBSDKKeychainStore *_keychainStore; +} + +- (instancetype)init +{ + if ((self = [super init])) { + NSString *keyChainServiceIdentifier = [NSString stringWithFormat:@"com.facebook.sdk.tokencache.%@", [[NSBundle mainBundle] bundleIdentifier]]; + _keychainStore = [[FBSDKKeychainStore alloc] initWithService:keyChainServiceIdentifier accessGroup:nil]; + } + return self; +} + +- (FBSDKAccessToken *)fetchAccessToken +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *uuid = [defaults objectForKey:kFBSDKAccessTokenUserDefaultsKey]; + + NSDictionary *dict = [_keychainStore dictionaryForKey:kFBSDKAccessTokenUserDefaultsKey]; + if (![dict[kFBSDKAccessTokenUUIDKey] isEqualToString:uuid]) { + // if the uuid doesn't match (including if there is no uuid in defaults which means uninstalled case) + // clear the keychain and return nil. + [self clearCache]; + return nil; + } + + id tokenData = dict[kFBSDKAccessTokenEncodedKey]; + if ([tokenData isKindOfClass:[NSData class]]) { + return [NSKeyedUnarchiver unarchiveObjectWithData:tokenData]; + } else { + return nil; + } +} + +- (void)cacheAccessToken:(FBSDKAccessToken *)token +{ + if (!token) { + [self clearCache]; + return; + } + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *uuid = [defaults objectForKey:kFBSDKAccessTokenUserDefaultsKey]; + if (!uuid) { + uuid = [[NSUUID UUID] UUIDString]; + [defaults setObject:uuid forKey:kFBSDKAccessTokenUserDefaultsKey]; + [defaults synchronize]; + } + NSData *tokenData = [NSKeyedArchiver archivedDataWithRootObject:token]; + NSDictionary *dict = @{ + kFBSDKAccessTokenUUIDKey : uuid, + kFBSDKAccessTokenEncodedKey : tokenData + }; + + [_keychainStore setDictionary:dict + forKey:kFBSDKAccessTokenUserDefaultsKey + accessibility:[FBSDKDynamicFrameworkLoader loadkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly]]; +} + +- (void)clearCache +{ + [_keychainStore setDictionary:nil + forKey:kFBSDKAccessTokenUserDefaultsKey + accessibility:NULL]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kFBSDKAccessTokenUserDefaultsKey]; + [defaults synchronize]; +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h new file mode 100644 index 0000000..8562245 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +@protocol FBSDKAccessTokenCaching + +- (FBSDKAccessToken *)fetchAccessToken; + +- (void)cacheAccessToken:(FBSDKAccessToken *)token; + +- (void)clearCache; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h new file mode 100644 index 0000000..f603635 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKKeychainStore : NSObject + +@property (nonatomic, readonly, copy) NSString *service; +@property (nonatomic, readonly, copy) NSString *accessGroup; + +- (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup NS_DESIGNATED_INITIALIZER; + +- (BOOL)setDictionary:(NSDictionary *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility; +- (NSDictionary *)dictionaryForKey:(NSString *)key; + +- (BOOL)setString:(NSString *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility; +- (NSString *)stringForKey:(NSString *)key; + +- (BOOL)setData:(NSData *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility; +- (NSData *)dataForKey:(NSString *)key; + +// hook for subclasses to override keychain query construction. +- (NSMutableDictionary *)queryForKey:(NSString *)key; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.m new file mode 100644 index 0000000..b2e4f56 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.m @@ -0,0 +1,161 @@ +/** + * Contains code from UICKeyChainStore + * + * Copyright (c) 2011 kishikawa katsumi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import "FBSDKKeychainStore.h" + +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKMacros.h" + +@implementation FBSDKKeychainStore + +- (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup +{ + if ((self = [super init])) { + _service = service ? [service copy] : [[NSBundle mainBundle] bundleIdentifier]; + _accessGroup = [accessGroup copy]; + NSAssert(_service, @"Keychain must be initialized with service"); + } + + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithService:accessGroup:); + return [self initWithService:nil accessGroup:nil]; +} + +- (BOOL)setDictionary:(NSDictionary *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility +{ + NSData *data = value == nil ? nil : [NSKeyedArchiver archivedDataWithRootObject:value]; + return [self setData:data forKey:key accessibility:accessibility]; +} + +- (NSDictionary *)dictionaryForKey:(NSString *)key +{ + NSData *data = [self dataForKey:key]; + if (!data) { + return nil; + } + + NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + if (![dict isKindOfClass:[NSDictionary class]]) { + return nil; + } + + return dict; +} + +- (BOOL)setString:(NSString *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility +{ + NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding]; + return [self setData:data forKey:key accessibility:accessibility]; +} + +- (NSString *)stringForKey:(NSString *)key +{ + NSData *data = [self dataForKey:key]; + if (!data) { + return nil; + } + + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + +- (BOOL)setData:(NSData *)value forKey:(NSString *)key accessibility:(CFTypeRef)accessibility +{ + if (!key) { + return NO; + } + + NSMutableDictionary *query = [self queryForKey:key]; + + OSStatus status; + if (value) { + NSMutableDictionary *attributesToUpdate = [NSMutableDictionary dictionary]; + [attributesToUpdate setObject:value forKey:[FBSDKDynamicFrameworkLoader loadkSecValueData]]; + + status = fbsdkdfl_SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate); + if (status == errSecItemNotFound) { +#if TARGET_OS_IPHONE || (defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9) + if (accessibility) { + [query setObject:(__bridge id)(accessibility) forKey:[FBSDKDynamicFrameworkLoader loadkSecAttrAccessible]]; + } +#endif + [query setObject:value forKey:[FBSDKDynamicFrameworkLoader loadkSecValueData]]; + + status = fbsdkdfl_SecItemAdd((__bridge CFDictionaryRef)query, NULL); + } + } else { + status = fbsdkdfl_SecItemDelete((__bridge CFDictionaryRef)query); + if (status == errSecItemNotFound) { + status = errSecSuccess; + } + } + + return (status == errSecSuccess); +} + +- (NSData *)dataForKey:(NSString *)key +{ + if (!key) { + return nil; + } + + NSMutableDictionary *query = [self queryForKey:key]; + [query setObject:(id)kCFBooleanTrue forKey:[FBSDKDynamicFrameworkLoader loadkSecReturnData]]; + [query setObject:[FBSDKDynamicFrameworkLoader loadkSecMatchLimitOne] forKey:[FBSDKDynamicFrameworkLoader loadkSecMatchLimit]]; + + CFTypeRef data = nil; + OSStatus status = fbsdkdfl_SecItemCopyMatching((__bridge CFDictionaryRef)query, &data); + if (status != errSecSuccess) { + return nil; + } + + if (!data || CFGetTypeID(data) != CFDataGetTypeID()) { + return nil; + } + + NSData *ret = [NSData dataWithData:(__bridge NSData *)(data)]; + CFRelease(data); + + return ret; +} + +- (NSMutableDictionary *)queryForKey:(NSString *)key +{ + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + [query setObject:[FBSDKDynamicFrameworkLoader loadkSecClassGenericPassword] forKey:[FBSDKDynamicFrameworkLoader loadkSecClass]]; + [query setObject:_service forKey:[FBSDKDynamicFrameworkLoader loadkSecAttrService]]; + [query setObject:key forKey:[FBSDKDynamicFrameworkLoader loadkSecAttrAccount]]; +#if !TARGET_IPHONE_SIMULATOR + if (_accessGroup) { + [query setObject:_accessGroup forKey:[FBSDKDynamicFrameworkLoader loadkSecAttrAccessGroup]]; + } +#endif + + return query; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.h new file mode 100644 index 0000000..0a0fb86 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKKeychainStore.h" + +// This is the keychainstore defined in 3.17 that incorrectly used the bundle id as the service id +// and should NOT be used outside of this cache. +@interface FBSDKKeychainStoreViaBundleID : FBSDKKeychainStore + +// since this subclass represents the old keychainstore behavior, +// the designated initializer is just the `init`. +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.m new file mode 100644 index 0000000..d36335c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.m @@ -0,0 +1,50 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKKeychainStoreViaBundleID.h" + +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKInternalUtility.h" + +@implementation FBSDKKeychainStoreViaBundleID + +- (instancetype)init +{ + return [super initWithService:[[NSBundle mainBundle] bundleIdentifier] accessGroup:nil]; +} + +- (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self init]; +} + +- (NSMutableDictionary*)queryForKey:(NSString *)key +{ + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + query[(__bridge id)[FBSDKDynamicFrameworkLoader loadkSecClass]] = (__bridge id)([FBSDKDynamicFrameworkLoader loadkSecClassGenericPassword]); + query[(__bridge id)[FBSDKDynamicFrameworkLoader loadkSecAttrService]] = self.service; + query[(__bridge id)[FBSDKDynamicFrameworkLoader loadkSecAttrGeneric]] = key; + +#if !TARGET_IPHONE_SIMULATOR + [FBSDKInternalUtility dictionary:query setObject:self.accessGroup forKey:[FBSDKDynamicFrameworkLoader loadkSecAttrAccessGroup]]; +#endif + + return query; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h new file mode 100644 index 0000000..788d94d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h @@ -0,0 +1,59 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKIcon.h" + +@protocol FBSDKButtonImpressionTracking + +- (NSDictionary *)analyticsParameters; +- (NSString *)impressionTrackingEventName; +- (NSString *)impressionTrackingIdentifier; + +@end + +@interface FBSDKButton () + +- (void)logTapEventWithEventName:(NSString *)eventName + parameters:(NSDictionary *)parameters; +- (void)checkImplicitlyDisabled; +- (void)configureButton; +- (void)configureWithIcon:(FBSDKIcon *)icon + title:(NSString *)title + backgroundColor:(UIColor *)backgroundColor + highlightedColor:(UIColor *)highlightedColor; +- (void)configureWithIcon:(FBSDKIcon *)icon + title:(NSString *)title + backgroundColor:(UIColor *)backgroundColor + highlightedColor:(UIColor *)highlightedColor + selectedTitle:(NSString *)selectedTitle + selectedIcon:(FBSDKIcon *)selectedIcon + selectedColor:(UIColor *)selectedColor + selectedHighlightedColor:(UIColor *)selectedHighlightedColor; +- (UIColor *)defaultBackgroundColor; +- (UIColor *)defaultDisabledColor; +- (UIColor *)defaultHighlightedColor; +- (FBSDKIcon *)defaultIcon; +- (UIColor *)defaultSelectedColor; +- (BOOL)isImplicitlyDisabled; +- (CGSize)sizeThatFits:(CGSize)size title:(NSString *)title; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h new file mode 100644 index 0000000..ec55385 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKCloseIcon : NSObject + +- (UIImage *)imageWithSize:(CGSize)size; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.m new file mode 100644 index 0000000..1bbb746 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.m @@ -0,0 +1,89 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCloseIcon.h" + +#import "FBSDKMacros.h" + +@implementation FBSDKCloseIcon + +#pragma mark - Public API + +- (UIImage *)imageWithSize:(CGSize)size +{ + CGFloat scale = [UIScreen mainScreen].scale; + UIGraphicsBeginImageContextWithOptions(size, NO, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGFloat iconSize = MIN(size.width, size.height); + + CGRect rect = CGRectMake((size.width - iconSize) / 2, (size.height - iconSize) / 2, iconSize, iconSize); + CGFloat step = iconSize / 12; + + // shadow + rect = CGRectIntegral(CGRectInset(rect, step, step)); + NSArray *colors = @[ + (__bridge id)[UIColor colorWithWhite:0.0 alpha:0.7].CGColor, + (__bridge id)[UIColor colorWithWhite:0.0 alpha:0.3].CGColor, + (__bridge id)[UIColor colorWithWhite:0.0 alpha:0.1].CGColor, + (__bridge id)[UIColor colorWithWhite:0.0 alpha:0.0].CGColor, + ]; + CGFloat locations[4] = { + 0.70, + 0.80, + 0.90, + 1.0, + }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); + CGColorSpaceRelease(colorSpace); + CGPoint center = CGPointMake(CGRectGetMidX(rect) - step / 6, CGRectGetMidY(rect) + step / 4); + CGContextDrawRadialGradient(context, gradient, center, 0.0, center, (CGRectGetWidth(rect) - step / 2) / 2, 0); + CGGradientRelease(gradient); + + // outer circle + rect = CGRectIntegral(CGRectInset(rect, step, step)); + [[UIColor whiteColor] setFill]; + CGContextFillEllipseInRect(context, rect); + + // inner circle + rect = CGRectIntegral(CGRectInset(rect, step, step)); + [[UIColor blackColor] setFill]; + CGContextFillEllipseInRect(context, rect); + + // cross + rect = CGRectIntegral(CGRectInset(rect, step, step)); + CGFloat lineWidth = step * 5 / 4; + rect.origin.y = CGRectGetMidY(rect) - lineWidth / 2; + rect.size.height = lineWidth; + [[UIColor whiteColor] setFill]; + CGContextTranslateCTM(context, size.width / 2, size.height / 2); + CGContextRotateCTM(context, M_PI_4); + CGContextTranslateCTM(context, -size.width / 2, -size.height / 2); + CGContextFillRect(context, rect); + CGContextTranslateCTM(context, size.width / 2, size.height / 2); + CGContextRotateCTM(context, M_PI_2); + CGContextTranslateCTM(context, -size.width / 2, -size.height / 2); + CGContextFillRect(context, rect); + + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h new file mode 100644 index 0000000..54825b6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h @@ -0,0 +1,22 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +UIColor *FBSDKUIColorWithRGBA(uint8_t r, uint8_t g, uint8_t b, CGFloat a); +UIColor *FBSDKUIColorWithRGB(uint8_t r, uint8_t g, uint8_t b); diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.m new file mode 100644 index 0000000..71b3d80 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.m @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKColor.h" + +static const CGFloat kFBRGBMax = 255.0; + +UIColor *FBSDKUIColorWithRGBA(uint8_t r, uint8_t g, uint8_t b, CGFloat a) +{ + return [UIColor colorWithRed:(r / kFBRGBMax) green:(g / kFBRGBMax) blue:(b / kFBRGBMax) alpha:a]; +} + +UIColor *FBSDKUIColorWithRGB(uint8_t r, uint8_t g, uint8_t b) +{ + return FBSDKUIColorWithRGBA(r, g, b, 1.0); +} diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.h new file mode 100644 index 0000000..5be3445 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKIcon : NSObject + +- (instancetype)initWithColor:(UIColor *)color NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, strong, readonly) UIColor *color; + +- (UIImage *)imageWithSize:(CGSize)size; + +- (CGPathRef)pathWithSize:(CGSize)size; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.m new file mode 100644 index 0000000..06b778e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.m @@ -0,0 +1,64 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKIcon.h" + +#import "FBSDKMacros.h" + +@implementation FBSDKIcon + +#pragma mark - Object Lifecycle + +- (instancetype)initWithColor:(UIColor *)color +{ + if ((self = [super init])) { + _color = [color copy]; + } + return self; +} + +- (instancetype)init +{ + return [self initWithColor:[UIColor whiteColor]]; +} + +#pragma mark - Public API + +- (UIImage *)imageWithSize:(CGSize)size +{ + if ((size.width == 0) || (size.height == 0)) { + return nil; + } + CGFloat scale = [UIScreen mainScreen].scale; + UIGraphicsBeginImageContextWithOptions(size, NO, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGPathRef path = [self pathWithSize:size]; + CGContextAddPath(context, path); + CGContextSetFillColorWithColor(context, self.color.CGColor); + CGContextFillPath(context); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} + +- (CGPathRef)pathWithSize:(CGSize)size +{ + return NULL; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.h new file mode 100644 index 0000000..76affe6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKIcon.h" + +@interface FBSDKLogo : FBSDKIcon + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.m new file mode 100644 index 0000000..47d0dc4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.m @@ -0,0 +1,59 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLogo.h" + +@implementation FBSDKLogo + +- (CGPathRef)pathWithSize:(CGSize)size +{ + CGAffineTransform transformValue = CGAffineTransformMakeScale(size.width / 136.0, size.height / 136.0); + const CGAffineTransform *transform = &transformValue; + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, transform, 127.856, 0.676); + CGPathAddLineToPoint(path, transform, 7.469, 0.676); + CGPathAddCurveToPoint(path, transform, 3.344, 0.676, 0.0, 4.02, 0.0, 8.145); + CGPathAddLineToPoint(path, transform, 0.0, 128.531); + CGPathAddCurveToPoint(path, transform, 0.0, 132.656, 3.344, 136.0, 7.469, 136.0); + CGPathAddLineToPoint(path, transform, 72.282, 136.0); + CGPathAddLineToPoint(path, transform, 72.282, 83.596); + CGPathAddLineToPoint(path, transform, 54.646, 83.596); + CGPathAddLineToPoint(path, transform, 54.646, 63.173); + CGPathAddLineToPoint(path, transform, 72.282, 63.173); + CGPathAddLineToPoint(path, transform, 72.282, 48.112); + CGPathAddCurveToPoint(path, transform, 72.282, 30.633, 82.957, 21.116, 98.549, 21.116); + CGPathAddCurveToPoint(path, transform, 106.018, 21.116, 112.438, 21.671, 114.309, 21.92); + CGPathAddLineToPoint(path, transform, 114.309, 40.187); + CGPathAddLineToPoint(path, transform, 103.495, 40.191); + CGPathAddCurveToPoint(path, transform, 95.014, 40.191, 93.372, 44.221, 93.372, 50.133); + CGPathAddLineToPoint(path, transform, 93.372, 63.173); + CGPathAddLineToPoint(path, transform, 113.596, 63.173); + CGPathAddLineToPoint(path, transform, 110.963, 83.596); + CGPathAddLineToPoint(path, transform, 93.372, 83.596); + CGPathAddLineToPoint(path, transform, 93.372, 136.0); + CGPathAddLineToPoint(path, transform, 127.856, 136.0); + CGPathAddCurveToPoint(path, transform, 131.981, 136.0, 135.325, 132.656, 135.325, 128.531); + CGPathAddLineToPoint(path, transform, 135.325, 8.145); + CGPathAddCurveToPoint(path, transform, 135.325, 4.02, 131.981, 0.676, 127.856, 0.676); + CGPathCloseSubpath(path); + CGPathRef result = CGPathCreateCopy(path); + CGPathRelease(path); + return CFAutorelease(result); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.h new file mode 100644 index 0000000..1a44797 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKIcon.h" + +@interface FBSDKMaleSilhouetteIcon : FBSDKIcon + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.m new file mode 100644 index 0000000..6e0e1ed --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.m @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMaleSilhouetteIcon.h" + +@implementation FBSDKMaleSilhouetteIcon + +- (CGPathRef)pathWithSize:(CGSize)size +{ + CGAffineTransform transformValue = CGAffineTransformMakeScale(size.width / 158.783, size.height / 158.783); + CGAffineTransform *transform = &transformValue; + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, transform, 158.783, 158.783); + CGPathAddCurveToPoint(path, transform, 156.39, 131.441, 144.912, 136.964, 105.607, 117.32); + CGPathAddCurveToPoint(path, transform, 103.811, 113.941, 103.348, 108.8965, 103.013, 107.4781); + CGPathAddLineToPoint(path, transform, 100.434, 106.7803); + CGPathAddCurveToPoint(path, transform, 97.2363, 82.7701, 100.67, 101.5845, 106.006, 75.2188); + CGPathAddCurveToPoint(path, transform, 107.949, 76.2959, 108.268, 70.7417, 108.971, 66.5743); + CGPathAddCurveToPoint(path, transform, 109.673, 62.4068, 110.864, 58.9082, 107.139, 58.9082); + CGPathAddCurveToPoint(path, transform, 107.94, 42.7652, 110.299, 31.3848, 101.335, 23.3072); + CGPathAddCurveToPoint(path, transform, 92.3808, 15.23781, 87.874, 15.52349, 95.0483, 9.6036128); + CGPathAddCurveToPoint(path, transform, 91.2319, 8.892613, 70.2036, 12.01861, 57.4487, 23.3072); + CGPathAddCurveToPoint(path, transform, 48.4121, 31.3042, 50.8437, 42.7652, 51.6445, 58.9082); + CGPathAddCurveToPoint(path, transform, 47.9194, 58.9082, 49.1108, 62.4068, 49.813, 66.5743); + CGPathAddCurveToPoint(path, transform, 50.5156, 70.7417, 50.8349, 76.2959, 52.7778, 75.2188); + CGPathAddCurveToPoint(path, transform, 58.1138, 110.1135, 61.5478, 82.7701, 58.3501, 106.7803); + CGPathAddLineToPoint(path, transform, 55.7705, 107.4781); + CGPathAddCurveToPoint(path, transform, 55.4355, 108.8965, 54.9722, 113.941, 53.1767, 117.32); + CGPathAddCurveToPoint(path, transform, 13.8711, 136.964, 2.3945, 131.441, 0.0, 158.783); + CGPathAddLineToPoint(path, transform, 158.783, 158.783); + CGPathRef result = CGPathCreateCopy(path); + CGPathRelease(path); + return CFAutorelease(result); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h new file mode 100644 index 0000000..60458e1 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h @@ -0,0 +1,89 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "../FBSDKMath.h" + +/*! + @abstract Insets a CGSize with the insets in a UIEdgeInsets. + */ +FBSDK_STATIC_INLINE CGSize FBSDKEdgeInsetsInsetSize(CGSize size, UIEdgeInsets insets) +{ + CGRect rect = CGRectZero; + rect.size = size; + return UIEdgeInsetsInsetRect(rect, insets).size; +} + +/*! + @abstract Outsets a CGSize with the insets in a UIEdgeInsets. + */ +FBSDK_STATIC_INLINE CGSize FBSDKEdgeInsetsOutsetSize(CGSize size, UIEdgeInsets insets) +{ + CGRect rect = CGRectZero; + rect.size = size; + return CGSizeMake(insets.left + size.width + insets.right, + insets.top + size.height + insets.bottom); +} + +/*! + @abstract Limits a CGFloat value, using the scale to limit to pixels (instead of points). + + @discussion The limitFunction is frequention floorf, ceilf or roundf. If the scale is 2.0, + you may get back values of *.5 to correspond to pixels. + */ +typedef float (*FBSDKLimitFunctionType)(float); +FBSDK_STATIC_INLINE CGFloat FBSDKPointsForScreenPixels(FBSDKLimitFunctionType limitFunction, + CGFloat screenScale, + CGFloat pointValue) +{ + return limitFunction(pointValue * screenScale) / screenScale; +} + +FBSDK_STATIC_INLINE CGSize FBSDKTextSize(NSString *text, + UIFont *font, + CGSize constrainedSize, + NSLineBreakMode lineBreakMode) +{ + if (!text) { + return CGSizeZero; + } + CGSize size; + if ([NSAttributedString instancesRespondToSelector:@selector(boundingRectWithSize:options:context:)]) { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.lineBreakMode = lineBreakMode; + NSDictionary *attributes = @{ + NSFontAttributeName: font, + NSParagraphStyleAttributeName: paragraphStyle, + }; + NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text attributes:attributes]; + size = [FBSDKMath ceilForSize:[attributedString boundingRectWithSize:constrainedSize + options:(NSStringDrawingUsesDeviceMetrics | + NSStringDrawingUsesLineFragmentOrigin | + NSStringDrawingUsesFontLeading) + context:NULL].size]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + size = [text sizeWithFont:font constrainedToSize:constrainedSize lineBreakMode:lineBreakMode]; +#pragma clang diagnostic pop + } + return [FBSDKMath ceilForSize:size]; +} diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.h new file mode 100644 index 0000000..f280228 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKViewImpressionTracker : NSObject + ++ (instancetype)impressionTrackerWithEventName:(NSString *)eventName; + +@property (nonatomic, copy, readonly) NSString *eventName; + +- (void)logImpressionWithIdentifier:(NSString *)identifier parameters:(NSDictionary *)parameters; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.m new file mode 100644 index 0000000..4f95ad7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.m @@ -0,0 +1,97 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKViewImpressionTracker.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKAppEvents+Internal.h" + +@implementation FBSDKViewImpressionTracker +{ + NSMutableSet *_trackedImpressions; +} + +#pragma mark - Class Methods + ++ (instancetype)impressionTrackerWithEventName:(NSString *)eventName +{ + static NSMutableDictionary *_impressionTrackers = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _impressionTrackers = [[NSMutableDictionary alloc] init]; + }); + // Maintains a single instance of an impression tracker for each event name + FBSDKViewImpressionTracker *impressionTracker = _impressionTrackers[eventName]; + if (!impressionTracker) { + impressionTracker = [[self alloc] initWithEventName:eventName]; + _impressionTrackers[eventName] = impressionTracker; + } + return impressionTracker; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithEventName:(NSString *)eventName +{ + if ((self = [super init])) { + _eventName = [eventName copy]; + _trackedImpressions = [[NSMutableSet alloc] init]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_applicationDidEnterBackgroundNotification:) + name:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Public API + +- (void)logImpressionWithIdentifier:(NSString *)identifier parameters:(NSDictionary *)parameters +{ + NSMutableDictionary *keys = [NSMutableDictionary dictionary]; + keys[@"__view_impression_identifier__"] = identifier; + [keys addEntriesFromDictionary:parameters]; + NSDictionary *impressionKey = [keys copy]; + // Ensure that each impression is only tracked once + if ([_trackedImpressions containsObject:impressionKey]) { + return; + } + [_trackedImpressions addObject:impressionKey]; + + [FBSDKAppEvents logImplicitEvent:self.eventName + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; +} + +#pragma mark - Helper Methods + +- (void)_applicationDidEnterBackgroundNotification:(NSNotification *)notification +{ + // reset all tracked impressions when the app backgrounds so we will start tracking them again the next time they + // are triggered. + [_trackedImpressions removeAllObjects]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.h new file mode 100644 index 0000000..3ad35f3 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@protocol FBSDKWebDialogDelegate; + +@interface FBSDKWebDialog : NSObject + ++ (instancetype)showWithName:(NSString *)name + parameters:(NSDictionary *)parameters + delegate:(id)delegate; + +@property (nonatomic, assign) BOOL deferVisibility; +@property (nonatomic, assign) id delegate; +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSDictionary *parameters; + +- (BOOL)show; + +@end + +@protocol FBSDKWebDialogDelegate + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results; +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error; +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.m new file mode 100644 index 0000000..d398891 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.m @@ -0,0 +1,340 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKWebDialog.h" + +#import "FBSDKAccessToken.h" +#import "FBSDKDynamicFrameworkLoader.h" +#import "FBSDKInternalUtility.h" +#import "FBSDKSettings.h" +#import "FBSDKTypeUtility.h" +#import "FBSDKWebDialogView.h" + +#define FBSDK_WEB_DIALOG_SHOW_ANIMATION_DURATION 0.2 +#define FBSDK_WEB_DIALOG_DISMISS_ANIMATION_DURATION 0.3 + +static FBSDKWebDialog *g_currentDialog = nil; + +@interface FBSDKWebDialog () +@end + +@implementation FBSDKWebDialog +{ + UIView *_backgroundView; + FBSDKWebDialogView *_dialogView; +} + +#pragma mark - Class Methods + ++ (instancetype)showWithName:(NSString *)name + parameters:(NSDictionary *)parameters + delegate:(id)delegate +{ + FBSDKWebDialog *dialog = [[self alloc] init]; + dialog.name = name; + dialog.parameters = parameters; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Object Lifecycle + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + _dialogView.delegate = nil; + [_dialogView removeFromSuperview]; + [_backgroundView removeFromSuperview]; +} + +#pragma mark - Public Methods + +- (BOOL)show +{ + if (g_currentDialog == self) { + return NO; + } + [g_currentDialog _dismissAnimated:YES]; + + NSError *error; + NSURL *URL = [self _generateURL:&error]; + if (!URL) { + [self _failWithError:error]; + return NO; + } + + g_currentDialog = self; + + UIWindow *window = [self _findWindow]; + if (!window) { + [self _failWithError:nil]; + return NO; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + _dialogView = [[FBSDKWebDialogView alloc] initWithFrame:window.screen.applicationFrame]; +#pragma clang diagnostic pop + + _dialogView.delegate = self; + [_dialogView loadURL:URL]; + + if (!_deferVisibility) { + [self _showWebView]; + } + + return YES; +} + +#pragma mark - FBSDKWebDialogViewDelegate + +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didCompleteWithResults:(NSDictionary *)results +{ + [self _completeWithResults:results]; +} + +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didFailWithError:(NSError *)error +{ + [self _failWithError:error]; +} + +- (void)webDialogViewDidCancel:(FBSDKWebDialogView *)webDialogView +{ + [self _cancel]; +} + +- (void)webDialogViewDidFinishLoad:(FBSDKWebDialogView *)webDialogView +{ + if (_deferVisibility) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if (_dialogView) { + [self _showWebView]; + } + }); + } +} + +#pragma mark - Notifications + +- (void)_addObservers +{ + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(_deviceOrientationDidChangeNotification:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; +} + +- (void)_deviceOrientationDidChangeNotification:(NSNotification *)notification +{ + BOOL animated = [FBSDKTypeUtility boolValue:notification.userInfo[@"UIDeviceOrientationRotateAnimatedUserInfoKey"]]; + Class CATransactionClass = fbsdkdfl_CATransactionClass(); + CFTimeInterval animationDuration = (animated ? [CATransactionClass animationDuration] : 0.0); + [self _updateViewsWithScale:1.0 alpha:1.0 animationDuration:animationDuration completion:NULL]; +} + +- (void)_removeObservers +{ + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; +} + +#pragma mark - Helper Methods + +- (void)_cancel +{ + FBSDKWebDialog *dialog = self; + [self _dismissAnimated:YES]; // may cause the receiver to be released + [_delegate webDialogDidCancel:dialog]; +} + +- (void)_completeWithResults:(NSDictionary *)results +{ + FBSDKWebDialog *dialog = self; + [self _dismissAnimated:YES]; // may cause the receiver to be released + [_delegate webDialog:dialog didCompleteWithResults:results]; +} + +- (void)_dismissAnimated:(BOOL)animated +{ + [self _removeObservers]; + UIView *backgroundView = _backgroundView; + _backgroundView = nil; + FBSDKWebDialogView *dialogView = _dialogView; + _dialogView.delegate = nil; + _dialogView = nil; + void(^didDismiss)(BOOL) = ^(BOOL finished){ + [backgroundView removeFromSuperview]; + [dialogView removeFromSuperview]; + }; + if (animated) { + [UIView animateWithDuration:FBSDK_WEB_DIALOG_DISMISS_ANIMATION_DURATION animations:^{ + dialogView.alpha = 0.0; + backgroundView.alpha = 0.0; + } completion:didDismiss]; + } else { + didDismiss(YES); + } + if (g_currentDialog == self) { + g_currentDialog = nil; + } +} + +- (void)_failWithError:(NSError *)error +{ + // defer so that the consumer is guaranteed to have an opportunity to set the delegate before we fail + dispatch_async(dispatch_get_main_queue(), ^{ + [self _dismissAnimated:YES]; + [_delegate webDialog:self didFailWithError:error]; + }); +} + +- (UIWindow *)_findWindow +{ + UIWindow *window = [UIApplication sharedApplication].keyWindow; + if (window == nil || window.windowLevel != UIWindowLevelNormal) { + for (window in [UIApplication sharedApplication].windows) { + if (window.windowLevel == UIWindowLevelNormal) { + break; + } + } + } + return window; +} + +- (NSURL *)_generateURL:(NSError **)errorRef +{ + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + parameters[@"display"] = @"touch"; + parameters[@"sdk"] = [NSString stringWithFormat:@"ios-%@", [FBSDKSettings sdkVersion]]; + parameters[@"redirect_uri"] = @"fbconnect://success"; + [FBSDKInternalUtility dictionary:parameters setObject:[FBSDKSettings appID] forKey:@"app_id"]; + [FBSDKInternalUtility dictionary:parameters + setObject:[FBSDKAccessToken currentAccessToken].tokenString + forKey:@"access_token"]; + [parameters addEntriesFromDictionary:self.parameters]; + return [FBSDKInternalUtility facebookURLWithHostPrefix:@"m" + path:[@"/dialog/" stringByAppendingString:self.name] + queryParameters:parameters + error:errorRef]; +} + +- (BOOL)_showWebView +{ + UIWindow *window = [self _findWindow]; + if (!window) { + [self _failWithError:nil]; + return NO; + } + + [self _addObservers]; + + _backgroundView = [[UIView alloc] initWithFrame:window.bounds]; + _backgroundView.alpha = 0.0; + _backgroundView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + _backgroundView.backgroundColor = [UIColor colorWithWhite:0.3 alpha:0.8]; + [window addSubview:_backgroundView]; + + [window addSubview:_dialogView]; + + [_dialogView becomeFirstResponder]; // dismisses the keyboard if it there was another first responder with it + [self _updateViewsWithScale:0.001 alpha:0.0 animationDuration:0.0 completion:NULL]; + [self _updateViewsWithScale:1.1 alpha:1.0 animationDuration:FBSDK_WEB_DIALOG_SHOW_ANIMATION_DURATION completion:^(BOOL finished1) { + [self _updateViewsWithScale:0.9 alpha:1.0 animationDuration:FBSDK_WEB_DIALOG_SHOW_ANIMATION_DURATION completion:^(BOOL finished2) { + [self _updateViewsWithScale:1.0 alpha:1.0 animationDuration:FBSDK_WEB_DIALOG_SHOW_ANIMATION_DURATION completion:NULL]; + }]; + }]; + return YES; +} + +- (CGAffineTransform)_transformForOrientation +{ + // iOS 8 simply adjusts the application frame to adapt to the current orientation and deprecated the concept of + // interface orientations + if ([FBSDKInternalUtility shouldManuallyAdjustOrientation]) { + switch ([UIApplication sharedApplication].statusBarOrientation) { + case UIInterfaceOrientationLandscapeLeft: + return CGAffineTransformMakeRotation(M_PI * 1.5); + case UIInterfaceOrientationLandscapeRight: + return CGAffineTransformMakeRotation(M_PI/2); + case UIInterfaceOrientationPortraitUpsideDown: + return CGAffineTransformMakeRotation(-M_PI); + case UIInterfaceOrientationPortrait: + case UIInterfaceOrientationUnknown: + // don't adjust the orientation + break; + } + } + return CGAffineTransformIdentity; +} + +- (CGRect)_applicationFrameForOrientation +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CGRect applicationFrame = _dialogView.window.screen.applicationFrame; +#pragma clang diagnostic pop + if ([FBSDKInternalUtility shouldManuallyAdjustOrientation]) { + switch ([UIApplication sharedApplication].statusBarOrientation) { + case UIInterfaceOrientationLandscapeLeft: + case UIInterfaceOrientationLandscapeRight: + return CGRectMake(0, 0, CGRectGetHeight(applicationFrame), CGRectGetWidth(applicationFrame)); + case UIInterfaceOrientationPortraitUpsideDown: + case UIInterfaceOrientationPortrait: + case UIInterfaceOrientationUnknown: + return applicationFrame; + } + } else { + return applicationFrame; + } +} + +- (void)_updateViewsWithScale:(CGFloat)scale + alpha:(CGFloat)alpha + animationDuration:(CFTimeInterval)animationDuration + completion:(void(^)(BOOL finished))completion +{ + CGAffineTransform transform; + CGRect applicationFrame = [self _applicationFrameForOrientation]; + if (scale == 1.0) { + transform = _dialogView.transform; + _dialogView.transform = CGAffineTransformIdentity; + _dialogView.frame = applicationFrame; + _dialogView.transform = transform; + } + transform = CGAffineTransformScale([self _transformForOrientation], scale, scale); + void(^updateBlock)(void) = ^{ + _dialogView.transform = transform; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CGRect mainFrame = _dialogView.window.screen.applicationFrame; +#pragma clang diagnostic pop + _dialogView.center = CGPointMake(CGRectGetMidX(mainFrame), + CGRectGetMidY(mainFrame)); + _backgroundView.alpha = alpha; + }; + if (animationDuration == 0.0) { + updateBlock(); + } else { + [UIView animateWithDuration:animationDuration animations:updateBlock completion:completion]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h new file mode 100644 index 0000000..9ad7427 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@protocol FBSDKWebDialogViewDelegate; + +@interface FBSDKWebDialogView : UIView + +@property (nonatomic, assign) id delegate; + +- (void)loadURL:(NSURL *)URL; +- (void)stopLoading; + +@end + +@protocol FBSDKWebDialogViewDelegate + +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didCompleteWithResults:(NSDictionary *)results; +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didFailWithError:(NSError *)error; +- (void)webDialogViewDidCancel:(FBSDKWebDialogView *)webDialogView; +- (void)webDialogViewDidFinishLoad:(FBSDKWebDialogView *)webDialogView; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.m b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.m new file mode 100644 index 0000000..92df897 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.m @@ -0,0 +1,188 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKWebDialogView.h" + +#import "FBSDKCloseIcon.h" +#import "FBSDKError.h" +#import "FBSDKTypeUtility.h" +#import "FBSDKUtility.h" + +#define FBSDK_WEB_DIALOG_VIEW_BORDER_WIDTH 10.0 + +@interface FBSDKWebDialogView () +@end + +@implementation FBSDKWebDialogView +{ + UIButton *_closeButton; + UIActivityIndicatorView *_loadingView; + UIWebView *_webView; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + + _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + _webView.delegate = self; + [self addSubview:_webView]; + + _closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + UIImage *closeImage = [[[FBSDKCloseIcon alloc] init] imageWithSize:CGSizeMake(29.0, 29.0)]; + [_closeButton setImage:closeImage forState:UIControlStateNormal]; + [_closeButton setTitleColor:[UIColor colorWithRed:167.0/255.0 + green:184.0/255.0 + blue:216.0/255.0 + alpha:1.0] forState:UIControlStateNormal]; + [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; + _closeButton.showsTouchWhenHighlighted = YES; + [_closeButton sizeToFit]; + [self addSubview:_closeButton]; + [_closeButton addTarget:self action:@selector(_close:) forControlEvents:UIControlEventTouchUpInside]; + + _loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + _loadingView.color = [UIColor grayColor]; + [_webView addSubview:_loadingView]; + } + return self; +} + +- (void)dealloc +{ + _webView.delegate = nil; +} + +#pragma mark - Public Methods + +- (void)loadURL:(NSURL *)URL +{ + [_loadingView startAnimating]; + [_webView loadRequest:[NSURLRequest requestWithURL:URL]]; +} + +- (void)stopLoading +{ + [_webView stopLoading]; +} + +#pragma mark - Layout + +- (void)drawRect:(CGRect)rect +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + [self.backgroundColor setFill]; + CGContextFillRect(context, self.bounds); + [[UIColor blackColor] setStroke]; + CGContextSetLineWidth(context, 1.0 / self.layer.contentsScale); + CGContextStrokeRect(context, _webView.frame); + CGContextRestoreGState(context); + [super drawRect:rect]; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect bounds = self.bounds; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + CGFloat horizontalInset = CGRectGetWidth(bounds) * 0.2; + CGFloat verticalInset = CGRectGetHeight(bounds) * 0.2; + UIEdgeInsets iPadInsets = UIEdgeInsetsMake(verticalInset, horizontalInset, verticalInset, horizontalInset); + bounds = UIEdgeInsetsInsetRect(bounds, iPadInsets); + } + UIEdgeInsets webViewInsets = UIEdgeInsetsMake(FBSDK_WEB_DIALOG_VIEW_BORDER_WIDTH, + FBSDK_WEB_DIALOG_VIEW_BORDER_WIDTH, + FBSDK_WEB_DIALOG_VIEW_BORDER_WIDTH, + FBSDK_WEB_DIALOG_VIEW_BORDER_WIDTH); + _webView.frame = UIEdgeInsetsInsetRect(bounds, webViewInsets); + + CGRect webViewBounds = _webView.bounds; + _loadingView.center = CGPointMake(CGRectGetMidX(webViewBounds), CGRectGetMidY(webViewBounds)); + + CGRect closeButtonFrame = _closeButton.bounds; + closeButtonFrame.origin = bounds.origin; + _closeButton.frame = closeButtonFrame; +} + +#pragma mark - Actions + +- (void)_close:(id)sender +{ + [_delegate webDialogViewDidCancel:self]; +} + +#pragma mark - UIWebViewDelegate + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error +{ + [_loadingView stopAnimating]; + + // 102 == WebKitErrorFrameLoadInterruptedByPolicyChange + // NSURLErrorCancelled == "Operation could not be completed", note NSURLErrorCancelled occurs when the user clicks + // away before the page has completely loaded, if we find cases where we want this to result in dialog failure + // (usually this just means quick-user), then we should add something more robust here to account for differences in + // application needs + if (!(([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) || + ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102))) { + [_delegate webDialogView:self didFailWithError:error]; + } +} + +- (BOOL)webView:(UIWebView *)webView +shouldStartLoadWithRequest:(NSURLRequest *)request + navigationType:(UIWebViewNavigationType)navigationType +{ + NSURL *URL = request.URL; + + if ([URL.scheme isEqualToString:@"fbconnect"]) { + NSMutableDictionary *parameters = [[FBSDKUtility dictionaryWithQueryString:URL.query] mutableCopy]; + [parameters addEntriesFromDictionary:[FBSDKUtility dictionaryWithQueryString:URL.fragment]]; + if ([URL.resourceSpecifier hasPrefix:@"//cancel"]) { + NSInteger errorCode = [FBSDKTypeUtility integerValue:parameters[@"error_code"]]; + if (errorCode) { + NSString *errorMessage = [FBSDKTypeUtility stringValue:parameters[@"error_msg"]]; + NSError *error = [FBSDKError errorWithCode:errorCode message:errorMessage]; + [_delegate webDialogView:self didFailWithError:error]; + } else { + [_delegate webDialogViewDidCancel:self]; + } + } else { + [_delegate webDialogView:self didCompleteWithResults:parameters]; + } + return NO; + } else if (navigationType == UIWebViewNavigationTypeLinkClicked) { + [[UIApplication sharedApplication] openURL:request.URL]; + return NO; + } else { + return YES; + } +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [_loadingView stopAnimating]; + [_delegate webDialogViewDidFinishLoad:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/LICENSE b/Unit-2-Journal/Pods/FBSDKCoreKit/LICENSE new file mode 100644 index 0000000..bdb9fc5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Unit-2-Journal/Pods/FBSDKCoreKit/README.mdown b/Unit-2-Journal/Pods/FBSDKCoreKit/README.mdown new file mode 100644 index 0000000..d14a5e4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKCoreKit/README.mdown @@ -0,0 +1,46 @@ +Facebook SDK for iOS +==================== + +This open-source library allows you to integrate Facebook into your iOS app. + +Learn more about the provided samples, documentation, integrating the SDK into your app, accessing source code, and more at https://developers.facebook.com/docs/ios + +NOTE: By default, the Facebook SDK for iOS is installed in ~/Documents/FacebookSDK + +TRY IT OUT +---------- +1. Download the SDK at https://developers.facebook.com/docs/ios or via Cocoapods by adding the 'FBSDKCoreKit', 'FBSDKLoginKit', and 'FBSDKShareKit' pods. +2. Test your install: build and run the project at ~/Documents/FacebookSDK/Samples/Scrumptious/Scrumptious.xcodeproj +3. Check-out the tutorials available online at: https://developers.facebook.com/docs/ios/getting-started +4. Start coding! Visit https://developers.facebook.com/docs/ios for tutorials and reference documentation. + +FEATURES +-------- +* Login - https://developers.facebook.com/docs/facebook-login +* Sharing - https://developers.facebook.com/docs/sharing +* App Links - https://developers.facebook.com/docs/applinks +* Graph API - https://developers.facebook.com/docs/ios/graph +* Analytics for Apps - https://developers.facebook.com/docs/analytics + +GIVE FEEDBACK +------------- +Please report bugs or issues to https://developers.facebook.com/bugs/ + +You can also join the Facebook Developers Group on Facebook (https://www.facebook.com/groups/fbdevelopers/) or ask questions on Stack Overflow (http://facebook.stackoverflow.com) + +LICENSE +------- +See the LICENSE file. + +DEVELOPER TERMS +--------------- + +- By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including information about people’s use of your app. Facebook will use information received in accordance with our Data Use Policy [https://www.facebook.com/about/privacy/], including to provide you with insights about the effectiveness of your ads and the use of your app. These integrations also enable us and our partners to serve ads on and off Facebook. + +- You may limit your sharing of information with us by updating the Insights control in the developer tool [https://developers.facebook.com/apps/{app_id}/settings/advanced]. + +- If you use a Facebook integration, including to share information with us, you agree and confirm that you have provided appropriate and sufficiently prominent notice to and obtained the appropriate consent from your users regarding such collection, use, and disclosure (including, at a minimum, through your privacy policy). You further agree that you will not share information with us about children under the age of 13. + +- You agree to comply with all applicable laws and regulations and also agree to our Terms , including our Platform Policies .and Advertising Guidelines, as applicable . + +By using the Facebook SDK for iOS you agree to these terms. diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h new file mode 100644 index 0000000..51499d4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h @@ -0,0 +1,128 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +#import "FBSDKTooltipView.h" + +@protocol FBSDKLoginButtonDelegate; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKLoginButtonTooltipBehavior) + @abstract Indicates the desired login tooltip behavior. + */ +typedef NS_ENUM(NSUInteger, FBSDKLoginButtonTooltipBehavior) +{ + /*! The default behavior. The tooltip will only be displayed if + the app is eligible (determined by possible server round trip) */ + FBSDKLoginButtonTooltipBehaviorAutomatic = 0, + /*! Force display of the tooltip (typically for UI testing) */ + FBSDKLoginButtonTooltipBehaviorForceDisplay = 1, + /*! Force disable. In this case you can still exert more refined + control by manually constructing a `FBSDKLoginTooltipView` instance. */ + FBSDKLoginButtonTooltipBehaviorDisable = 2 +}; + +/*! + @abstract A button that initiates a log in or log out flow upon tapping. + @discussion `FBSDKLoginButton` works with `[FBSDKAccessToken currentAccessToken]` to + determine what to display, and automatically starts authentication when tapped (i.e., + you do not need to manually subscribe action targets). + + Like `FBSDKLoginManager`, you should make sure your app delegate is connected to + `FBSDKApplicationDelegate` in order for the button's delegate to receive messages. + + `FBSDKLoginButton` has a fixed height, but you may change the width. `initWithFrame:CGRectZero` + will size the button to its minimum frame. +*/ +@interface FBSDKLoginButton : FBSDKButton + +/*! + @abstract The default audience to use, if publish permissions are requested at login time. + */ +@property (assign, nonatomic) FBSDKDefaultAudience defaultAudience; +/*! + @abstract Gets or sets the delegate. + */ +@property (weak, nonatomic) IBOutlet id delegate; +/*! + @abstract Gets or sets the login behavior to use + */ +@property (assign, nonatomic) FBSDKLoginBehavior loginBehavior; +/*! + @abstract The publish permissions to request. + + @discussion Use `defaultAudience` to specify the default audience to publish to. + Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + */ +@property (copy, nonatomic) NSArray *publishPermissions; +/*! + @abstract The read permissions to request. + + @discussion Note, that if read permissions are specified, then publish permissions should not be specified. This is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + */ +@property (copy, nonatomic) NSArray *readPermissions; +/*! + @abstract Gets or sets the desired tooltip behavior. + */ +@property (assign, nonatomic) FBSDKLoginButtonTooltipBehavior tooltipBehavior; +/*! + @abstract Gets or sets the desired tooltip color style. + */ +@property (assign, nonatomic) FBSDKTooltipColorStyle tooltipColorStyle; + +@end + +/*! + @protocol + @abstract A delegate for `FBSDKLoginButton` + */ +@protocol FBSDKLoginButtonDelegate + +@required +/*! + @abstract Sent to the delegate when the button was used to login. + @param loginButton the sender + @param result The results of the login + @param error The error (if any) from the login + */ +- (void) loginButton:(FBSDKLoginButton *)loginButton +didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result + error:(NSError *)error; + +/*! + @abstract Sent to the delegate when the button was used to logout. + @param loginButton The button that was clicked. +*/ +- (void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton; + +@optional +/*! + @abstract Sent to the delegate when the button is about to login. + @param loginButton the sender + @return YES if the login should be allowed to proceed, NO otherwise + */ +- (BOOL) loginButtonWillLogin:(FBSDKLoginButton *)loginButton; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.m new file mode 100644 index 0000000..5ad8daa --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.m @@ -0,0 +1,287 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginButton.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLoginTooltipView.h" + +@interface FBSDKLoginButton() +@end + +@implementation FBSDKLoginButton +{ + BOOL _hasShownTooltipBubble; + FBSDKLoginManager *_loginManager; + NSString *_userID; + NSString *_userName; +} + +#pragma mark - Object Lifecycle + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Properties + +- (FBSDKDefaultAudience)defaultAudience +{ + return _loginManager.defaultAudience; +} + +- (void)setDefaultAudience:(FBSDKDefaultAudience)defaultAudience +{ + _loginManager.defaultAudience = defaultAudience; +} + +- (FBSDKLoginBehavior)loginBehavior +{ + return _loginManager.loginBehavior; +} + +- (void)setLoginBehavior:(FBSDKLoginBehavior)loginBehavior +{ + _loginManager.loginBehavior = loginBehavior; +} + +#pragma mark - UIView + +- (void)didMoveToWindow +{ + [super didMoveToWindow]; + + if (self.window && + ((self.tooltipBehavior == FBSDKLoginButtonTooltipBehaviorForceDisplay) || !_hasShownTooltipBubble)) { + [self performSelector:@selector(_showTooltipIfNeeded) withObject:nil afterDelay:0]; + _hasShownTooltipBubble = YES; + } +} + +#pragma mark - Layout + +- (void)layoutSubviews +{ + CGSize size = self.bounds.size; + CGSize longTitleSize = [self sizeThatFits:size title:[self _longLogInTitle]]; + NSString *title = (longTitleSize.width <= size.width ? + [self _longLogInTitle] : + [self _shortLogInTitle]); + if (![title isEqualToString:[self titleForState:UIControlStateNormal]]) { + [self setTitle:title forState:UIControlStateNormal]; + } + + [super layoutSubviews]; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + if ([self isHidden]) { + return CGSizeZero; + } + CGSize selectedSize = [self sizeThatFits:size title:[self _logOutTitle]]; + CGSize normalSize = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, size.height) title:[self _longLogInTitle]]; + if (normalSize.width > size.width) { + return normalSize = [self sizeThatFits:size title:[self _shortLogInTitle]]; + } + return CGSizeMake(MAX(normalSize.width, selectedSize.width), MAX(normalSize.height, selectedSize.height)); +} + +#pragma mark - UIActionSheetDelegate + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == 0) { + FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init]; + [login logOut]; + [self.delegate loginButtonDidLogOut:self]; + } +} + +#pragma mark - FBSDKButtonImpressionTracking + +- (NSDictionary *)analyticsParameters +{ + return nil; +} + +- (NSString *)impressionTrackingEventName +{ + return FBSDKAppEventNameFBSDKLoginButtonImpression; +} + +- (NSString *)impressionTrackingIdentifier +{ + return @"login"; +} + +#pragma mark - FBSDKButton + +- (void)configureButton +{ + _loginManager = [[FBSDKLoginManager alloc] init]; + + NSString *logInTitle = [self _shortLogInTitle]; + NSString *logOutTitle = [self _logOutTitle]; + + [self configureWithIcon:nil + title:logInTitle + backgroundColor:[super defaultBackgroundColor] + highlightedColor:nil + selectedTitle:logOutTitle + selectedIcon:nil + selectedColor:[super defaultBackgroundColor] + selectedHighlightedColor:nil]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + + [self _updateContent]; + + [self addTarget:self action:@selector(_buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_acessTokenDidChangeNotification:) + name:FBSDKAccessTokenDidChangeNotification + object:nil]; +} + +#pragma mark - Helper Methods + +- (void)_acessTokenDidChangeNotification:(NSNotification *)notification +{ + if (notification.userInfo[FBSDKAccessTokenDidChangeUserID]) { + [self _updateContent]; + } +} + +- (void)_buttonPressed:(id)sender +{ + if ([self.delegate respondsToSelector:@selector(loginButtonWillLogin:)]) { + if (![self.delegate loginButtonWillLogin:self]) { + return; + } + } + + [self logTapEventWithEventName:FBSDKAppEventNameFBSDKLoginButtonDidTap parameters:[self analyticsParameters]]; + if ([FBSDKAccessToken currentAccessToken]) { + NSString *title = nil; + + if (_userName) { + NSString *localizedFormatString = + NSLocalizedStringWithDefaultValue(@"LoginButton.LoggedInAs", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Logged in as %@", + @"The format string for the FBSDKLoginButton label when the user is logged in"); + title = [NSString localizedStringWithFormat:localizedFormatString, _userName]; + } else { + NSString *localizedLoggedIn = + NSLocalizedStringWithDefaultValue(@"LoginButton.LoggedIn", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Logged in using Facebook", + @"The fallback string for the FBSDKLoginButton label when the user name is not available yet"); + title = localizedLoggedIn; + } + NSString *cancelTitle = + NSLocalizedStringWithDefaultValue(@"LoginButton.CancelLogout", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Cancel", + @"The label for the FBSDKLoginButton action sheet to cancel logging out"); + NSString *logOutTitle = + NSLocalizedStringWithDefaultValue(@"LoginButton.ConfirmLogOut", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Log Out", + @"The label for the FBSDKLoginButton action sheet to confirm logging out"); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:title + delegate:self + cancelButtonTitle:cancelTitle + destructiveButtonTitle:logOutTitle + otherButtonTitles:nil]; + [sheet showInView:self]; +#pragma clang diagnostic pop + } else { + FBSDKLoginManagerRequestTokenHandler handler = ^(FBSDKLoginManagerLoginResult *result, NSError *error) { + if ([self.delegate respondsToSelector:@selector(loginButton:didCompleteWithResult:error:)]) { + [self.delegate loginButton:self didCompleteWithResult:result error:error]; + } + }; + + if (self.publishPermissions.count > 0) { + [_loginManager logInWithPublishPermissions:self.publishPermissions + fromViewController:[FBSDKInternalUtility viewControllerforView:self] + handler:handler]; + } else { + [_loginManager logInWithReadPermissions:self.readPermissions + fromViewController:[FBSDKInternalUtility viewControllerforView:self] + handler:handler]; + } + } +} + +- (NSString *)_logOutTitle +{ + return NSLocalizedStringWithDefaultValue(@"LoginButton.LogOut", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Log out", + @"The label for the FBSDKLoginButton when the user is currently logged in"); + ; +} + +- (NSString *)_longLogInTitle +{ + return NSLocalizedStringWithDefaultValue(@"LoginButton.LogInLong", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Log in with Facebook", + @"The long label for the FBSDKLoginButton when the user is currently logged out"); +} + +- (NSString *)_shortLogInTitle +{ + return NSLocalizedStringWithDefaultValue(@"LoginButton.LogIn", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Log in", + @"The short label for the FBSDKLoginButton when the user is currently logged out"); +} + +- (void)_showTooltipIfNeeded +{ + if ([FBSDKAccessToken currentAccessToken] || self.tooltipBehavior == FBSDKLoginButtonTooltipBehaviorDisable) { + return; + } else { + FBSDKLoginTooltipView *tooltipView = [[FBSDKLoginTooltipView alloc] init]; + tooltipView.colorStyle = self.tooltipColorStyle; + if (self.tooltipBehavior == FBSDKLoginButtonTooltipBehaviorForceDisplay) { + tooltipView.forceDisplay = YES; + } + [tooltipView presentFromView:self]; + } +} + +- (void)_updateContent +{ + self.selected = ([FBSDKAccessToken currentAccessToken] != nil); + if ([FBSDKAccessToken currentAccessToken]) { + if (![[FBSDKAccessToken currentAccessToken].userID isEqualToString:_userID]) { + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me?fields=id,name" + parameters:nil + flags:FBSDKGraphRequestFlagDisableErrorRecovery]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + NSString *userID = [FBSDKTypeUtility stringValue:result[@"id"]]; + if (!error && [[FBSDKAccessToken currentAccessToken].userID isEqualToString:userID]) { + _userName = [FBSDKTypeUtility stringValue:result[@"name"]]; + _userID = userID; + } + }]; + } + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h new file mode 100644 index 0000000..100c09a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h @@ -0,0 +1,75 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKLoginKit + @discussion Error codes from the SDK in the range 300-399 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKLoginErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKLoginErrorCode) + @abstract Error codes for FBSDKLoginErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKLoginErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKLoginReservedErrorCode = 300, + /*! + @abstract The error code for unknown errors. + */ + FBSDKLoginUnknownErrorCode, + + /*! + @abstract The user's password has changed and must log in again + */ + FBSDKLoginPasswordChangedErrorCode, + /*! + @abstract The user must log in to their account on www.facebook.com to restore access + */ + FBSDKLoginUserCheckpointedErrorCode, + /*! + @abstract Indicates a failure to request new permissions because the user has changed. + */ + FBSDKLoginUserMismatchErrorCode, + /*! + @abstract The user must confirm their account with Facebook before logging in + */ + FBSDKLoginUnconfirmedUserErrorCode, + + /*! + @abstract The Accounts framework failed without returning an error, indicating the + app's slider in the iOS Facebook Settings (device Settings -> Facebook -> App Name) has + been disabled. + */ + FBSDKLoginSystemAccountAppDisabledErrorCode, + /*! + @abstract An error occurred related to Facebook system Account store + */ + FBSDKLoginSystemAccountUnavailableErrorCode, + /*! + @abstract The login response was missing a valid challenge string. + */ + FBSDKLoginBadChallengeString, +}; diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.m new file mode 100644 index 0000000..1897305 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.m @@ -0,0 +1,21 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginConstants.h" + +NSString *const FBSDKLoginErrorDomain = @"com.facebook.sdk.login"; diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h new file mode 100644 index 0000000..4723940 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h new file mode 100644 index 0000000..ee35bd8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h @@ -0,0 +1,202 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import +#import + +@class FBSDKLoginManagerLoginResult; + +/*! + @abstract Describes the call back to the FBSDKLoginManager + @param result the result of the authorization + @param error the authorization error, if any. + */ +typedef void (^FBSDKLoginManagerRequestTokenHandler)(FBSDKLoginManagerLoginResult *result, NSError *error); + + +/*! + @typedef FBSDKDefaultAudience enum + + @abstract + Passed to open to indicate which default audience to use for sessions that post data to Facebook. + + @discussion + Certain operations such as publishing a status or publishing a photo require an audience. When the user + grants an application permission to perform a publish operation, a default audience is selected as the + publication ceiling for the application. This enumerated value allows the application to select which + audience to ask the user to grant publish permission for. + */ +typedef NS_ENUM(NSUInteger, FBSDKDefaultAudience) +{ + /*! Indicates that the user's friends are able to see posts made by the application */ + FBSDKDefaultAudienceFriends = 0, + /*! Indicates that only the user is able to see posts made by the application */ + FBSDKDefaultAudienceOnlyMe, + /*! Indicates that all Facebook users are able to see posts made by the application */ + FBSDKDefaultAudienceEveryone, +}; + +/*! + @typedef FBSDKLoginBehavior enum + + @abstract + Passed to the \c FBSDKLoginManager to indicate how Facebook Login should be attempted. + + @discussion + Facebook Login authorizes the application to act on behalf of the user, using the user's + Facebook account. Usually a Facebook Login will rely on an account maintained outside of + the application, by the native Facebook application, the browser, or perhaps the device + itself. This avoids the need for a user to enter their username and password directly, and + provides the most secure and lowest friction way for a user to authorize the application to + interact with Facebook. + + The \c FBSDKLoginBehavior enum specifies which log-in methods may be used. The SDK + will determine the best behavior based on the current device (such as iOS version). + */ +typedef NS_ENUM(NSUInteger, FBSDKLoginBehavior) +{ + /*! + @abstract This is the default behavior, and indicates logging in through the native + Facebook app may be used. The SDK may still use Safari instead. + */ + FBSDKLoginBehaviorNative = 0, + /*! + @abstract Attempts log in through the Safari or SFSafariViewController, if available. + */ + FBSDKLoginBehaviorBrowser, + /*! + @abstract Attempts log in through the Facebook account currently signed in through + the device Settings. + @note If the account is not available to the app (either not configured by user or + as determined by the SDK) this behavior falls back to \c FBSDKLoginBehaviorNative. + */ + FBSDKLoginBehaviorSystemAccount, + /*! + @abstract Attemps log in through a modal \c UIWebView pop up + + @note This behavior is only available to certain types of apps. Please check the Facebook + Platform Policy to verify your app meets the restrictions. + */ + FBSDKLoginBehaviorWeb, +}; + +/*! + @abstract `FBSDKLoginManager` provides methods for logging the user in and out. + @discussion `FBSDKLoginManager` works directly with `[FBSDKAccessToken currentAccessToken]` and + sets the "currentAccessToken" upon successful authorizations (or sets `nil` in case of `logOut`). + + You should check `[FBSDKAccessToken currentAccessToken]` before calling logIn* to see if there is + a cached token available (typically in your viewDidLoad). + + If you are managing your own token instances outside of "currentAccessToken", you will need to set + "currentAccessToken" before calling logIn* to authorize futher permissions on your tokens. + */ +@interface FBSDKLoginManager : NSObject + +/*! + @abstract the default audience. + @discussion you should set this if you intend to ask for publish permissions. + */ +@property (assign, nonatomic) FBSDKDefaultAudience defaultAudience; + +/*! + @abstract the login behavior + */ +@property (assign, nonatomic) FBSDKLoginBehavior loginBehavior; + +/*! + @deprecated use logInWithReadPermissions:fromViewController:handler: instead + */ +- (void)logInWithReadPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler +__attribute__ ((deprecated("use logInWithReadPermissions:fromViewController:handler: instead"))); + +/*! + @deprecated use logInWithPublishPermissions:fromViewController:handler: instead + */ +- (void)logInWithPublishPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler +__attribute__ ((deprecated("use logInWithPublishPermissions:fromViewController:handler: instead"))); + +/*! + @abstract Logs the user in or authorizes additional permissions. + @param permissions the optional array of permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param fromViewController the view controller to present from. If nil, the topmost view controller will be + automatically determined as best as possible. + @param handler the callback. + @discussion Use this method when asking for read permissions. You should only ask for permissions when they + are needed and explain the value to the user. You can inspect the result.declinedPermissions to also + provide more information to the user if they decline permissions. + + If `[FBSDKAccessToken currentAccessToken]` is not nil, it will be treated as a reauthorization for that user + and will pass the "rerequest" flag to the login dialog. + + This method will present UI the user. You typically should check if `[FBSDKAccessToken currentAccessToken]` + already contains the permissions you need before asking to reduce unnecessary app switching. For example, + you could make that check at viewDidLoad. + */ +- (void)logInWithReadPermissions:(NSArray *)permissions + fromViewController:(UIViewController *)fromViewController + handler:(FBSDKLoginManagerRequestTokenHandler)handler; + +/*! + @abstract Logs the user in or authorizes additional permissions. + @param permissions the optional array of permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param fromViewController the view controller to present from. If nil, the topmost view controller will be + automatically determined as best as possible. + @param handler the callback. + @discussion Use this method when asking for publish permissions. You should only ask for permissions when they + are needed and explain the value to the user. You can inspect the result.declinedPermissions to also + provide more information to the user if they decline permissions. + + If `[FBSDKAccessToken currentAccessToken]` is not nil, it will be treated as a reauthorization for that user + and will pass the "rerequest" flag to the login dialog. + + This method will present UI the user. You typically should check if `[FBSDKAccessToken currentAccessToken]` + already contains the permissions you need before asking to reduce unnecessary app switching. For example, + you could make that check at viewDidLoad. + */ +- (void)logInWithPublishPermissions:(NSArray *)permissions + fromViewController:(UIViewController *)fromViewController + handler:(FBSDKLoginManagerRequestTokenHandler)handler; + +/*! + @abstract Logs the user out + @discussion This calls [FBSDKAccessToken setCurrentAccessToken:nil] and [FBSDKProfile setCurrentProfile:nil]. + */ +- (void)logOut; + +/*! + @method + + @abstract Issues an asychronous renewCredentialsForAccount call to the device's Facebook account store. + + @param handler The completion handler to call when the renewal is completed. This can be invoked on an arbitrary thread. + + @discussion This can be used to explicitly renew account credentials and is provided as a convenience wrapper around + `[ACAccountStore renewCredentialsForAccount:completion]`. Note the method will not issue the renewal call if the the + Facebook account has not been set on the device, or if access had not been granted to the account (though the handler + wil receive an error). + + If the `[FBSDKAccessToken currentAccessToken]` was from the account store, a succesful renewal will also set + a new "currentAccessToken". + */ ++ (void)renewSystemCredentials:(void (^)(ACAccountCredentialRenewResult result, NSError *error))handler; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.m new file mode 100644 index 0000000..5b91b8f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.m @@ -0,0 +1,785 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginManager+Internal.h" +#import "FBSDKLoginManagerLoginResult+Internal.h" + +#import +#import + +#import "_FBSDKLoginRecoveryAttempter.h" +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLoginCompletion.h" +#import "FBSDKLoginConstants.h" +#import "FBSDKLoginError.h" +#import "FBSDKLoginManagerLogger.h" +#import "FBSDKLoginUtility.h" + +static int const FBClientStateChallengeLength = 20; +static NSString *const FBSDKExpectedChallengeKey = @"expected_login_challenge"; + +@implementation FBSDKLoginManager +{ + FBSDKLoginManagerRequestTokenHandler _handler; + FBSDKLoginManagerLogger *_logger; + // YES if we're calling out to the Facebook app or Safari to perform a log in + BOOL _performingLogIn; + FBSDKKeychainStore *_keychainStore; +} + ++ (void)initialize +{ + if (self == [FBSDKLoginManager class]) { + [_FBSDKLoginRecoveryAttempter class]; + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + NSString *keyChainServiceIdentifier = [NSString stringWithFormat:@"com.facebook.sdk.loginmanager.%@", [[NSBundle mainBundle] bundleIdentifier]]; + _keychainStore = [[FBSDKKeychainStore alloc] initWithService:keyChainServiceIdentifier accessGroup:nil]; + } + return self; +} + +- (void)logInWithReadPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + [self logInWithReadPermissions:permissions + fromViewController:nil + handler:handler]; +} +- (void)logInWithReadPermissions:(NSArray *)permissions + fromViewController:(UIViewController *)fromViewController + handler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + [self assertPermissions:permissions]; + NSSet *permissionSet = [NSSet setWithArray:permissions]; + if (![FBSDKLoginUtility areAllPermissionsReadPermissions:permissionSet]) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"Publish or manage permissions are not permitted to be requested with read permissions." + userInfo:nil] + raise]; + } + self.fromViewController = fromViewController; + [self logInWithPermissions:permissionSet handler:handler]; +} + +- (void)logInWithPublishPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + [self logInWithPublishPermissions:permissions + fromViewController:nil + handler:handler]; +} + +- (void)logInWithPublishPermissions:(NSArray *)permissions + fromViewController:(UIViewController *)fromViewController + handler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + [self assertPermissions:permissions]; + NSSet *permissionSet = [NSSet setWithArray:permissions]; + if (![FBSDKLoginUtility areAllPermissionsPublishPermissions:permissionSet]) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"Read permissions are not permitted to be requested with publish or manage permissions." + userInfo:nil] + raise]; + } + self.fromViewController = fromViewController; + [self logInWithPermissions:permissionSet handler:handler]; +} + +- (void)logOut +{ + [FBSDKAccessToken setCurrentAccessToken:nil]; + [FBSDKProfile setCurrentProfile:nil]; +} + ++ (void)renewSystemCredentials:(void (^)(ACAccountCredentialRenewResult result, NSError *error))handler +{ + FBSDKSystemAccountStoreAdapter *adapter = [FBSDKSystemAccountStoreAdapter sharedInstance]; + + if (!adapter.accountType) { + handler(ACAccountCredentialRenewResultFailed, [FBSDKLoginError errorForFailedLoginWithCode:FBSDKLoginSystemAccountUnavailableErrorCode]); + } else if (!adapter.accountType.accessGranted) { + handler(ACAccountCredentialRenewResultFailed, [FBSDKLoginError errorForFailedLoginWithCode:FBSDKLoginSystemAccountAppDisabledErrorCode]); + } else { + [[FBSDKSystemAccountStoreAdapter sharedInstance] renewSystemAuthorization:handler]; + } +} + +#pragma mark - Private + +- (void)assertPermissions:(NSArray *)permissions +{ + for (NSString *permission in permissions) { + if (![permission isKindOfClass:[NSString class]]) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"Permissions must be string values." + userInfo:nil] + raise]; + } + if ([permission rangeOfString:@","].location != NSNotFound) { + [[NSException exceptionWithName:NSInvalidArgumentException + reason:@"Permissions should each be specified in separate string values in the array." + userInfo:nil] + raise]; + } + } +} + +- (void)completeAuthentication:(FBSDKLoginCompletionParameters *)parameters expectChallenge:(BOOL)expectChallenge +{ + FBSDKLoginManagerLoginResult *result = nil; + NSError *error = parameters.error; + + NSString *tokenString = parameters.accessTokenString; + BOOL cancelled = (tokenString == nil); + + BOOL challengePassed = YES; + if (expectChallenge) { + // Perform this check early so we be sure to clear expected challenge in all cases. + NSString *challengeReceived = parameters.challenge; + NSString *challengeExpected = [self loadExpectedChallenge]; + if (![challengeExpected isEqualToString:challengeReceived]) { + challengePassed = NO; + } + + // Don't overwrite an existing error, if any. + if (!error && !cancelled && !challengePassed) { + error = [FBSDKLoginError errorForFailedLoginWithCode:FBSDKLoginBadChallengeString]; + } + } + + [self storeExpectedChallenge:nil]; + + if (!error) { + if (!cancelled) { + NSSet *grantedPermissions = parameters.permissions; + NSSet *declinedPermissions = parameters.declinedPermissions; + + NSSet *recentlyGrantedPermissions = nil; + NSSet *recentlyDeclinedPermissions = nil; + + [self determineRecentlyGrantedPermissions:&recentlyGrantedPermissions + recentlyDeclinedPermissions:&recentlyDeclinedPermissions + forGrantedPermission:grantedPermissions + declinedPermissions:declinedPermissions]; + + if (recentlyGrantedPermissions.count > 0) { + FBSDKAccessToken *token = [[FBSDKAccessToken alloc] initWithTokenString:tokenString + permissions:[grantedPermissions allObjects] + declinedPermissions:[declinedPermissions allObjects] + appID:parameters.appID + userID:parameters.userID + expirationDate:parameters.expirationDate + refreshDate:[NSDate date]]; + result = [[FBSDKLoginManagerLoginResult alloc] initWithToken:token + isCancelled:NO + grantedPermissions:recentlyGrantedPermissions + declinedPermissions:recentlyDeclinedPermissions]; + + if ([FBSDKAccessToken currentAccessToken]) { + [self validateReauthentication:[FBSDKAccessToken currentAccessToken] withResult:result]; + // in a reauth, short circuit and let the login handler be called when the validation finishes. + return; + } + } else { + cancelled = YES; + } + } + + if (cancelled) { + NSSet *declinedPermissions = nil; + + // If a System Account reauthorization was cancelled by the user tapping Don't Allow + // then add the declined permissions to the login result. The Accounts framework + // doesn't register the decline with Facebook, which is why we don't update the + // access token. + if ([FBSDKAccessToken currentAccessToken] != nil && parameters.isSystemAccount) { + declinedPermissions = parameters.declinedPermissions; + } + + result = [[FBSDKLoginManagerLoginResult alloc] initWithToken:nil + isCancelled:YES + grantedPermissions:nil + declinedPermissions:declinedPermissions]; + } + } + + if (result.token) { + [FBSDKAccessToken setCurrentAccessToken:result.token]; + } + + [self invokeHandler:result error:error]; +} + +- (void)determineRecentlyGrantedPermissions:(NSSet **)recentlyGrantedPermissionsRef + recentlyDeclinedPermissions:(NSSet **)recentlyDeclinedPermissionsRef + forGrantedPermission:(NSSet *)grantedPermissions + declinedPermissions:(NSSet *)declinedPermissions +{ + NSMutableSet *recentlyGrantedPermissions = [grantedPermissions mutableCopy]; + NSSet *previouslyGrantedPermissions = ([FBSDKAccessToken currentAccessToken] ? + [FBSDKAccessToken currentAccessToken].permissions : + nil); + if (previouslyGrantedPermissions.count > 0) { + // this is a reauth, so recentlyGranted should be a subset of what was requested. + [recentlyGrantedPermissions intersectSet:_requestedPermissions]; + } + + NSMutableSet *recentlyDeclinedPermissions = [_requestedPermissions mutableCopy]; + [recentlyDeclinedPermissions intersectSet:declinedPermissions]; + + if (recentlyGrantedPermissionsRef != NULL) { + *recentlyGrantedPermissionsRef = [recentlyGrantedPermissions copy]; + } + if (recentlyDeclinedPermissionsRef != NULL) { + *recentlyDeclinedPermissionsRef = [recentlyDeclinedPermissions copy]; + } +} + +- (void)invokeHandler:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error +{ + [_logger endLoginWithResult:result error:error]; + [_logger endSession]; + _logger = nil; + + if (_handler) { + FBSDKLoginManagerRequestTokenHandler handler = _handler; + _handler(result, error); + if (handler == _handler) { + _handler = nil; + } else { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"** WARNING: You are requesting permissions inside the completion block of an existing login." + "This is unsupported behavior. You should request additional permissions only when they are needed, such as requesting for publish_actions" + "when the user performs a sharing action."]; + } + } +} + +- (NSString *)loadExpectedChallenge +{ + return [_keychainStore stringForKey:FBSDKExpectedChallengeKey]; +} + +- (NSDictionary *)logInParametersWithPermissions:(NSSet *)permissions +{ + [FBSDKInternalUtility validateURLSchemes]; + + NSMutableDictionary *loginParams = [NSMutableDictionary dictionary]; + loginParams[@"client_id"] = [FBSDKSettings appID]; + loginParams[@"response_type"] = @"token,signed_request"; + loginParams[@"redirect_uri"] = @"fbconnect://success"; + loginParams[@"display"] = @"touch"; + loginParams[@"sdk"] = @"ios"; + loginParams[@"return_scopes"] = @"true"; + loginParams[@"sdk_version"] = FBSDK_VERSION_STRING; + loginParams[@"fbapp_pres"] = @([FBSDKInternalUtility isFacebookAppInstalled]); + if ([FBSDKAccessToken currentAccessToken]) { + loginParams[@"auth_type"] = @"rerequest"; + } + [FBSDKInternalUtility dictionary:loginParams setObject:[FBSDKSettings appURLSchemeSuffix] forKey:@"local_client_id"]; + [FBSDKInternalUtility dictionary:loginParams setObject:[FBSDKLoginUtility stringForAudience:self.defaultAudience] forKey:@"default_audience"]; + [FBSDKInternalUtility dictionary:loginParams setObject:[[permissions allObjects] componentsJoinedByString:@","] forKey:@"scope"]; + + NSString *expectedChallenge = [FBSDKLoginManager stringForChallenge]; + NSDictionary *state = @{@"challenge": [FBSDKUtility URLEncode:expectedChallenge]}; + loginParams[@"state"] = [FBSDKInternalUtility JSONStringForObject:state error:NULL invalidObjectHandler:nil]; + + [self storeExpectedChallenge:expectedChallenge]; + + return loginParams; +} + +- (void)logInWithPermissions:(NSSet *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + _logger = [[FBSDKLoginManagerLogger alloc] init]; + + _handler = [handler copy]; + _requestedPermissions = permissions; + + [_logger startSessionForLoginManager:self]; + + [self logInWithBehavior:self.loginBehavior]; +} + +- (void)logInWithBehavior:(FBSDKLoginBehavior)loginBehavior +{ + NSDictionary *loginParams = [self logInParametersWithPermissions:_requestedPermissions]; + + void(^completion)(BOOL, NSString *, NSError *) = ^void(BOOL didPerformLogIn, NSString *authMethod, NSError *error) { + if (didPerformLogIn) { + [_logger startAuthMethod:authMethod]; + _performingLogIn = YES; + } else { + if (!error) { + error = [NSError errorWithDomain:FBSDKLoginErrorDomain code:FBSDKLoginUnknownErrorCode userInfo:nil]; + } + [self invokeHandler:nil error:error]; + } + }; + + switch (loginBehavior) { + case FBSDKLoginBehaviorNative: { + if ([FBSDKInternalUtility isFacebookAppInstalled]) { + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *loadError) { + BOOL useNativeDialog = [serverConfiguration useNativeDialogForDialogName:FBSDKDialogConfigurationNameLogin]; + if (useNativeDialog && loadError == nil) { + [self performNativeLogInWithParameters:loginParams handler:^(BOOL openedURL, NSError *openedURLError) { + if (openedURLError) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors + formatString:@"FBSDKLoginBehaviorNative failed : %@\nTrying FBSDKLoginBehaviorBrowser", openedURLError]; + } + if (openedURL) { + completion(YES, FBSDKLoginManagerLoggerAuthMethod_Native, openedURLError); + } else { + [self logInWithBehavior:FBSDKLoginBehaviorBrowser]; + } + }]; + } else { + [self logInWithBehavior:FBSDKLoginBehaviorBrowser]; + } + }]; + break; + } + // intentional fall through. + } + case FBSDKLoginBehaviorBrowser: { + [self performBrowserLogInWithParameters:loginParams handler:^(BOOL openedURL, + NSString *authMethod, + NSError *openedURLError) { + if (openedURL) { + completion(YES, authMethod, openedURLError); + } else { + completion(NO, authMethod, openedURLError); + } + }]; + break; + } + case FBSDKLoginBehaviorSystemAccount: { + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *loadError) { + if (serverConfiguration.isSystemAuthenticationEnabled && loadError == nil) { + [self beginSystemLogIn]; + } else { + [self logInWithBehavior:FBSDKLoginBehaviorNative]; + } + }]; + completion(YES, FBSDKLoginManagerLoggerAuthMethod_System, nil); + break; + } + case FBSDKLoginBehaviorWeb: + [self performWebLogInWithParameters:loginParams handler:^(BOOL openedURL, NSError *openedURLError) { + completion(openedURL, FBSDKLoginManagerLoggerAuthMethod_Webview, openedURLError); + }]; + break; + } +} + +- (void)storeExpectedChallenge:(NSString *)challengeExpected +{ + [_keychainStore setString:challengeExpected + forKey:FBSDKExpectedChallengeKey + accessibility:[FBSDKDynamicFrameworkLoader loadkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly]]; +} + ++ (NSString *)stringForChallenge { + return [FBSDKCrypto randomString:FBClientStateChallengeLength]; +} + +- (void)validateReauthentication:(FBSDKAccessToken *)currentToken withResult:(FBSDKLoginManagerLoginResult *)loginResult +{ + FBSDKGraphRequest *requestMe = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" + parameters:@{@"fields":@""} + tokenString:loginResult.token.tokenString + HTTPMethod:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + [requestMe startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + NSString *actualID = result[@"id"]; + if ([currentToken.userID isEqualToString:actualID]) { + [FBSDKAccessToken setCurrentAccessToken:loginResult.token]; + [self invokeHandler:loginResult error:nil]; + } else { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [FBSDKInternalUtility dictionary:userInfo setObject:error forKey:NSUnderlyingErrorKey]; + NSError *resultError = [NSError errorWithDomain:FBSDKLoginErrorDomain + code:FBSDKLoginUserMismatchErrorCode + userInfo:userInfo]; + [self invokeHandler:nil error:resultError]; + } + }]; +} + +#pragma mark - Test Methods + +- (void)setHandler:(FBSDKLoginManagerRequestTokenHandler)handler +{ + _handler = [handler copy]; +} + +- (void)setRequestedPermissions:(NSSet *)requestedPermissions +{ + _requestedPermissions = [requestedPermissions copy]; +} + +@end + +#pragma mark - + +@implementation FBSDKLoginManager (Native) + +- (void)performNativeLogInWithParameters:(NSDictionary *)loginParams handler:(void(^)(BOOL, NSError*))handler +{ + [_logger willAttemptAppSwitchingBehavior]; + loginParams = [_logger parametersWithTimeStampAndClientState:loginParams forAuthMethod:FBSDKLoginManagerLoggerAuthMethod_Native]; + + NSString *scheme = ([FBSDKSettings appURLSchemeSuffix] ? @"fbauth2" : @"fbauth"); + NSMutableDictionary *mutableParams = [NSMutableDictionary dictionaryWithDictionary:loginParams]; + mutableParams[@"legacy_override"] = FBSDK_TARGET_PLATFORM_VERSION; + NSError *error; + NSURL *authURL = [FBSDKInternalUtility URLWithScheme:scheme host:@"authorize" path:@"" queryParameters:mutableParams error:&error]; + + [[FBSDKApplicationDelegate sharedInstance] openURL:authURL sender:self handler:^(BOOL openedURL) { + if (handler) { + handler(openedURL, error); + } + }]; +} + +// change bool to auth method string. +- (void)performBrowserLogInWithParameters:(NSDictionary *)loginParams + handler:(void(^)(BOOL didOpen, NSString *authMethod, NSError *error))handler +{ + [_logger willAttemptAppSwitchingBehavior]; + + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useSafariViewController = [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameLogin]; + NSString *authMethod = (useSafariViewController ? FBSDKLoginManagerLoggerAuthMethod_SFVC : FBSDKLoginManagerLoggerAuthMethod_Browser); + + loginParams = [_logger parametersWithTimeStampAndClientState:loginParams forAuthMethod:authMethod]; + + NSURL *authURL = nil; + NSError *error; + NSURL *redirectURL = [FBSDKInternalUtility appURLWithHost:@"authorize" path:nil queryParameters:nil error:&error]; + if (!error) { + NSMutableDictionary *browserParams = [loginParams mutableCopy]; + [FBSDKInternalUtility dictionary:browserParams + setObject:redirectURL + forKey:@"redirect_uri"]; + authURL = [FBSDKInternalUtility facebookURLWithHostPrefix:@"m." + path:@"/dialog/oauth" + queryParameters:browserParams + error:&error]; + } + if (authURL) { + void(^handlerWrapper)(BOOL) = ^(BOOL didOpen) { + if (handler) { + handler(didOpen, authMethod, nil); + } + }; + if (useSafariViewController) { + // Note based on above, authURL must be a http scheme. If that changes, add a guard, otherwise SFVC can throw + [[FBSDKApplicationDelegate sharedInstance] openURLWithSafariViewController:authURL + sender:self + fromViewController:self.fromViewController + handler:handlerWrapper]; + } else { + [[FBSDKApplicationDelegate sharedInstance] openURL:authURL sender:self handler:handlerWrapper]; + } + } else { + error = error ?: [FBSDKError errorWithCode:FBSDKLoginUnknownErrorCode message:@"Failed to construct oauth browser url"]; + if (handler) { + handler(NO, nil, error); + } + } +} + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation +{ + // verify the URL is intended as a callback for the SDK's log in + BOOL isFacebookURL = [[url scheme] hasPrefix:[NSString stringWithFormat:@"fb%@", [FBSDKSettings appID]]] && + [[url host] isEqualToString:@"authorize"]; + + BOOL isExpectedSourceApplication = [sourceApplication hasPrefix:@"com.facebook"] || [sourceApplication hasPrefix:@"com.apple"]; + + if (!isFacebookURL && _performingLogIn) { + [self handleImplicitCancelOfLogIn]; + } + _performingLogIn = NO; + + if (isFacebookURL && isExpectedSourceApplication) { + NSDictionary *urlParameters = [FBSDKLoginUtility queryParamsFromLoginURL:url]; + id completer = [[FBSDKLoginURLCompleter alloc] initWithURLParameters:urlParameters appID:[FBSDKSettings appID]]; + + if (_logger == nil) { + _logger = [FBSDKLoginManagerLogger loggerFromParameters:urlParameters]; + } + + // any necessary strong reference is maintained by the FBSDKLoginURLCompleter handler + [completer completeLogIn:self withHandler:^(FBSDKLoginCompletionParameters *parameters) { + [self completeAuthentication:parameters expectChallenge:YES]; + }]; + } + + return isFacebookURL; +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + if (_performingLogIn) { + _performingLogIn = NO; + [self handleImplicitCancelOfLogIn]; + } +} + +- (void)handleImplicitCancelOfLogIn { + FBSDKLoginManagerLoginResult *result = [[FBSDKLoginManagerLoginResult alloc] initWithToken:nil + isCancelled:YES + grantedPermissions:nil + declinedPermissions:nil]; + [result addLoggingExtra:@(YES) forKey:@"implicit_cancel"]; + [self invokeHandler:result error:nil]; +} + +@end + +@implementation FBSDKLoginManager (Accounts) + +- (void)beginSystemLogIn +{ + // First, we need to validate the current access token. The user may have uninstalled the + // app, changed their password, etc., or the acceess token may have expired, which + // requires us to renew the account before asking for additional permissions. + NSString *accessTokenString = [FBSDKSystemAccountStoreAdapter sharedInstance].accessTokenString; + if (accessTokenString.length > 0) { + FBSDKGraphRequest *meRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" + parameters:@{ @"fields" : @"id" } + tokenString:accessTokenString + HTTPMethod:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + [meRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!error) { + // If there was no error, make an explicit renewal call anyway to cover cases where user has revoked some read permission like email. + // Otherwise, iOS system account may continue to think email was granted and never prompt UI again. + [[FBSDKSystemAccountStoreAdapter sharedInstance] renewSystemAuthorization:^(ACAccountCredentialRenewResult renewResult, NSError *renewError) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self performSystemLogIn]; + }); + }]; + } else { + // If there was an error, FBSDKGraphRequestConnection would have already done work already (like renewal calls) + [self performSystemLogIn]; + } + }]; + } else { + [self performSystemLogIn]; + } +} + +- (void)performSystemLogIn +{ + if (![FBSDKSystemAccountStoreAdapter sharedInstance].accountType) { + // There is no Facebook system account type. Fallback to Native behavior + [self fallbackToNativeBehavior]; + return; + } + BOOL isReauthorize = [FBSDKAccessToken currentAccessToken] != nil; + + // app may be asking for nothing, but we will always have a set here + NSMutableSet *permissionsToUse = _requestedPermissions ? [_requestedPermissions mutableCopy] : [NSMutableSet set]; + // Only add basic info if this is not reauthorize case, if it is the app should already have basic info ToSed + if (!isReauthorize) { + // Ensure that basic info is among the permissions requested so that the app will install if necessary. + // "email" is used as a proxy for basic_info permission. + [permissionsToUse addObject:@"email"]; + } + + [permissionsToUse removeObject:@"public_profile"]; + [permissionsToUse removeObject:@"user_friends"]; + + NSString *audience; + switch (self.defaultAudience) { + case FBSDKDefaultAudienceOnlyMe: + audience = fbsdkdfl_ACFacebookAudienceOnlyMe(); + break; + case FBSDKDefaultAudienceFriends: + audience = fbsdkdfl_ACFacebookAudienceFriends(); + break; + case FBSDKDefaultAudienceEveryone: + audience = fbsdkdfl_ACFacebookAudienceEveryone(); + break; + default: + audience = nil; + } + + unsigned long timePriorToSystemAuthUI = [FBSDKInternalUtility currentTimeInMilliseconds]; + + // the FBSDKSystemAccountStoreAdapter completion handler maintains the strong reference during the the asynchronous operation + [[FBSDKSystemAccountStoreAdapter sharedInstance] + requestAccessToFacebookAccountStore:permissionsToUse + defaultAudience:audience + isReauthorize:isReauthorize + appID:[FBSDKSettings appID] + handler:^(NSString *oauthToken, NSError *accountStoreError) { + + // There doesn't appear to be a reliable way to determine whether UI was shown or + // whether the cached token was sufficient. So we use a timer heuristic assuming that + // human response time couldn't complete a dialog in under the interval given here, but + // the process will return here fast enough if the token is cached. The threshold was + // chosen empirically, so there may be some edge cases that are false negatives or + // false positives. + BOOL didShowDialog = [FBSDKInternalUtility currentTimeInMilliseconds] - timePriorToSystemAuthUI > 350; + BOOL isUnTOSedDevice = !oauthToken && accountStoreError.code == ACErrorAccountNotFound; + [_logger systemAuthDidShowDialog:didShowDialog isUnTOSedDevice:isUnTOSedDevice]; + + if (accountStoreError && [FBSDKSystemAccountStoreAdapter sharedInstance].forceBlockingRenew) { + accountStoreError = [FBSDKLoginError errorForSystemPasswordChange:accountStoreError]; + } + if (!oauthToken && !accountStoreError) { + // This means iOS did not give an error nor granted, even after a renew. In order to + // surface this to users, stuff in our own error that can be inspected. + accountStoreError = [FBSDKLoginError errorForFailedLoginWithCode:FBSDKLoginSystemAccountAppDisabledErrorCode]; + } + + FBSDKLoginManagerSystemAccountState *state = [[FBSDKLoginManagerSystemAccountState alloc] init]; + state.didShowDialog = didShowDialog; + state.reauthorize = isReauthorize; + state.unTOSedDevice = isUnTOSedDevice; + + [self continueSystemLogInWithTokenString:oauthToken error:accountStoreError state:state]; + }]; +} + +- (void)continueSystemLogInWithTokenString:(NSString *)oauthToken error:(NSError *)accountStoreError state:(FBSDKLoginManagerSystemAccountState *)state +{ + id completer = nil; + + if (!oauthToken && accountStoreError.code == ACErrorAccountNotFound) { + // Even with the Accounts framework we use the Facebook app or Safari to log in if + // the user has not signed in. This condition can only be detected by attempting to + // log in because the framework does not otherwise indicate whether a Facebook account + // exists on the device unless the user has granted the app permissions. + + // Do this asynchronously so the logger correctly notes the system account was skipped + dispatch_async(dispatch_get_main_queue(), ^{ + [self fallbackToNativeBehavior]; + }); + } else if (oauthToken) { + completer = [[FBSDKLoginSystemAccountCompleter alloc] initWithTokenString:oauthToken appID:[FBSDKSettings appID]]; + } else { + completer = [[FBSDKLoginSystemAccountErrorCompleter alloc] initWithError:accountStoreError permissions:_requestedPermissions]; + } + + // any necessary strong reference is maintained by the FBSDKLoginSystemAccount[Error]Completer handler + [completer completeLogIn:self withHandler:^(FBSDKLoginCompletionParameters *parameters) { + NSString *eventName = [NSString stringWithFormat:@"%@ %@", + (state.isReauthorize ? @"Reauthorization" : @"Authorization"), + (parameters.error ? @"Error" : (parameters.accessTokenString ? @"succeeded" : @"cancelled")) + ]; + + [self completeAuthentication:parameters expectChallenge:NO]; + + if (eventName != nil) { + NSString *sortedPermissions = (parameters.permissions.count == 0) + ? @"" + : [[parameters.permissions.allObjects sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] componentsJoinedByString:@","]; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNamePermissionsUILaunch + valueToSum:nil + parameters:@{ @"ui_dialog_type" : @"iOS integrated auth", + @"permissions_requested" : sortedPermissions } + accessToken:nil]; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNamePermissionsUIDismiss + valueToSum:nil + parameters:@{ @"ui_dialog_type" : @"iOS integrated auth", + FBSDKAppEventParameterDialogOutcome : eventName, + @"permissions_requested" : sortedPermissions } + accessToken:nil]; + } + }]; +} + +- (void)fallbackToNativeBehavior +{ + FBSDKLoginManagerLoginResult *skippedResult = [[FBSDKLoginManagerLoginResult alloc] initWithToken:nil + isCancelled:NO + grantedPermissions:nil + declinedPermissions:nil]; + skippedResult.isSkipped = YES; + [_logger endLoginWithResult:skippedResult error:nil]; + // any necessary strong reference will be maintained by the mechanism that is used + [self logInWithBehavior:FBSDKLoginBehaviorNative]; +} + +@end + +@implementation FBSDKLoginManager (WebDialog) + +- (void)performWebLogInWithParameters:(NSDictionary *)loginParams handler:(void(^)(BOOL, NSError*))handler +{ + [FBSDKInternalUtility registerTransientObject:self]; + [FBSDKInternalUtility deleteFacebookCookies]; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] initWithDictionary:loginParams]; + parameters[@"title"] = NSLocalizedStringWithDefaultValue(@"LoginWeb.LogInTitle", + @"FacebookSDK", + [FBSDKInternalUtility bundleForStrings], + @"Log In", + @"Title of the web dialog that prompts the user to log in to Facebook."); + [FBSDKWebDialog showWithName:@"oauth" parameters:loginParams delegate:self]; + + if (handler) { + handler(YES, nil); + } +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results +{ + NSString *token = results[@"access_token"]; + + if (token.length == 0) { + [self webDialogDidCancel:webDialog]; + } else { + id completer = [[FBSDKLoginURLCompleter alloc] initWithURLParameters:results appID:[FBSDKSettings appID]]; + [completer completeLogIn:self withHandler:^(FBSDKLoginCompletionParameters *parameters) { + [self completeAuthentication:parameters expectChallenge:YES]; + }]; + [FBSDKInternalUtility unregisterTransientObject:self]; + } +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error +{ + FBSDKLoginCompletionParameters *parameters = [[FBSDKLoginCompletionParameters alloc] initWithError:error]; + [self completeAuthentication:parameters expectChallenge:YES]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog +{ + FBSDKLoginCompletionParameters *parameters = [[FBSDKLoginCompletionParameters alloc] init]; + [self completeAuthentication:parameters expectChallenge:YES]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +@end + +@implementation FBSDKLoginManagerSystemAccountState +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h new file mode 100644 index 0000000..36a1af6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h @@ -0,0 +1,62 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +/*! + @abstract Describes the result of a login attempt. + */ +@interface FBSDKLoginManagerLoginResult : NSObject + +/*! + @abstract the access token. + */ +@property (copy, nonatomic) FBSDKAccessToken *token; + +/*! + @abstract whether the login was cancelled by the user. + */ +@property (readonly, nonatomic) BOOL isCancelled; + +/*! + @abstract the set of permissions granted by the user in the associated request. + @discussion inspect the token's permissions set for a complete list. + */ +@property (copy, nonatomic) NSSet *grantedPermissions; + +/*! + @abstract the set of permissions declined by the user in the associated request. + @discussion inspect the token's permissions set for a complete list. + */ +@property (copy, nonatomic) NSSet *declinedPermissions; + +/*! + @abstract Initializes a new instance. + @param token the access token + @param isCancelled whether the login was cancelled by the user + @param grantedPermissions the set of granted permissions + @param declinedPermissions the set of declined permissions + */ +- (instancetype)initWithToken:(FBSDKAccessToken *)token + isCancelled:(BOOL)isCancelled + grantedPermissions:(NSSet *)grantedPermissions + declinedPermissions:(NSSet *)declinedPermissions +NS_DESIGNATED_INITIALIZER; +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.m new file mode 100644 index 0000000..d03b022 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.m @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginManagerLoginResult+Internal.h" + +#import "FBSDKCoreKit+Internal.h" + +@implementation FBSDKLoginManagerLoginResult { + NSMutableDictionary *_mutableLoggingExtras; +} + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithToken:(FBSDKAccessToken *)token + isCancelled:(BOOL)isCancelled + grantedPermissions:(NSSet *)grantedPermissions + declinedPermissions:(NSSet *)declinedPermissions { + if ((self = [super init])) { + _mutableLoggingExtras = [NSMutableDictionary dictionary]; + _token = [token copy]; + _isCancelled = isCancelled; + _grantedPermissions = [grantedPermissions copy]; + _declinedPermissions = [declinedPermissions copy]; + }; + return self; +} + +- (void)addLoggingExtra:(id)object forKey:(id)key +{ + [FBSDKInternalUtility dictionary:_mutableLoggingExtras setObject:object forKey:key]; +} + +- (NSDictionary *)loggingExtras +{ + return [_mutableLoggingExtras copy]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h new file mode 100644 index 0000000..e6a9411 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h @@ -0,0 +1,93 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKLoginTooltipViewDelegate; + +/*! + @class FBSDKLoginTooltipView + + @abstract Represents a tooltip to be displayed next to a Facebook login button + to highlight features for new users. + + @discussion The `FBSDKLoginButton` may display this view automatically. If you do + not use the `FBSDKLoginButton`, you can manually call one of the `present*` methods + as appropriate and customize behavior via `FBSDKLoginTooltipViewDelegate` delegate. + + By default, the `FBSDKLoginTooltipView` is not added to the superview until it is + determined the app has migrated to the new login experience. You can override this + (e.g., to test the UI layout) by implementing the delegate or setting `forceDisplay` to YES. + + */ +@interface FBSDKLoginTooltipView : FBSDKTooltipView + +/*! @abstract the delegate */ +@property (nonatomic, assign) id delegate; + +/*! @abstract if set to YES, the view will always be displayed and the delegate's + `loginTooltipView:shouldAppear:` will NOT be called. */ +@property (nonatomic, assign) BOOL forceDisplay; + +@end + +/*! + @protocol + + @abstract + The `FBSDKLoginTooltipViewDelegate` protocol defines the methods used to receive event + notifications from `FBSDKLoginTooltipView` objects. + */ +@protocol FBSDKLoginTooltipViewDelegate + +@optional + +/*! + @abstract + Asks the delegate if the tooltip view should appear + + @param view The tooltip view. + @param appIsEligible The value fetched from the server identifying if the app + is eligible for the new login experience. + + @discussion Use this method to customize display behavior. + */ +- (BOOL)loginTooltipView:(FBSDKLoginTooltipView *)view shouldAppear:(BOOL)appIsEligible; + +/*! + @abstract + Tells the delegate the tooltip view will appear, specifically after it's been + added to the super view but before the fade in animation. + + @param view The tooltip view. + */ +- (void)loginTooltipViewWillAppear:(FBSDKLoginTooltipView *)view; + +/*! + @abstract + Tells the delegate the tooltip view will not appear (i.e., was not + added to the super view). + + @param view The tooltip view. + */ +- (void)loginTooltipViewWillNotAppear:(FBSDKLoginTooltipView *)view; + + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.m new file mode 100644 index 0000000..59d4c17 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.m @@ -0,0 +1,62 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginTooltipView.h" + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKLoginTooltipView () +@end + +@implementation FBSDKLoginTooltipView + +- (instancetype)init +{ + NSString *tooltipMessage = + NSLocalizedStringWithDefaultValue(@"LoginTooltip.Message", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"New! You're in control - choose what info you want to share with apps.", + @"The message of the FBSDKLoginTooltipView"); + return [super initWithTagline:nil message:tooltipMessage colorStyle:FBSDKTooltipColorStyleFriendlyBlue]; +} + +- (void)presentInView:(UIView *)view withArrowPosition:(CGPoint)arrowPosition direction:(FBSDKTooltipViewArrowDirection)arrowDirection +{ + if (self.forceDisplay) { + [super presentInView:view withArrowPosition:arrowPosition direction:arrowDirection]; + } else { + + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) { + self.message = serverConfiguration.loginTooltipText; + BOOL shouldDisplay = serverConfiguration.loginTooltipEnabled; + if ([self.delegate respondsToSelector:@selector(loginTooltipView:shouldAppear:)]) { + shouldDisplay = [self.delegate loginTooltipView:self shouldAppear:shouldDisplay]; + } + if (shouldDisplay) { + [super presentInView:view withArrowPosition:arrowPosition direction:arrowDirection]; + if ([self.delegate respondsToSelector:@selector(loginTooltipViewWillAppear:)]) { + [self.delegate loginTooltipViewWillAppear:self]; + } + } else { + if ([self.delegate respondsToSelector:@selector(loginTooltipViewWillNotAppear:)]) { + [self.delegate loginTooltipViewWillNotAppear:self]; + } + } + }]; + } +} +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h new file mode 100644 index 0000000..aff1067 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h @@ -0,0 +1,141 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @typedef FBSDKTooltipViewArrowDirection enum + + @abstract + Passed on construction to determine arrow orientation. + */ +typedef NS_ENUM(NSUInteger, FBSDKTooltipViewArrowDirection) +{ + /*! View is located above given point, arrow is pointing down. */ + FBSDKTooltipViewArrowDirectionDown = 0, + /*! View is located below given point, arrow is pointing up. */ + FBSDKTooltipViewArrowDirectionUp = 1, +}; + +/*! + @typedef FBSDKTooltipColorStyle enum + + @abstract + Passed on construction to determine color styling. + */ +typedef NS_ENUM(NSUInteger, FBSDKTooltipColorStyle) +{ + /*! Light blue background, white text, faded blue close button. */ + FBSDKTooltipColorStyleFriendlyBlue = 0, + /*! Dark gray background, white text, light gray close button. */ + FBSDKTooltipColorStyleNeutralGray = 1, +}; + +/*! + @class FBSDKTooltipView + + @abstract + Tooltip bubble with text in it used to display tips for UI elements, + with a pointed arrow (to refer to the UI element). + + @discussion + The tooltip fades in and will automatically fade out. See `displayDuration`. + */ +@interface FBSDKTooltipView : UIView + +/*! + @abstract Gets or sets the amount of time in seconds the tooltip should be displayed. + + @discussion Set this to zero to make the display permanent until explicitly dismissed. + Defaults to six seconds. + */ +@property (nonatomic, assign) CFTimeInterval displayDuration; + +/*! + @abstract Gets or sets the color style after initialization. + + @discussion Defaults to value passed to -initWithTagline:message:colorStyle:. + */ +@property (nonatomic, assign) FBSDKTooltipColorStyle colorStyle; + +/*! + @abstract Gets or sets the message. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract Gets or sets the optional phrase that comprises the first part of the label (and is highlighted differently). + */ +@property (nonatomic, copy) NSString *tagline; + +/*! + @abstract + Designated initializer. + + @param tagline First part of the label, that will be highlighted with different color. Can be nil. + + @param message Main message to display. + + @param colorStyle Color style to use for tooltip. + + @discussion + If you need to show a tooltip for login, consider using the `FBSDKLoginTooltipView` view. + + @see FBSDKLoginTooltipView + */ +- (instancetype)initWithTagline:(NSString *)tagline message:(NSString *)message colorStyle:(FBSDKTooltipColorStyle)colorStyle; + +/*! + @abstract + Show tooltip at the top or at the bottom of given view. + Tooltip will be added to anchorView.window.rootViewController.view + + @param anchorView view to show at, must be already added to window view hierarchy, in order to decide + where tooltip will be shown. (If there's not enough space at the top of the anchorView in window bounds - + tooltip will be shown at the bottom of it) + + @discussion + Use this method to present the tooltip with automatic positioning or + use -presentInView:withArrowPosition:direction: for manual positioning + If anchorView is nil or has no window - this method does nothing. + */ +- (void)presentFromView:(UIView *)anchorView; + +/*! + @abstract + Adds tooltip to given view, with given position and arrow direction. + + @param view View to be used as superview. + + @param arrowPosition Point in view's cordinates, where arrow will be pointing + + @param arrowDirection whenever arrow should be pointing up (message bubble is below the arrow) or + down (message bubble is above the arrow). + */ +- (void)presentInView:(UIView *)view withArrowPosition:(CGPoint)arrowPosition direction:(FBSDKTooltipViewArrowDirection)arrowDirection; + +/*! + @abstract + Remove tooltip manually. + + @discussion + Calling this method isn't necessary - tooltip will dismiss itself automatically after the `displayDuration`. + */ +- (void)dismiss; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.m new file mode 100644 index 0000000..839e98f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.m @@ -0,0 +1,603 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKTooltipView.h" + +#import + +#import "FBSDKCoreKit+Internal.h" + +static const CGFloat kTransitionDuration = 0.3; +static const CGFloat kZoomOutScale = 0.001f; +static const CGFloat kZoomInScale = 1.1f; +static const CGFloat kZoomBounceScale = 0.98f; + +static const CGFloat kNUXRectInset = 6; +static const CGFloat kNUXBubbleMargin = 17 - kNUXRectInset; +static const CGFloat kNUXPointMargin = -3; +static const CGFloat kNUXCornerRadius = 4; +static const CGFloat kNUXStrokeLineWidth = 0.5f; +static const CGFloat kNUXSideCap = 6; +static const CGFloat kNUXFontSize = 10; +static const CGFloat kNUXCrossGlyphSize = 11; + +static CGMutablePathRef _fbsdkCreateUpPointingBubbleWithRect(CGRect rect, CGFloat arrowMidpoint, CGFloat arrowHeight, CGFloat radius); +static CGMutablePathRef _fbsdkCreateDownPointingBubbleWithRect(CGRect rect, CGFloat arrowMidpoint, CGFloat arrowHeight, CGFloat radius); + +#pragma mark - + +@implementation FBSDKTooltipView +{ + CGPoint _positionInView; + CFAbsoluteTime _displayTime; + CFTimeInterval _minimumDisplayDuration; + UILabel *_textLabel; + UITapGestureRecognizer *_insideTapGestureRecognizer; + CGFloat _leftWidth; + CGFloat _rightWidth; + CGFloat _arrowMidpoint; + BOOL _pointingUp; + BOOL _isFadingOut; + // style + UIColor *_innerStrokeColor; + CGFloat _arrowHeight; + CGFloat _textPadding; + CGFloat _maximumTextWidth; + CGFloat _verticalTextOffset; + CGFloat _verticalCrossOffset; + FBSDKTooltipColorStyle _colorStyle; + NSArray *_gradientColors; + UIColor *_crossCloseGlyphColor; +} + +- (instancetype)initWithTagline:(NSString *)tagline message:(NSString *)message colorStyle:(FBSDKTooltipColorStyle)colorStyle +{ + self = [super initWithFrame:CGRectZero]; + if (self) { + // Define style + _textLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _textLabel.backgroundColor = [UIColor clearColor]; + _textLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin; + _textLabel.numberOfLines = 0; + _textLabel.font = [UIFont boldSystemFontOfSize: kNUXFontSize]; + _textLabel.textAlignment = NSTextAlignmentLeft; + _arrowHeight = 7; + _textPadding = 10; + _maximumTextWidth = 185; + _verticalCrossOffset = - 2.5f; + _verticalTextOffset = 0; + _displayDuration = 6.0; + [self setColorStyle:colorStyle]; + + _message = [message copy]; + _tagline = [tagline copy]; + [self setMessage:message tagline:tagline]; + [self addSubview:_textLabel]; + + _insideTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapInTooltip:)]; + [self addGestureRecognizer:_insideTapGestureRecognizer]; + + self.opaque = NO; + self.backgroundColor = [UIColor clearColor]; + self.layer.needsDisplayOnBoundsChange = YES; + self.layer.shadowColor = [UIColor blackColor].CGColor; + self.layer.shadowOpacity = 0.5f; + self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f); + self.layer.shadowRadius = 5.0f; + self.layer.masksToBounds = NO; + } + return self; +} + +- (void)dealloc +{ + [_insideTapGestureRecognizer removeTarget:self action:NULL]; +} + +#pragma mark - Public Methods + +- (void)setMessage:(NSString *)message +{ + if (![message isEqualToString:_message]) { + _message = [message copy]; + [self setMessage:_message tagline:self.tagline]; + } +} + +- (void)setTagline:(NSString *)tagline +{ + if (![tagline isEqualToString:_tagline]) { + _tagline = [tagline copy]; + [self setMessage:self.message tagline:_tagline]; + } +} + +#pragma mark Presentation + +- (void)presentFromView:(UIView *)anchorView +{ + UIView *superview = anchorView.window.rootViewController.view; + if (!superview) { + return; + } + + // By default - attach to the top, pointing down + CGPoint position = CGPointMake(CGRectGetMidX(anchorView.bounds), CGRectGetMinY(anchorView.bounds)); + CGPoint positionInSuperview = [superview convertPoint:position fromView:anchorView]; + FBSDKTooltipViewArrowDirection direction = FBSDKTooltipViewArrowDirectionDown; + + // If not enough space to point up from top of anchor view - point up to it's bottom + CGFloat bubbleHeight = CGRectGetHeight(_textLabel.bounds) + _verticalTextOffset + _textPadding * 2; + if (positionInSuperview.y - bubbleHeight - kNUXBubbleMargin < CGRectGetMinY(superview.bounds)) { + direction = FBSDKTooltipViewArrowDirectionUp; + position = CGPointMake(CGRectGetMidX(anchorView.bounds), CGRectGetMaxY(anchorView.bounds)); + positionInSuperview = [superview convertPoint:position fromView:anchorView]; + } + + [self presentInView:superview withArrowPosition:positionInSuperview direction:direction]; +} + +- (void)presentInView:(UIView *)view withArrowPosition:(CGPoint)arrowPosition direction:(FBSDKTooltipViewArrowDirection)arrowDirection +{ + _pointingUp = arrowDirection == FBSDKTooltipViewArrowDirectionUp; + _positionInView = arrowPosition; + self.frame = [self layoutSubviewsAndDetermineFrame]; + + // Add to view, while invisible. + self.hidden = YES; + if ([self superview]) { + [self removeFromSuperview]; + } + [view addSubview:self]; + + // Layout & schedule dismissal. + _displayTime = CFAbsoluteTimeGetCurrent(); + _isFadingOut = NO; + [self scheduleAutomaticFadeout]; + [self layoutSubviews]; + + [self animateFadeIn]; +} + +- (void)dismiss +{ + if (_isFadingOut) { + return; + } + _isFadingOut = YES; + + [self animateFadeOutWithCompletion:^{ + [self removeFromSuperview]; + [self cancelAllScheduledFadeOutMethods]; + _isFadingOut = NO; + }]; +} + +#pragma mark Style + +- (FBSDKTooltipColorStyle)colorStyle +{ + return _colorStyle; +} + +- (void)setColorStyle:(FBSDKTooltipColorStyle)colorStyle +{ + _colorStyle = colorStyle; + switch (colorStyle) { + case FBSDKTooltipColorStyleNeutralGray: + _gradientColors = @[ + (id)(FBSDKUIColorWithRGB(0x51, 0x50, 0x4f).CGColor), + (id)(FBSDKUIColorWithRGB(0x2d, 0x2c, 0x2c).CGColor) + ]; + _innerStrokeColor = [UIColor colorWithWhite:0.13f alpha:1.0f]; + _crossCloseGlyphColor = [UIColor colorWithWhite:0.69f alpha:1.0f]; + break; + + case FBSDKTooltipColorStyleFriendlyBlue: + default: + _gradientColors = @[ + (id)(FBSDKUIColorWithRGB(0x6e, 0x9c, 0xf5).CGColor), + (id)(FBSDKUIColorWithRGB(0x49, 0x74, 0xc6).CGColor) + ]; + _innerStrokeColor = [UIColor colorWithRed:0.12f green:0.26f blue:0.55f alpha:1.0f]; + _crossCloseGlyphColor = [UIColor colorWithRed:0.60f green:0.73f blue:1.0f alpha:1.0f]; + break; + } + + _textLabel.textColor = [UIColor whiteColor]; +} + +#pragma mark - Private Methods +#pragma mark Animation + +- (void)animateFadeIn +{ + // Prepare Animation: Zoom in with bounce. Keep the arrow point in place. + // Set initial transform (zoomed out) & become visible. + CGFloat centerPos = self.bounds.size.width / 2.0; + CGFloat zoomOffsetX = (centerPos - _arrowMidpoint) * (kZoomOutScale - 1.0f); + CGFloat zoomOffsetY = -0.5f * self.bounds.size.height * (kZoomOutScale - 1.0f); + if (_pointingUp) { + zoomOffsetY = -zoomOffsetY; + } + self.layer.transform = fbsdkdfl_CATransform3DConcat(fbsdkdfl_CATransform3DMakeScale(kZoomOutScale, kZoomOutScale, kZoomOutScale), + fbsdkdfl_CATransform3DMakeTranslation(zoomOffsetX, zoomOffsetY, 0)); + self.hidden = NO; + + // Prepare animation steps + // 1st Step. + void (^zoomIn)(void) = ^{ + self.alpha = 1.0; + + CGFloat newZoomOffsetX = (centerPos - _arrowMidpoint) * (kZoomInScale - 1.0f); + CGFloat newZoomOffsetY = -0.5f * self.bounds.size.height * (kZoomInScale - 1.0f); + if (_pointingUp) { + newZoomOffsetY = -newZoomOffsetY; + } + + CATransform3D scale = fbsdkdfl_CATransform3DMakeScale(kZoomInScale, kZoomInScale, kZoomInScale); + CATransform3D translate =fbsdkdfl_CATransform3DMakeTranslation(newZoomOffsetX, newZoomOffsetY, 0); + self.layer.transform = fbsdkdfl_CATransform3DConcat(scale, translate); + }; + + // 2nd Step. + void (^bounceZoom)(void) = ^{ + CGFloat centerPos2 = self.bounds.size.width / 2.0; + CGFloat zoomOffsetX2 = (centerPos2 - _arrowMidpoint) * (kZoomBounceScale - 1.0f); + CGFloat zoomOffsetY2 = -0.5f * self.bounds.size.height * (kZoomBounceScale - 1.0f); + if (_pointingUp) { + zoomOffsetY2 = -zoomOffsetY2; + } + self.layer.transform = fbsdkdfl_CATransform3DConcat(fbsdkdfl_CATransform3DMakeScale(kZoomBounceScale, kZoomBounceScale, kZoomBounceScale), + fbsdkdfl_CATransform3DMakeTranslation(zoomOffsetX2, zoomOffsetY2, 0)); + }; + + // 3rd Step. + void (^normalizeZoom)(void) = ^{ + self.layer.transform = fbsdkdfl_CATransform3DIdentity; + }; + + // Animate 3 steps sequentially + [UIView animateWithDuration:kTransitionDuration/1.5 + delay:0 + options:UIViewAnimationOptionCurveEaseInOut + animations:zoomIn + completion:^(BOOL finished) { + [UIView animateWithDuration:kTransitionDuration/2.2 + animations:bounceZoom + completion:^(BOOL innerFinished) { + [UIView animateWithDuration:kTransitionDuration/5 + animations:normalizeZoom]; + }]; + }]; +} + +- (void) animateFadeOutWithCompletion: (void(^)(void)) completionHandler +{ + [UIView animateWithDuration:0.3 + delay:0 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + self.alpha = 0.0; + } + completion:^(BOOL complete) { + if(completionHandler) + completionHandler(); + }]; +} + +#pragma mark Gestures + +- (void)onTapInTooltip:(UIGestureRecognizer*)sender +{ + // ignore incomplete tap gestures + if (sender.state != UIGestureRecognizerStateEnded) { + return; + } + + // fade out the tooltip view right away + [self dismiss]; +} + +#pragma mark Drawing + +CGMutablePathRef _fbsdkCreateUpPointingBubbleWithRect(CGRect rect, CGFloat arrowMidpoint, CGFloat arrowHeight, CGFloat radius) +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGFloat arrowHalfWidth = arrowHeight; + // start with arrow + CGPathMoveToPoint(path, NULL, arrowMidpoint - arrowHalfWidth, CGRectGetMinY(rect)); + CGPathAddLineToPoint(path, NULL, arrowMidpoint, CGRectGetMinY(rect) - arrowHeight); + CGPathAddLineToPoint(path, NULL, arrowMidpoint + arrowHalfWidth, CGRectGetMinY(rect)); + + // rest of curved rectangle + CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius); + CGPathCloseSubpath(path); + return path; +} + +CGMutablePathRef _fbsdkCreateDownPointingBubbleWithRect(CGRect rect, CGFloat arrowMidpoint, CGFloat arrowHeight, CGFloat radius) +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGFloat arrowHalfWidth = arrowHeight; + + // start with arrow + CGPathMoveToPoint(path, NULL, arrowMidpoint + arrowHalfWidth, CGRectGetMaxY(rect)); + CGPathAddLineToPoint(path, NULL, arrowMidpoint, CGRectGetMaxY(rect) + arrowHeight); + CGPathAddLineToPoint(path, NULL, arrowMidpoint - arrowHalfWidth, CGRectGetMaxY(rect)); + + // rest of curved rectangle + CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius); + CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius); + CGPathCloseSubpath(path); + return path; +} + +static CGMutablePathRef _createCloseCrossGlyphWithRect(CGRect rect) +{ + CGFloat lineThickness = 0.20f * CGRectGetHeight(rect); + + // One rectangle + CGMutablePathRef path1 = CGPathCreateMutable(); + CGPathMoveToPoint(path1, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect) + lineThickness); + CGPathAddLineToPoint(path1, NULL, CGRectGetMinX(rect) + lineThickness, CGRectGetMinY(rect)); + CGPathAddLineToPoint(path1, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect) - lineThickness); + CGPathAddLineToPoint(path1, NULL, CGRectGetMaxX(rect) - lineThickness, CGRectGetMaxY(rect)); + CGPathCloseSubpath(path1); + + // 2nd rectange - mirrored horizontally + CGMutablePathRef path2 = CGPathCreateMutable(); + CGPathMoveToPoint(path2, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect) - lineThickness); + CGPathAddLineToPoint(path2, NULL, CGRectGetMaxX(rect) - lineThickness, CGRectGetMinY(rect)); + CGPathAddLineToPoint(path2, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect) + lineThickness); + CGPathAddLineToPoint(path2, NULL, CGRectGetMinX(rect) + lineThickness, CGRectGetMaxY(rect)); + CGPathCloseSubpath(path2); + + CGMutablePathRef groupedPath = CGPathCreateMutable(); + CGPathAddPath(groupedPath, NULL, path1); + CGPathAddPath(groupedPath, NULL, path2); + CFRelease(path1); + CFRelease(path2); + + return groupedPath; +} + +- (void)drawRect:(CGRect)rect +{ + // Ignore dirty rect and just redraw the entire nux bubble + CGFloat arrowSideMargin = 1 + 0.5f * MAX(kNUXRectInset, _arrowHeight); + CGFloat arrowYMarginOffset = _pointingUp ? arrowSideMargin : kNUXRectInset; + CGFloat halfStroke = kNUXStrokeLineWidth / 2.0; + CGRect outerRect = CGRectMake(kNUXRectInset + halfStroke, + arrowYMarginOffset + halfStroke, + self.bounds.size.width - 2 * kNUXRectInset - kNUXStrokeLineWidth, + self.bounds.size.height - kNUXRectInset - arrowSideMargin - kNUXStrokeLineWidth); + outerRect = CGRectInset(outerRect, 5, 5); + CGRect innerRect = CGRectInset(outerRect, kNUXStrokeLineWidth, kNUXStrokeLineWidth); + CGRect fillRect = CGRectInset(innerRect, kNUXStrokeLineWidth/2.0, kNUXStrokeLineWidth/2.0); + CGFloat closeCrossGlyphPositionY = MIN(CGRectGetMinY(fillRect) + _textPadding + _verticalCrossOffset, + CGRectGetMidY(fillRect) - 0.5f * kNUXCrossGlyphSize); + CGRect closeCrossGlyphRect = CGRectMake(CGRectGetMaxX(fillRect) - 2 * kNUXFontSize, closeCrossGlyphPositionY, + kNUXCrossGlyphSize, kNUXCrossGlyphSize); + + // setup and get paths + CGContextRef context = UIGraphicsGetCurrentContext(); + CGMutablePathRef outerPath; + CGMutablePathRef innerPath; + CGMutablePathRef fillPath; + CGMutablePathRef crossCloseGlyphPath = _createCloseCrossGlyphWithRect(closeCrossGlyphRect); + CGRect gradientRect = fillRect; + if (_pointingUp) { + outerPath = _fbsdkCreateUpPointingBubbleWithRect(outerRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius + kNUXStrokeLineWidth); + innerPath = _fbsdkCreateUpPointingBubbleWithRect(innerRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius); + fillPath = _fbsdkCreateUpPointingBubbleWithRect(fillRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius - kNUXStrokeLineWidth); + gradientRect.origin.y -= _arrowHeight; + gradientRect.size.height += _arrowHeight; + } else { + outerPath = _fbsdkCreateDownPointingBubbleWithRect(outerRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius + kNUXStrokeLineWidth); + innerPath = _fbsdkCreateDownPointingBubbleWithRect(innerRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius); + fillPath = _fbsdkCreateDownPointingBubbleWithRect(fillRect, + _arrowMidpoint, _arrowHeight, + kNUXCornerRadius - kNUXStrokeLineWidth); + gradientRect.size.height += _arrowHeight; + } + self.layer.shadowPath = outerPath; + + // This tooltip has two borders, so draw two strokes and a fill. + CGColorRef strokeColor = _innerStrokeColor.CGColor; + CGContextSaveGState(context); + CGContextSetStrokeColorWithColor(context, strokeColor); + CGContextSetLineWidth(context, kNUXStrokeLineWidth); + CGContextAddPath(context, innerPath); + CGContextStrokePath(context); + CGContextAddPath(context, fillPath); + CGContextClip(context); + CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB(); + CGGradientRef gradient = CGGradientCreateWithColors(rgbColorspace, (CFArrayRef)_gradientColors, nil); + CGColorSpaceRelease(rgbColorspace); + CGPoint start = CGPointMake(gradientRect.origin.x, gradientRect.origin.y); + CGPoint end = CGPointMake(gradientRect.origin.x, CGRectGetMaxY(gradientRect)); + CGContextDrawLinearGradient(context, gradient, start, end, 0); + CGContextAddPath(context, crossCloseGlyphPath); + CGContextSetFillColorWithColor(context, _crossCloseGlyphColor.CGColor); + CGContextFillPath(context); + CGGradientRelease(gradient); + CGContextRestoreGState(context); + CFRelease(outerPath); + CFRelease(innerPath); + CFRelease(fillPath); + CFRelease(crossCloseGlyphPath); +} + +#pragma mark Layout + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + // We won't set the frame in layoutSubviews to avoid potential infinite loops. + // Frame is set in -presentInView:withArrowPosition:direction: method. + [self layoutSubviewsAndDetermineFrame]; +} + +- (CGRect)layoutSubviewsAndDetermineFrame +{ + // Compute the positioning of the arrow. + CGRect screenBounds = [[UIScreen mainScreen] bounds]; + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (!UIInterfaceOrientationIsPortrait(orientation)) { + screenBounds = CGRectMake(0, 0, screenBounds.size.height, screenBounds.size.width); + } + CGFloat arrowHalfWidth = _arrowHeight; + CGFloat arrowXPos = _positionInView.x - arrowHalfWidth; + arrowXPos = MAX(arrowXPos, kNUXSideCap + kNUXBubbleMargin); + arrowXPos = MIN(arrowXPos, screenBounds.size.width - kNUXBubbleMargin - kNUXSideCap - 2 * arrowHalfWidth); + _positionInView = CGPointMake(arrowXPos + arrowHalfWidth, _positionInView.y); + + CGFloat arrowYMarginOffset = _pointingUp ? MAX(kNUXRectInset, _arrowHeight) : kNUXRectInset; + + // Set the lock image frame. + CGFloat xPos = kNUXRectInset + _textPadding + kNUXStrokeLineWidth; + CGFloat yPos = arrowYMarginOffset + kNUXStrokeLineWidth + _textPadding; + + // Set the text label frame. + _textLabel.frame = CGRectMake(xPos, + yPos + _verticalTextOffset, // sizing function may not return desired height exactly + CGRectGetWidth(_textLabel.bounds), + CGRectGetHeight(_textLabel.bounds)); + + // Determine the size of the nux bubble. + CGFloat bubbleHeight = CGRectGetHeight(_textLabel.bounds) + _verticalTextOffset + _textPadding * 2; + CGFloat crossGlyphWidth = 2 * kNUXFontSize; + CGFloat bubbleWidth = CGRectGetWidth(_textLabel.bounds) + _textPadding * 2 + kNUXStrokeLineWidth * 2 + crossGlyphWidth; + + // Compute the widths to the left and right of the arrow. + _leftWidth = roundf(0.5f * (bubbleWidth - 2 * arrowHalfWidth)); + _rightWidth = _leftWidth; + CGFloat originX = arrowXPos - _leftWidth; + if (originX < kNUXBubbleMargin) { + CGFloat xShift = kNUXBubbleMargin - originX; + originX += xShift; + _leftWidth -= xShift; + _rightWidth += xShift; + } else if (originX + bubbleWidth > screenBounds.size.width - kNUXBubbleMargin) { + CGFloat xShift = originX + bubbleWidth - (screenBounds.size.width - kNUXBubbleMargin); + originX -= xShift; + _leftWidth += xShift; + _rightWidth -= xShift; + } + + _arrowMidpoint = _positionInView.x - originX + kNUXRectInset; + + // Set the frame for the view. + CGFloat nuxWidth = bubbleWidth + 2 * kNUXRectInset; + CGFloat nuxHeight = bubbleHeight + kNUXRectInset + MAX(kNUXRectInset, _arrowHeight) + 2 * kNUXStrokeLineWidth; + CGFloat yOrigin = 0; + if (_pointingUp) { + yOrigin = _positionInView.y + kNUXPointMargin - MAX(0, kNUXRectInset - _arrowHeight); + } else { + yOrigin = _positionInView.y - nuxHeight - kNUXPointMargin + MAX(0, kNUXRectInset - _arrowHeight); + } + + return CGRectMake(originX - kNUXRectInset, + yOrigin, + nuxWidth, + nuxHeight); +} + +#pragma mark Message & Tagline + +- (void)setMessage:(NSString *)message tagline:(NSString *)tagline +{ + message = message ?: @""; + // Ensure tagline is empty string or ends with space + tagline = tagline ?: @""; + if ([tagline length] && ![tagline hasSuffix:@" "]) + tagline = [tagline stringByAppendingString:@" "]; + + // Concatenate tagline & main message + message = [tagline stringByAppendingString:message]; + + NSRange fullRange = NSMakeRange(0, message.length); + NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString: message]; + + UIFont *font=[UIFont boldSystemFontOfSize:kNUXFontSize]; + [attrString addAttribute:NSFontAttributeName value:font range:fullRange]; + [attrString addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:fullRange]; + if ([tagline length]) { + [attrString addAttribute:NSForegroundColorAttributeName value: FBSDKUIColorWithRGB(0x6D, 0x87, 0xC7) range:NSMakeRange(0, [tagline length])]; + } + + _textLabel.attributedText = attrString; + + CGSize textLabelSize = [_textLabel sizeThatFits:CGSizeMake(_maximumTextWidth, MAXFLOAT)]; + _textLabel.bounds = CGRectMake(0, 0, textLabelSize.width, textLabelSize.height); + self.frame = [self layoutSubviewsAndDetermineFrame]; + [self setNeedsDisplay]; +} + +#pragma mark Auto Dismiss Timeout + +- (void)scheduleAutomaticFadeout +{ + [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(scheduleFadeoutRespectingMinimumDisplayDuration) object:nil]; + + if (_displayDuration > 0.0 && [self superview]) { + CFTimeInterval intervalAlreadyDisplaying = CFAbsoluteTimeGetCurrent() - _displayTime; + CFTimeInterval timeRemainingBeforeAutomaticFadeout = _displayDuration - intervalAlreadyDisplaying; + if (timeRemainingBeforeAutomaticFadeout > 0.0) { + [self performSelector:@selector(scheduleFadeoutRespectingMinimumDisplayDuration) withObject:nil afterDelay:timeRemainingBeforeAutomaticFadeout]; + } else { + [self scheduleFadeoutRespectingMinimumDisplayDuration]; + } + } +} + +- (void)scheduleFadeoutRespectingMinimumDisplayDuration +{ + CFTimeInterval intervalAlreadyDisplaying = CFAbsoluteTimeGetCurrent() - _displayTime; + CFTimeInterval remainingDisplayTime = _minimumDisplayDuration - intervalAlreadyDisplaying; + if (remainingDisplayTime > 0.0) { + [self performSelector:@selector(dismiss) withObject:nil afterDelay:remainingDisplayTime]; + } else { + [self dismiss]; + } +} + +- (void)cancelAllScheduledFadeOutMethods +{ + [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(scheduleFadeoutRespectingMinimumDisplayDuration) object:nil]; + [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(dismiss) object:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion+Internal.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion+Internal.h new file mode 100644 index 0000000..ea90965 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion+Internal.h @@ -0,0 +1,37 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginCompletion.h" + +@interface FBSDKLoginCompletionParameters () + +@property (nonatomic, copy, readwrite) NSString *accessTokenString; + +@property (nonatomic, copy, readwrite) NSSet *permissions; +@property (nonatomic, copy, readwrite) NSSet *declinedPermissions; + +@property (nonatomic, copy, readwrite) NSString *appID; +@property (nonatomic, copy, readwrite) NSString *userID; + +@property (nonatomic, copy, readwrite) NSError *error; + +@property (nonatomic, readwrite, getter=isSystemAccount) BOOL systemAccount; +@property (nonatomic, copy, readwrite) NSDate *expirationDate; +@property (nonatomic, copy, readwrite) NSString *challenge; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.h new file mode 100644 index 0000000..c8423d7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.h @@ -0,0 +1,96 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKLoginManager; + +/*! + @abstract Structured interface for accessing the parameters used to complete a log in request. + If \c accessTokenString is non-nil, the authentication succeeded. If \c error is + non-nil the request failed. If both are \c nil, the request was cancelled. + */ +@interface FBSDKLoginCompletionParameters : NSObject + +- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithError:(NSError *)error; + +@property (nonatomic, copy, readonly) NSString *accessTokenString; + +@property (nonatomic, copy, readonly) NSSet *permissions; +@property (nonatomic, copy, readonly) NSSet *declinedPermissions; + +@property (nonatomic, copy, readonly) NSString *appID; +@property (nonatomic, copy, readonly) NSString *userID; + +@property (nonatomic, copy, readonly) NSError *error; + +@property (nonatomic, readonly, getter=isSystemAccount) BOOL systemAccount; +@property (nonatomic, copy, readonly) NSDate *expirationDate; +@property (nonatomic, copy, readonly) NSString *challenge; +@end + +@protocol FBSDKLoginCompleting + +/*! + @abstract Invoke \p handler with the login parameters derived from the authentication result. + See the implementing class's documentation for whether it completes synchronously or asynchronously. + */ +- (void)completeLogIn:(FBSDKLoginManager *)loginManager withHandler:(void(^)(FBSDKLoginCompletionParameters *parameters))handler; + +@end + +#pragma mark - Completers + +/*! + @abstract Extracts the log in completion parameters from the \p parameters dictionary, + which must contain the parsed result of the return URL query string. + + The \c user_id key is first used to derive the User ID. If that fails, \c signed_request + is used. + + Completion occurs synchronously. + */ +@interface FBSDKLoginURLCompleter : NSObject + +- (instancetype)initWithURLParameters:(NSDictionary *)parameters appID:(NSString *)appID NS_DESIGNATED_INITIALIZER; + +@end + +/*! + @abstract Requests the User ID, granted permissions and declined permissions from the server + using the given access token, which must occur before authentication can be completed. + + Completion occurs asynchronously. + */ +@interface FBSDKLoginSystemAccountCompleter : NSObject + +- (instancetype)initWithTokenString:(NSString *)tokenString appID:(NSString *)appID NS_DESIGNATED_INITIALIZER; + +@end + +/*! + @abstract Converts an Accounts framework error in to an error or cancellation result + + Completion occurs synchronously. + */ +@interface FBSDKLoginSystemAccountErrorCompleter : NSObject + +- (instancetype)initWithError:(NSError *)accountStoreError permissions:(NSSet *)permissions NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.m new file mode 100644 index 0000000..6ae6427 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.m @@ -0,0 +1,326 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginCompletion+Internal.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLoginConstants.h" +#import "FBSDKLoginError.h" +#import "FBSDKLoginManager+Internal.h" +#import "FBSDKLoginUtility.h" + +static void FBSDKLoginRequestMeAndPermissions(FBSDKLoginCompletionParameters *parameters, void(^completionBlock)(void)) +{ + __block NSUInteger pendingCount = 1; + void(^didCompleteBlock)(void) = ^{ + if (--pendingCount == 0) { + completionBlock(); + } + }; + + NSString *tokenString = parameters.accessTokenString; + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + + pendingCount++; + FBSDKGraphRequest *userIDRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" + parameters:@{ @"fields" : @"id" } + tokenString:tokenString + HTTPMethod:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:userIDRequest completionHandler:^(FBSDKGraphRequestConnection *requestConnection, + id result, + NSError *error) { + parameters.userID = [result objectForKey:@"id"]; + if (error) { + parameters.error = error; + } + didCompleteBlock(); + }]; + + pendingCount++; + FBSDKGraphRequest *permissionsRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me/permissions" + parameters:@{@"fields":@""} + tokenString:tokenString + HTTPMethod:nil + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:permissionsRequest completionHandler:^(FBSDKGraphRequestConnection *requestConnection, + id result, + NSError *error) { + NSMutableSet *grantedPermissions = [NSMutableSet set]; + NSMutableSet *declinedPermissions = [NSMutableSet set]; + + [FBSDKInternalUtility extractPermissionsFromResponse:result + grantedPermissions:grantedPermissions + declinedPermissions:declinedPermissions]; + + parameters.permissions = [grantedPermissions copy]; + parameters.declinedPermissions = [declinedPermissions copy]; + if (error) { + parameters.error = error; + } + didCompleteBlock(); + }]; + + [connection start]; + didCompleteBlock(); +} + +@implementation FBSDKLoginCompletionParameters + +- (instancetype)init +{ + return [super init]; +} + +- (instancetype)initWithError:(NSError *)error +{ + if ((self = [self init]) != nil) { + self.error = error; + } + return self; +} + +@end + +#pragma mark - Completers + +@implementation FBSDKLoginURLCompleter +{ + FBSDKLoginCompletionParameters *_parameters; + id _observer + ; BOOL _performExplicitFallback; +} + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithURLParameters:(NSDictionary *)parameters appID:(NSString *)appID +{ + if ((self = [super init]) != nil) { + _parameters = [[FBSDKLoginCompletionParameters alloc] init]; + + _parameters.accessTokenString = parameters[@"access_token"]; + + if (_parameters.accessTokenString.length > 0) { + [self setParametersWithDictionary:parameters appID:appID]; + } else { + _parameters.accessTokenString = nil; + [self setErrorWithDictionary:parameters]; + } + } + return self; +} + +- (void)completeLogIn:(FBSDKLoginManager *)loginManager withHandler:(void(^)(FBSDKLoginCompletionParameters *parameters))handler +{ + if (_performExplicitFallback && loginManager.loginBehavior == FBSDKLoginBehaviorNative) { + // UIKit and iOS don't like an application opening a URL during a URL open callback, so + // we need to wait until *at least* the next turn of the run loop to open the URL to + // perform the browser log in behavior. However we also need to wait for the application + // to become active so FBSDKApplicationDelegate doesn't erroneously call back the URL + // opener before the URL has been opened. + if ([FBSDKApplicationDelegate sharedInstance].isActive) { + // The application is active so there's no need to wait. + [loginManager logInWithBehavior:FBSDKLoginBehaviorBrowser]; + } else { + // use the block version to guarantee there's a strong reference to self + _observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^ (NSNotification *notification) { + [self attemptBrowserLogIn:loginManager]; + }]; + } + return; + } + + if (_parameters.accessTokenString && !_parameters.userID) { + void(^handlerCopy)(FBSDKLoginCompletionParameters *) = [handler copy]; + FBSDKLoginRequestMeAndPermissions(_parameters, ^{ + handlerCopy(_parameters); + }); + return; + } + + handler(_parameters); +} + +- (void)setParametersWithDictionary:(NSDictionary *)parameters appID:(NSString *)appID +{ + NSString *grantedPermissionsString = parameters[@"granted_scopes"]; + NSString *declinedPermissionsString = parameters[@"denied_scopes"]; + + NSString *signedRequest = parameters[@"signed_request"]; + NSString *userID = parameters[@"user_id"]; + + // check the string length so that we assign an empty set rather than a set with an empty string + _parameters.permissions = (grantedPermissionsString.length > 0) + ? [NSSet setWithArray:[grantedPermissionsString componentsSeparatedByString:@","]] + : [NSSet set]; + _parameters.declinedPermissions = (declinedPermissionsString.length > 0) + ? [NSSet setWithArray:[declinedPermissionsString componentsSeparatedByString:@","]] + : [NSSet set]; + + _parameters.appID = appID; + + if (userID.length == 0 && signedRequest.length > 0) { + _parameters.userID = [FBSDKLoginUtility userIDFromSignedRequest:signedRequest]; + } else { + _parameters.userID = userID; + } + + NSString *expirationDateString = parameters[@"expires"] ?: parameters[@"expires_at"]; + NSDate *expirationDate = [NSDate distantFuture]; + if (expirationDateString && [expirationDateString doubleValue] > 0) { + expirationDate = [NSDate dateWithTimeIntervalSince1970:[expirationDateString doubleValue]]; + } else if (parameters[@"expires_in"]) { + expirationDate = [NSDate dateWithTimeIntervalSinceNow:[parameters[@"expires_in"] integerValue]]; + } + _parameters.expirationDate = expirationDate; + + NSError *error = nil; + NSDictionary *state = [FBSDKInternalUtility objectForJSONString:parameters[@"state"] error:&error]; + _parameters.challenge = [FBSDKUtility URLDecode:state[@"challenge"]]; +} + +- (void)setErrorWithDictionary:(NSDictionary *)parameters +{ + NSString *legacyErrorReason = parameters[@"error"]; + + if ([legacyErrorReason isEqualToString:@"service_disabled_use_browser"] || + [legacyErrorReason isEqualToString:@"service_disabled"]) { + _performExplicitFallback = YES; + } + + // if error is nil, then this should be processed as a cancellation unless + // _performExplicitFallback is set to YES and the log in behavior is Native. + _parameters.error = [FBSDKLoginError errorFromReturnURLParameters:parameters]; +} + +- (void)attemptBrowserLogIn:(FBSDKLoginManager *)loginManager { + if (_observer != nil) { + [[NSNotificationCenter defaultCenter] removeObserver:_observer]; + _observer = nil; + } + + if ([FBSDKApplicationDelegate sharedInstance].isActive) { + [loginManager logInWithBehavior:FBSDKLoginBehaviorBrowser]; + } else { + // The application is active but due to notification ordering the FBSDKApplicationDelegate + // doesn't know it yet. Wait one more turn of the run loop. + dispatch_async(dispatch_get_main_queue(), ^{ + [self attemptBrowserLogIn:loginManager]; + }); + } +} + +@end + +@implementation FBSDKLoginSystemAccountCompleter +{ + FBSDKLoginCompletionParameters *_parameters; +} + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithTokenString:(NSString *)tokenString appID:(NSString *)appID +{ + if ((self = [super init]) != nil) { + _parameters = [[FBSDKLoginCompletionParameters alloc] init]; + + _parameters.accessTokenString = tokenString; + _parameters.appID = appID; + + _parameters.systemAccount = YES; + } + return self; +} + +- (void)completeLogIn:(FBSDKLoginManager *)loginManager withHandler:(void(^)(FBSDKLoginCompletionParameters *parameters))handler +{ + void(^handlerCopy)(FBSDKLoginCompletionParameters *) = [handler copy]; + FBSDKLoginRequestMeAndPermissions(_parameters, ^{ + // Transform the FBSDKCoreKit error in to an FBSDKLoginKit error, if necessary. This specializes + // the graph errors in to User Checkpointed, Password Changed or Unconfirmed User. + // + // It's possible the graph error has a value set for NSRecoveryAttempterErrorKey but we don't + // have any login-specific attempter to provide since system auth succeeded and the error is a + // graph API error. + NSError *serverError = _parameters.error; + NSError *error = [FBSDKLoginError errorFromServerError:serverError]; + if (error != nil) { + // In the event the user's password changed the Accounts framework will still return + // an access token but API calls will fail. Clear the access token from the result + // and use the special-case System Password changed error, which has different text + // to display to the user. + if (error.code == FBSDKLoginPasswordChangedErrorCode) { + [FBSDKSystemAccountStoreAdapter sharedInstance].forceBlockingRenew = YES; + + _parameters.accessTokenString = nil; + _parameters.appID = nil; + + error = [FBSDKLoginError errorForSystemPasswordChange:serverError]; + } + + _parameters.error = error; + } + + handlerCopy(_parameters); + }); +} + +@end + +@implementation FBSDKLoginSystemAccountErrorCompleter +{ + FBSDKLoginCompletionParameters *_parameters; +} + +- (instancetype)init NS_UNAVAILABLE +{ + assert(0); +} + +- (instancetype)initWithError:(NSError *)accountStoreError permissions:(NSSet *)permissions +{ + if ((self = [super init]) != nil) { + _parameters = [[FBSDKLoginCompletionParameters alloc] init]; + + NSError *error = [FBSDKLoginError errorForSystemAccountStoreError:accountStoreError]; + if (error != nil) { + _parameters.error = error; + } else { + // The lack of an error indicates the user declined permissions + _parameters.declinedPermissions = permissions; + } + + _parameters.systemAccount = YES; + } + return self; +} + +- (void)completeLogIn:(FBSDKLoginManager *)loginManager withHandler:(void(^)(FBSDKLoginCompletionParameters *parameters))handler +{ + handler(_parameters); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.h new file mode 100644 index 0000000..34b6647 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@interface FBSDKLoginError : NSObject + ++ (NSString *)errorDomain; + ++ (NSError *)errorForFailedLoginWithCode:(FBSDKLoginErrorCode)code; + ++ (NSError *)errorForSystemAccountStoreError:(NSError *)accountStoreError; ++ (NSError *)errorForSystemPasswordChange:(NSError *)innerError; + ++ (NSError *)errorFromReturnURLParameters:(NSDictionary *)parameters; ++ (NSError *)errorFromServerError:(NSError *)serverError; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.m new file mode 100644 index 0000000..856b7f9 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.m @@ -0,0 +1,252 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginError.h" + +#import "FBSDKCoreKit+Internal.h" + +typedef NS_ENUM(NSUInteger, FBSDKLoginErrorSubcode) +{ + FBSDKLoginUserCheckpointedErrorSubcode = 459, + FBSDKLoginPasswordChangedErrorSubcode = 460, + FBSDKLoginUnconfirmedUserErrorSubcode = 464, +}; + +@implementation FBSDKLoginError + ++ (NSString *)errorDomain +{ + return FBSDKLoginErrorDomain; +} + ++ (NSError *)errorForFailedLoginWithCode:(FBSDKLoginErrorCode)code; +{ + return [self errorForFailedLoginWithCode:code innerError:nil]; +} + ++ (NSError *)errorForFailedLoginWithCode:(FBSDKLoginErrorCode)code + innerError:(NSError *)innerError +{ + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + + [FBSDKInternalUtility dictionary:userInfo setObject:innerError forKey:NSUnderlyingErrorKey]; + + NSString *errorDomain = [self errorDomain]; + NSString *localizedDescription = nil; + + switch ((NSInteger)code) { + case FBSDKNetworkErrorCode: + errorDomain = FBSDKErrorDomain; + localizedDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.Network", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Unable to connect to Facebook. Check your network connection and try again.", + @"The user facing error message when the Accounts framework encounters a network error."); + break; + case FBSDKLoginUserCheckpointedErrorCode: + localizedDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.UserCheckpointed", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"You cannot log in to apps at this time. Please log in to www.facebook.com and follow the instructions given.", + @"The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed."); + break; + case FBSDKLoginUnconfirmedUserErrorCode: + localizedDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.UnconfirmedUser", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Your account is not confirmed. Please log in to www.facebook.com and follow the instructions given.", + @"The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed."); + break; + case FBSDKLoginSystemAccountAppDisabledErrorCode: + localizedDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.Disabled", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Access has not been granted to the Facebook account. Verify device settings.", + @"The user facing error message when the app slider has been disabled and login fails."); + break; + case FBSDKLoginSystemAccountUnavailableErrorCode: + localizedDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.Unavailable", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"The Facebook account has not been configured on the device.", + @"The user facing error message when the device Facebook account is unavailable and login fails."); + break; + default: + break; + } + + [FBSDKInternalUtility dictionary:userInfo setObject:localizedDescription forKey:NSLocalizedDescriptionKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:localizedDescription forKey:FBSDKErrorLocalizedDescriptionKey]; + + return [NSError errorWithDomain:errorDomain + code:code + userInfo:userInfo]; +} + ++ (NSError *)errorForSystemAccountStoreError:(NSError *)accountStoreError +{ + NSError *err = nil; + BOOL cancellation = NO; + + if ([accountStoreError.domain isEqualToString:[self errorDomain]] || + [accountStoreError.domain isEqualToString:[FBSDKError errorDomain]]) { + // If the requestAccess call results in a Facebook error, surface it as a top-level + // error. This implies it is not the typical user "disallows" case. + err = accountStoreError; + } else if ([accountStoreError.domain isEqualToString:@"com.apple.accounts"] && accountStoreError.code == 7) { + err = [self errorWithSystemAccountStoreDeniedError:accountStoreError isCancellation:&cancellation]; + } + + if (err == nil && !cancellation) { + // create an error object with additional info regarding failed login + NSInteger errorCode = FBSDKLoginSystemAccountUnavailableErrorCode; + + NSString *errorDomain = accountStoreError.domain; + if ([errorDomain isEqualToString:NSURLErrorDomain] || + [errorDomain isEqualToString:@"kCFErrorDomainCFNetwork"]) { + errorCode = FBSDKNetworkErrorCode; + } + + err = [self errorForFailedLoginWithCode:errorCode + innerError:accountStoreError]; + } + + return err; +} + ++ (NSError *)errorForSystemPasswordChange:(NSError *)innerError +{ + NSString *failureReasonAndDescription = + NSLocalizedStringWithDefaultValue(@"LoginError.SystemAccount.PasswordChange", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Your Facebook password has changed. To confirm your password, open Settings > Facebook and tap your name.", + @"The user facing error message when the device Facebook account password is incorrect and login fails."); + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + failureReasonAndDescription, FBSDKErrorLocalizedDescriptionKey, + failureReasonAndDescription, NSLocalizedDescriptionKey, + nil]; + + [FBSDKInternalUtility dictionary:userInfo setObject:innerError forKey:NSUnderlyingErrorKey]; + + return [NSError errorWithDomain:[self errorDomain] + code:FBSDKLoginPasswordChangedErrorCode + userInfo:userInfo]; +} + ++ (NSError *)errorFromReturnURLParameters:(NSDictionary *)parameters +{ + NSError *error = nil; + + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:userInfo setObject:parameters[@"error_message"] forKey:FBSDKErrorDeveloperMessageKey]; + + if (userInfo.count > 0) { + [FBSDKInternalUtility dictionary:userInfo setObject:parameters[@"error"] forKey:FBSDKErrorDeveloperMessageKey]; + [FBSDKInternalUtility dictionary:userInfo setObject:parameters[@"error_code"] forKey:FBSDKGraphRequestErrorGraphErrorCode]; + + if (!userInfo[FBSDKErrorDeveloperMessageKey]) { + [FBSDKInternalUtility dictionary:userInfo setObject:parameters[@"error_reason"] forKey:FBSDKErrorDeveloperMessageKey]; + } + + userInfo[FBSDKGraphRequestErrorCategoryKey] = @(FBSDKGraphRequestErrorCategoryOther); + + error = [NSError errorWithDomain:FBSDKErrorDomain + code:FBSDKGraphRequestGraphAPIErrorCode + userInfo:userInfo]; + } + + return error; +} + ++ (NSError *)errorFromServerError:(NSError *)serverError +{ + NSError *loginError = nil; + + if ([serverError.domain isEqualToString:FBSDKErrorDomain]) { + NSDictionary *response = [FBSDKTypeUtility dictionaryValue:serverError.userInfo[FBSDKGraphRequestErrorParsedJSONResponseKey]]; + NSDictionary *body = [FBSDKTypeUtility dictionaryValue:response[@"body"]]; + NSDictionary *error = [FBSDKTypeUtility dictionaryValue:body[@"error"]]; + NSInteger subcode = [FBSDKTypeUtility integerValue:error[@"error_subcode"]]; + + switch (subcode) { + case FBSDKLoginUserCheckpointedErrorSubcode: + loginError = [self errorForFailedLoginWithCode:FBSDKLoginUserCheckpointedErrorCode + innerError:serverError]; + break; + case FBSDKLoginPasswordChangedErrorSubcode: + loginError = [self errorForFailedLoginWithCode:FBSDKLoginPasswordChangedErrorCode + innerError:serverError]; + break; + case FBSDKLoginUnconfirmedUserErrorSubcode: + loginError = [self errorForFailedLoginWithCode:FBSDKLoginUnconfirmedUserErrorCode + innerError:serverError]; + break; + } + } + + return loginError; +} + ++ (NSError *)errorWithSystemAccountStoreDeniedError:(NSError *)accountStoreError isCancellation:(BOOL *)cancellation +{ + // The Accounts framework returns an ACErrorPermissionDenied error for both user denied errors, + // Facebook denied errors, and other things. Unfortunately examining the contents of the + // description is the only means available to determine the reason for the error. + NSString *description = accountStoreError.userInfo[NSLocalizedDescriptionKey]; + NSError *err = nil; + + if (description) { + // If a parenthetical error code exists, map it ot a Facebook server error + FBSDKLoginErrorCode errorCode = FBSDKLoginReservedErrorCode; + if ([description rangeOfString:@"(459)"].location != NSNotFound) { + // The Facebook server could not fulfill this access request: Error validating access token: + // You cannot access the app till you log in to www.facebook.com and follow the instructions given. (459) + + // The OAuth endpoint directs people to www.facebook.com when an account has been + // checkpointed. If the web address is present, assume it's due to a checkpoint. + errorCode = FBSDKLoginUserCheckpointedErrorCode; + } else if ([description rangeOfString:@"(452)"].location != NSNotFound || + [description rangeOfString:@"(460)"].location != NSNotFound) { + // The Facebook server could not fulfill this access request: Error validating access token: + // Session does not match current stored session. This may be because the user changed the password since + // the time the session was created or Facebook has changed the session for security reasons. (452)or(460) + + // If the login failed due to the session changing, maybe it's due to the password + // changing. Direct the user to update the password in the Settings > Facebook. + err = [self errorForSystemPasswordChange:accountStoreError]; + } else if ([description rangeOfString:@"(464)"].location != NSNotFound) { + // The Facebook server could not fulfill this access request: Error validating access token: + // Sessions for the user are not allowed because the user is not a confirmed user. (464) + errorCode = FBSDKLoginUnconfirmedUserErrorCode; + } + + if (errorCode != FBSDKLoginReservedErrorCode) { + err = [self errorForFailedLoginWithCode:errorCode]; + } + } else { + // If there is no description, assume this is a user cancellation. No error object is + // returned for a cancellation. + if (cancellation != NULL) { + *cancellation = YES; + } + } + + return err; +} + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginKit+Internal.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginKit+Internal.h new file mode 100644 index 0000000..74b6597 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginKit+Internal.h @@ -0,0 +1,24 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKLoginCompletion+Internal.h" +#import "FBSDKLoginError.h" +#import "FBSDKLoginManager+Internal.h" +#import "FBSDKLoginUtility.h" diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h new file mode 100644 index 0000000..344e14f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h @@ -0,0 +1,81 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKCoreKit+Internal.h" + +@class FBSDKAccessToken; +@class FBSDKLoginCompletionParameters; + +@interface FBSDKLoginManagerSystemAccountState : NSObject +@property (nonatomic) BOOL didShowDialog; +@property (nonatomic, getter=isReauthorize) BOOL reauthorize; +@property (nonatomic, getter=isUnTOSedDevice) BOOL unTOSedDevice; +@end + +@interface FBSDKLoginManager () +@property (nonatomic, weak) UIViewController *fromViewController; +@property (nonatomic, readonly) NSSet *requestedPermissions; + +- (void)completeAuthentication:(FBSDKLoginCompletionParameters *)parameters expectChallenge:(BOOL)expectChallenge; + +// available to internal types to trigger login without checking read/publish mixtures. +- (void)logInWithPermissions:(NSSet *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler; +- (void)logInWithBehavior:(FBSDKLoginBehavior)loginBehavior; + +// made available for testing only +- (NSDictionary *)logInParametersWithPermissions:(NSSet *)permissions; +// made available for testing only +- (void)validateReauthentication:(FBSDKAccessToken *)currentToken withResult:(FBSDKLoginManagerLoginResult *)loginResult; + +// for testing only +- (void)setHandler:(FBSDKLoginManagerRequestTokenHandler)handler; +// for testing only +- (void)setRequestedPermissions:(NSSet *)requestedPermissions; +// for testing only +- (NSString *)loadExpectedChallenge; +@end + +// the category is made available for testing only +@interface FBSDKLoginManager (Native) + +- (void)performNativeLogInWithParameters:(NSDictionary *)loginParams handler:(void(^)(BOOL, NSError*))handler; +- (void)performBrowserLogInWithParameters:(NSDictionary *)loginParams handler:(void(^)(BOOL, NSString *,NSError*))handler; + +@end + +// the category is made available for testing only +@interface FBSDKLoginManager (Accounts) + +- (void)beginSystemLogIn; +- (void)performSystemLogIn; +- (void)continueSystemLogInWithTokenString:(NSString *)oauthToken error:(NSError *)accountStoreError state:(FBSDKLoginManagerSystemAccountState *)state; + +- (void)fallbackToNativeBehavior; + +@end + +// the category is made available for testing only +@interface FBSDKLoginManager (WebDialog) + +- (void)performWebLogInWithParameters:(NSDictionary *)loginParams handler:(void(^)(BOOL, NSError*))handler; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.h new file mode 100644 index 0000000..8d2459f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.h @@ -0,0 +1,41 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginManager+Internal.h" + +extern NSString *const FBSDKLoginManagerLoggerAuthMethod_Native; +extern NSString *const FBSDKLoginManagerLoggerAuthMethod_Browser; +extern NSString *const FBSDKLoginManagerLoggerAuthMethod_System; +extern NSString *const FBSDKLoginManagerLoggerAuthMethod_Webview; +extern NSString *const FBSDKLoginManagerLoggerAuthMethod_SFVC; + + +@interface FBSDKLoginManagerLogger : NSObject ++ (FBSDKLoginManagerLogger *)loggerFromParameters:(NSDictionary *)parameters; + +// this must not retain loginManager - only used to conveniently grab various properties to log. +- (void)startSessionForLoginManager:(FBSDKLoginManager *)loginManager; +- (void)endSession; + +- (void)startAuthMethod:(NSString *)authMethod; +- (void)endLoginWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error; + +- (NSDictionary *)parametersWithTimeStampAndClientState:(NSDictionary *)loginParams forAuthMethod:(NSString *)authMethod; +- (void)willAttemptAppSwitchingBehavior; +- (void)systemAuthDidShowDialog:(BOOL)didShowDialog isUnTOSedDevice:(BOOL)isUnTOSedDevice; +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.m new file mode 100644 index 0000000..531fd21 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.m @@ -0,0 +1,293 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginManagerLogger.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLoginError.h" +#import "FBSDKLoginManagerLoginResult+Internal.h" +#import "FBSDKLoginUtility.h" + +NSString *const FBSDKLoginManagerLoggerAuthMethod_Native = @"fb_application_web_auth"; +NSString *const FBSDKLoginManagerLoggerAuthMethod_Browser = @"browser_auth"; +NSString *const FBSDKLoginManagerLoggerAuthMethod_System = @"integrated_auth"; +NSString *const FBSDKLoginManagerLoggerAuthMethod_Webview = @"fallback_auth"; +NSString *const FBSDKLoginManagerLoggerAuthMethod_SFVC = @"sfvc_auth"; + +static NSString *const FBSDKLoginManagerLoggingClientStateKey = @"state"; +static NSString *const FBSDKLoginManagerLoggingClientStateIsClientState = @"com.facebook.sdk_client_state"; + +static NSString *const FBSDKLoginManagerLoggerParamIdentifierKey = @"0_auth_logger_id"; +static NSString *const FBSDKLoginManagerLoggerParamTimestampKey = @"1_timestamp_ms"; +static NSString *const FBSDKLoginManagerLoggerParamResultKey = @"2_result"; +static NSString *const FBSDKLoginManagerLoggerParamAuthMethodKey = @"3_method"; +static NSString *const FBSDKLoginManagerLoggerParamErrorCodeKey = @"4_error_code"; +static NSString *const FBSDKLoginManagerLoggerParamErrorMessageKey = @"5_error_message"; +static NSString *const FBSDKLoginManagerLoggerParamExtrasKey = @"6_extras"; + +static NSString *const FBSDKLoginManagerLoggerValueEmpty = @""; + +static NSString *const FBSDKLoginManagerLoggerResultSuccessString = @"success"; +static NSString *const FBSDKLoginManagerLoggerResultCancelString = @"cancelled"; +static NSString *const FBSDKLoginManagerLoggerResultErrorString = @"error"; +static NSString *const FBSDKLoginManagerLoggerResultSkippedString = @"skipped"; + +static NSString *const FBSDKLoginManagerLoggerTryNative = @"tryFBAppAuth"; +static NSString *const FBSDKLoginManagerLoggerTryBrowser = @"trySafariAuth"; +static NSString *const FBSDKLoginManagerLoggerTrySystemAccount = @"tryIntegratedAuth"; +static NSString *const FBSDKLoginManagerLoggerTryWebView = @"tryFallback"; + +@implementation FBSDKLoginManagerLogger +{ +@private + NSString *_identifier; + NSMutableDictionary *_extras; + + NSString *_lastResult; + NSError *_lastError; + + NSString *_authMethod; +} + ++ (FBSDKLoginManagerLogger *)loggerFromParameters:(NSDictionary *)parameters +{ + NSDictionary *clientState = [FBSDKInternalUtility objectForJSONString:parameters[FBSDKLoginManagerLoggingClientStateKey] error:NULL]; + + id isClientState = clientState[FBSDKLoginManagerLoggingClientStateIsClientState]; + if ([isClientState isKindOfClass:[NSNumber class]] && [isClientState boolValue]) { + FBSDKLoginManagerLogger *logger = [[self alloc] init]; + if (logger != nil) { + logger->_identifier = clientState[FBSDKLoginManagerLoggerParamIdentifierKey]; + logger->_authMethod = clientState[FBSDKLoginManagerLoggerParamAuthMethodKey]; + return logger; + } + } + return nil; +} + +- (instancetype)init +{ + if ((self = [super init]) != nil) { + _identifier = [[NSUUID UUID] UUIDString]; + _extras = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)startSessionForLoginManager:(FBSDKLoginManager *)loginManager +{ + BOOL isReauthorize = ([FBSDKAccessToken currentAccessToken] != nil); + BOOL willTryNative = NO; + BOOL willTryBrowser = NO; + BOOL willTrySystemAccount = NO; + BOOL willTryWebView = NO; + NSString *behaviorString = nil; + + switch (loginManager.loginBehavior) { + case FBSDKLoginBehaviorNative: + willTryNative = YES; + willTryBrowser = YES; + behaviorString = @"FBSDKLoginBehaviorNative"; + break; + case FBSDKLoginBehaviorBrowser: + willTryBrowser = YES; + behaviorString = @"FBSDKLoginBehaviorBrowser"; + break; + case FBSDKLoginBehaviorSystemAccount: + willTryNative = YES; + willTryBrowser = YES; + willTrySystemAccount = YES; + behaviorString = @"FBSDKLoginBehaviorSystemAccount"; + break; + case FBSDKLoginBehaviorWeb: + willTryWebView = YES; + behaviorString = @"FBSDKLoginBehaviorWeb"; + break; + } + + [_extras addEntriesFromDictionary:@{ + FBSDKLoginManagerLoggerTryNative : @(willTryNative), + FBSDKLoginManagerLoggerTryBrowser : @(willTryBrowser), + FBSDKLoginManagerLoggerTrySystemAccount : @(willTrySystemAccount), + FBSDKLoginManagerLoggerTryWebView : @(willTryWebView), + @"isReauthorize" : @(isReauthorize), + @"login_behavior" : behaviorString, + @"default_audience" : [FBSDKLoginUtility stringForAudience:loginManager.defaultAudience], + @"permissions" : [[loginManager.requestedPermissions allObjects] componentsJoinedByString:@","] ?: @"" + }]; + + [self logEvent:FBSDKAppEventNameFBSessionAuthStart params:[self _parametersForNewEvent]]; +} + +- (void)endSession +{ + [self logEvent:FBSDKAppEventNameFBSessionAuthEnd result:_lastResult error:_lastError]; +} + +- (void)startAuthMethod:(NSString *)authMethod +{ + _authMethod = authMethod; + [self logEvent:FBSDKAppEventNameFBSessionAuthMethodStart params:[self _parametersForNewEvent]]; +} + +- (void)endLoginWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error +{ + NSString *resultString = @""; + + if (error != nil) { + resultString = FBSDKLoginManagerLoggerResultErrorString; + } else if (result.isCancelled) { + resultString = FBSDKLoginManagerLoggerResultCancelString; + } else if (result.isSkipped) { + resultString = FBSDKLoginManagerLoggerResultSkippedString; + } else if (result.token) { + resultString = FBSDKLoginManagerLoggerResultSuccessString; + if (result.declinedPermissions.count) { + _extras[@"declined_permissions"] = [[result.declinedPermissions allObjects] componentsJoinedByString:@","]; + } + } + + _lastResult = resultString; + _lastError = error; + [_extras addEntriesFromDictionary:result.loggingExtras]; + + [self logEvent:FBSDKAppEventNameFBSessionAuthMethodEnd result:resultString error:error]; +} + +- (NSDictionary *)parametersWithTimeStampAndClientState:(NSDictionary *)loginParams forAuthMethod:(NSString *)authMethod +{ + NSMutableDictionary *params = [loginParams mutableCopy]; + + NSTimeInterval timeValue = (NSTimeInterval)FBSDKMonotonicTimeGetCurrentSeconds(); + NSString *e2eTimestampString = [FBSDKInternalUtility JSONStringForObject:@{ @"init" : @(timeValue) } + error:NULL + invalidObjectHandler:NULL]; + params[@"e2e"] = e2eTimestampString; + + NSDictionary *existingState = [FBSDKInternalUtility objectForJSONString:params[FBSDKLoginManagerLoggingClientStateKey] error:NULL]; + params[FBSDKLoginManagerLoggingClientStateKey] = [self clientStateForAuthMethod:authMethod andExistingState:existingState]; + + return params; +} + +- (void)willAttemptAppSwitchingBehavior +{ + NSString *defaultUrlScheme = [NSString stringWithFormat:@"fb%@%@", [FBSDKSettings appID], [FBSDKSettings appURLSchemeSuffix] ?: @""]; + BOOL isURLSchemeRegistered = [FBSDKInternalUtility isRegisteredURLScheme:defaultUrlScheme]; + + BOOL isFacebookAppCanOpenURLSchemeRegistered = [FBSDKInternalUtility isRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK]; + BOOL isMessengerAppCanOpenURLSchemeRegistered = [FBSDKInternalUtility isRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_MESSENGER]; + + [_extras addEntriesFromDictionary:@{ + @"isURLSchemeRegistered" : @(isURLSchemeRegistered), + @"isFacebookAppCanOpenURLSchemeRegistered" : @(isFacebookAppCanOpenURLSchemeRegistered), + @"isMessengerAppCanOpenURLSchemeRegistered" : @(isMessengerAppCanOpenURLSchemeRegistered), + }]; +} + +- (void)systemAuthDidShowDialog:(BOOL)didShowDialog isUnTOSedDevice:(BOOL)isUnTOSedDevice +{ + [_extras addEntriesFromDictionary:@{ + @"isUntosedDevice" : @(isUnTOSedDevice), + @"dialogShown" : @(didShowDialog), + }]; +} + +#pragma mark - Private + +- (NSString *)clientStateForAuthMethod:(NSString *)authMethod andExistingState:(NSDictionary *)existingState +{ + NSDictionary *clientState = @{ + FBSDKLoginManagerLoggerParamAuthMethodKey: authMethod ?: @"", + FBSDKLoginManagerLoggerParamIdentifierKey: _identifier, + FBSDKLoginManagerLoggingClientStateIsClientState: @YES, + }; + + if (existingState) { + NSMutableDictionary *mutableState = [clientState mutableCopy]; + [mutableState addEntriesFromDictionary:existingState]; + clientState = mutableState; + } + + return [FBSDKInternalUtility JSONStringForObject:clientState error:NULL invalidObjectHandler:NULL]; +} + +- (NSMutableDictionary *)_parametersForNewEvent +{ + NSMutableDictionary *eventParameters = [[NSMutableDictionary alloc] init]; + + // NOTE: We ALWAYS add all params to each event, to ensure predictable mapping on the backend. + eventParameters[FBSDKLoginManagerLoggerParamIdentifierKey] = _identifier ?: FBSDKLoginManagerLoggerValueEmpty; + eventParameters[FBSDKLoginManagerLoggerParamTimestampKey] = [NSNumber numberWithDouble:round(1000 * [[NSDate date] timeIntervalSince1970])]; + eventParameters[FBSDKLoginManagerLoggerParamResultKey] = FBSDKLoginManagerLoggerValueEmpty; + [FBSDKInternalUtility dictionary:eventParameters setObject:_authMethod forKey:FBSDKLoginManagerLoggerParamAuthMethodKey]; + eventParameters[FBSDKLoginManagerLoggerParamErrorCodeKey] = FBSDKLoginManagerLoggerValueEmpty; + eventParameters[FBSDKLoginManagerLoggerParamErrorMessageKey] = FBSDKLoginManagerLoggerValueEmpty; + eventParameters[FBSDKLoginManagerLoggerParamExtrasKey] = FBSDKLoginManagerLoggerValueEmpty; + + return eventParameters; +} + +- (void)logEvent:(NSString *)eventName params:(NSMutableDictionary *)params +{ + if (_identifier) { + NSString *extrasJSONString = [FBSDKInternalUtility JSONStringForObject:_extras + error:NULL + invalidObjectHandler:NULL]; + if (extrasJSONString) { + params[FBSDKLoginManagerLoggerParamExtrasKey] = extrasJSONString; + } + [_extras removeAllObjects]; + + [FBSDKAppEvents logImplicitEvent:eventName valueToSum:nil parameters:params accessToken:nil]; + } +} + +- (void)logEvent:(NSString *)eventName result:(NSString *)result error:(NSError *)error +{ + NSMutableDictionary *params = [self _parametersForNewEvent]; + + params[FBSDKLoginManagerLoggerParamResultKey] = result; + + if ([error.domain isEqualToString:FBSDKErrorDomain] || [error.domain isEqualToString:FBSDKLoginErrorDomain]) { + // tease apart the structure. + + // first see if there is an explicit message in the error's userInfo. If not, default to the reason, + // which is less useful. + NSString *value = error.userInfo[@"error_message"] ?: error.userInfo[FBSDKErrorLocalizedDescriptionKey]; + [FBSDKInternalUtility dictionary:params setObject:value forKey:FBSDKLoginManagerLoggerParamErrorMessageKey]; + + value = error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] ?: [NSString stringWithFormat:@"%ld", (long)error.code]; + [FBSDKInternalUtility dictionary:params setObject:value forKey:FBSDKLoginManagerLoggerParamErrorCodeKey]; + + NSError *innerError = error.userInfo[NSUnderlyingErrorKey]; + if (innerError != nil) { + value = innerError.userInfo[@"error_message"] ?: innerError.userInfo[NSLocalizedDescriptionKey]; + [FBSDKInternalUtility dictionary:_extras setObject:value forKey:@"inner_error_message"]; + + value = innerError.userInfo[FBSDKGraphRequestErrorGraphErrorCode] ?: [NSString stringWithFormat:@"%ld", (long)innerError.code]; + [FBSDKInternalUtility dictionary:_extras setObject:value forKey:@"inner_error_code"]; + } + } else if (error) { + params[FBSDKLoginManagerLoggerParamErrorCodeKey] = @(error.code); + } + + [self logEvent:eventName params:params]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h new file mode 100644 index 0000000..3191aa9 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@interface FBSDKLoginManagerLoginResult() + +@property (nonatomic, readonly) NSDictionary *loggingExtras; + +// legacy flag indicating this is an intermediary result only for logging purposes. +@property (nonatomic) BOOL isSkipped; + +// adds additional logging entry to extras - only sent as part of `endLoginWithResult:` +-(void)addLoggingExtra:(id)object forKey:(id)key; +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.h new file mode 100644 index 0000000..109dec8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@interface FBSDKLoginUtility : NSObject + ++ (BOOL)isPublishPermission:(NSString *)permission; ++ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions; ++ (BOOL)areAllPermissionsPublishPermissions:(NSSet *)permissions; ++ (NSString *)stringForAudience:(FBSDKDefaultAudience)audience; ++ (NSDictionary *)queryParamsFromLoginURL:(NSURL *)url; + ++ (NSString *)userIDFromSignedRequest:(NSString *)signedRequest; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.m new file mode 100644 index 0000000..c95a9ed --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.m @@ -0,0 +1,115 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLoginUtility.h" + +#import +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLoginConstants.h" + +@implementation FBSDKLoginUtility + ++ (BOOL)isPublishPermission:(NSString *)permission +{ + return [permission hasPrefix:@"publish"] || + [permission hasPrefix:@"manage"] || + [permission isEqualToString:@"ads_management"] || + [permission isEqualToString:@"create_event"] || + [permission isEqualToString:@"rsvp_event"]; +} + ++ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions +{ + for (NSString *permission in permissions) { + if ([[self class] isPublishPermission:permission]) { + return NO; + } + } + return YES; +} + ++ (BOOL)areAllPermissionsPublishPermissions:(NSSet *)permissions +{ + for (NSString *permission in permissions) { + if (![[self class] isPublishPermission:permission]) { + return NO; + } + } + return YES; +} + ++ (NSString *)stringForAudience:(FBSDKDefaultAudience)audience +{ + switch (audience) { + case FBSDKDefaultAudienceOnlyMe: + return @"only_me"; + case FBSDKDefaultAudienceFriends: + return @"friends"; + case FBSDKDefaultAudienceEveryone: + return @"everyone"; + } +} + ++ (NSDictionary *)queryParamsFromLoginURL:(NSURL *)url +{ + NSString *expectedUrlPrefix = [FBSDKInternalUtility appURLWithHost:@"authorize" path:nil queryParameters:nil error:NULL].absoluteString; + if (![[url absoluteString] hasPrefix:expectedUrlPrefix]) { + // Don't have an App ID, just verify path. + NSString *host = url.host; + if (![host isEqualToString:@"authorize"]) { + return nil; + } + } + NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:[FBSDKInternalUtility dictionaryFromFBURL:url]]; + + NSString *userID = [[self class] userIDFromSignedRequest:params[@"signed_request"]]; + if (userID) { + params[@"user_id"] = userID; + } + + return params; +} + ++ (NSString *)userIDFromSignedRequest:(NSString *)signedRequest +{ + if (!signedRequest) { + return nil; + } + + NSArray *signatureAndPayload = [signedRequest componentsSeparatedByString:@"."]; + NSString *userID = nil; + + if (signatureAndPayload.count == 2) { + NSData *data = [FBSDKBase64 decodeAsData:signatureAndPayload[1]]; + if (data) { + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + userID = dictionary[@"user_id"]; + } + } + return userID; +} + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.h b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.h new file mode 100644 index 0000000..b979138 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.h @@ -0,0 +1,23 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCoreKit+Internal.h" + +@interface _FBSDKLoginRecoveryAttempter : FBSDKErrorRecoveryAttempter + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.m b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.m new file mode 100644 index 0000000..efeab2d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.m @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "_FBSDKLoginRecoveryAttempter.h" + +#import "FBSDKLoginKit+Internal.h" + +@implementation _FBSDKLoginRecoveryAttempter + +- (void)attemptRecoveryFromError:(NSError *)error + optionIndex:(NSUInteger)recoveryOptionIndex + delegate:(id)delegate + didRecoverSelector:(SEL)didRecoverSelector + contextInfo:(void *)contextInfo { + + void(^handler)(BOOL) = ^(BOOL didRecover) { + [super completeRecovery:didRecover delegate:delegate didRecoverSelector:didRecoverSelector contextInfo:contextInfo]; + }; + NSSet *currentPermissions = [FBSDKAccessToken currentAccessToken].permissions; + if (recoveryOptionIndex == 0 && currentPermissions.count > 0) { + FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init]; + [login logInWithPermissions:currentPermissions handler:^(FBSDKLoginManagerLoginResult *result, NSError *loginError) { + // we can only consider a recovery successful if there are no declines + // (note this could still set an updated currentAccessToken). + if (!loginError && !result.isCancelled && result.declinedPermissions.count == 0) { + handler(YES); + } else { + handler(NO); + } + }]; + } else { + handler(NO); + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/LICENSE b/Unit-2-Journal/Pods/FBSDKLoginKit/LICENSE new file mode 100644 index 0000000..bdb9fc5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Unit-2-Journal/Pods/FBSDKLoginKit/README.mdown b/Unit-2-Journal/Pods/FBSDKLoginKit/README.mdown new file mode 100644 index 0000000..d14a5e4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKLoginKit/README.mdown @@ -0,0 +1,46 @@ +Facebook SDK for iOS +==================== + +This open-source library allows you to integrate Facebook into your iOS app. + +Learn more about the provided samples, documentation, integrating the SDK into your app, accessing source code, and more at https://developers.facebook.com/docs/ios + +NOTE: By default, the Facebook SDK for iOS is installed in ~/Documents/FacebookSDK + +TRY IT OUT +---------- +1. Download the SDK at https://developers.facebook.com/docs/ios or via Cocoapods by adding the 'FBSDKCoreKit', 'FBSDKLoginKit', and 'FBSDKShareKit' pods. +2. Test your install: build and run the project at ~/Documents/FacebookSDK/Samples/Scrumptious/Scrumptious.xcodeproj +3. Check-out the tutorials available online at: https://developers.facebook.com/docs/ios/getting-started +4. Start coding! Visit https://developers.facebook.com/docs/ios for tutorials and reference documentation. + +FEATURES +-------- +* Login - https://developers.facebook.com/docs/facebook-login +* Sharing - https://developers.facebook.com/docs/sharing +* App Links - https://developers.facebook.com/docs/applinks +* Graph API - https://developers.facebook.com/docs/ios/graph +* Analytics for Apps - https://developers.facebook.com/docs/analytics + +GIVE FEEDBACK +------------- +Please report bugs or issues to https://developers.facebook.com/bugs/ + +You can also join the Facebook Developers Group on Facebook (https://www.facebook.com/groups/fbdevelopers/) or ask questions on Stack Overflow (http://facebook.stackoverflow.com) + +LICENSE +------- +See the LICENSE file. + +DEVELOPER TERMS +--------------- + +- By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including information about people’s use of your app. Facebook will use information received in accordance with our Data Use Policy [https://www.facebook.com/about/privacy/], including to provide you with insights about the effectiveness of your ads and the use of your app. These integrations also enable us and our partners to serve ads on and off Facebook. + +- You may limit your sharing of information with us by updating the Insights control in the developer tool [https://developers.facebook.com/apps/{app_id}/settings/advanced]. + +- If you use a Facebook integration, including to share information with us, you agree and confirm that you have provided appropriate and sufficiently prominent notice to and obtained the appropriate consent from your users regarding such collection, use, and disclosure (including, at a minimum, through your privacy policy). You further agree that you will not share information with us about children under the age of 13. + +- You agree to comply with all applicable laws and regulations and also agree to our Terms , including our Platform Policies .and Advertising Guidelines, as applicable . + +By using the Facebook SDK for iOS you agree to these terms. diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h new file mode 100644 index 0000000..05b26ff --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h @@ -0,0 +1,101 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKAppGroupAddDialogDelegate; + +/*! + @abstract A dialog for creating app groups. + */ +@interface FBSDKAppGroupAddDialog : NSObject + +/*! + @abstract Convenience method to build up an app group dialog with content and a delegate. + @param content The content for the app group. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(FBSDKAppGroupContent *)content + delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for app group. + */ +@property (nonatomic, copy) FBSDKAppGroupContent *content; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app group dialog. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app group dialog from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppGroupAddDialog. + @discussion The delegate is notified with the results of the app group request as long as the application has + permissions to receive the information. For example, if the person is not signed into the containing app, the shower + may not be able to distinguish between completion of an app group request and cancellation. + */ +@protocol FBSDKAppGroupAddDialogDelegate + +/*! + @abstract Sent to the delegate when the app group request completes without error. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appGroupAddDialog:(FBSDKAppGroupAddDialog *)appGroupAddDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app group request encounters an error. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + @param error The error. + */ +- (void)appGroupAddDialog:(FBSDKAppGroupAddDialog *)appGroupAddDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the app group dialog is cancelled. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + */ +- (void)appGroupAddDialogDidCancel:(FBSDKAppGroupAddDialog *)appGroupAddDialog; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.m new file mode 100644 index 0000000..805ccef --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.m @@ -0,0 +1,185 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppGroupAddDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareError.h" +#import "FBSDKShareUtility.h" + +@interface FBSDKAppGroupAddDialog () +@end + +@implementation FBSDKAppGroupAddDialog +{ + FBSDKWebDialog *_webDialog; +} + +#define FBSDK_APP_GROUP_CREATE_METHOD_NAME @"game_group_create" + +#pragma mark - Class Methods + ++ (instancetype)showWithContent:(FBSDKAppGroupContent *)content + delegate:(id)delegate +{ + FBSDKAppGroupAddDialog *dialog = [[self alloc] init]; + dialog.content = content; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _webDialog = [[FBSDKWebDialog alloc] init]; + _webDialog.delegate = self; + _webDialog.name = FBSDK_APP_GROUP_CREATE_METHOD_NAME; + } + return self; +} + +- (void)dealloc +{ + _webDialog.delegate = nil; +} + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + return YES; +} + +- (BOOL)show +{ + NSError *error; + if (![self canShow]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"App group create dialog is not available."]; + [_delegate appGroupAddDialog:self didFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [_delegate appGroupAddDialog:self didFailWithError:error]; + return NO; + } + + FBSDKAppGroupContent *content = self.content; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:parameters setObject:content.name forKey:@"name"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.groupDescription forKey:@"description"]; + [FBSDKInternalUtility dictionary:parameters + setObject:NSStringFromFBSDKAppGroupPrivacy(content.privacy) + forKey:@"privacy"]; + + _webDialog.parameters = parameters; + [_webDialog show]; + [FBSDKInternalUtility registerTransientObject:self]; + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + FBSDKAppGroupContent *content = self.content; + if (!content) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"content" message:nil]; + } + return NO; + } + if (![content.name length]) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"name" message:nil]; + } + return NO; + } + if (![content.groupDescription length]) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"groupDescription" message:nil]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + +#pragma mark - FBSDKWebDialogDelegate + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results +{ + if (_webDialog != webDialog) { + return; + } + NSError *error = [FBSDKShareError errorWithCode:[FBSDKTypeUtility unsignedIntegerValue:results[@"error_code"]] + message:[FBSDKTypeUtility stringValue:results[@"error_message"]]]; + [self _handleCompletionWithDialogResults:results error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error +{ + if (_webDialog != webDialog) { + return; + } + [self _handleCompletionWithDialogResults:nil error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog +{ + if (_webDialog != webDialog) { + return; + } + [_delegate appGroupAddDialogDidCancel:self]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +#pragma mark - Helper Methods + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results error:(NSError *)error +{ + if (!_delegate) { + return; + } + switch (error.code) { + case 0:{ + [_delegate appGroupAddDialog:self didCompleteWithResults:results]; + break; + } + case 4201:{ + [_delegate appGroupAddDialogDidCancel:self]; + break; + } + default:{ + [_delegate appGroupAddDialog:self didFailWithError:error]; + break; + } + } + if (error) { + return; + } else { + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h new file mode 100644 index 0000000..a5c5823 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h @@ -0,0 +1,68 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKAppGroupPrivacy) + @abstract Specifies the privacy of a group. + */ +typedef NS_ENUM(NSUInteger, FBSDKAppGroupPrivacy) +{ + /*! Anyone can see the group, who's in it and what members post. */ + FBSDKAppGroupPrivacyOpen = 0, + /*! Anyone can see the group and who's in it, but only members can see posts. */ + FBSDKAppGroupPrivacyClosed, +}; + +/*! + @abstract Converts an FBSDKAppGroupPrivacy to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKAppGroupPrivacy(FBSDKAppGroupPrivacy privacy); + +/*! + @abstract A model for creating an app group. + */ +@interface FBSDKAppGroupContent : NSObject + +/*! + @abstract The description of the group. + */ +@property (nonatomic, copy) NSString *groupDescription; + +/*! + @abstract The name of the group. + */ +@property (nonatomic, copy) NSString *name; + +/*! + @abstract The privacy for the group. + */ +@property (nonatomic, assign) FBSDKAppGroupPrivacy privacy; + +/*! + @abstract Compares the receiver to another app group content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToAppGroupContent:(FBSDKAppGroupContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.m new file mode 100644 index 0000000..d3f429f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.m @@ -0,0 +1,109 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppGroupContent.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_APP_GROUP_CONTENT_GROUP_DESCRIPTION_KEY @"groupDescription" +#define FBSDK_APP_GROUP_CONTENT_NAME_KEY @"name" +#define FBSDK_APP_GROUP_CONTENT_PRIVACY_KEY @"privacy" + +NSString *NSStringFromFBSDKAppGroupPrivacy(FBSDKAppGroupPrivacy privacy) +{ + switch (privacy) { + case FBSDKAppGroupPrivacyClosed:{ + return @"closed"; + } + case FBSDKAppGroupPrivacyOpen:{ + return @"open"; + } + } +} + +@implementation FBSDKAppGroupContent + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_groupDescription hash], + [_name hash], + _privacy, + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKAppGroupContent class]]) { + return NO; + } + return [self isEqualToAppGroupContent:(FBSDKAppGroupContent *)object]; +} + +- (BOOL)isEqualToAppGroupContent:(FBSDKAppGroupContent *)content +{ + return (content && + (_privacy == content.privacy) && + [FBSDKInternalUtility object:_name isEqualToObject:content.name] && + [FBSDKInternalUtility object:_groupDescription isEqualToObject:content.groupDescription]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _groupDescription = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_APP_GROUP_CONTENT_GROUP_DESCRIPTION_KEY]; + _name = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APP_GROUP_CONTENT_PRIVACY_KEY]; + _privacy = [decoder decodeIntegerForKey:FBSDK_APP_GROUP_CONTENT_PRIVACY_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_groupDescription forKey:FBSDK_APP_GROUP_CONTENT_GROUP_DESCRIPTION_KEY]; + [encoder encodeObject:_name forKey:FBSDK_APP_GROUP_CONTENT_NAME_KEY]; + [encoder encodeInteger:_privacy forKey:FBSDK_APP_GROUP_CONTENT_PRIVACY_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKAppGroupContent *copy = [[FBSDKAppGroupContent alloc] init]; + copy->_groupDescription = [_groupDescription copy]; + copy->_name = [_name copy]; + copy->_privacy = _privacy; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h new file mode 100644 index 0000000..70e4e7a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h @@ -0,0 +1,99 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@protocol FBSDKAppGroupJoinDialogDelegate; + +/*! + @abstract A dialog for joining app groups. + */ +@interface FBSDKAppGroupJoinDialog : NSObject + +/*! + @abstract Convenience method to build up an app group dialog with content and a delegate. + @param groupID The ID for the group. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithGroupID:(NSString *)groupID + delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The ID for group. + */ +@property (nonatomic, copy) NSString *groupID; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app group dialog. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app group dialog from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppGroupJoinDialog. + @discussion The delegate is notified with the results of the app group request as long as the application has + permissions to receive the information. For example, if the person is not signed into the containing app, the shower + may not be able to distinguish between completion of an app group request and cancellation. + */ +@protocol FBSDKAppGroupJoinDialogDelegate + +/*! + @abstract Sent to the delegate when the app group request completes without error. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appGroupJoinDialog:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app group request encounters an error. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + @param error The error. + */ +- (void)appGroupJoinDialog:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the app group dialog is cancelled. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + */ +- (void)appGroupJoinDialogDidCancel:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.m new file mode 100644 index 0000000..dd7a11a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.m @@ -0,0 +1,167 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppGroupJoinDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareError.h" +#import "FBSDKShareUtility.h" + +@interface FBSDKAppGroupJoinDialog () +@end + +@implementation FBSDKAppGroupJoinDialog +{ + FBSDKWebDialog *_webDialog; +} + +#define FBSDK_APP_GROUP_JOIN_METHOD_NAME @"game_group_join" + +#pragma mark - Class Methods + ++ (instancetype)showWithGroupID:(NSString *)groupID + delegate:(id)delegate +{ + FBSDKAppGroupJoinDialog *dialog = [[self alloc] init]; + dialog.groupID = groupID; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _webDialog = [[FBSDKWebDialog alloc] init]; + _webDialog.delegate = self; + _webDialog.name = FBSDK_APP_GROUP_JOIN_METHOD_NAME; + } + return self; +} + +- (void)dealloc +{ + _webDialog.delegate = nil; +} + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + return YES; +} + +- (BOOL)show +{ + NSError *error; + if (![self canShow]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"App group join dialog is not available."]; + [_delegate appGroupJoinDialog:self didFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [_delegate appGroupJoinDialog:self didFailWithError:error]; + return NO; + } + + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:parameters setObject:self.groupID forKey:@"id"]; + + _webDialog.parameters = parameters; + [_webDialog show]; + [FBSDKInternalUtility registerTransientObject:self]; + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + if (![self.groupID length]) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"groupID" message:nil]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + +#pragma mark - FBSDKWebDialogDelegate + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results +{ + if (_webDialog != webDialog) { + return; + } + NSError *error = [FBSDKShareError errorWithCode:[FBSDKTypeUtility unsignedIntegerValue:results[@"error_code"]] + message:[FBSDKTypeUtility stringValue:results[@"error_message"]]]; + [self _handleCompletionWithDialogResults:results error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error +{ + if (_webDialog != webDialog) { + return; + } + [self _handleCompletionWithDialogResults:nil error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog +{ + if (_webDialog != webDialog) { + return; + } + [_delegate appGroupJoinDialogDidCancel:self]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +#pragma mark - Helper Methods + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results error:(NSError *)error +{ + if (!_delegate) { + return; + } + switch (error.code) { + case 0:{ + [_delegate appGroupJoinDialog:self didCompleteWithResults:results]; + break; + } + case 4201:{ + [_delegate appGroupJoinDialogDidCancel:self]; + break; + } + default:{ + [_delegate appGroupJoinDialog:self didFailWithError:error]; + break; + } + } + if (error) { + return; + } else { + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h new file mode 100644 index 0000000..1feb828 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h @@ -0,0 +1,54 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for app invite. + */ +@interface FBSDKAppInviteContent : NSObject + +/*! + @abstract A URL to a preview image that will be displayed with the app invite + + @discussion This is optional. If you don't include it a fallback image will be used. +*/ +@property (nonatomic, copy) NSURL *appInvitePreviewImageURL; + +/*! + @abstract An app link target that will be used as a target when the user accept the invite. + + @discussion This is a requirement. + */ +@property (nonatomic, copy) NSURL *appLinkURL; + +/*! + @deprecated Use `appInvitePreviewImageURL` instead. + */ +@property (nonatomic, copy) NSURL *previewImageURL __attribute__ ((deprecated("use appInvitePreviewImageURL instead"))); + +/*! + @abstract Compares the receiver to another app invite content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToAppInviteContent:(FBSDKAppInviteContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.m new file mode 100644 index 0000000..d54ff1c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.m @@ -0,0 +1,99 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppInviteContent.h" + +#import "FBSDKCoreKit+Internal.h" + +#define FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY @"appLinkURL" +#define FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY @"previewImage" + +@implementation FBSDKAppInviteContent + +- (NSURL *)previewImageURL +{ + return self.appInvitePreviewImageURL; +} + +- (void)setPreviewImageURL:(NSURL *)previewImageURL +{ + self.appInvitePreviewImageURL = previewImageURL; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_appLinkURL hash], + [_appInvitePreviewImageURL hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKAppInviteContent class]]) { + return NO; + } + return [self isEqualToAppInviteContent:(FBSDKAppInviteContent *)object]; +} + +- (BOOL)isEqualToAppInviteContent:(FBSDKAppInviteContent *)content +{ + return (content && + [FBSDKInternalUtility object:_appLinkURL isEqualToObject:content.appLinkURL] && + [FBSDKInternalUtility object:_appInvitePreviewImageURL isEqualToObject:content.appInvitePreviewImageURL]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _appLinkURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY]; + _appInvitePreviewImageURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_appLinkURL forKey:FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY]; + [encoder encodeObject:_appInvitePreviewImageURL forKey:FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKAppInviteContent *copy = [[FBSDKAppInviteContent alloc] init]; + copy->_appLinkURL = [_appLinkURL copy]; + copy->_appInvitePreviewImageURL = [_appInvitePreviewImageURL copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h new file mode 100644 index 0000000..0859d4c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h @@ -0,0 +1,111 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import + +@protocol FBSDKAppInviteDialogDelegate; + +/*! + @abstract A dialog for sending App Invites. + */ +@interface FBSDKAppInviteDialog : NSObject + +/*! + @abstract Convenience method to show a FBSDKAppInviteDialog + @param viewController A UIViewController to present the dialog from. + @param content The content for the app invite. + @param delegate The receiver's delegate. +*/ ++ (instancetype)showFromViewController:(UIViewController *)viewController + withContent:(FBSDKAppInviteContent *)content + delegate:(id)delegate; + + +/*! + @deprecated use showFromViewController:withContent:delegate: instead + */ ++ (instancetype)showWithContent:(FBSDKAppInviteContent *)content delegate:(id)delegate +__attribute__ ((deprecated("use showFromViewController:withContent:delegate: instead"))); + +/*! + @abstract A UIViewController to present the dialog from. + @discussion If not specified, the top most view controller will be automatically determined as best as possible. + */ +@property (nonatomic, weak) UIViewController *fromViewController; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for app invite. + */ +@property (nonatomic, copy) FBSDKAppInviteContent *content; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app invite. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can show the dialog, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app invite from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppInviteDialog. + @discussion The delegate is notified with the results of the app invite as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the shower may not be able + to distinguish between completion of an app invite and cancellation. + */ +@protocol FBSDKAppInviteDialogDelegate + +/*! + @abstract Sent to the delegate when the app invite completes without error. + @param appInviteDialog The FBSDKAppInviteDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appInviteDialog:(FBSDKAppInviteDialog *)appInviteDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app invite encounters an error. + @param appInviteDialog The FBSDKAppInviteDialog that completed. + @param error The error. + */ +- (void)appInviteDialog:(FBSDKAppInviteDialog *)appInviteDialog didFailWithError:(NSError *)error; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.m new file mode 100644 index 0000000..15fdcc6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.m @@ -0,0 +1,197 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKAppInviteDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" +#import "FBSDKShareUtility.h" + +@implementation FBSDKAppInviteDialog + +#define FBSDK_APP_INVITE_METHOD_MIN_VERSION @"20140410" +#define FBSDK_APP_INVITE_METHOD_NAME @"appinvites" + ++ (void)initialize +{ + if ([FBSDKAppInviteDialog class] == self) { + [FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK]; + // ensure that we have updated the dialog configs if we haven't already + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + +#pragma mark - Class Methods + + ++ (instancetype)showWithContent:(FBSDKAppInviteContent *)content delegate:(id)delegate +{ + return [self showFromViewController:nil withContent:content delegate:delegate]; +} + ++ (instancetype)showFromViewController:(UIViewController *)viewController + withContent:(FBSDKAppInviteContent *)content + delegate:(id)delegate; +{ + FBSDKAppInviteDialog *appInvite = [[self alloc] init]; + appInvite.content = content; + appInvite.delegate = delegate; + appInvite.fromViewController = viewController; + [appInvite show]; + return appInvite; +} + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + return YES; +} + +- (BOOL)show +{ + NSError *error; + if (![self canShow]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"App invite dialog is not available."]; + [self _invokeDelegateDidFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [self _invokeDelegateDidFailWithError:error]; + return NO; + } + + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:parameters setObject:self.content.appLinkURL forKey:@"app_link_url"]; + [FBSDKInternalUtility dictionary:parameters setObject:self.content.appInvitePreviewImageURL forKey:@"preview_image_url"]; + FBSDKBridgeAPIRequest *webBridgeRequest = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeWeb + scheme:FBSDK_SHARE_JS_DIALOG_SCHEME + methodName:FBSDK_APP_INVITE_METHOD_NAME + methodVersion:nil + parameters:parameters + userInfo:nil]; + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + [self _handleCompletionWithDialogResults:response.responseParameters error:response.error]; + }; + + [self _logDialogShow]; + + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useSafariViewController = [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameAppInvite]; + if ([self _canShowNative]) { + FBSDKBridgeAPIRequest *nativeRequest = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeNative + scheme:FBSDK_CANOPENURL_FACEBOOK + methodName:FBSDK_APP_INVITE_METHOD_NAME + methodVersion:FBSDK_APP_INVITE_METHOD_MIN_VERSION + parameters:parameters + userInfo:nil]; + void (^nativeCompletionBlock)(FBSDKBridgeAPIResponse *) = ^(FBSDKBridgeAPIResponse *response) { + if (response.error.code == FBSDKAppVersionUnsupportedErrorCode) { + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:webBridgeRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:completionBlock]; + } else { + completionBlock(response); + } + }; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:nativeRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:nativeCompletionBlock]; + } else { + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:webBridgeRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:completionBlock]; + } + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + return [FBSDKShareUtility validateAppInviteContent:self.content error:errorRef]; +} + +#pragma mark - Helper Methods + +- (BOOL)_canShowNative +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useNativeDialog = [configuration useNativeDialogForDialogName:FBSDKDialogConfigurationNameAppInvite]; + return (useNativeDialog && [FBSDKInternalUtility isFacebookAppInstalled]); +} + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results error:(NSError *)error +{ + if (error) { + [self _invokeDelegateDidFailWithError:error]; + } else { + [self _invokeDelegateDidCompleteWithResults:results]; + } +} + +- (void)_invokeDelegateDidCompleteWithResults:(NSDictionary *)results +{ + NSDictionary * parameters =@{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Completed, + }; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + if (!_delegate) { + return; + } + + [_delegate appInviteDialog:self didCompleteWithResults:[results copy]]; +} + +- (void)_invokeDelegateDidFailWithError:(NSError *)error +{ + NSDictionary * parameters =@{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Failed, + FBSDKAppEventParameterDialogErrorMessage : [NSString stringWithFormat:@"%@", error] + }; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + if (!_delegate) { + return; + } + + [_delegate appInviteDialog:self didFailWithError:error]; +} + +- (void)_logDialogShow +{ + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow + valueToSum:nil + parameters:nil + accessToken:[FBSDKAccessToken currentAccessToken]]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h new file mode 100644 index 0000000..13edc06 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h @@ -0,0 +1,131 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGameRequestActionType) + @abstract Additional context about the nature of the request. + */ +typedef NS_ENUM(NSUInteger, FBSDKGameRequestActionType) +{ + /*! No action type */ + FBSDKGameRequestActionTypeNone = 0, + /*! Send action type: The user is sending an object to the friends. */ + FBSDKGameRequestActionTypeSend, + /*! Ask For action type: The user is asking for an object from friends. */ + FBSDKGameRequestActionTypeAskFor, + /*! Turn action type: It is the turn of the friends to play against the user in a match. (no object) */ + FBSDKGameRequestActionTypeTurn, +}; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGameRequestFilters) + @abstract Filter for who can be displayed in the multi-friend selector. + */ +typedef NS_ENUM(NSUInteger, FBSDKGameRequestFilter) +{ + /*! No filter, all friends can be displayed. */ + FBSDKGameRequestFilterNone = 0, + /*! Friends using the app can be displayed. */ + FBSDKGameRequestFilterAppUsers, + /*! Friends not using the app can be displayed. */ + FBSDKGameRequestFilterAppNonUsers, +}; + +/*! + @abstract A model for a game request. + */ +@interface FBSDKGameRequestContent : NSObject + +/*! + @abstract Used when defining additional context about the nature of the request. + @discussion The parameter 'objectID' is required if the action type is either + 'FBSDKGameRequestSendActionType' or 'FBSDKGameRequestAskForActionType'. + @seealso objectID + */ +@property (nonatomic, assign) FBSDKGameRequestActionType actionType; + +/*! + @abstract Compares the receiver to another game request content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToGameRequestContent:(FBSDKGameRequestContent *)content; + +/*! + @abstract Additional freeform data you may pass for tracking. This will be stored as part of + the request objects created. The maximum length is 255 characters. + */ +@property (nonatomic, copy) NSString *data; + +/*! + @abstract This controls the set of friends someone sees if a multi-friend selector is shown. + It is FBSDKGameRequestNoFilter by default, meaning that all friends can be shown. + If specify as FBSDKGameRequestAppUsersFilter, only friends who use the app will be shown. + On the other hands, use FBSDKGameRequestAppNonUsersFilter to filter only friends who do not use the app. + @discussion The parameter name is preserved to be consistent with the counter part on desktop. + */ +@property (nonatomic, assign) FBSDKGameRequestFilter filters; + +/*! + @abstract A plain-text message to be sent as part of the request. This text will surface in the App Center view + of the request, but not on the notification jewel. Required parameter. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract The Open Graph object ID of the object being sent. + @seealso actionType + */ +@property (nonatomic, copy) NSString *objectID; + +/*! + @abstract An array of user IDs, usernames or invite tokens (NSString) of people to send request. + @discussion These may or may not be a friend of the sender. If this is specified by the app, + the sender will not have a choice of recipients. If not, the sender will see a multi-friend selector + + This is equivalent to the "to" parameter when using the web game request dialog. + */ +@property (nonatomic, copy) NSArray *recipients; + +/*! + @abstract An array of user IDs that will be included in the dialog as the first suggested friends. + Cannot be used together with filters. + @discussion This is equivalent to the "suggestions" parameter when using the web game request dialog. +*/ +@property (nonatomic, copy) NSArray *recipientSuggestions; + +/*! + @deprecated Use `recipientSuggestions` instead. +*/ +@property (nonatomic, copy) NSArray *suggestions __attribute__ ((deprecated("use recipientSuggestions instead"))); + +/*! + @abstract The title for the dialog. + */ +@property (nonatomic, copy) NSString *title; + +/*! + @deprecated Use `recipients` instead. + */ +@property (nonatomic, copy) NSArray *to __attribute__ ((deprecated("use recipients instead"))); + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.m new file mode 100644 index 0000000..c2f629e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.m @@ -0,0 +1,164 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGameRequestContent.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_APP_REQUEST_CONTENT_TO_KEY @"to" +#define FBSDK_APP_REQUEST_CONTENT_MESSAGE_KEY @"message" +#define FBSDK_APP_REQUEST_CONTENT_ACTION_TYPE_KEY @"actionType" +#define FBSDK_APP_REQUEST_CONTENT_OBJECT_ID_KEY @"objectID" +#define FBSDK_APP_REQUEST_CONTENT_FILTERS_KEY @"filters" +#define FBSDK_APP_REQUEST_CONTENT_SUGGESTIONS_KEY @"suggestions" +#define FBSDK_APP_REQUEST_CONTENT_DATA_KEY @"data" +#define FBSDK_APP_REQUEST_CONTENT_TITLE_KEY @"title" + +@implementation FBSDKGameRequestContent + +#pragma mark - Properties + +-(void)setRecipients:(NSArray *)recipients +{ + [FBSDKShareUtility assertCollection:recipients ofClass:[NSString class] name:@"recipients"]; + if (![_recipients isEqual:recipients]) { + _recipients = [recipients copy]; + } +} + +- (void)setRecipientSuggestions:(NSArray *)recipientSuggestions +{ + [FBSDKShareUtility assertCollection:recipientSuggestions ofClass:[NSString class] name:@"recipientSuggestions"]; + if (![_recipientSuggestions isEqual:recipientSuggestions]) { + _recipientSuggestions = [recipientSuggestions copy]; + } +} + +- (NSArray *)suggestions +{ + return self.recipientSuggestions; +} + +- (void)setSuggestions:(NSArray *)suggestions +{ + self.recipientSuggestions = suggestions; +} + +- (NSArray *)to +{ + return self.recipients; +} + +- (void)setTo:(NSArray *)to +{ + self.recipients = to; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [FBSDKMath hashWithInteger:_actionType], + [_data hash], + [FBSDKMath hashWithInteger:_filters], + [_message hash], + [_objectID hash], + [_recipientSuggestions hash], + [_title hash], + [_recipients hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKGameRequestContent class]]) { + return NO; + } + return [self isEqualToGameRequestContent:(FBSDKGameRequestContent *)object]; +} + +- (BOOL)isEqualToGameRequestContent:(FBSDKGameRequestContent *)content +{ + return (content && + _actionType == content.actionType && + _filters == content.filters && + [FBSDKInternalUtility object:_data isEqualToObject:content.data] && + [FBSDKInternalUtility object:_message isEqualToObject:content.message] && + [FBSDKInternalUtility object:_objectID isEqualToObject:content.objectID] && + [FBSDKInternalUtility object:_recipientSuggestions isEqualToObject:content.recipientSuggestions] && + [FBSDKInternalUtility object:_title isEqualToObject:content.title] && + [FBSDKInternalUtility object:_recipients isEqualToObject:content.recipients]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _actionType = [decoder decodeIntegerForKey:FBSDK_APP_REQUEST_CONTENT_ACTION_TYPE_KEY]; + _data = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APP_REQUEST_CONTENT_DATA_KEY]; + _filters = [decoder decodeIntegerForKey:FBSDK_APP_REQUEST_CONTENT_FILTERS_KEY]; + _message = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APP_REQUEST_CONTENT_MESSAGE_KEY]; + _objectID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APP_REQUEST_CONTENT_OBJECT_ID_KEY]; + _recipientSuggestions = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_APP_REQUEST_CONTENT_SUGGESTIONS_KEY]; + _title = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APP_REQUEST_CONTENT_TITLE_KEY]; + _recipients = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_APP_REQUEST_CONTENT_TO_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeInteger:_actionType forKey:FBSDK_APP_REQUEST_CONTENT_ACTION_TYPE_KEY]; + [encoder encodeObject:_data forKey:FBSDK_APP_REQUEST_CONTENT_DATA_KEY]; + [encoder encodeInteger:_filters forKey:FBSDK_APP_REQUEST_CONTENT_FILTERS_KEY]; + [encoder encodeObject:_message forKey:FBSDK_APP_REQUEST_CONTENT_MESSAGE_KEY]; + [encoder encodeObject:_objectID forKey:FBSDK_APP_REQUEST_CONTENT_OBJECT_ID_KEY]; + [encoder encodeObject:_recipientSuggestions forKey:FBSDK_APP_REQUEST_CONTENT_SUGGESTIONS_KEY]; + [encoder encodeObject:_title forKey:FBSDK_APP_REQUEST_CONTENT_TITLE_KEY]; + [encoder encodeObject:_recipients forKey:FBSDK_APP_REQUEST_CONTENT_TO_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKGameRequestContent *copy = [[FBSDKGameRequestContent alloc] init]; + copy->_actionType = _actionType; + copy->_data = [_data copy]; + copy->_filters = _filters; + copy->_message = [_message copy]; + copy->_objectID = [_objectID copy]; + copy->_recipientSuggestions = [_recipientSuggestions copy]; + copy->_title = [_title copy]; + copy->_recipients = [_recipients copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h new file mode 100644 index 0000000..2f5acc5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h @@ -0,0 +1,105 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKGameRequestDialogDelegate; + +/*! + @abstract A dialog for sending game requests. + */ +@interface FBSDKGameRequestDialog : NSObject + +/*! + @abstract Convenience method to build up a game request with content and a delegate. + @param content The content for the game request. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(FBSDKGameRequestContent *)content delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for game request. + */ +@property (nonatomic, copy) FBSDKGameRequestContent *content; + +/*! + @abstract Specifies whether frictionless requests are enabled. + */ +@property (nonatomic, assign) BOOL frictionlessRequestsEnabled; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate a game request. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the game request from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKGameRequestDialog. + @discussion The delegate is notified with the results of the game request as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the shower may not be able + to distinguish between completion of a game request and cancellation. + */ +@protocol FBSDKGameRequestDialogDelegate + +/*! + @abstract Sent to the delegate when the game request completes without error. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the game request encounters an error. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + @param error The error. + */ +- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the game request dialog is cancelled. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + */ +- (void)gameRequestDialogDidCancel:(FBSDKGameRequestDialog *)gameRequestDialog; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.m new file mode 100644 index 0000000..11932ae --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.m @@ -0,0 +1,265 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGameRequestDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKGameRequestFrictionlessRecipientCache.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareError.h" +#import "FBSDKShareUtility.h" + +@interface FBSDKGameRequestDialog () +@end + +@implementation FBSDKGameRequestDialog +{ + BOOL _dialogIsFrictionless; + FBSDKWebDialog *_webDialog; +} + +#define FBSDK_APP_REQUEST_METHOD_NAME @"apprequests" + +#pragma mark - Class Methods + +static FBSDKGameRequestFrictionlessRecipientCache *_recipientCache = nil; + ++ (void)initialize +{ + if (self == [FBSDKGameRequestDialog class]) { + _recipientCache = [[FBSDKGameRequestFrictionlessRecipientCache alloc] init]; + } +} + ++ (instancetype)showWithContent:(FBSDKGameRequestContent *)content delegate:(id)delegate +{ + FBSDKGameRequestDialog *dialog = [[self alloc] init]; + dialog.content = content; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _webDialog = [[FBSDKWebDialog alloc] init]; + _webDialog.delegate = self; + _webDialog.name = FBSDK_APP_REQUEST_METHOD_NAME; + } + return self; +} + +- (void)dealloc +{ + _webDialog.delegate = nil; +} + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + return YES; +} + +- (BOOL)show +{ + NSError *error; + if (![self canShow]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Game request dialog is not available."]; + [_delegate gameRequestDialog:self didFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [_delegate gameRequestDialog:self didFailWithError:error]; + return NO; + } + + FBSDKGameRequestContent *content = self.content; + + if (error) { + return NO; + } + + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:parameters setObject:[content.recipients componentsJoinedByString:@","] forKey:@"to"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.message forKey:@"message"]; + [FBSDKInternalUtility dictionary:parameters setObject:[self _actionTypeNameForActionType:content.actionType] forKey:@"action_type"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.objectID forKey:@"object_id"]; + [FBSDKInternalUtility dictionary:parameters setObject:[self _filtersNameForFilters:content.filters] forKey:@"filters"]; + [FBSDKInternalUtility dictionary:parameters setObject:[content.recipientSuggestions componentsJoinedByString:@","] forKey:@"suggestions"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.data forKey:@"data"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.title forKey:@"title"]; + + // check if we are sending to a specific set of recipients. if we are and they are all frictionless recipients, we + // can perform this action without displaying the web dialog + _webDialog.deferVisibility = NO; + NSArray *recipients = content.recipients; + if (_frictionlessRequestsEnabled && recipients) { + // specify these parameters to get the frictionless recipients from the dialog when it is presented + parameters[@"frictionless"] = @YES; + parameters[@"get_frictionless_recipients"] = @YES; + + _dialogIsFrictionless = YES; + if ([_recipientCache recipientsAreFrictionless:recipients]) { + _webDialog.deferVisibility = YES; + } + } + + _webDialog.parameters = parameters; + [_webDialog show]; + [FBSDKInternalUtility registerTransientObject:self]; + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + return [FBSDKShareUtility validateGameRequestContent:self.content error:errorRef]; +} + +#pragma mark - FBSDKWebDialogDelegate + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results +{ + if (_webDialog != webDialog) { + return; + } + if (_dialogIsFrictionless && results) { + [_recipientCache updateWithResults:results]; + } + [self _cleanUp]; + + NSError *error = [FBSDKShareError errorWithCode:[FBSDKTypeUtility unsignedIntegerValue:results[@"error_code"]] + message:[FBSDKTypeUtility stringValue:results[@"error_message"]]]; + if (!error.code) { + // reformat "to[x]" keys into an array. + int counter = 0; + NSMutableArray *toArray = [NSMutableArray array]; + while (true) { + NSString *key = [NSString stringWithFormat:@"to[%d]", counter++]; + if (results[key]) { + [toArray addObject:results[key]]; + } else { + break; + } + } + if (toArray.count) { + NSMutableDictionary *mutableResults = [results mutableCopy]; + mutableResults[@"to"] = toArray; + results = mutableResults; + } + } + [self _handleCompletionWithDialogResults:results error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error +{ + if (_webDialog != webDialog) { + return; + } + [self _cleanUp]; + [self _handleCompletionWithDialogResults:nil error:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog +{ + if (_webDialog != webDialog) { + return; + } + [self _cleanUp]; + [_delegate gameRequestDialogDidCancel:self]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +#pragma mark - Helper Methods + +- (void)_cleanUp +{ + _dialogIsFrictionless = NO; +} + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results error:(NSError *)error +{ + if (!_delegate) { + return; + } + switch (error.code) { + case 0:{ + [_delegate gameRequestDialog:self didCompleteWithResults:results]; + break; + } + case 4201:{ + [_delegate gameRequestDialogDidCancel:self]; + break; + } + default:{ + [_delegate gameRequestDialog:self didFailWithError:error]; + break; + } + } + if (error) { + return; + } else { + } +} + +- (NSString *)_actionTypeNameForActionType:(FBSDKGameRequestActionType)actionType +{ + switch (actionType) { + case FBSDKGameRequestActionTypeNone:{ + return nil; + } + case FBSDKGameRequestActionTypeSend:{ + return @"send"; + } + case FBSDKGameRequestActionTypeAskFor:{ + return @"askfor"; + } + case FBSDKGameRequestActionTypeTurn:{ + return @"turn"; + } + default:{ + return nil; + } + } +} + +- (NSString *)_filtersNameForFilters:(FBSDKGameRequestFilter)filters +{ + switch (filters) { + case FBSDKGameRequestFilterNone:{ + return nil; + } + case FBSDKGameRequestFilterAppUsers:{ + return @"app_users"; + } + case FBSDKGameRequestFilterAppNonUsers:{ + return @"app_non_users"; + } + default:{ + return nil; + } + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h new file mode 100644 index 0000000..0b01c4e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h @@ -0,0 +1,42 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @abstract A button to like an object. + @discussion Tapping the receiver will invoke an API call to the Facebook app through a fast-app-switch that allows + the object to be liked. Upon return to the calling app, the view will update with the new state. If the + currentAccessToken has "publish_actions" permission and the object is an Open Graph object, then the like can happen + seamlessly without the fast-app-switch. + */ +@interface FBSDKLikeButton : FBSDKButton + +/*! + @abstract If YES, a sound is played when the receiver is toggled. + + @default YES + */ +@property (nonatomic, assign, getter = isSoundEnabled) BOOL soundEnabled; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.m new file mode 100644 index 0000000..150cece --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.m @@ -0,0 +1,294 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeButton.h" +#import "FBSDKLikeButton+Internal.h" + +#import "FBSDKCheckmarkIcon.h" +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLikeActionController.h" +#import "FBSDKLikeControl+Internal.h" + +#define FBSDK_LIKE_BUTTON_ANIMATION_DURATION 0.2 +#define FBSDK_LIKE_BUTTON_ANIMATION_SPRING_DAMPING 0.3 +#define FBSDK_LIKE_BUTTON_ANIMATION_SPRING_VELOCITY 0.2 + +@implementation FBSDKLikeButton +{ + BOOL _isExplicitlyDisabled; + FBSDKLikeActionController *_likeActionController; + NSString *_objectID; + FBSDKLikeObjectType _objectType; +} + +#pragma mark - Class Methods + ++ (void)initialize +{ + if ([FBSDKLikeButton class] == self) { + // ensure that we have updated the dialog configs if we haven't already + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + +#pragma mark - Object Lifecycle + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [_likeActionController endContentAccess]; +} + +#pragma mark - Properties + +- (FBSDKLikeActionController *)likeActionController +{ + [self _ensureLikeActionController:NO]; + return _likeActionController; +} + +- (void)setLikeActionController:(FBSDKLikeActionController *)likeActionController +{ + [self _setLikeActionController:likeActionController]; +} + +- (NSString *)objectID +{ + return _objectID; +} + +- (void)setObjectID:(NSString *)objectID +{ + if (![_objectID isEqualToString:objectID]) { + _objectID = objectID; + [self checkImplicitlyDisabled]; + [self _resetLikeActionController]; + } +} + +- (FBSDKLikeObjectType)objectType +{ + return _objectType; +} + +- (void)setObjectType:(FBSDKLikeObjectType)objectType +{ + if (_objectType != objectType) { + _objectType = objectType; + [self _resetLikeActionController]; + } +} + +#pragma mark - Layout + +- (void)layoutSubviews +{ + [self _ensureLikeActionController:YES]; + [super layoutSubviews]; +} + +#pragma mark - FBSDKButtonImpressionTracking + +- (NSDictionary *)analyticsParameters +{ + UIView *superview = self.superview; + while (superview && ![superview isKindOfClass:[FBSDKLikeControl class]]) { + superview = superview.superview; + } + if ([superview isKindOfClass:[FBSDKLikeControl class]]) { + return ((FBSDKLikeControl *)superview).analyticsParameters; + } + return @{ + @"object_id": (self.objectID ?: [NSNull null]), + @"object_type": (NSStringFromFBSDKLikeObjectType(self.objectType) ?: [NSNull null]), + @"sound_enabled": @(self.soundEnabled), + }; +} + +- (NSString *)impressionTrackingEventName +{ + return FBSDKAppEventNameFBSDKLikeButtonImpression; +} + +- (NSString *)impressionTrackingIdentifier +{ + return self.objectID; +} + +#pragma mark - FBSDKButton + +- (void)configureButton +{ + self.soundEnabled = YES; + + NSString *title = + NSLocalizedStringWithDefaultValue(@"LikeButton.Like", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Like", + @"The label for the FBSDKLikeButton when the object is not currently liked."); + NSString *selectedTitle = + NSLocalizedStringWithDefaultValue(@"LikeButton.Liked", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Liked", + @"The label for the FBSDKLikeButton when the object is currently liked."); + + UIColor *backgroundColor = [self defaultBackgroundColor]; + UIColor *highlightedColor = [self defaultHighlightedColor]; + UIColor *selectedColor = [self defaultSelectedColor]; + UIColor *selectedHighlightedColor = [UIColor colorWithRed:99.0/255.0 green:119.0/255.0 blue:178.0/255.0 alpha:1.0]; + + [self configureWithIcon:nil + title:title + backgroundColor:backgroundColor + highlightedColor:highlightedColor + selectedTitle:selectedTitle + selectedIcon:[[FBSDKCheckmarkIcon alloc] init] + selectedColor:selectedColor + selectedHighlightedColor:selectedHighlightedColor]; + + [self addTarget:self action:@selector(_handleTap:) forControlEvents:UIControlEventTouchUpInside]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(_likeActionControllerDidDisableNotification:) + name:FBSDKLikeActionControllerDidDisableNotification + object:nil]; + [nc addObserver:self + selector:@selector(_likeActionControllerDidResetNotification:) + name:FBSDKLikeActionControllerDidResetNotification + object:nil]; + [nc addObserver:self + selector:@selector(_likeActionControllerDidUpdateNotification:) + name:FBSDKLikeActionControllerDidUpdateNotification + object:nil]; +} + +- (BOOL)isImplicitlyDisabled +{ + return !self.objectID || [FBSDKLikeActionController isDisabled]; +} + +#pragma mark - Helper Methods + +- (void)_ensureLikeActionController:(BOOL)notifyKVO +{ + if (!_likeActionController) { + FBSDKLikeActionController *likeActionController = [FBSDKLikeActionController likeActionControllerForObjectID:_objectID + objectType:_objectType]; + if (notifyKVO) { + self.likeActionController = likeActionController; + } else { + [self _setLikeActionController:likeActionController]; + } + [likeActionController endContentAccess]; + self.selected = _likeActionController.objectIsLiked; + } +} + +- (void)_handleTap:(FBSDKLikeButton *)likeButton +{ + [self logTapEventWithEventName:FBSDKAppEventNameFBSDKLikeButtonDidTap parameters:[self analyticsParameters]]; + [self _ensureLikeActionController:YES]; + [_likeActionController toggleLikeWithSoundEnabled:self.soundEnabled + analyticsParameters:[self analyticsParameters] + fromViewController:[FBSDKInternalUtility viewControllerforView:self]]; +} + +- (void)_like:(id)sender +{ + [_likeActionController toggleLikeWithSoundEnabled:_soundEnabled + analyticsParameters:[self analyticsParameters] + fromViewController:[FBSDKInternalUtility viewControllerforView:self]]; +} + +- (void)_likeActionControllerDidDisableNotification:(NSNotification *)notification +{ + [self checkImplicitlyDisabled]; +} + +- (void)_likeActionControllerDidResetNotification:(NSNotification *)notification +{ + [self _resetLikeActionController]; + [self _ensureLikeActionController:YES]; +} + +- (void)_likeActionControllerDidUpdateNotification:(NSNotification *)notification +{ + [self _ensureLikeActionController:YES]; + FBSDKLikeActionController *likeActionController = (FBSDKLikeActionController *)notification.object; + NSString *objectID = likeActionController.objectID; + if ([self.objectID isEqualToString:objectID]) { + BOOL animated = [notification.userInfo[FBSDKLikeActionControllerAnimatedKey] boolValue]; + [self _setSelected:likeActionController.objectIsLiked animated:animated]; + } +} + +- (void)_resetLikeActionController +{ + self.likeActionController = nil; + [self setNeedsLayout]; +} + +- (void)_setLikeActionController:(FBSDKLikeActionController *)likeActionController +{ + if (_likeActionController != likeActionController) { + [_likeActionController endContentAccess]; + _likeActionController = likeActionController; + [_likeActionController beginContentAccess]; + } +} + +- (void)_setSelected:(BOOL)selected animated:(BOOL)animated +{ + if (self.selected != selected) { + if (animated) { + CFTimeInterval duration = FBSDK_LIKE_BUTTON_ANIMATION_DURATION; + UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState; + UIImageView *imageView = self.imageView; + imageView.frame = [self imageRectForContentRect:UIEdgeInsetsInsetRect(self.bounds, self.contentEdgeInsets)]; + [UIView animateWithDuration:duration delay:0.0 options:options animations:^{ + CGPoint iconImageViewCenter = imageView.center; + imageView.frame = CGRectMake(iconImageViewCenter.x, iconImageViewCenter.y, 0.0, 0.0); + } completion:^(BOOL animateOutFinished) { + self.selected = selected; + CGPoint iconImageViewCenter = imageView.center; + imageView.frame = CGRectMake(iconImageViewCenter.x, iconImageViewCenter.y, 0.0, 0.0); + + void(^animations)(void) = ^{ + imageView.frame = [self imageRectForContentRect:UIEdgeInsetsInsetRect(self.bounds, self.contentEdgeInsets)]; + }; + if ([UIView respondsToSelector:@selector(animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)]) { + [UIView animateWithDuration:(duration * 2) + delay:0.0 + usingSpringWithDamping:FBSDK_LIKE_BUTTON_ANIMATION_SPRING_DAMPING + initialSpringVelocity:FBSDK_LIKE_BUTTON_ANIMATION_SPRING_VELOCITY + options:options + animations:animations + completion:NULL]; + } else { + [UIView animateWithDuration:(duration * 2) + delay:0.0 + options:options + animations:animations + completion:NULL]; + } + }]; + } else { + self.selected = selected; + } + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h new file mode 100644 index 0000000..bbc88f2 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h @@ -0,0 +1,139 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeControlAuxiliaryPosition) + + @abstract Specifies the position of the auxiliary view relative to the like button. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlAuxiliaryPosition) +{ + /*! The auxiliary view is inline with the like button. */ + FBSDKLikeControlAuxiliaryPositionInline, + /*! The auxiliary view is above the like button. */ + FBSDKLikeControlAuxiliaryPositionTop, + /*! The auxiliary view is below the like button. */ + FBSDKLikeControlAuxiliaryPositionBottom, +}; + +/*! + @abstract Converts an FBSDKLikeControlAuxiliaryPosition to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlAuxiliaryPosition(FBSDKLikeControlAuxiliaryPosition auxiliaryPosition); + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKLikeControlHorizontalAlignment) + + @abstract Specifies the horizontal alignment for FBSDKLikeControlStyleStandard with + FBSDKLikeControlAuxiliaryPositionTop or FBSDKLikeControlAuxiliaryPositionBottom. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlHorizontalAlignment) +{ + /*! The subviews are left aligned. */ + FBSDKLikeControlHorizontalAlignmentLeft, + /*! The subviews are center aligned. */ + FBSDKLikeControlHorizontalAlignmentCenter, + /*! The subviews are right aligned. */ + FBSDKLikeControlHorizontalAlignmentRight, +}; + +/*! + @abstract Converts an FBSDKLikeControlHorizontalAlignment to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlHorizontalAlignment(FBSDKLikeControlHorizontalAlignment horizontalAlignment); + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeControlStyle) + + @abstract Specifies the style of a like control. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlStyle) +{ + /*! Displays the button and the social sentence. */ + FBSDKLikeControlStyleStandard = 0, + /*! Displays the button and a box that contains the like count. */ + FBSDKLikeControlStyleBoxCount, +}; + +/*! + @abstract Converts an FBSDKLikeControlStyle to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlStyle(FBSDKLikeControlStyle style); + +/*! + @class FBSDKLikeControl + + @abstract UI control to like an object in the Facebook graph. + + @discussion Taps on the like button within this control will invoke an API call to the Facebook app through a + fast-app-switch that allows the user to like the object. Upon return to the calling app, the view will update + with the new state and send actions for the UIControlEventValueChanged event. + */ +@interface FBSDKLikeControl : UIControl + +/*! + @abstract The foreground color to use for the content of the receiver. + */ +@property (nonatomic, strong) UIColor *foregroundColor; + +/*! + @abstract The position for the auxiliary view for the receiver. + + @see FBSDKLikeControlAuxiliaryPosition + */ +@property (nonatomic, assign) FBSDKLikeControlAuxiliaryPosition likeControlAuxiliaryPosition; + +/*! + @abstract The text alignment of the social sentence. + + @discussion This value is only valid for FBSDKLikeControlStyleStandard with + FBSDKLikeControlAuxiliaryPositionTop|Bottom. + */ +@property (nonatomic, assign) FBSDKLikeControlHorizontalAlignment likeControlHorizontalAlignment; + +/*! + @abstract The style to use for the receiver. + + @see FBSDKLikeControlStyle + */ +@property (nonatomic, assign) FBSDKLikeControlStyle likeControlStyle; + +/*! + @abstract The preferred maximum width (in points) for autolayout. + + @discussion This property affects the size of the receiver when layout constraints are applied to it. During layout, + if the text extends beyond the width specified by this property, the additional text is flowed to one or more new + lines, thereby increasing the height of the receiver. + */ +@property (nonatomic, assign) CGFloat preferredMaxLayoutWidth; + +/*! + @abstract If YES, a sound is played when the receiver is toggled. + + @default YES + */ +@property (nonatomic, assign, getter = isSoundEnabled) BOOL soundEnabled; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.m new file mode 100644 index 0000000..6a8167a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.m @@ -0,0 +1,664 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeControl.h" +#import "FBSDKLikeControl+Internal.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLikeActionController.h" +#import "FBSDKLikeBoxView.h" +#import "FBSDKLikeButton+Internal.h" +#import "FBSDKLikeButton.h" + +#define kFBLikeControlAnimationDuration 0.2 +#define kFBLikeControlSocialSentenceAnimationOffset 10.0 + +static void *FBSDKLikeControlKVOLikeActionControllerContext = &FBSDKLikeControlKVOLikeActionControllerContext; + +NSString *NSStringFromFBSDKLikeControlAuxiliaryPosition(FBSDKLikeControlAuxiliaryPosition auxiliaryPosition) +{ + switch (auxiliaryPosition) { + case FBSDKLikeControlAuxiliaryPositionBottom: + return @"bottom"; + case FBSDKLikeControlAuxiliaryPositionInline: + return @"inline"; + case FBSDKLikeControlAuxiliaryPositionTop: + return @"top"; + } + return nil; +} + +NSString *NSStringFromFBSDKLikeControlHorizontalAlignment(FBSDKLikeControlHorizontalAlignment horizontalAlignment) +{ + switch (horizontalAlignment) { + case FBSDKLikeControlHorizontalAlignmentCenter: + return @"center"; + case FBSDKLikeControlHorizontalAlignmentLeft: + return @"left"; + case FBSDKLikeControlHorizontalAlignmentRight: + return @"right"; + } + return nil; +} + +NSString *NSStringFromFBSDKLikeControlStyle(FBSDKLikeControlStyle style) +{ + switch (style) { + case FBSDKLikeControlStyleBoxCount: + return @"box_count"; + case FBSDKLikeControlStyleStandard: + return @"standard"; + } + return nil; +} + +typedef struct FBSDKLikeControlLayout +{ + CGSize contentSize; + CGRect likeButtonFrame; + CGRect auxiliaryViewFrame; +} FBSDKLikeControlLayout; + +typedef CGSize (^fbsdk_like_control_sizing_block_t)(UIView *subview, CGSize constrainedSize); + +@implementation FBSDKLikeControl +{ + BOOL _isExplicitlyDisabled; + FBSDKLikeBoxView *_likeBoxView; + FBSDKLikeButton *_likeButton; + UIView *_likeButtonContainer; + UILabel *_socialSentenceLabel; +} + +#pragma mark - Class Methods + ++ (void)initialize +{ + if ([FBSDKLikeControl class] == self) { + // ensure that we have updated the dialog configs if we haven't already + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + [self _initializeContent]; + if (CGRectEqualToRect(frame, CGRectZero)) { + [self sizeToFit]; + } + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) { + [self _initializeContent]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [_likeButton removeObserver:self forKeyPath:@"likeActionController"]; +} + +#pragma mark - Properties + +- (void)setBackgroundColor:(UIColor *)backgroundColor +{ + [super setBackgroundColor:backgroundColor]; + _likeButtonContainer.backgroundColor = backgroundColor; +} + +- (void)setForegroundColor:(UIColor *)foregroundColor +{ + if (![_foregroundColor isEqual:foregroundColor]) { + _foregroundColor = foregroundColor; + [_likeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + _socialSentenceLabel.textColor = foregroundColor; + } +} + +- (void)setEnabled:(BOOL)enabled +{ + _isExplicitlyDisabled = !enabled; + [self _updateEnabled]; +} + +- (void)setLikeControlAuxiliaryPosition:(FBSDKLikeControlAuxiliaryPosition)likeControlAuxiliaryPosition +{ + if (_likeControlAuxiliaryPosition != likeControlAuxiliaryPosition) { + _likeControlAuxiliaryPosition = likeControlAuxiliaryPosition; + [self _updateLikeBoxCaretPosition]; + [self setNeedsLayout]; + [self setNeedsUpdateConstraints]; + [self invalidateIntrinsicContentSize]; + } +} + +- (void)setLikeControlHorizontalAlignment:(FBSDKLikeControlHorizontalAlignment)likeControlHorizontalAlignment +{ + if (_likeControlHorizontalAlignment != likeControlHorizontalAlignment) { + _likeControlHorizontalAlignment = likeControlHorizontalAlignment; + [self _updateLikeBoxCaretPosition]; + [self setNeedsLayout]; + [self setNeedsUpdateConstraints]; + [self invalidateIntrinsicContentSize]; + } +} + +- (void)setLikeControlStyle:(FBSDKLikeControlStyle)likeControlStyle +{ + if (_likeControlStyle != likeControlStyle) { + _likeControlStyle = likeControlStyle; + [self _updateLikeBoxCaretPosition]; + [self setNeedsLayout]; + [self setNeedsUpdateConstraints]; + [self invalidateIntrinsicContentSize]; + } +} + +- (NSString *)objectID +{ + return _likeButton.objectID; +} + +- (void)setObjectID:(NSString *)objectID +{ + if (![_likeButton.objectID isEqualToString:objectID]) { + _likeButton.objectID = objectID; + [self _updateEnabled]; + [self setNeedsLayout]; + } +} + +- (FBSDKLikeObjectType)objectType +{ + return _likeButton.objectType; +} + +- (void)setObjectType:(FBSDKLikeObjectType)objectType +{ + if (_likeButton.objectType != objectType) { + _likeButton.objectType = objectType; + [self setNeedsLayout]; + } +} + +- (void)setOpaque:(BOOL)opaque +{ + [super setOpaque:opaque]; + _likeButtonContainer.opaque = opaque; +} + +- (BOOL)isSoundEnabled +{ + return _likeButton.soundEnabled; +} + +- (void)setSoundEnabled:(BOOL)soundEnabled +{ + _likeButton.soundEnabled = soundEnabled; +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize +{ + CGFloat width = self.preferredMaxLayoutWidth; + if (width == 0) { + width = CGFLOAT_MAX; + } + CGRect bounds = CGRectMake(0.0, 0.0, width, CGFLOAT_MAX); + return [self _layoutWithBounds:bounds subviewSizingBlock:^CGSize(UIView *subview, CGSize constrainedSize) { + if ([subview respondsToSelector:@selector(setPreferredMaxLayoutWidth:)]) { + [(id)subview setPreferredMaxLayoutWidth:constrainedSize.width]; + } + return subview.intrinsicContentSize; + }].contentSize; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + NSString *objectID = self.objectID; + if (objectID) { + FBSDKViewImpressionTracker *impressionTracker = + [FBSDKViewImpressionTracker impressionTrackerWithEventName:FBSDKAppEventNameFBSDKLikeControlImpression]; + [impressionTracker logImpressionWithIdentifier:objectID parameters:[self analyticsParameters]]; + } + + [self _ensureLikeActionController]; + + CGRect bounds = self.bounds; + CGSize(^sizingBlock)(UIView *, CGSize) = ^CGSize(UIView *subview, CGSize constrainedSize) { + return [subview sizeThatFits:constrainedSize]; + }; + FBSDKLikeControlLayout layout = [self _layoutWithBounds:bounds subviewSizingBlock:sizingBlock]; + + UIView *auxiliaryView = [self _auxiliaryView]; + _likeBoxView.hidden = (_likeBoxView != auxiliaryView); + _socialSentenceLabel.hidden = (_socialSentenceLabel != auxiliaryView); + + _likeButtonContainer.frame = layout.likeButtonFrame; + _likeButton.frame = _likeButtonContainer.bounds; + auxiliaryView.frame = layout.auxiliaryViewFrame; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + switch (self.likeControlAuxiliaryPosition) { + case FBSDKLikeControlAuxiliaryPositionInline:{ + size.height = MAX(size.height, CGRectGetHeight(self.bounds)); + break; + } + case FBSDKLikeControlAuxiliaryPositionTop: + case FBSDKLikeControlAuxiliaryPositionBottom:{ + size.width = MAX(size.width, CGRectGetWidth(self.bounds)); + break; + } + } + + CGRect bounds = CGRectMake(0.0, 0.0, size.width, size.height); + return [self _layoutWithBounds:bounds subviewSizingBlock:^CGSize(UIView *subview, CGSize constrainedSize) { + return [subview sizeThatFits:constrainedSize]; + }].contentSize; +} + +#pragma mark - Internal Methods + +- (NSDictionary *)analyticsParameters +{ + return @{ + @"auxiliary_position": NSStringFromFBSDKLikeControlAuxiliaryPosition(self.likeControlAuxiliaryPosition), + @"horizontal_alignment": NSStringFromFBSDKLikeControlHorizontalAlignment(self.likeControlHorizontalAlignment), + @"object_id": (self.objectID ?: [NSNull null]), + @"object_type": (NSStringFromFBSDKLikeObjectType(self.objectType) ?: [NSNull null]), + @"sound_enabled": @(self.soundEnabled), + @"style": NSStringFromFBSDKLikeControlStyle(self.likeControlStyle), + }; +} + +#pragma mark - Helper Methods + +- (UIView *)_auxiliaryView +{ + [self _ensureLikeActionController]; + switch (_likeControlStyle) { + case FBSDKLikeControlStyleStandard:{ + return (_socialSentenceLabel.text.length == 0 ? nil : _socialSentenceLabel); + } + case FBSDKLikeControlStyleBoxCount:{ + return (_likeButton.likeActionController.likeCountString == nil ? nil : _likeBoxView); + } + } + return nil; +} + +- (CGFloat)_auxiliaryViewPadding +{ + switch (_likeControlStyle) { + case FBSDKLikeControlStyleStandard:{ + return 8.0; + } + case FBSDKLikeControlStyleBoxCount:{ + return 0.0; + } + } + return 0.0; +} + +- (void)_ensureLikeActionController +{ + FBSDKLikeActionController *likeActionController = _likeButton.likeActionController; + if (likeActionController) { + _socialSentenceLabel.text = likeActionController.socialSentence; + _likeBoxView.text = likeActionController.likeCountString; + } +} + +- (void)_handleLikeButtonTap:(FBSDKLikeButton *)likeButton +{ + [self _ensureLikeActionController]; + [self sendActionsForControlEvents:UIControlEventTouchUpInside]; +} + +- (void)_initializeContent +{ + self.backgroundColor = [UIColor clearColor]; + _foregroundColor = [UIColor blackColor]; + + _likeButtonContainer = [[UIView alloc] initWithFrame:CGRectZero]; + _likeButtonContainer.backgroundColor = self.backgroundColor; + _likeButtonContainer.opaque = self.opaque; + [self addSubview:_likeButtonContainer]; + + _likeButton = [[FBSDKLikeButton alloc] initWithFrame:CGRectZero]; + [_likeButton addTarget:self action:@selector(_handleLikeButtonTap:) forControlEvents:UIControlEventTouchUpInside]; + [_likeButtonContainer addSubview:_likeButton]; + + _socialSentenceLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _socialSentenceLabel.font = [UIFont systemFontOfSize:11.0]; + _socialSentenceLabel.numberOfLines = 2; + [self addSubview:_socialSentenceLabel]; + + _likeBoxView = [[FBSDKLikeBoxView alloc] initWithFrame:CGRectZero]; + [self addSubview:_likeBoxView]; + + // use KVO to monitor changes to the likeActionController instance on FBSDKButton in order to avoid race conditions + // between notification observers + [_likeButton addObserver:self + forKeyPath:@"likeActionController" + options:NSKeyValueObservingOptionInitial + context:FBSDKLikeControlKVOLikeActionControllerContext]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(_likeActionControllerDidDisableNotification:) + name:FBSDKLikeActionControllerDidDisableNotification + object:nil]; + [nc addObserver:self + selector:@selector(_likeActionControllerDidUpdateNotification:) + name:FBSDKLikeActionControllerDidUpdateNotification + object:nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + if (context == FBSDKLikeControlKVOLikeActionControllerContext) { + [self _likeActionControllerDidUpdateWithAnimated:NO]; + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +static void FBSDKLikeControlApplyHorizontalAlignment(CGRect *frameRef, + CGRect bounds, + FBSDKLikeControlHorizontalAlignment alignment) +{ + if (frameRef == NULL) { + return; + } + + CGRect frame = *frameRef; + switch (alignment) { + case FBSDKLikeControlHorizontalAlignmentLeft:{ + frame.origin.x = CGRectGetMinX(bounds); + break; + } + case FBSDKLikeControlHorizontalAlignmentCenter:{ + frame.origin.x = CGRectGetMinX(bounds) + floorf((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2); + break; + } + case FBSDKLikeControlHorizontalAlignmentRight:{ + frame.origin.x = CGRectGetMinX(bounds) + CGRectGetWidth(bounds) - CGRectGetWidth(frame); + break; + } + } + *frameRef = frame; +} + +static CGFloat FBSDKLikeControlPaddedDistance(CGFloat distance, CGFloat padding, BOOL includeDistance) +{ + return (distance == 0.0 ? 0.0 : (includeDistance ? distance : 0.0) + padding); +} + +static CGSize FBSDKLikeControlCalculateContentSize(FBSDKLikeControlLayout layout) +{ + return CGSizeMake(MAX(CGRectGetMaxX(layout.likeButtonFrame), CGRectGetMaxX(layout.auxiliaryViewFrame)), + MAX(CGRectGetMaxY(layout.likeButtonFrame), CGRectGetMaxY(layout.auxiliaryViewFrame))); + +} + +- (FBSDKLikeControlLayout)_layoutWithBounds:(CGRect)bounds + subviewSizingBlock:(fbsdk_like_control_sizing_block_t)subviewSizingBlock +{ + FBSDKLikeControlLayout layout; + + CGSize likeButtonSize = subviewSizingBlock(_likeButton, bounds.size); + layout.likeButtonFrame = CGRectMake(CGRectGetMinX(bounds), + CGRectGetMinY(bounds), + likeButtonSize.width, + likeButtonSize.height); + layout.auxiliaryViewFrame = CGRectZero; + + UIView *auxiliaryView = [self _auxiliaryView]; + CGFloat auxiliaryViewPadding = [self _auxiliaryViewPadding]; + CGSize auxiliaryViewSize = CGSizeZero; + switch (self.likeControlAuxiliaryPosition) { + case FBSDKLikeControlAuxiliaryPositionInline:{ + if (auxiliaryView) { + auxiliaryViewSize = CGSizeMake((CGRectGetWidth(bounds) - + auxiliaryViewPadding - + CGRectGetWidth(layout.likeButtonFrame)), + CGRectGetHeight(bounds)); + auxiliaryViewSize = subviewSizingBlock(auxiliaryView, auxiliaryViewSize); + + layout.auxiliaryViewFrame = CGRectMake(CGRectGetMinX(bounds), + CGRectGetMinY(bounds), + auxiliaryViewSize.width, + MAX(auxiliaryViewSize.height, + CGRectGetHeight(layout.likeButtonFrame))); + } + + // align the views next to each other for sizing + FBSDKLikeControlApplyHorizontalAlignment(&layout.likeButtonFrame, + bounds, + FBSDKLikeControlHorizontalAlignmentLeft); + if (auxiliaryView) { + layout.auxiliaryViewFrame.origin.x = CGRectGetMaxX(layout.likeButtonFrame) + auxiliaryViewPadding; + } + + // calculate the size before offsetting the horizontal alignment, using the total calculated width + layout.contentSize = FBSDKLikeControlCalculateContentSize(layout); + + // layout the subviews next to each other + switch (self.likeControlHorizontalAlignment) { + case FBSDKLikeControlHorizontalAlignmentLeft:{ + // already done + break; + } + case FBSDKLikeControlHorizontalAlignmentCenter:{ + layout.likeButtonFrame.origin.x = floorf((CGRectGetWidth(bounds) - layout.contentSize.width) / 2); + if (auxiliaryView) { + layout.auxiliaryViewFrame.origin.x = (CGRectGetMaxX(layout.likeButtonFrame) + + auxiliaryViewPadding); + } + break; + } + case FBSDKLikeControlHorizontalAlignmentRight:{ + layout.likeButtonFrame.origin.x = CGRectGetMaxX(bounds) - CGRectGetWidth(layout.likeButtonFrame); + if (auxiliaryView) { + layout.auxiliaryViewFrame.origin.x = (CGRectGetMinX(layout.likeButtonFrame) - + auxiliaryViewPadding - + CGRectGetWidth(layout.auxiliaryViewFrame)); + } + break; + } + } + + break; + } + case FBSDKLikeControlAuxiliaryPositionTop:{ + if (auxiliaryView) { + auxiliaryViewSize = CGSizeMake(CGRectGetWidth(bounds), + (CGRectGetHeight(bounds) - + auxiliaryViewPadding - + CGRectGetHeight(layout.likeButtonFrame))); + auxiliaryViewSize = subviewSizingBlock(auxiliaryView, auxiliaryViewSize); + + layout.auxiliaryViewFrame = CGRectMake(CGRectGetMinX(bounds), + CGRectGetMinY(bounds), + MAX(auxiliaryViewSize.width, + CGRectGetWidth(layout.likeButtonFrame)), + auxiliaryViewSize.height); + } + layout.likeButtonFrame.origin.y = FBSDKLikeControlPaddedDistance(CGRectGetMaxY(layout.auxiliaryViewFrame), + auxiliaryViewPadding, + YES); + + // calculate the size before offsetting the horizontal alignment, using the total calculated width + layout.contentSize = FBSDKLikeControlCalculateContentSize(layout); + + FBSDKLikeControlApplyHorizontalAlignment(&layout.likeButtonFrame, bounds, self.likeControlHorizontalAlignment); + FBSDKLikeControlApplyHorizontalAlignment(&layout.auxiliaryViewFrame, + bounds, + self.likeControlHorizontalAlignment); + break; + } + case FBSDKLikeControlAuxiliaryPositionBottom:{ + if (auxiliaryView) { + auxiliaryViewSize = CGSizeMake(CGRectGetWidth(bounds), + (CGRectGetHeight(bounds) - + auxiliaryViewPadding - + CGRectGetHeight(layout.likeButtonFrame))); + auxiliaryViewSize = subviewSizingBlock(auxiliaryView, auxiliaryViewSize); + + layout.auxiliaryViewFrame = CGRectMake(CGRectGetMinX(bounds), + CGRectGetMaxY(layout.likeButtonFrame) + auxiliaryViewPadding, + MAX(auxiliaryViewSize.width, + CGRectGetWidth(layout.likeButtonFrame)), + auxiliaryViewSize.height); + } + + // calculate the size before offsetting the horizontal alignment, using the total calculated width + layout.contentSize = FBSDKLikeControlCalculateContentSize(layout); + + FBSDKLikeControlApplyHorizontalAlignment(&layout.likeButtonFrame, bounds, self.likeControlHorizontalAlignment); + FBSDKLikeControlApplyHorizontalAlignment(&layout.auxiliaryViewFrame, + bounds, + self.likeControlHorizontalAlignment); + break; + } + } + + return layout; +} + +- (void)_likeActionControllerDidDisableNotification:(NSNotification *)notification +{ + [self _updateEnabled]; +} + +- (void)_likeActionControllerDidUpdateNotification:(NSNotification *)notification +{ + [self _ensureLikeActionController]; + FBSDKLikeActionController *likeActionController = (FBSDKLikeActionController *)notification.object; + NSString *objectID = likeActionController.objectID; + if ([self.objectID isEqualToString:objectID]) { + BOOL animated = [notification.userInfo[FBSDKLikeActionControllerAnimatedKey] boolValue]; + [self _likeActionControllerDidUpdateWithAnimated:animated]; + } +} + +- (void)_likeActionControllerDidUpdateWithAnimated:(BOOL)animated +{ + FBSDKLikeActionController *likeActionController = _likeButton.likeActionController; + NSString *objectID = likeActionController.objectID; + if ([self.objectID isEqualToString:objectID]) { + _likeBoxView.text = _likeButton.likeActionController.likeCountString; + + if (animated) { + void(^hideView)(UIView *) = ^(UIView *view){ + view.alpha = 0.0; + CGRect frame = view.frame; + frame.origin.y += kFBLikeControlSocialSentenceAnimationOffset; + view.frame = frame; + }; + [UIView animateWithDuration:kFBLikeControlAnimationDuration animations:^{ + hideView(_socialSentenceLabel); + } completion:^(BOOL finished) { + _socialSentenceLabel.text = likeActionController.socialSentence; + [self setNeedsLayout]; + [self setNeedsUpdateConstraints]; + [self invalidateIntrinsicContentSize]; + [self layoutIfNeeded]; + hideView(_socialSentenceLabel); + + [UIView animateWithDuration:kFBLikeControlAnimationDuration animations:^{ + _socialSentenceLabel.alpha = 1.0; + [self setNeedsLayout]; + [self layoutIfNeeded]; + }]; + }]; + } else { + _socialSentenceLabel.text = likeActionController.socialSentence; + [self setNeedsLayout]; + [self setNeedsUpdateConstraints]; + [self invalidateIntrinsicContentSize]; + } + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + } +} + +- (void)_updateEnabled +{ + BOOL enabled = (!_isExplicitlyDisabled && + self.objectID && + ![FBSDKLikeActionController isDisabled]); + BOOL currentEnabled = [self isEnabled]; + [super setEnabled:enabled]; + if (currentEnabled != enabled) { + [self invalidateIntrinsicContentSize]; + [self setNeedsLayout]; + } +} + +- (void)_updateLikeBoxCaretPosition +{ + if (self.likeControlStyle != FBSDKLikeControlStyleBoxCount) { + return; + } + + switch (self.likeControlAuxiliaryPosition) { + case FBSDKLikeControlAuxiliaryPositionInline:{ + switch (self.likeControlHorizontalAlignment) { + case FBSDKLikeControlHorizontalAlignmentLeft: + case FBSDKLikeControlHorizontalAlignmentCenter:{ + _likeBoxView.caretPosition = FBSDKLikeBoxCaretPositionLeft; + break; + } + case FBSDKLikeControlHorizontalAlignmentRight:{ + _likeBoxView.caretPosition = FBSDKLikeBoxCaretPositionRight; + break; + } + } + break; + } + case FBSDKLikeControlAuxiliaryPositionTop:{ + _likeBoxView.caretPosition = FBSDKLikeBoxCaretPositionBottom; + break; + } + case FBSDKLikeControlAuxiliaryPositionBottom:{ + _likeBoxView.caretPosition = FBSDKLikeBoxCaretPositionTop; + break; + } + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h new file mode 100644 index 0000000..dadff43 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeObjectType) + @abstract Specifies the type of object referenced by the objectID for likes. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeObjectType) +{ + /*! The objectID refers to an unknown object type. */ + FBSDKLikeObjectTypeUnknown = 0, + /*! The objectID refers to an Open Graph object. */ + FBSDKLikeObjectTypeOpenGraph, + /*! The objectID refers to an Page object. */ + FBSDKLikeObjectTypePage, +}; + +/*! + @abstract Converts an FBLikeControlObjectType to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeObjectType(FBSDKLikeObjectType objectType); diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.m new file mode 100644 index 0000000..273fab1 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.m @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeObjectType.h" + +NSString *NSStringFromFBSDKLikeObjectType(FBSDKLikeObjectType objectType) +{ + switch (objectType) { + case FBSDKLikeObjectTypeUnknown: + return @"unknown"; + case FBSDKLikeObjectTypeOpenGraph: + return @"open_graph"; + case FBSDKLikeObjectTypePage: + return @"page"; + } + return nil; +} diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h new file mode 100644 index 0000000..e2d4a4a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h @@ -0,0 +1,45 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract The common interface for components that initiate liking. + @see FBSDKLikeButton + @see FBSDKLikeControl + */ +@protocol FBSDKLiking + +/*! + @abstract The objectID for the object to like. + + @discussion This value may be an Open Graph object ID or a string representation of an URL that describes an + Open Graph object. The objects may be public objects, like pages, or objects that are defined by your application. + */ +@property (nonatomic, copy) NSString *objectID; + +/*! + @abstract The type of object referenced by the objectID. + + @discussion If the objectType is unknown, the control will determine the objectType by querying the server with the + objectID. Specifying a value for the objectType is an optimization that should be used if the type is known by the + consumer. Consider setting the objectType if it is known when setting the objectID. + */ +@property (nonatomic, assign) FBSDKLikeObjectType objectType; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h new file mode 100644 index 0000000..2819eb7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A dialog for sharing content through Messenger. + */ +@interface FBSDKMessageDialog : NSObject + +/*! + @abstract Convenience method to show a Message Share Dialog with content and a delegate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(id)content delegate:(id)delegate; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.m new file mode 100644 index 0000000..070fd99 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.m @@ -0,0 +1,221 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMessageDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" +#import "FBSDKShareOpenGraphContent.h" +#import "FBSDKShareUtility.h" +#import "FBSDKShareVideoContent.h" + +#define FBSDK_MESSAGE_DIALOG_APP_SCHEME @"fb-messenger-api" +#define FBSDK_MESSAGE_METHOD_MIN_VERSION @"20140430" + +@implementation FBSDKMessageDialog + +#pragma mark - Class Methods + ++ (void)initialize +{ + if ([FBSDKMessageDialog class] == self) { + [FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_MESSENGER]; + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + ++ (instancetype)showWithContent:(id)content delegate:(id)delegate +{ + FBSDKMessageDialog *dialog = [[self alloc] init]; + dialog.shareContent = content; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Properties + +@synthesize delegate = _delegate; +@synthesize shareContent = _shareContent; +@synthesize shouldFailOnDataError = _shouldFailOnDataError; + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + return [self _canShowNative]; +} + +- (BOOL)show +{ + NSError *error; + if (![self canShow]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Message dialog is not available."]; + [self _invokeDelegateDidFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [self _invokeDelegateDidFailWithError:error]; + return NO; + } + + id shareContent = self.shareContent; + NSDictionary *parameters = [FBSDKShareUtility parametersForShareContent:shareContent + shouldFailOnDataError:self.shouldFailOnDataError]; + NSString *methodName = ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]] ? + FBSDK_SHARE_OPEN_GRAPH_METHOD_NAME : + FBSDK_SHARE_METHOD_NAME); + FBSDKBridgeAPIRequest *request; + request = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeNative + scheme:FBSDK_MESSAGE_DIALOG_APP_SCHEME + methodName:methodName + methodVersion:FBSDK_MESSAGE_METHOD_MIN_VERSION + parameters:parameters + userInfo:nil]; + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useSafariViewController = [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameMessage]; + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + [self _handleCompletionWithDialogResults:response.responseParameters response:response]; + [FBSDKInternalUtility unregisterTransientObject:self]; + }; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:request + useSafariViewController:useSafariViewController + fromViewController:nil + completionBlock:completionBlock]; + + [self _logDialogShow]; + [FBSDKInternalUtility registerTransientObject:self]; + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + id shareContent = self.shareContent; + if (!shareContent) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"shareContent" message:nil]; + } + return NO; + } + return [FBSDKShareUtility validateShareContent:self.shareContent error:errorRef]; +} + +#pragma mark - Helper Methods + +- (BOOL)_canShowNative +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useNativeDialog = [configuration useNativeDialogForDialogName:FBSDKDialogConfigurationNameMessage]; + return (useNativeDialog && [FBSDKInternalUtility isMessengerAppInstalled]); +} + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results response:(FBSDKBridgeAPIResponse *)response +{ + NSString *completionGesture = results[FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + if ([completionGesture isEqualToString:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_CANCEL] || + response.isCancelled) { + [self _invokeDelegateDidCancel]; + } else if (response.error) { + [self _invokeDelegateDidFailWithError:response.error]; + } else { + [self _invokeDelegateDidCompleteWithResults:results]; + } +} + +- (void)_invokeDelegateDidCancel +{ + NSDictionary * parameters =@{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Cancelled, + }; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventMessengerShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + if (!_delegate) { + return; + } + + [_delegate sharerDidCancel:self]; +} + +- (void)_invokeDelegateDidCompleteWithResults:(NSDictionary *)results +{ + NSDictionary * parameters =@{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Completed, + }; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventMessengerShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + if (!_delegate) { + return; + } + + [_delegate sharer:self didCompleteWithResults:[results copy]]; +} + +- (void)_invokeDelegateDidFailWithError:(NSError *)error +{ + NSMutableDictionary * parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:FBSDKAppEventsDialogOutcomeValue_Failed, FBSDKAppEventParameterDialogOutcome, nil]; + if (error) { + parameters[FBSDKAppEventParameterDialogErrorMessage] = [NSString stringWithFormat:@"%@", error]; + } + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventMessengerShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + if (!_delegate) { + return; + } + + [_delegate sharer:self didFailWithError:error]; +} + +- (void)_logDialogShow +{ + NSString *contentType; + if([self.shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeOpenGraph; + } else if ([self.shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeStatus; + } else if ([self.shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypePhoto; + } else if ([self.shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeVideo; + } else { + contentType = FBSDKAppEventsDialogShareContentTypeUnknown; + } + + NSDictionary *parameters = @{FBSDKAppEventParameterDialogShareContentType : contentType}; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventMessengerShareDialogShow + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h new file mode 100644 index 0000000..347f0e4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract A button to send content through Messenger. + @discussion Tapping the receiver will invoke the FBSDKShareDialog with the attached shareContent. If the dialog cannot + be shown, the button will be disable. + */ +@interface FBSDKSendButton : FBSDKButton + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.m new file mode 100644 index 0000000..cc0ee18 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.m @@ -0,0 +1,97 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKSendButton.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKMessageDialog.h" +#import "FBSDKMessengerIcon.h" + +@interface FBSDKSendButton () +@end + +@implementation FBSDKSendButton +{ + FBSDKMessageDialog *_dialog; +} + +#pragma mark - Properties + +- (id)shareContent +{ + return _dialog.shareContent; +} + +- (void)setShareContent:(id)shareContent +{ + _dialog.shareContent = shareContent; + [self checkImplicitlyDisabled]; +} + +#pragma mark - FBSDKButtonImpressionTracking + +- (NSDictionary *)analyticsParameters +{ + return nil; +} + +- (NSString *)impressionTrackingEventName +{ + return FBSDKAppEventNameFBSDKSendButtonImpression; +} + +- (NSString *)impressionTrackingIdentifier +{ + return @"send"; +} + +#pragma mark - FBSDKButton + +- (void)configureButton +{ + NSString *title = + NSLocalizedStringWithDefaultValue(@"SendButton.Send", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Send", + @"The label for FBSDKSendButton"); + + UIColor *backgroundColor = [UIColor colorWithRed:0.0 green:132.0/255.0 blue:1.0 alpha:1.0]; + UIColor *highlightedColor = [UIColor colorWithRed:0.0 green:111.0/255.0 blue:1.0 alpha:1.0]; + + [self configureWithIcon:[[FBSDKMessengerIcon alloc] init] + title:title + backgroundColor:backgroundColor + highlightedColor:highlightedColor]; + + [self addTarget:self action:@selector(_share:) forControlEvents:UIControlEventTouchUpInside]; + _dialog = [[FBSDKMessageDialog alloc] init]; +} + +- (BOOL)isImplicitlyDisabled +{ + return ![_dialog canShow] || ![_dialog validateWithError:NULL]; +} + +#pragma mark - Helper Methods + +- (void)_share:(id)sender +{ + [self logTapEventWithEventName:FBSDKAppEventNameFBSDKSendButtonDidTap parameters:[self analyticsParameters]]; + [_dialog show]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h new file mode 100644 index 0000000..ddbeafe --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h @@ -0,0 +1,79 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @abstract A utility class for sharing through the graph API. Using this class requires an access token in + [FBSDKAccessToken currentAccessToken] that has been granted the "publish_actions" permission. + @discussion FBSDKShareAPI network requests are scheduled on the current run loop in the default run loop mode + (like NSURLConnection). If you want to use FBSDKShareAPI in a background thread, you must manage the run loop + yourself. + */ +@interface FBSDKShareAPI : NSObject + +/*! + @abstract Convenience method to build up a share API with content and a delegate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)shareWithContent:(id)content delegate:(id)delegate; + +/*! + @abstract The message the person has provided through the custom dialog that will accompany the share content. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract The graph node to which content should be shared. + */ +@property (nonatomic, copy) NSString *graphNode; + +/*! + @abstract A Boolean value that indicates whether the receiver can send the share. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see [FBSDKSharing validateWithError:] + @result YES if the receiver can send, otherwise NO. + */ +- (BOOL)canShare; + +/*! + @abstract Creates an User Owned Open Graph object without an action. + @param openGraphObject The open graph object to create. + @discussion Use this method to create an object alone, when an action is not going to be posted with the object. If + the object will be used within an action, just put the object in the action and share that as the shareContent and the + object will be created in the process. The delegate will be messaged with the results. + + Also see https://developers.facebook.com/docs/sharing/opengraph/object-api#objectapi-creatinguser + + @result YES if the receiver was able to send the request to create the object, otherwise NO. + */ +- (BOOL)createOpenGraphObject:(FBSDKShareOpenGraphObject *)openGraphObject; + +/*! + @abstract Begins the send from the receiver. + @result YES if the receiver was able to send the share, otherwise NO. + */ +- (BOOL)share; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.m new file mode 100644 index 0000000..69f124f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.m @@ -0,0 +1,701 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareAPI.h" + +#import + +#import +#import +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" +#import "FBSDKShareLinkContent.h" +#import "FBSDKShareOpenGraphAction.h" +#import "FBSDKShareOpenGraphContent.h" +#import "FBSDKShareOpenGraphObject.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKSharePhotoContent.h" +#import "FBSDKShareUtility.h" +#import "FBSDKShareVideo.h" +#import "FBSDKShareVideoContent.h" + +static NSString *const FBSDKShareAPIDefaultGraphNode = @"me"; +static NSString *const FBSDKShareAPIPhotosEdge = @"photos"; +static NSString *const FBSDKShareAPIVideosEdge = @"videos"; + +@implementation FBSDKShareAPI + +#pragma mark - Class Methods + ++ (instancetype)shareWithContent:(id)content delegate:(id)delegate +{ + FBSDKShareAPI *API = [[self alloc] init]; + API.shareContent = content; + API.delegate = delegate; + [API share]; + return API; +} + +#pragma mark - Properties + +@synthesize delegate = _delegate; +@synthesize shareContent = _shareContent; +@synthesize shouldFailOnDataError = _shouldFailOnDataError; + +#pragma mark - Object Lifecycle +- (instancetype)init +{ + if ((self = [super init])) { + _graphNode = FBSDKShareAPIDefaultGraphNode; + } + return self; +} + +#pragma mark - Public Methods + +- (BOOL)canShare +{ + return YES; +} + +- (BOOL)createOpenGraphObject:(FBSDKShareOpenGraphObject *)openGraphObject +{ + NSError *error; + if (![self canShare]) { + NSString *message = @"Share API is not available; verify 'canShare' returns YES"; + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode message:message]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } + if (![self _hasPublishActions]) { + NSString *message = @"Warning: [FBSDKAccessToken currentAccessToken] is missing publish_actions permissions"; + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:message]; + } + if (!openGraphObject) { + error = [FBSDKShareError requiredArgumentErrorWithName:@"openGraphObject" message:nil]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } + + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + void(^completionHandler)(id) = ^(NSDictionary *result) { + [_delegate sharer:self didCompleteWithResults:result]; + }; + if (![self _stageOpenGraphObject:openGraphObject + connection:connection + stagingHandler:NULL + completionHandler:completionHandler]) { + return NO; + } + [connection start]; + return YES; +} + +- (BOOL)share +{ + NSError *error; + if (![self canShare]) { + NSString *message = @"Share API is not available; verify 'canShare' returns YES"; + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode message:message]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } + if (![self _hasPublishActions]) { + NSString *message = @"Warning: [FBSDKAccessToken currentAccessToken] is missing publish_actions permissions"; + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:message]; + } + if (![self validateWithError:&error]) { + [_delegate sharer:self didFailWithError:error]; + return NO; + } + id shareContent = self.shareContent; + + if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + return [self _shareLinkContent:(FBSDKShareLinkContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + return [self _sharePhotoContent:(FBSDKSharePhotoContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + return [self _shareVideoContent:(FBSDKShareVideoContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + return [self _shareOpenGraphContent:(FBSDKShareOpenGraphContent *)shareContent]; + } else { + return NO; + } +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + id shareContent = self.shareContent; + if (!shareContent) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"shareContent" message:nil]; + } + return NO; + } + return [FBSDKShareUtility validateShareContent:shareContent error:errorRef]; +} + +#pragma mark - Helper Methods + +- (NSString *)_graphPathWithSuffix:(NSString *)suffix, ... NS_REQUIRES_NIL_TERMINATION +{ + NSMutableString *graphPath = [[NSMutableString alloc] initWithString:self.graphNode]; + va_list args; + va_start(args, suffix); + for (NSString *arg = suffix; arg != nil; arg = va_arg(args, NSString *)) { + [graphPath appendFormat:@"/%@", arg]; + } + va_end(args); + return graphPath; +} + +- (void)_addCommonParameters:(NSMutableDictionary *)parameters content:(id)content +{ + NSString *tags = [content.peopleIDs componentsJoinedByString:@","]; + [FBSDKInternalUtility dictionary:parameters setObject:tags forKey:@"tags"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.placeID forKey:@"place"]; + [FBSDKInternalUtility dictionary:parameters setObject:content.ref forKey:@"ref"]; +} + +- (BOOL)_hasPublishActions +{ + FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken]; + return [accessToken.permissions containsObject:@"publish_actions"]; +} + +- (BOOL)_shareLinkContent:(FBSDKShareLinkContent *)linkContent +{ + FBSDKGraphRequestHandler completionHandler = ^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!_delegate) { + return; + } + if (error) { + [_delegate sharer:self didFailWithError:error]; + } else { + result = [FBSDKTypeUtility dictionaryValue:result]; + NSMutableDictionary *shareResults = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:shareResults setObject:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_POST + forKey:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + [FBSDKInternalUtility dictionary:shareResults setObject:[FBSDKTypeUtility stringValue:result[@"id"]] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [_delegate sharer:self didCompleteWithResults:shareResults]; + } + }; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [self _addCommonParameters:parameters content:linkContent]; + [FBSDKInternalUtility dictionary:parameters setObject:self.message forKey:@"message"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentURL forKey:@"link"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.imageURL forKey:@"picture"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentTitle forKey:@"name"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentDescription forKey:@"description"]; + + [[[FBSDKGraphRequest alloc] initWithGraphPath:[self _graphPathWithSuffix:@"feed", nil] + parameters:parameters + HTTPMethod:@"POST"] startWithCompletionHandler:completionHandler]; + return YES; +} + +- (BOOL)_shareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent +{ + // In order to create a new Open Graph action using a custom object that does not already exist (objectID or URL), you + // must first send a request to post the object and then another to post the action. If a local image is supplied + // with the object or action, that must be staged first and then referenced by the staging URL that is returned by + // that request. + FBSDKShareOpenGraphAction *action = openGraphContent.action; + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + void(^stagingHandler)(NSDictionary *) = ^(NSDictionary *stagedContainer) { + NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:stagedContainer]; + [self _addCommonParameters:parameters content:openGraphContent]; + [FBSDKInternalUtility dictionary:parameters setObject:self.message forKey:@"message"]; + + FBSDKGraphRequestHandler requestHandler = ^(FBSDKGraphRequestConnection *requestConnection, + id result, + NSError *requestError) { + if (!_delegate) { + return; + } + if (requestError) { + NSError *error = [FBSDKShareError errorWithCode:FBSDKShareOpenGraphErrorCode + message:@"Error sharing Open Graph content" + underlyingError:requestError]; + [_delegate sharer:self didFailWithError:error]; + } else if (result) { + NSMutableDictionary *shareResults = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:shareResults setObject:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_POST + forKey:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + [FBSDKInternalUtility dictionary:shareResults setObject:[FBSDKTypeUtility stringValue:result[@"id"]] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [_delegate sharer:self didCompleteWithResults:shareResults]; + } + }; + NSString *graphPath = [self _graphPathWithSuffix:[FBSDKUtility URLEncode:action.actionType], nil]; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + HTTPMethod:@"POST"]; + [self _connection:connection addRequest:request completionHandler:requestHandler]; + [connection start]; + }; + if (![self _stageOpenGraphValueContainer:action connection:connection stagingHandler:stagingHandler]) { + return NO; + } + return YES; +} + +- (BOOL)_sharePhotoContent:(FBSDKSharePhotoContent *)photoContent +{ + NSArray *photos = photoContent.photos; + NSMutableArray *requests = [[NSMutableArray alloc] init]; + for (FBSDKSharePhoto *photo in photos) { + UIImage *image = photo.image; + if (!image && [photo.imageURL isFileURL]) { + image = [UIImage imageWithContentsOfFile:[photo.imageURL path]]; + } + if (image) { + NSString *graphPath = [self _graphPathWithSuffix:FBSDKShareAPIPhotosEdge, nil]; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [self _addCommonParameters:parameters content:photoContent]; + NSString *caption = photo.caption ?: self.message; + [FBSDKInternalUtility dictionary:parameters setObject:caption forKey:@"caption"]; + parameters[@"picture"] = image; + [requests addObject:[[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + HTTPMethod:@"POST"]]; + } + } + NSUInteger requestCount = [requests count]; + NSMutableArray *results = [[NSMutableArray alloc] init]; + NSMutableArray *errors = [[NSMutableArray alloc] init]; + __block NSUInteger completedCount = 0; + FBSDKGraphRequestHandler completionHandler = ^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + result = [FBSDKTypeUtility dictionaryValue:result]; + [FBSDKInternalUtility array:results addObject:result]; + [FBSDKInternalUtility array:errors addObject:error]; + if (++completedCount != requestCount) { + return; + } + if (!_delegate) { + return; + } + if ([errors count]) { + [_delegate sharer:self didFailWithError:errors[0]]; + } else if ([results count]) { + // each photo upload will be merged into the same post, so grab the post_id from the first and use that + NSMutableDictionary *shareResults = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:shareResults setObject:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_POST + forKey:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + NSDictionary *firstResult = [FBSDKTypeUtility dictionaryValue:results[0]]; + [FBSDKInternalUtility dictionary:shareResults setObject:[FBSDKTypeUtility stringValue:firstResult[@"post_id"]] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [_delegate sharer:self didCompleteWithResults:shareResults]; + } + }; + for (FBSDKGraphRequest *request in requests) { + [request startWithCompletionHandler:completionHandler]; + } + return YES; +} + +- (BOOL)_shareVideoContent:(FBSDKShareVideoContent *)videoContent +{ + FBSDKGraphRequestHandler completionHandler = ^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!_delegate) { + return; + } + if (error) { + [_delegate sharer:self didFailWithError:error]; + } else { + result = [FBSDKTypeUtility dictionaryValue:result]; + NSMutableDictionary *shareResults = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:shareResults setObject:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_POST + forKey:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + [FBSDKInternalUtility dictionary:shareResults setObject:[FBSDKTypeUtility stringValue:result[@"id"]] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [_delegate sharer:self didCompleteWithResults:shareResults]; + } + }; + NSString *graphPath = [self _graphPathWithSuffix:FBSDKShareAPIVideosEdge, nil]; + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [self _addCommonParameters:parameters content:videoContent]; + [FBSDKInternalUtility dictionary:parameters setObject:self.message forKey:@"description"]; + if ([[FBSDKAccessToken currentAccessToken].permissions containsObject:@"ads_management"]) { + FBSDKSharePhoto *photo = videoContent.previewPhoto; + UIImage *image = photo.image; + if (!image && [photo.imageURL isFileURL]) { + image = [UIImage imageWithContentsOfFile:[photo.imageURL path]]; + } + [FBSDKInternalUtility dictionary:parameters setObject:image forKey:@"thumb"]; + } + FBSDKShareVideo *video = videoContent.video; + NSURL *videoURL = video.videoURL; + void(^postVideoBlock)(NSData *,NSString *) = ^(NSData *videoData, NSString *filename){ + FBSDKGraphRequestDataAttachment *dataAttachment = [[FBSDKGraphRequestDataAttachment alloc] initWithData:videoData + filename:filename + contentType:nil]; + [FBSDKInternalUtility dictionary:parameters setObject:dataAttachment forKey:filename]; + [[[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + HTTPMethod:@"POST"] startWithCompletionHandler:completionHandler]; + }; + if ([videoURL isFileURL]) { + NSError *fileError; + NSData *videoData = [NSData dataWithContentsOfURL:video.videoURL + options:NSDataReadingMapped + error:&fileError]; + if (!videoData) { + [_delegate sharer:self didFailWithError:fileError]; + return NO; + } + NSString *filename = [[NSString alloc] initWithFormat:@"video.%@", video.videoURL.pathExtension]; + postVideoBlock(videoData, filename); + return YES; + } else if (videoURL) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[[fbsdkdfl_ALAssetsLibraryClass() alloc] init] assetForURL:video.videoURL resultBlock:^(ALAsset *asset) { + ALAssetRepresentation *defaultRepresentation = [asset defaultRepresentation]; + NSUInteger size = (NSUInteger)defaultRepresentation.size; + Byte *buffer = (Byte *)malloc(size); + NSError *error; + NSUInteger bufferedLength = [defaultRepresentation getBytes:buffer fromOffset:0.0 length:size error:&error]; + if (bufferedLength == 0) { + free(buffer); + [_delegate sharer:self didFailWithError:error]; + return; + } + NSData *videoData = [NSData dataWithBytesNoCopy:buffer length:bufferedLength freeWhenDone:YES]; + NSString *filename = [[NSString alloc] initWithFormat:@"video.%@", defaultRepresentation.filename.pathExtension]; +#pragma clang diagnostic pop + postVideoBlock(videoData, filename); + } failureBlock:^(NSError *error) { + [_delegate sharer:self didFailWithError:error]; + }]; + return YES; + } else { + return NO; + } +} + +- (BOOL)_addEncodedParametersToDictionary:(NSMutableDictionary *)parameters + key:(NSString *)key + value:(id)value + error:(NSError **)errorRef +{ + if ([value isKindOfClass:[NSString class]] || + [value isKindOfClass:[NSNumber class]] || + [value isKindOfClass:[NSNull class]]) { + parameters[key] = value; + } else if ([value isKindOfClass:[NSArray class]]) { + __block BOOL didEncode = YES; + [(NSArray *)value enumerateObjectsUsingBlock:^(id subvalue, NSUInteger idx, BOOL *stop) { + NSString *subkey = [[NSString alloc] initWithFormat:@"%@[%lu]", key, (unsigned long)idx]; + if (![self _addEncodedParametersToDictionary:parameters key:subkey value:subvalue error:errorRef]) { + *stop = YES; + didEncode = NO; + } + }]; + if (!didEncode) { + return NO; + } + } else if ([value isKindOfClass:[NSDictionary class]]) { + __block BOOL didEncode = YES; + [(NSDictionary *)value enumerateKeysAndObjectsUsingBlock:^(id subkey, id subvalue, BOOL *stop) { + subkey = [[NSString alloc] initWithFormat:@"%@[%@]", key, subkey]; + if (![self _addEncodedParametersToDictionary:parameters key:subkey value:subvalue error:errorRef]) { + *stop = YES; + didEncode = NO; + } + }]; + if (!didEncode) { + return NO; + } + } else { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:key value:value message:nil]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + +- (BOOL)_stageArray:(NSArray *)array + connection:(FBSDKGraphRequestConnection *)connection + stagingHandler:(void(^)(NSArray *stagedArray))stagingHandler +{ + __block BOOL result = YES; + __block NSUInteger pendingCount = 1; + NSMutableArray *stagedArray = [[NSMutableArray alloc] initWithArray:array]; + void(^itemDidFail)(void) = ^{ + if (!result) { + return; + } + result = NO; + }; + void(^itemDidSucceed)(void) = ^{ + if (!result) { + return; + } + if ((--pendingCount == 0) && (stagingHandler != NULL)) { + stagingHandler(stagedArray); + } + }; + [array enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) { + pendingCount++; + void(^itemHandler)(id) = ^(id stagedValue) { + if (stagedValue) { + stagedArray[idx] = stagedValue; + itemDidSucceed(); + } else { + NSError *error = [FBSDKShareError invalidArgumentErrorWithName:@"value" + value:item + message:@"Error staging object."]; + [_delegate sharer:self didFailWithError:error]; + itemDidFail(); + *stop = YES; + result = NO; + } + }; + if (![self _stageValue:item connection:connection stagingHandler:itemHandler]) { + itemDidFail(); + *stop = YES; + result = NO; + } + }]; + if (result) { + itemDidSucceed(); + } + return result; +} + +- (BOOL)_stageOpenGraphObject:(FBSDKShareOpenGraphObject *)openGraphObject + connection:(FBSDKGraphRequestConnection *)connection + stagingHandler:(void(^)(id stagedObject))stagingHandler + completionHandler:(void(^)(NSDictionary *result))completionHandler +{ + NSString *type = [FBSDKTypeUtility stringValue:openGraphObject[@"og:type"]]; + if (!type) { + NSString *message = @"Open Graph objects must contain a og:type value."; + NSError *error = [FBSDKShareError requiredArgumentErrorWithName:@"og:type" message:message]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } + void(^containerHandler)(NSDictionary *) = ^(NSDictionary *stagedContainer) { + NSError *JSONError; + NSString *objectString = [FBSDKInternalUtility JSONStringForObject:stagedContainer + error:&JSONError + invalidObjectHandler:NULL]; + if (!objectString) { + [_delegate sharer:self didFailWithError:JSONError]; + return; + } + NSString *tokenString = [FBSDKAccessToken currentAccessToken].tokenString; + NSString *graphPath = [self _graphPathWithSuffix:@"objects", type, nil]; + NSDictionary *parameters = @{ @"object": objectString }; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + tokenString:tokenString + version:nil + HTTPMethod:@"POST"]; + FBSDKGraphRequestHandler requestCompletionHandler = ^(FBSDKGraphRequestConnection *requestConnection, + id result, + NSError *requestError) { + if (!_delegate) { + return; + } + if (requestError) { + NSString *message = [[NSString alloc] initWithFormat:@"Error creating Open Graph object: %@", + requestError.description]; + NSError *error = [FBSDKShareError errorWithCode:FBSDKShareOpenGraphErrorCode + message:message + underlyingError:requestError]; + [_delegate sharer:self didFailWithError:error]; + } else if (completionHandler != NULL) { + completionHandler([FBSDKTypeUtility dictionaryValue:result]); + } + }; + NSString *batchEntryName = [self _connection:connection + addRequest:request + completionHandler:requestCompletionHandler]; + if (stagingHandler != NULL) { + stagingHandler([[NSString alloc] initWithFormat:@"{result=%@:$.id}", batchEntryName]); + } + }; + return [self _stageOpenGraphValueContainer:openGraphObject connection:connection stagingHandler:containerHandler]; + return YES; +} + +- (BOOL)_stageOpenGraphValueContainer:(id)container + connection:(FBSDKGraphRequestConnection *)connection + stagingHandler:(void(^)(NSDictionary *stagedContainer))stagingHandler +{ + __block BOOL result = YES; + __block NSUInteger pendingCount = 1; + NSMutableDictionary *stagedContainer = [[NSMutableDictionary alloc] init]; + void(^itemDidFail)(void) = ^{ + if (!result) { + return; + } + result = NO; + }; + void(^itemDidSucceed)(void) = ^{ + if (!result) { + return; + } + if ((--pendingCount == 0) && (stagingHandler != NULL)) { + stagingHandler(stagedContainer); + } + }; + BOOL isAction = [container isKindOfClass:[FBSDKShareOpenGraphAction class]]; + [container enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) { + pendingCount++; + + // The server does not understand custom namespaces remove them until the server is fixed + NSString *namespace; + key = [FBSDKShareUtility getOpenGraphNameAndNamespaceFromFullName:key namespace:&namespace]; + if (namespace && !isAction) { + if (!stagedContainer[namespace]) { + stagedContainer[namespace] = [[NSMutableDictionary alloc] init]; + } + } + + void(^itemHandler)(id) = ^(id stagedValue) { + if (stagedValue) { + if (isAction) { + NSError *error; + if (![self _addEncodedParametersToDictionary:stagedContainer key:key value:stagedValue error:&error]) { + [_delegate sharer:self didFailWithError:error]; + itemDidFail(); + return; + } + } else { + NSMutableDictionary *valueContainer = (namespace ? stagedContainer[namespace] : stagedContainer); + valueContainer[key] = stagedValue; + } + } + itemDidSucceed(); + }; + if (![self _stageValue:object connection:connection stagingHandler:itemHandler]) { + *stop = YES; + result = NO; + } + }]; + if (result) { + itemDidSucceed(); + } + return result; +} + +- (BOOL)_stagePhoto:(FBSDKSharePhoto *)photo + connection:(FBSDKGraphRequestConnection *)connection + stagingHandler:(void(^)(id stagedPhoto))stagingHandler +{ + if (photo.imageURL) { + NSMutableDictionary *stagedPhoto = [[NSMutableDictionary alloc]initWithDictionary: @{ + @"url": photo.imageURL.absoluteString, + @"user_generated": @(photo.userGenerated), + }]; + [FBSDKInternalUtility dictionary:stagedPhoto setObject:photo.caption forKey:@"caption"]; + if (stagingHandler) { + stagingHandler(stagedPhoto); + } + return YES; + } else if (photo.image) { + NSString *graphPath = @"/me/staging_resources"; + NSDictionary *parameters = @{ @"file": photo.image }; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath + parameters:parameters + HTTPMethod:@"POST"]; + FBSDKGraphRequestHandler completionHandler = ^(FBSDKGraphRequestConnection *requestConnection, + id result, + NSError *requestError) { + NSString *stagedPhotoURLString = [FBSDKTypeUtility stringValue:result[@"uri"]]; + if (requestError || !stagedPhotoURLString) { + NSError *error = [FBSDKShareError errorWithCode:FBSDKShareOpenGraphErrorCode + message:@"Error staging photo" + underlyingError:requestError]; + [_delegate sharer:self didFailWithError:error]; + } else if (stagingHandler) { + NSMutableDictionary *stagedPhoto = [[NSMutableDictionary alloc] initWithDictionary: @{ + @"url": stagedPhotoURLString, + @"user_generated": @(photo.userGenerated), + }]; + [FBSDKInternalUtility dictionary:stagedPhoto setObject:photo.caption forKey:@"caption"]; + stagingHandler(stagedPhoto); + } + }; + [request startWithCompletionHandler:completionHandler]; + return YES; + } else { + NSError *error = [FBSDKShareError invalidArgumentErrorWithName:@"photo" + value:photo + message:@"Photos must have an imageURL or image."]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } +} + +- (BOOL)_stageValue:(id)value + connection:(FBSDKGraphRequestConnection *)connection + stagingHandler:(void(^)(id stagedValue))stagingHandler +{ + if ([value isKindOfClass:[NSString class]] || + [value isKindOfClass:[NSNumber class]]) { + if (stagingHandler != NULL) { + stagingHandler(value); + } + return YES; + } else if ([value isKindOfClass:[NSURL class]]) { + if (stagingHandler != NULL) { + stagingHandler([(NSURL *)value absoluteString]); + } + return YES; + } else if ([value isKindOfClass:[FBSDKSharePhoto class]]) { + return [self _stagePhoto:(FBSDKSharePhoto *)value connection:connection stagingHandler:stagingHandler]; + } else if ([value isKindOfClass:[FBSDKShareOpenGraphObject class]]) { + return [self _stageOpenGraphObject:(FBSDKShareOpenGraphObject *)value + connection:connection + stagingHandler:stagingHandler + completionHandler:NULL]; + } else if ([value isKindOfClass:[NSArray class]]) { + return [self _stageArray:(NSArray *)value connection:connection stagingHandler:stagingHandler]; + } else { + NSError *error = [FBSDKShareError invalidArgumentErrorWithName:@"value" + value:value + message:@"Invalid value type found in Open Graph object."]; + [_delegate sharer:self didFailWithError:error]; + return NO; + } +} + +- (NSString *)_connection:(FBSDKGraphRequestConnection *)connection + addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)completionHandler +{ + NSUInteger requestCount = [connection.requests count]; + NSString *batchEntryName = [[NSString alloc] initWithFormat:@"request_%lu", (unsigned long)requestCount]; + [connection addRequest:request completionHandler:completionHandler batchEntryName:batchEntryName]; + return batchEntryName; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h new file mode 100644 index 0000000..d6b46fd --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract A button to share content. + @discussion Tapping the receiver will invoke the FBSDKShareDialog with the attached shareContent. If the dialog cannot + be shown, the button will be disabled. + */ +@interface FBSDKShareButton : FBSDKButton + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.m new file mode 100644 index 0000000..17ecf71 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.m @@ -0,0 +1,90 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareButton.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareDialog.h" + +@implementation FBSDKShareButton +{ + FBSDKShareDialog *_dialog; +} + +#pragma mark - Properties + +- (id)shareContent +{ + return _dialog.shareContent; +} + +- (void)setShareContent:(id)shareContent +{ + _dialog.shareContent = shareContent; + [self checkImplicitlyDisabled]; +} + +#pragma mark - FBSDKButtonImpressionTracking + +- (NSDictionary *)analyticsParameters +{ + return nil; +} + +- (NSString *)impressionTrackingEventName +{ + return FBSDKAppEventNameFBSDKShareButtonImpression; +} + +- (NSString *)impressionTrackingIdentifier +{ + return @"share"; +} + +#pragma mark - FBSDKButton + +- (void)configureButton +{ + NSString *title = + NSLocalizedStringWithDefaultValue(@"ShareButton.Share", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings], + @"Share", + @"The label for FBSDKShareButton"); + + [self configureWithIcon:nil + title:title + backgroundColor:nil + highlightedColor:nil]; + + [self addTarget:self action:@selector(_share:) forControlEvents:UIControlEventTouchUpInside]; + _dialog = [[FBSDKShareDialog alloc] init]; +} + +- (BOOL)isImplicitlyDisabled +{ + return ![_dialog canShow] || ![_dialog validateWithError:NULL]; +} + +#pragma mark - Helper Methods + +- (void)_share:(id)sender +{ + [self logTapEventWithEventName:FBSDKAppEventNameFBSDKShareButtonDidTap parameters:[self analyticsParameters]]; + [_dialog show]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h new file mode 100644 index 0000000..4f2af4f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h @@ -0,0 +1,50 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKShareKit. + @discussion Error codes from the SDK in the range 200-299 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKShareErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKShareErrorCode) + @abstract Error codes for FBSDKShareErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKShareErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKShareReservedErrorCode = 200, + + /*! + @abstract The error code for errors from uploading open graph objects. + */ + FBSDKShareOpenGraphErrorCode, + + /*! + @abstract The error code for when a sharing dialog is not available. + @discussion Use the canShare methods to check for this case before calling show. + */ + FBSDKShareDialogNotAvailableErrorCode, +}; diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.m new file mode 100644 index 0000000..8de78c7 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.m @@ -0,0 +1,24 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareConstants.h" + +NSString *const FBSDKShareErrorDomain = @"com.facebook.sdk.share"; + +NSString *const FBSDKShareOpenGraphKeyErrorKey = @"key"; +NSString *const FBSDKShareOpenGraphValueErrorKey = @"value"; diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h new file mode 100644 index 0000000..29489a6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract A dialog for sharing content on Facebook. + */ +@interface FBSDKShareDialog : NSObject + +/*! + @abstract Convenience method to show an FBSDKShareDialog with a fromViewController, content and a delegate. + @param viewController A UIViewController to present the dialog from, if appropriate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)showFromViewController:(UIViewController *)viewController + withContent:(id)content + delegate:(id)delegate; + +/*! + @abstract A UIViewController to present the dialog from. + @discussion If not specified, the top most view controller will be automatically determined as best as possible. + */ +@property (nonatomic, weak) UIViewController *fromViewController; + +/*! + @abstract The mode with which to display the dialog. + @discussion Defaults to FBSDKShareDialogModeAutomatic, which will automatically choose the best available mode. + */ +@property (nonatomic, assign) FBSDKShareDialogMode mode; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.m new file mode 100644 index 0000000..dca5b20 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.m @@ -0,0 +1,781 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareDialog.h" + +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" +#import "FBSDKShareLinkContent.h" +#import "FBSDKShareOpenGraphAction.h" +#import "FBSDKShareOpenGraphContent.h" +#import "FBSDKShareOpenGraphObject.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKSharePhotoContent.h" +#import "FBSDKShareUtility.h" +#import "FBSDKShareVideo.h" +#import "FBSDKShareVideoContent.h" + +#define FBSDK_SHARE_DIALOG_APP_SCHEME @"fbapi" +#define FBSDK_SHARE_EXTENSION_APP_SCHEME @"fbshareextension" +#define FBSDK_SHARE_FEED_METHOD_NAME @"feed" +#define FBSDK_SHARE_METHOD_MIN_VERSION @"20130410" +#define FBSDK_SHARE_METHOD_OG_MIN_VERSION @"20130214" +#define FBSDK_SHARE_METHOD_OG_IMAGE_MIN_VERSION @"20130410" +#define FBSDK_SHARE_METHOD_PHOTOS_MIN_VERSION @"20140116" +#define FBSDK_SHARE_METHOD_VIDEO_MIN_VERSION @"20150313" +#define FBSDK_SHARE_METHOD_ATTRIBUTED_SHARE_SHEET_MIN_VERSION @"20150629" + +@interface FBSDKShareDialog () +@end + +@implementation FBSDKShareDialog +{ + FBSDKWebDialog *_webDialog; +} + +#pragma mark - Class Methods + ++ (void)initialize +{ + if ([FBSDKShareDialog class] == self) { + [FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK]; + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + ++ (instancetype)showFromViewController:(UIViewController *)viewController + withContent:(id)content + delegate:(id)delegate +{ + FBSDKShareDialog *dialog = [[self alloc] init]; + dialog.fromViewController = viewController; + dialog.shareContent = content; + dialog.delegate = delegate; + [dialog show]; + return dialog; +} + +#pragma mark - Object Lifecycle + +- (void)dealloc +{ + _webDialog.delegate = nil; +} + +#pragma mark - Properties + +@synthesize delegate = _delegate; +@synthesize shareContent = _shareContent; +@synthesize shouldFailOnDataError = _shouldFailOnDataError; + +#pragma mark - Public Methods + +- (BOOL)canShow +{ + switch (self.mode) { + case FBSDKShareDialogModeAutomatic: + case FBSDKShareDialogModeBrowser: + case FBSDKShareDialogModeFeedBrowser: + case FBSDKShareDialogModeFeedWeb: + case FBSDKShareDialogModeWeb:{ + return YES; + } + case FBSDKShareDialogModeNative:{ + return [self _canShowNative]; + } + case FBSDKShareDialogModeShareSheet:{ + return [self _canShowShareSheet]; + } + } +} + +- (BOOL)show +{ + BOOL didShow = NO; + NSError *error = nil; + + if ([self validateWithError:&error]) { + switch (self.mode) { + case FBSDKShareDialogModeAutomatic:{ + didShow = [self _showAutomatic:&error]; + break; + } + case FBSDKShareDialogModeBrowser:{ + didShow = [self _showBrowser:&error]; + break; + } + case FBSDKShareDialogModeFeedBrowser:{ + didShow = [self _showFeedBrowser:&error]; + break; + } + case FBSDKShareDialogModeFeedWeb:{ + didShow = [self _showFeedWeb:&error]; + break; + } + case FBSDKShareDialogModeNative:{ + didShow = [self _showNativeWithCanShowError:&error validationError:&error]; + break; + } + case FBSDKShareDialogModeShareSheet:{ + didShow = [self _showShareSheetWithCanShowError:&error validationError:&error]; + break; + } + case FBSDKShareDialogModeWeb:{ + didShow = [self _showWeb:&error]; + break; + } + } + } + if (!didShow) { + [self _invokeDelegateDidFailWithError:error]; + } else { + [self _logDialogShow]; + [FBSDKInternalUtility registerTransientObject:self]; + } + return didShow; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + if (errorRef != NULL) { + *errorRef = nil; + } + id shareContent = self.shareContent; + if (!shareContent) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"shareContent" message:nil]; + } + return NO; + } + if (![FBSDKShareUtility validateShareContent:shareContent error:errorRef]) { + return NO; + } + switch (self.mode) { + case FBSDKShareDialogModeAutomatic:{ + return ( + ([self _canShowNative] && [self _validateShareContentForNative:errorRef]) || + ([self _canShowShareSheet] && [self _validateShareContentForShareSheet:errorRef]) || + [self _validateShareContentForFeed:errorRef] || + [self _validateShareContentForBrowser:errorRef]); + } + case FBSDKShareDialogModeNative:{ + return [self _validateShareContentForNative:errorRef]; + } + case FBSDKShareDialogModeShareSheet:{ + return [self _validateShareContentForShareSheet:errorRef]; + } + case FBSDKShareDialogModeBrowser: + case FBSDKShareDialogModeWeb:{ + return [self _validateShareContentForBrowser:errorRef]; + } + case FBSDKShareDialogModeFeedBrowser: + case FBSDKShareDialogModeFeedWeb:{ + return [self _validateShareContentForFeed:errorRef]; + } + } +} + +#pragma mark - FBSDKWebDialogDelegate + +- (void)webDialog:(FBSDKWebDialog *)webDialog didCompleteWithResults:(NSDictionary *)results +{ + if (_webDialog != webDialog) { + return; + } + [self _cleanUpWebDialog]; + NSInteger errorCode = [results[@"error_code"] integerValue]; + if (errorCode == 4201) { + [self _invokeDelegateDidCancel]; + } else { + // not all web dialogs report cancellation, so assume that the share has completed with no additional information + [self _handleWebResponseParameters:results error:nil]; + } + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialog:(FBSDKWebDialog *)webDialog didFailWithError:(NSError *)error +{ + if (_webDialog != webDialog) { + return; + } + [self _cleanUpWebDialog]; + [self _invokeDelegateDidFailWithError:error]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +- (void)webDialogDidCancel:(FBSDKWebDialog *)webDialog +{ + if (_webDialog != webDialog) { + return; + } + [self _cleanUpWebDialog]; + [self _invokeDelegateDidCancel]; + [FBSDKInternalUtility unregisterTransientObject:self]; +} + +#pragma mark - Helper Methods + +-(BOOL)_isDefaultToShareSheet +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + return [configuration.defaultShareMode isEqualToString:@"share_sheet"]; +} + +-(BOOL)_showAutomatic:(NSError *__autoreleasing *)errorRef +{ + BOOL isDefaultToShareSheet = [self _isDefaultToShareSheet]; + BOOL useNativeDialog = [self _useNativeDialog]; + return ((isDefaultToShareSheet && [self _showShareSheetWithCanShowError:NULL validationError:errorRef]) || + (useNativeDialog && [self _showNativeWithCanShowError:NULL validationError:errorRef]) || + (!isDefaultToShareSheet && [self _showShareSheetWithCanShowError:NULL validationError:errorRef]) || + [self _showFeedBrowser:errorRef] || + [self _showFeedWeb:errorRef] || + [self _showBrowser:errorRef] || + [self _showWeb:errorRef] || + (!useNativeDialog && [self _showNativeWithCanShowError:NULL validationError:errorRef])); +} + +- (void)_loadNativeMethodName:(NSString **)methodNameRef methodVersion:(NSString **)methodVersionRef +{ + if (methodNameRef != NULL) { + *methodNameRef = nil; + } + if (methodVersionRef != NULL) { + *methodVersionRef = nil; + } + + id shareContent = self.shareContent; + if (!shareContent) { + return; + } + + // if there is shareContent on the receiver already, we can check the minimum app version, otherwise we can only check + // for an app that can handle the native share dialog + NSString *methodName = nil; + NSString *methodVersion = nil; + if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + methodName = FBSDK_SHARE_OPEN_GRAPH_METHOD_NAME; + BOOL containsMedia = NO; + [FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:NULL]; + if (containsMedia) { + methodVersion = FBSDK_SHARE_METHOD_OG_IMAGE_MIN_VERSION; + } else { + methodVersion = FBSDK_SHARE_METHOD_OG_MIN_VERSION; + } + } else { + methodName = FBSDK_SHARE_METHOD_NAME; + if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + methodVersion = FBSDK_SHARE_METHOD_PHOTOS_MIN_VERSION; + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + methodVersion = FBSDK_SHARE_METHOD_VIDEO_MIN_VERSION; + } else { + methodVersion = FBSDK_SHARE_METHOD_MIN_VERSION; + } + } + if (methodNameRef != NULL) { + *methodNameRef = methodName; + } + if (methodVersionRef != NULL) { + *methodVersionRef = methodVersion; + } +} + +- (BOOL)_canShowNative +{ + return [FBSDKInternalUtility isFacebookAppInstalled]; +} + +- (BOOL)_canShowShareSheet +{ + Class composeViewControllerClass = [fbsdkdfl_SLComposeViewControllerClass() class]; + if (!composeViewControllerClass) { + return NO; + } + NSString *facebookServiceType = fbsdkdfl_SLServiceTypeFacebook(); + if (![composeViewControllerClass isAvailableForServiceType:facebookServiceType]) { + return NO; + } + return YES; +} + +- (BOOL)_canAttributeThroughShareSheet +{ + NSOperatingSystemVersion iOS8Version = { .majorVersion = 8, .minorVersion = 0, .patchVersion = 0 }; + if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) { + return NO; + } + NSString *scheme = FBSDK_SHARE_DIALOG_APP_SCHEME; + NSString *minimumVersion = FBSDK_SHARE_METHOD_ATTRIBUTED_SHARE_SHEET_MIN_VERSION; + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = [scheme stringByAppendingString:minimumVersion]; + components.path = @"/"; + return ([[UIApplication sharedApplication] canOpenURL:components.URL] || + [self _canUseFBShareSheet]); +} + +- (BOOL)_canUseFBShareSheet +{ + NSOperatingSystemVersion iOS8Version = { .majorVersion = 8, .minorVersion = 0, .patchVersion = 0 }; + if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) { + return NO; + } + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = FBSDK_SHARE_EXTENSION_APP_SCHEME; + components.path = @"/"; + return [[UIApplication sharedApplication] canOpenURL:components.URL]; +} + +- (void)_cleanUpWebDialog +{ + _webDialog.delegate = nil; + _webDialog = nil; +} + +- (NSArray *)_contentImages +{ + id shareContent = self.shareContent; + return ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]] ? + [((FBSDKSharePhotoContent *)shareContent).photos valueForKeyPath:@"@distinctUnionOfObjects.image"] : + nil); +} + +- (NSArray *)_contentURLs +{ + NSArray *URLs = nil; + id shareContent = self.shareContent; + if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + FBSDKShareLinkContent *linkContent = (FBSDKShareLinkContent *)shareContent; + URLs = (linkContent.contentURL ? @[linkContent.contentURL] : nil); + } else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + FBSDKSharePhotoContent *photoContent = (FBSDKSharePhotoContent *)shareContent; + URLs = (photoContent.contentURL ? @[photoContent.contentURL] : nil); + } + return URLs; +} + +- (void)_handleWebResponseParameters:(NSDictionary *)webResponseParameters error:(NSError *)error +{ + if (error) { + [self _invokeDelegateDidFailWithError:error]; + return; + } else { + NSString *completionGesture = webResponseParameters[FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + if ([completionGesture isEqualToString:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_CANCEL]) { + [self _invokeDelegateDidCancel]; + } else { + // not all web dialogs report cancellation, so assume that the share has completed with no additional information + NSMutableDictionary *results = [[NSMutableDictionary alloc] init]; + // the web response comes back with a different payload, so we need to translate it + [FBSDKInternalUtility dictionary:results + setObject:webResponseParameters[FBSDK_SHARE_WEB_PARAM_POST_ID_KEY] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [self _invokeDelegateDidCompleteWithResults:results]; + } + } +} + +- (BOOL)_showBrowser:(NSError **)errorRef +{ + if (![self _validateShareContentForBrowser:errorRef]) { + return NO; + } + id shareContent = self.shareContent; + NSString *methodName; + NSDictionary *parameters; + if (![FBSDKShareUtility buildWebShareContent:shareContent + methodName:&methodName + parameters:¶meters + error:errorRef]) { + return NO; + } + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + [self _handleWebResponseParameters:response.responseParameters error:response.error]; + [FBSDKInternalUtility unregisterTransientObject:self]; + }; + FBSDKBridgeAPIRequest *request; + request = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeWeb + scheme:FBSDK_SHARE_WEB_SCHEME + methodName:methodName + methodVersion:nil + parameters:parameters + userInfo:nil]; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:request + useSafariViewController:[self _useSafariViewController] + fromViewController:self.fromViewController + completionBlock:completionBlock]; + return YES; +} + +- (BOOL)_showFeedBrowser:(NSError **)errorRef +{ + if (![self _validateShareContentForFeed:errorRef]) { + return NO; + } + id shareContent = self.shareContent; + NSDictionary *parameters = [FBSDKShareUtility feedShareDictionaryForContent:shareContent]; + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + [self _handleWebResponseParameters:response.responseParameters error:response.error]; + [FBSDKInternalUtility unregisterTransientObject:self]; + }; + FBSDKBridgeAPIRequest *request; + request = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeWeb + scheme:FBSDK_SHARE_WEB_SCHEME + methodName:FBSDK_SHARE_FEED_METHOD_NAME + methodVersion:nil + parameters:parameters + userInfo:nil]; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:request + useSafariViewController:[self _useSafariViewController] + fromViewController:self.fromViewController + completionBlock:completionBlock]; + return YES; +} + +- (BOOL)_showFeedWeb:(NSError **)errorRef +{ + if (![self _validateShareContentForFeed:errorRef]) { + return NO; + } + id shareContent = self.shareContent; + NSDictionary *parameters = [FBSDKShareUtility feedShareDictionaryForContent:shareContent]; + _webDialog = [FBSDKWebDialog showWithName:FBSDK_SHARE_FEED_METHOD_NAME + parameters:parameters + delegate:self]; + return YES; +} + +- (BOOL)_showNativeWithCanShowError:(NSError **)canShowErrorRef validationError:(NSError **)validationErrorRef +{ + if (![self _canShowNative]) { + if (canShowErrorRef != NULL) { + *canShowErrorRef = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Native share dialog is not available."]; + } + return NO; + } + if (![self _validateShareContentForNative:validationErrorRef]) { + return NO; + } + + NSString *methodName; + NSString *methodVersion; + [self _loadNativeMethodName:&methodName methodVersion:&methodVersion]; + NSDictionary *parameters = [FBSDKShareUtility parametersForShareContent:self.shareContent + shouldFailOnDataError:self.shouldFailOnDataError]; + FBSDKBridgeAPIRequest *request; + request = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeNative + scheme:FBSDK_CANOPENURL_FACEBOOK + methodName:methodName + methodVersion:methodVersion + parameters:parameters + userInfo:nil]; + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + if (response.error.code == FBSDKAppVersionUnsupportedErrorCode) { + NSError *fallbackError; + if ([self _showShareSheetWithCanShowError:NULL validationError:&fallbackError] || + [self _showFeedBrowser:&fallbackError]) { + return; + } + } + NSDictionary *responseParameters = response.responseParameters; + NSString *completionGesture = responseParameters[FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + if ([completionGesture isEqualToString:FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_CANCEL] || + response.isCancelled) { + [self _invokeDelegateDidCancel]; + } else if (response.error) { + [self _invokeDelegateDidFailWithError:response.error]; + } else { + NSMutableDictionary *results = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:results + setObject:responseParameters[FBSDK_SHARE_RESULT_POST_ID_KEY] + forKey:FBSDK_SHARE_RESULT_POST_ID_KEY]; + [self _invokeDelegateDidCompleteWithResults:results]; + } + [FBSDKInternalUtility unregisterTransientObject:self]; + }; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:request + useSafariViewController:[self _useSafariViewController] + fromViewController:self.fromViewController + completionBlock:completionBlock]; + return YES; +} + +- (BOOL)_showShareSheetWithCanShowError:(NSError **)canShowErrorRef validationError:(NSError **)validationErrorRef +{ + if (![self _canShowShareSheet]) { + if (canShowErrorRef != NULL) { + *canShowErrorRef = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Share sheet is not available."]; + } + return NO; + } + if (![self _validateShareContentForShareSheet:validationErrorRef]) { + return NO; + } + UIViewController *fromViewController = self.fromViewController; + if (!fromViewController) { + if (validationErrorRef != NULL) { + *validationErrorRef = [FBSDKShareError requiredArgumentErrorWithName:@"fromViewController" message:nil]; + } + return NO; + } + NSArray *images = [self _contentImages]; + NSArray *URLs = [self _contentURLs]; + NSURL *videoURL = ([self.shareContent isKindOfClass:[FBSDKShareVideoContent class]] ? + ((FBSDKShareVideoContent *)self.shareContent).video.videoURL : + nil); + + Class composeViewControllerClass = [fbsdkdfl_SLComposeViewControllerClass() class]; + NSString *facebookServiceType = fbsdkdfl_SLServiceTypeFacebook(); + SLComposeViewController *composeViewController; + composeViewController = [composeViewControllerClass composeViewControllerForServiceType:facebookServiceType]; + + if (!composeViewController) { + if (canShowErrorRef != NULL) { + *canShowErrorRef = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Error creating SLComposeViewController."]; + } + return NO; + } + if ([self _canAttributeThroughShareSheet]) { + NSString *attributionToken = [NSString stringWithFormat:@"fb-app-id:%@", [FBSDKSettings appID]]; + [composeViewController setInitialText:attributionToken]; + } + for (UIImage *image in images) { + [composeViewController addImage:image]; + } + for (NSURL *URL in URLs) { + [composeViewController addURL:URL]; + } + if (videoURL) { + [composeViewController addURL:videoURL]; + } + composeViewController.completionHandler = ^(SLComposeViewControllerResult result) { + switch (result) { + case SLComposeViewControllerResultCancelled:{ + [self _invokeDelegateDidCancel]; + break; + } + case SLComposeViewControllerResultDone:{ + [self _invokeDelegateDidCompleteWithResults:@{}]; + break; + } + } + [FBSDKInternalUtility unregisterTransientObject:self]; + }; + [fromViewController presentViewController:composeViewController animated:YES completion:nil]; + return YES; +} + +- (BOOL)_showWeb:(NSError **)errorRef +{ + if (![self _validateShareContentForBrowser:errorRef]) { + return NO; + } + id shareContent = self.shareContent; + NSString *methodName; + NSDictionary *parameters; + if (![FBSDKShareUtility buildWebShareContent:shareContent + methodName:&methodName + parameters:¶meters + error:errorRef]) { + return NO; + } + _webDialog = [FBSDKWebDialog showWithName:methodName + parameters:parameters + delegate:self]; + return YES; +} + +- (BOOL)_useNativeDialog +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + return [configuration useNativeDialogForDialogName:FBSDKDialogConfigurationNameShare]; +} + +- (BOOL)_useSafariViewController +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + return [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameShare]; +} + +- (BOOL)_validateShareContentForBrowser:(NSError **)errorRef +{ + id shareContent = self.shareContent; + BOOL containsMedia; + BOOL containsPhotos; + [FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:&containsPhotos]; + if (containsPhotos) { + if ((errorRef != NULL) && !*errorRef) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" + value:shareContent + message:@"Web share dialogs cannot include photos."]; + } + return NO; + } + if (containsMedia) { + if ((errorRef != NULL) && !*errorRef) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" + value:shareContent + message:@"Web share dialogs cannot include local media."]; + } + return NO; + } + return YES; +} + +- (BOOL)_validateShareContentForFeed:(NSError **)errorRef +{ + id shareContent = self.shareContent; + if (![shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + if ((errorRef != NULL) && !*errorRef) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" + value:shareContent + message:@"Feed share dialogs support FBSDKShareLinkContent."]; + } + return NO; + } + return YES; +} + +- (BOOL)_validateShareContentForNative:(NSError **)errorRef +{ + id shareContent = self.shareContent; + if (![shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + return YES; + } + return [self _validateVideoURL:((FBSDKShareVideoContent *)shareContent).video.videoURL error:errorRef]; +} + +- (BOOL)_validateShareContentForShareSheet:(NSError **)errorRef +{ + id shareContent = self.shareContent; + if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + if ([self _contentImages] != 0) { + return YES; + } else { + if ((errorRef != NULL) && !*errorRef) { + NSString *message = @"Share photo content must have UIImage photos in order to share with the share sheet"; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" value:shareContent message:message]; + } + return NO; + } + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + return ([self _canUseFBShareSheet] && + [self _validateVideoURL:((FBSDKShareVideoContent *)shareContent).video.videoURL error:errorRef]); + } else if (![shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + if ((errorRef != NULL) && !*errorRef) { + NSString *message = @"Share content must be FBSDKShareLinkContent or FBSDKSharePhotoContent in order to share " + @"with the share sheet."; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" value:shareContent message:message]; + } + return NO; + } + return YES; +} + +- (BOOL)_validateVideoURL:(NSURL *)videoURL error:(NSError **)errorRef +{ + if (videoURL.isFileURL) { + if ((errorRef != NULL) && !*errorRef) { + NSString *message = @"Only asset file URLs are allowed for videos."; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"videoURL" value:videoURL message:message]; + } + return NO; + } + return YES; +} + +- (void)_invokeDelegateDidCancel +{ + NSDictionary * parameters = @{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Cancelled, + }; + + [FBSDKAppEvents logImplicitEvent:FBSDLAppEventNameFBSDKEventShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + [_delegate sharerDidCancel:self]; +} + +- (void)_invokeDelegateDidCompleteWithResults:(NSDictionary *)results +{ + NSDictionary * parameters = @{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Completed + }; + + [FBSDKAppEvents logImplicitEvent:FBSDLAppEventNameFBSDKEventShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + [_delegate sharer:self didCompleteWithResults:[results copy]]; +} + +- (void)_invokeDelegateDidFailWithError:(NSError *)error +{ + NSDictionary * parameters = @{ + FBSDKAppEventParameterDialogOutcome : FBSDKAppEventsDialogOutcomeValue_Failed, + FBSDKAppEventParameterDialogErrorMessage : [NSString stringWithFormat:@"%@", error] + }; + + [FBSDKAppEvents logImplicitEvent:FBSDLAppEventNameFBSDKEventShareDialogResult + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; + + [_delegate sharer:self didFailWithError:error]; +} + +- (void)_logDialogShow +{ + NSString *shareMode = NSStringFromFBSDKShareDialogMode(self.mode); + + NSString *contentType; + if([self.shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeOpenGraph; + } else if ([self.shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeStatus; + } else if ([self.shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypePhoto; + } else if ([self.shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + contentType = FBSDKAppEventsDialogShareContentTypeVideo; + } else { + contentType = FBSDKAppEventsDialogShareContentTypeUnknown; + } + + + NSDictionary *parameters = @{ + FBSDKAppEventParameterDialogMode : shareMode, + FBSDKAppEventParameterDialogShareContentType : contentType, + + }; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKEventShareDialogShow + valueToSum:nil + parameters:parameters + accessToken:[FBSDKAccessToken currentAccessToken]]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h new file mode 100644 index 0000000..bdea19e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKShareDialogMode) + @abstract Modes for the FBSDKShareDialog. + @discussion The automatic mode will progressively check the availability of different modes and open the most + appropriate mode for the dialog that is available. + */ +typedef NS_ENUM(NSUInteger, FBSDKShareDialogMode) +{ + /*! + @abstract Acts with the most appropriate mode that is available. + */ + FBSDKShareDialogModeAutomatic = 0, + /*! + @Displays the dialog in the main native Facebook app. + */ + FBSDKShareDialogModeNative, + /*! + @Displays the dialog in the iOS integrated share sheet. + */ + FBSDKShareDialogModeShareSheet, + /*! + @Displays the dialog in Safari. + */ + FBSDKShareDialogModeBrowser, + /*! + @Displays the dialog in a UIWebView within the app. + */ + FBSDKShareDialogModeWeb, + /*! + @Displays the feed dialog in Safari. + */ + FBSDKShareDialogModeFeedBrowser, + /*! + @Displays the feed dialog in a UIWebView within the app. + */ + FBSDKShareDialogModeFeedWeb, +}; + +/*! + @abstract Converts an FBLikeControlObjectType to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKShareDialogMode(FBSDKShareDialogMode dialogMode); diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.m new file mode 100644 index 0000000..7791adb --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.m @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareDialogMode.h" + +#import "FBSDKCoreKit+Internal.h" + +NSString *NSStringFromFBSDKShareDialogMode(FBSDKShareDialogMode dialogMode) +{ + switch (dialogMode) { + case FBSDKShareDialogModeAutomatic:{ + return FBSDKAppEventsDialogShareModeAutomatic; + } + case FBSDKShareDialogModeBrowser:{ + return FBSDKAppEventsDialogShareModeBrowser; + } + case FBSDKShareDialogModeNative:{ + return FBSDKAppEventsDialogShareModeNative; + } + case FBSDKShareDialogModeShareSheet:{ + return FBSDKAppEventsDialogShareModeShareSheet; + } + case FBSDKShareDialogModeWeb:{ + return FBSDKAppEventsDialogShareModeWeb; + } + case FBSDKShareDialogModeFeedBrowser: { + return FBSDKAppEventsDialogShareModeFeedBrowser; + } + case FBSDKShareDialogModeFeedWeb:{ + return FBSDKAppEventsDialogShareModeFeedWeb; + } + default:{ + return FBSDKAppEventsDialogShareModeUnknown; + } + } +} diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h new file mode 100644 index 0000000..c2406c8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h new file mode 100644 index 0000000..9995df6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for status and link content to be shared. + */ +@interface FBSDKShareLinkContent : NSObject + +/*! + @abstract The description of the link. + @discussion If not specified, this field is automatically populated by information scraped from the contentURL, + typically the title of the page. This value may be discarded for specially handled links (ex: iTunes URLs). + @return The description of the link + */ +@property (nonatomic, copy) NSString *contentDescription; + +/*! + @abstract The title to display for this link. + @discussion This value may be discarded for specially handled links (ex: iTunes URLs). + @return The link title + */ +@property (nonatomic, copy) NSString *contentTitle; + +/*! + @abstract The URL of a picture to attach to this content. + @return The network URL of an image + */ +@property (nonatomic, copy) NSURL *imageURL; + +/*! + @abstract Compares the receiver to another link content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareLinkContent:(FBSDKShareLinkContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.m new file mode 100644 index 0000000..cc49ed6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.m @@ -0,0 +1,150 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareLinkContent+Internal.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_DESCRIPTION_KEY @"contentDescription" +#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY @"contentTitle" +#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY @"contentURL" +#define FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY @"imageURL" +#define FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY @"peopleIDs" +#define FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY @"placeID" +#define FBSDK_SHARE_STATUS_CONTENT_REF_KEY @"ref" +#define FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY @"feedParameters" + +@implementation FBSDKShareLinkContent + +#pragma mark - Properties + +@synthesize contentURL = _contentURL; +@synthesize peopleIDs = _peopleIDs; +@synthesize placeID = _placeID; +@synthesize ref = _ref; +@synthesize feedParameters = _feedParameters; + +- (void)setPeopleIDs:(NSArray *)peopleIDs +{ + [FBSDKShareUtility assertCollection:peopleIDs ofClass:[NSString class] name:@"peopleIDs"]; + if (![FBSDKInternalUtility object:_peopleIDs isEqualToObject:peopleIDs]) { + _peopleIDs = [peopleIDs copy]; + } +} + +- (void)setFeedParameters:(NSDictionary *)feedParameters +{ + if (![_feedParameters isEqualToDictionary:feedParameters]) { + _feedParameters = [feedParameters copy]; + } +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_contentDescription hash], + [_contentURL hash], + [_imageURL hash], + [_peopleIDs hash], + [_placeID hash], + [_ref hash], + [_contentTitle hash], + [_feedParameters hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareLinkContent class]]) { + return NO; + } + return [self isEqualToShareLinkContent:(FBSDKShareLinkContent *)object]; +} + +- (BOOL)isEqualToShareLinkContent:(FBSDKShareLinkContent *)content +{ + return (content && + [FBSDKInternalUtility object:_contentDescription isEqualToObject:content.contentDescription] && + [FBSDKInternalUtility object:_contentTitle isEqualToObject:content.contentTitle] && + [FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] && + [FBSDKInternalUtility object:_feedParameters isEqualToObject:content.feedParameters] && + [FBSDKInternalUtility object:_imageURL isEqualToObject:content.imageURL] && + [FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] && + [FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] && + [FBSDKInternalUtility object:_ref isEqualToObject:content.ref]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _contentDescription = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_DESCRIPTION_KEY]; + _contentTitle = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY]; + _contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY]; + _feedParameters = [decoder decodeObjectOfClass:[NSDictionary class] forKey:FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY]; + _imageURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY]; + _peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY]; + _placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY]; + _ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_REF_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_contentDescription forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_DESCRIPTION_KEY]; + [encoder encodeObject:_contentTitle forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY]; + [encoder encodeObject:_contentURL forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY]; + [encoder encodeObject:_feedParameters forKey:FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY]; + [encoder encodeObject:_imageURL forKey:FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY]; + [encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY]; + [encoder encodeObject:_placeID forKey:FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY]; + [encoder encodeObject:_ref forKey:FBSDK_SHARE_STATUS_CONTENT_REF_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareLinkContent *copy = [[FBSDKShareLinkContent alloc] init]; + copy->_contentDescription = [_contentDescription copy]; + copy->_contentTitle = [_contentTitle copy]; + copy->_contentURL = [_contentURL copy]; + copy->_feedParameters = [_feedParameters copy]; + copy->_imageURL = [_imageURL copy]; + copy->_peopleIDs = [_peopleIDs copy]; + copy->_placeID = [_placeID copy]; + copy->_ref = [_ref copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h new file mode 100644 index 0000000..5f6db0a --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h @@ -0,0 +1,69 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @abstract An Open Graph Action for sharing. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`. + */ +@interface FBSDKShareOpenGraphAction : FBSDKShareOpenGraphValueContainer + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param object The Open Graph object represented by this action + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType object:(FBSDKShareOpenGraphObject *)object key:(NSString *)key; + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param objectID The ID of an existing Open Graph object + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType objectID:(NSString *)objectID key:(NSString *)key; + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param objectURL The URL to a page that defines the Open Graph object with meta tags + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType objectURL:(NSURL *)objectURL key:(NSString *)key; + +/*! + @abstract Gets the action type. + @return The action type + */ +@property (nonatomic, copy) NSString *actionType; + +/*! + @abstract Compares the receiver to another Open Graph Action. + @param action The other action + @return YES if the receiver's values are equal to the other action's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphAction:(FBSDKShareOpenGraphAction *)action; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.m new file mode 100644 index 0000000..8211b59 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.m @@ -0,0 +1,117 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareOpenGraphAction.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareOpenGraphValueContainer+Internal.h" + +#define FBSDK_SHARE_OPEN_GRAPH_ACTION_TYPE_KEY @"type" + +@implementation FBSDKShareOpenGraphAction + +#pragma mark - Class Methods + ++ (instancetype)actionWithType:(NSString *)actionType object:(FBSDKShareOpenGraphObject *)object key:(NSString *)key +{ + FBSDKShareOpenGraphAction *action = [[FBSDKShareOpenGraphAction alloc] init]; + action.actionType = actionType; + [action setObject:object forKey:key]; + return action; +} + ++ (instancetype)actionWithType:(NSString *)actionType objectID:(NSString *)objectID key:(NSString *)key +{ + FBSDKShareOpenGraphAction *action = [[FBSDKShareOpenGraphAction alloc] init]; + action.actionType = actionType; + [action setString:objectID forKey:key]; + return action; +} + ++ (instancetype)actionWithType:(NSString *)actionType objectURL:(NSURL *)objectURL key:(NSString *)key +{ + FBSDKShareOpenGraphAction *action = [[FBSDKShareOpenGraphAction alloc] init]; + action.actionType = actionType; + [action setURL:objectURL forKey:key]; + return action; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + return [FBSDKMath hashWithInteger:[super hash] andInteger:[_actionType hash]]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareOpenGraphAction class]]) { + return NO; + } + return [self isEqualToShareOpenGraphAction:(FBSDKShareOpenGraphAction *)object]; +} + +- (BOOL)isEqualToShareOpenGraphAction:(FBSDKShareOpenGraphAction *)action +{ + return (action && + [FBSDKInternalUtility object:_actionType isEqualToObject:action.actionType] && + [self isEqualToShareOpenGraphValueContainer:action]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) { + _actionType = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_OPEN_GRAPH_ACTION_TYPE_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [super encodeWithCoder:encoder]; + [encoder encodeObject:_actionType forKey:FBSDK_SHARE_OPEN_GRAPH_ACTION_TYPE_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareOpenGraphAction *copy = [[FBSDKShareOpenGraphAction alloc] init]; + copy->_actionType = [_actionType copy]; + [copy parseProperties:[self allProperties]]; + return copy; +} + +#pragma mark - Internal Methods + +- (BOOL)requireKeyNamespace +{ + return NO; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h new file mode 100644 index 0000000..4393b0c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @abstract A model for Open Graph content to be shared. + */ +@interface FBSDKShareOpenGraphContent : NSObject + +/*! + @abstract Open Graph Action to be shared. + @return The action + */ +@property (nonatomic, copy) FBSDKShareOpenGraphAction *action; + +/*! + @abstract Property name that points to the primary Open Graph Object in the action. + @discussion The value that this action points to will be use for rendering the preview for the share. + @return The property name for the Open Graph Object in the action + */ +@property (nonatomic, copy) NSString *previewPropertyName; + +/*! + @abstract Compares the receiver to another Open Graph content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphContent:(FBSDKShareOpenGraphContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.m new file mode 100644 index 0000000..8f3de20 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.m @@ -0,0 +1,132 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareOpenGraphContent.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY @"action" +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY @"contentURL" +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY @"peopleIDs" +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY @"placeID" +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PREVIEW_PROPERTY_NAME_KEY @"previewPropertyName" +#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_REF_KEY @"ref" + +@implementation FBSDKShareOpenGraphContent + +#pragma mark - Properties + +@synthesize contentURL = _contentURL; +@synthesize peopleIDs = _peopleIDs; +@synthesize placeID = _placeID; +@synthesize ref = _ref; + +- (void)setPeopleIDs:(NSArray *)peopleIDs +{ + [FBSDKShareUtility assertCollection:peopleIDs ofClass:[NSString class] name:@"peopleIDs"]; + if (![FBSDKInternalUtility object:_peopleIDs isEqualToObject:peopleIDs]) { + _peopleIDs = [peopleIDs copy]; + } +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_action hash], + [_contentURL hash], + [_peopleIDs hash], + [_placeID hash], + [_previewPropertyName hash], + [_ref hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + return NO; + } + return [self isEqualToShareOpenGraphContent:(FBSDKShareOpenGraphContent *)object]; +} + +- (BOOL)isEqualToShareOpenGraphContent:(FBSDKShareOpenGraphContent *)content +{ + return (content && + [FBSDKInternalUtility object:_action isEqualToObject:content.action] && + [FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] && + [FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] && + [FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] && + [FBSDKInternalUtility object:_previewPropertyName isEqualToObject:content.previewPropertyName] && + [FBSDKInternalUtility object:_ref isEqualToObject:content.ref]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super init])) { + _action = [decoder decodeObjectOfClass:[FBSDKShareOpenGraphAction class] + forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY]; + _contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY]; + _peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY]; + _placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY]; + _previewPropertyName = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PREVIEW_PROPERTY_NAME_KEY]; + _ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_REF_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_action forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY]; + [encoder encodeObject:_contentURL forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY]; + [encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY]; + [encoder encodeObject:_placeID forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY]; + [encoder encodeObject:_previewPropertyName forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PREVIEW_PROPERTY_NAME_KEY]; + [encoder encodeObject:_ref forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_REF_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareOpenGraphContent *copy = [[FBSDKShareOpenGraphContent alloc] init]; + copy->_action = [_action copy]; + copy->_contentURL = [_contentURL copy]; + copy->_peopleIDs = [_peopleIDs copy]; + copy->_placeID = [_placeID copy]; + copy->_previewPropertyName = [_previewPropertyName copy]; + copy->_ref = [_ref copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h new file mode 100644 index 0000000..3a1e1a5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract An Open Graph Object for sharing. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`, + and `og:type` is required. + + See https://developers.facebook.com/docs/sharing/opengraph/object-properties for other properties. + + You can specify nested namespaces inline to define complex properties. For example, the following + code will generate a fitness.course object with a location: + + FBSDKShareOpenGraphObject *course = [FBSDKShareOpenGraphObject objectWithProperties: + @{ + @"og:type": @"fitness.course", + @"og:title": @"Sample course", + @"fitness:metrics:location:latitude": @"41.40338", + @"fitness:metrics:location:longitude": @"2.17403", + }]; + */ +@interface FBSDKShareOpenGraphObject : FBSDKShareOpenGraphValueContainer + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param properties Properties for the Open Graph object, which will be parsed into the proper models + */ ++ (instancetype)objectWithProperties:(NSDictionary *)properties; + +/*! + @abstract Compares the receiver to another Open Graph Object. + @param object The other object + @return YES if the receiver's values are equal to the other object's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphObject:(FBSDKShareOpenGraphObject *)object; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.m new file mode 100644 index 0000000..eb6a1c5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.m @@ -0,0 +1,63 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareOpenGraphObject.h" + +#import "FBSDKShareOpenGraphValueContainer+Internal.h" + +#define FBSDK_SHARE_OPEN_GRAPH_OBJECT_DATA_KEY @"data" + +@implementation FBSDKShareOpenGraphObject + +#pragma mark - Class Methods + ++ (instancetype)objectWithProperties:(NSDictionary *)properties +{ + FBSDKShareOpenGraphObject *object = [[FBSDKShareOpenGraphObject alloc] init]; + [object parseProperties:properties]; + return object; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareOpenGraphObject class]]) { + return NO; + } + return [self isEqualToShareOpenGraphObject:(FBSDKShareOpenGraphObject *)object]; +} + +- (BOOL)isEqualToShareOpenGraphObject:(FBSDKShareOpenGraphObject *)object +{ + return [self isEqualToShareOpenGraphValueContainer:object]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareOpenGraphObject *copy = [[FBSDKShareOpenGraphObject alloc] init]; + [copy parseProperties:[self allProperties]]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h new file mode 100644 index 0000000..4687828 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h @@ -0,0 +1,160 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKShareOpenGraphObject; +@class FBSDKSharePhoto; + +/*! + @abstract Protocol defining operations on open graph actions and objects. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`. + */ +@protocol FBSDKShareOpenGraphValueContaining + +/*! + @abstract Gets an NSArray out of the receiver. + @param key The key for the value + @return The NSArray value or nil + */ +- (NSArray *)arrayForKey:(NSString *)key; + +/*! + @abstract Applies a given block object to the entries of the receiver. + @param block A block object to operate on entries in the receiver + */ +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, id object, BOOL *stop))block; + +/*! + @abstract Returns an enumerator object that lets you access each key in the receiver. + @return An enumerator object that lets you access each key in the receiver + */ +- (NSEnumerator *)keyEnumerator; + +/*! + @abstract Gets an NSNumber out of the receiver. + @param key The key for the value + @return The NSNumber value or nil + */ +- (NSNumber *)numberForKey:(NSString *)key; + +/*! + @abstract Returns an enumerator object that lets you access each value in the receiver. + @return An enumerator object that lets you access each value in the receiver + */ +- (NSEnumerator *)objectEnumerator; + +/*! + @abstract Gets an FBSDKShareOpenGraphObject out of the receiver. + @param key The key for the value + @return The FBSDKShareOpenGraphObject value or nil + */ +- (FBSDKShareOpenGraphObject *)objectForKey:(NSString *)key; + +/*! + @abstract Enables subscript access to the values in the receiver. + @param key The key for the value + @return The value + */ +- (id)objectForKeyedSubscript:(NSString *)key; + +/*! + @abstract Parses properties out of a dictionary into the receiver. + @param properties The properties to parse. + */ +- (void)parseProperties:(NSDictionary *)properties; + +/*! + @abstract Gets an FBSDKSharePhoto out of the receiver. + @param key The key for the value + @return The FBSDKSharePhoto value or nil + */ +- (FBSDKSharePhoto *)photoForKey:(NSString *)key; + +/*! + @abstract Removes a value from the receiver for the specified key. + @param key The key for the value + */ +- (void)removeObjectForKey:(NSString *)key; + +/*! + @abstract Sets an NSArray on the receiver. + @discussion This method will throw if the array contains any values that is not an NSNumber, NSString, NSURL, + FBSDKSharePhoto or FBSDKShareOpenGraphObject. + @param array The NSArray value + @param key The key for the value + */ +- (void)setArray:(NSArray *)array forKey:(NSString *)key; + +/*! + @abstract Sets an NSNumber on the receiver. + @param number The NSNumber value + @param key The key for the value + */ +- (void)setNumber:(NSNumber *)number forKey:(NSString *)key; + +/*! + @abstract Sets an FBSDKShareOpenGraphObject on the receiver. + @param object The FBSDKShareOpenGraphObject value + @param key The key for the value + */ +- (void)setObject:(FBSDKShareOpenGraphObject *)object forKey:(NSString *)key; + +/*! + @abstract Sets an FBSDKSharePhoto on the receiver. + @param photo The FBSDKSharePhoto value + @param key The key for the value + */ +- (void)setPhoto:(FBSDKSharePhoto *)photo forKey:(NSString *)key; + +/*! + @abstract Sets an NSString on the receiver. + @param string The NSString value + @param key The key for the value + */ +- (void)setString:(NSString *)string forKey:(NSString *)key; + +/*! + @abstract Sets an NSURL on the receiver. + @param URL The NSURL value + @param key The key for the value + */ +- (void)setURL:(NSURL *)URL forKey:(NSString *)key; + +/*! + @abstract Gets an NSString out of the receiver. + @param key The key for the value + @return The NSString value or nil + */ +- (NSString *)stringForKey:(NSString *)key; + +/*! + @abstract Gets an NSURL out of the receiver. + @param key The key for the value + @return The NSURL value or nil + */ +- (NSURL *)URLForKey:(NSString *)key; + +@end + +/*! + @abstract A base class to container Open Graph values. + */ +@interface FBSDKShareOpenGraphValueContainer : NSObject + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.m new file mode 100644 index 0000000..d19ce08 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.m @@ -0,0 +1,238 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareOpenGraphValueContainer.h" +#import "FBSDKShareOpenGraphValueContainer+Internal.h" + +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareOpenGraphObject.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_SHARE_OPEN_GRAPH_VALUE_CONTAINER_PROPERTIES_KEY @"properties" + +@implementation FBSDKShareOpenGraphValueContainer +{ + NSMutableDictionary *_properties; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + _properties = [[NSMutableDictionary alloc] init]; + } + return self; +} + +#pragma mark - Public Methods + +- (NSDictionary *)allData +{ + return [_properties copy]; +} + +- (NSArray *)arrayForKey:(NSString *)key +{ + return [self _valueOfClass:[NSArray class] forKey:key]; +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, id object, BOOL *stop))block +{ + [_properties enumerateKeysAndObjectsUsingBlock:block]; +} + +- (NSEnumerator *)keyEnumerator +{ + return [_properties keyEnumerator]; +} + +- (NSNumber *)numberForKey:(NSString *)key +{ + return [self _valueOfClass:[NSNumber class] forKey:key]; +} + +- (NSEnumerator *)objectEnumerator +{ + return [_properties objectEnumerator]; +} + +- (FBSDKShareOpenGraphObject *)objectForKey:(NSString *)key +{ + return [self _valueOfClass:[FBSDKShareOpenGraphObject class] forKey:key]; +} + +- (id)objectForKeyedSubscript:(id)key +{ + return [self _valueForKey:key]; +} + +- (void)parseProperties:(NSDictionary *)properties +{ + [FBSDKShareUtility assertOpenGraphValues:properties requireKeyNamespace:[self requireKeyNamespace]]; + [_properties addEntriesFromDictionary:[FBSDKShareUtility convertOpenGraphValues:properties]]; +} + +- (FBSDKSharePhoto *)photoForKey:(NSString *)key +{ + return [self _valueOfClass:[FBSDKSharePhoto class] forKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key +{ + [_properties removeObjectForKey:key]; +} + +- (void)setArray:(NSArray *)array forKey:(NSString *)key +{ + [self _setValue:array forKey:key]; +} + +- (void)setNumber:(NSNumber *)number forKey:(NSString *)key +{ + [self _setValue:number forKey:key]; +} + +- (void)setObject:(FBSDKShareOpenGraphObject *)object forKey:(NSString *)key +{ + [self _setValue:object forKey:key]; +} + +- (void)setPhoto:(FBSDKSharePhoto *)photo forKey:(NSString *)key +{ + [self _setValue:photo forKey:key]; +} + +- (void)setString:(NSString *)string forKey:(NSString *)key +{ + [self _setValue:string forKey:key]; +} + +- (void)setURL:(NSURL *)URL forKey:(NSString *)key +{ + [self _setValue:URL forKey:key]; +} +- (NSString *)stringForKey:(NSString *)key +{ + return [self _valueOfClass:[NSString class] forKey:key]; +} + +- (NSURL *)URLForKey:(NSString *)key +{ + return [self _valueOfClass:[NSURL class] forKey:key]; +} + +- (id)valueForKey:(NSString *)key +{ + return [self _valueForKey:key] ?: [super valueForKey:key]; +} + +#pragma mark - Internal Methods + +- (NSDictionary *)allProperties +{ + return _properties; +} + +- (BOOL)requireKeyNamespace +{ + return YES; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + return [_properties hash]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareOpenGraphValueContainer class]]) { + return NO; + } + return [self isEqualToShareOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object]; +} + +- (BOOL)isEqualToShareOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object +{ + return [FBSDKInternalUtility object:_properties isEqualToObject:[object allProperties]]; +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + NSSet *classes = [NSSet setWithObjects: + [NSArray class], + [NSDictionary class], + [FBSDKShareOpenGraphObject class], + [FBSDKSharePhoto class], + nil]; + NSDictionary *properties = [decoder decodeObjectOfClasses:classes + forKey:FBSDK_SHARE_OPEN_GRAPH_VALUE_CONTAINER_PROPERTIES_KEY]; + if ([properties count]) { + [self parseProperties:properties]; + } + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_properties forKey:FBSDK_SHARE_OPEN_GRAPH_VALUE_CONTAINER_PROPERTIES_KEY]; +} + +#pragma mark - Helper Methods + +- (void)_setValue:(id)value forKey:(NSString *)key +{ + [FBSDKShareUtility assertOpenGraphKey:key requireNamespace:[self requireKeyNamespace]]; + [FBSDKShareUtility assertOpenGraphValue:value]; + if (value) { + _properties[key] = value; + } else { + [self removeObjectForKey:key]; + } +} + +- (id)_valueForKey:(id)key +{ + key = [FBSDKTypeUtility stringValue:key]; + return (key ? [FBSDKTypeUtility objectValue:_properties[key]] : nil); +} + +- (id)_valueOfClass:(__unsafe_unretained Class)cls forKey:(NSString *)key +{ + id value = [self _valueForKey:key]; + return ([value isKindOfClass:cls] ? value : nil); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h new file mode 100644 index 0000000..c3b91a6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h @@ -0,0 +1,80 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A photo for sharing. + */ +@interface FBSDKSharePhoto : NSObject + +/*! + @abstract Convenience method to build a new photo object with an image. + @param image If the photo is resident in memory, this method supplies the data + @param userGenerated Specifies whether the photo represented by the receiver was generated by the user or by the + application + */ ++ (instancetype)photoWithImage:(UIImage *)image userGenerated:(BOOL)userGenerated; + +/*! + @abstract Convenience method to build a new photo object with an imageURL. + @param imageURL The URL to the photo + @param userGenerated Specifies whether the photo represented by the receiver was generated by the user or by the + application + @discussion This method should only be used when adding photo content to open graph stories. + For example, if you're trying to share a photo from the web by itself, download the image and use + `photoWithImage:userGenerated:` instead. + */ ++ (instancetype)photoWithImageURL:(NSURL *)imageURL userGenerated:(BOOL)userGenerated; + +/*! + @abstract If the photo is resident in memory, this method supplies the data. + @return UIImage representation of the photo + */ +@property (nonatomic, strong) UIImage *image; + +/*! + @abstract The URL to the photo. + @return URL that points to a network location or the location of the photo on disk + */ +@property (nonatomic, copy) NSURL *imageURL; + +/*! + @abstract Specifies whether the photo represented by the receiver was generated by the user or by the application. + @return YES if the photo is user-generated, otherwise NO + */ +@property (nonatomic, assign, getter=isUserGenerated) BOOL userGenerated; + +/*! + @abstract Compares the receiver to another photo. + @param photo The other photo + @return YES if the receiver's values are equal to the other photo's values; otherwise NO + */ +- (BOOL)isEqualToSharePhoto:(FBSDKSharePhoto *)photo; + +/*! + @abstract The user generated caption for the photo. Note that the 'caption' must come from + * the user, as pre-filled content is forbidden by the Platform Policies (2.3). + @return the Photo's caption if exists else returns null. + */ +@property (nonatomic, copy) NSString *caption; + + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.m new file mode 100644 index 0000000..27c67b5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.m @@ -0,0 +1,119 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKSharePhoto.h" + +#import "FBSDKCoreKit+Internal.h" + +#define FBSDK_SHARE_PHOTO_IMAGE_KEY @"image" +#define FBSDK_SHARE_PHOTO_IMAGE_URL_KEY @"imageURL" +#define FBSDK_SHARE_PHOTO_USER_GENERATED_KEY @"userGenerated" +#define FBSDK_SHARE_PHOTO_CAPTION_KEY @"caption" + +@implementation FBSDKSharePhoto + +#pragma mark - Class Methods + ++ (instancetype)photoWithImage:(UIImage *)image userGenerated:(BOOL)userGenerated +{ + FBSDKSharePhoto *photo = [[self alloc] init]; + photo.image = image; + photo.userGenerated = userGenerated; + return photo; +} + ++ (instancetype)photoWithImageURL:(NSURL *)imageURL userGenerated:(BOOL)userGenerated +{ + FBSDKSharePhoto *photo = [[self alloc] init]; + photo.imageURL = imageURL; + photo.userGenerated = userGenerated; + return photo; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_image hash], + [_imageURL hash], + [_caption hash], + (_userGenerated ? 1u : 0u) + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKSharePhoto class]]) { + return NO; + } + return [self isEqualToSharePhoto:(FBSDKSharePhoto *)object]; +} + +- (BOOL)isEqualToSharePhoto:(FBSDKSharePhoto *)photo +{ + return (photo && + (_userGenerated == photo.userGenerated) && + [FBSDKInternalUtility object:_image isEqualToObject:photo.image] && + [FBSDKInternalUtility object:_imageURL isEqualToObject:photo.imageURL] && + [FBSDKInternalUtility object:_caption isEqualToObject:photo.caption]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _image = [decoder decodeObjectOfClass:[UIImage class] forKey:FBSDK_SHARE_PHOTO_IMAGE_KEY]; + _imageURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_PHOTO_IMAGE_URL_KEY]; + _userGenerated = [decoder decodeBoolForKey:FBSDK_SHARE_PHOTO_USER_GENERATED_KEY]; + _caption = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_PHOTO_CAPTION_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_image forKey:FBSDK_SHARE_PHOTO_IMAGE_KEY]; + [encoder encodeObject:_imageURL forKey:FBSDK_SHARE_PHOTO_IMAGE_URL_KEY]; + [encoder encodeBool:_userGenerated forKey:FBSDK_SHARE_PHOTO_USER_GENERATED_KEY]; + [encoder encodeObject:_caption forKey:FBSDK_SHARE_PHOTO_CAPTION_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKSharePhoto *copy = [[FBSDKSharePhoto alloc] init]; + copy->_image = [_image copy]; + copy->_imageURL = [_imageURL copy]; + copy->_userGenerated = _userGenerated; + copy->_caption = [_caption copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h new file mode 100644 index 0000000..1fd0782 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h @@ -0,0 +1,41 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for photo content to be shared. + */ +@interface FBSDKSharePhotoContent : NSObject + +/*! + @abstract Photos to be shared. + @return Array of the photos (FBSDKSharePhoto) + */ +@property (nonatomic, copy) NSArray *photos; + +/*! + @abstract Compares the receiver to another photo content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToSharePhotoContent:(FBSDKSharePhotoContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.m new file mode 100644 index 0000000..b26b468 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.m @@ -0,0 +1,133 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKSharePhotoContent.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY @"contentURL" +#define FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY @"peopleIDs" +#define FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY @"photos" +#define FBSDK_SHARE_PHOTO_CONTENT_PLACE_ID_KEY @"placeID" +#define FBSDK_SHARE_PHOTO_CONTENT_REF_KEY @"ref" + +@implementation FBSDKSharePhotoContent + +#pragma mark - Properties + +@synthesize contentURL = _contentURL; +@synthesize peopleIDs = _peopleIDs; +@synthesize placeID = _placeID; +@synthesize ref = _ref; + +- (void)setPeopleIDs:(NSArray *)peopleIDs +{ + [FBSDKShareUtility assertCollection:peopleIDs ofClass:[NSString class] name:@"peopleIDs"]; + if (![FBSDKInternalUtility object:_peopleIDs isEqualToObject:peopleIDs]) { + _peopleIDs = [peopleIDs copy]; + } +} + +- (void)setPhotos:(NSArray *)photos +{ + [FBSDKShareUtility assertCollection:photos ofClass:[FBSDKSharePhoto class] name:@"photos"]; + if (![FBSDKInternalUtility object:_photos isEqualToObject:photos]) { + _photos = [photos copy]; + } +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_contentURL hash], + [_peopleIDs hash], + [_photos hash], + [_placeID hash], + [_ref hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKSharePhotoContent class]]) { + return NO; + } + return [self isEqualToSharePhotoContent:(FBSDKSharePhotoContent *)object]; +} + +- (BOOL)isEqualToSharePhotoContent:(FBSDKSharePhotoContent *)content +{ + return (content && + [FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] && + [FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] && + [FBSDKInternalUtility object:_photos isEqualToObject:content.photos] && + [FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] && + [FBSDKInternalUtility object:_ref isEqualToObject:content.ref]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY]; + _peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY]; + NSSet *classes = [NSSet setWithObjects:[NSArray class], [FBSDKSharePhoto class], nil]; + _photos = [decoder decodeObjectOfClasses:classes forKey:FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY]; + _placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_PHOTO_CONTENT_PLACE_ID_KEY]; + _ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_PHOTO_CONTENT_REF_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_contentURL forKey:FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY]; + [encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY]; + [encoder encodeObject:_photos forKey:FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY]; + [encoder encodeObject:_placeID forKey:FBSDK_SHARE_PHOTO_CONTENT_PLACE_ID_KEY]; + [encoder encodeObject:_ref forKey:FBSDK_SHARE_PHOTO_CONTENT_REF_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKSharePhotoContent *copy = [[FBSDKSharePhotoContent alloc] init]; + copy->_contentURL = [_contentURL copy]; + copy->_peopleIDs = [_peopleIDs copy]; + copy->_photos = [_photos copy]; + copy->_placeID = [_placeID copy]; + copy->_ref = [_ref copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h new file mode 100644 index 0000000..2b6ae0c --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A video for sharing. + */ +@interface FBSDKShareVideo : NSObject + +/*! + @abstract Convenience method to build a new video object with a videoURL. + @param videoURL The URL to the video + application + */ ++ (instancetype)videoWithVideoURL:(NSURL *)videoURL; + +/*! + @abstract The file URL to the video. + @return URL that points to the location of the video on disk + */ +@property (nonatomic, copy) NSURL *videoURL; + +/*! + @abstract Compares the receiver to another video. + @param video The other video + @return YES if the receiver's values are equal to the other video's values; otherwise NO + */ +- (BOOL)isEqualToShareVideo:(FBSDKShareVideo *)video; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.m new file mode 100644 index 0000000..ad8e10f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.m @@ -0,0 +1,89 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareVideo.h" + +#import "FBSDKCoreKit+Internal.h" + +#define FBSDK_SHARE_VIDEO_URL_KEY @"videoURL" + +@implementation FBSDKShareVideo + +#pragma mark - Class Methods + ++ (instancetype)videoWithVideoURL:(NSURL *)videoURL +{ + FBSDKShareVideo *video = [[FBSDKShareVideo alloc] init]; + video.videoURL = videoURL; + return video; +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + return [_videoURL hash]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareVideo class]]) { + return NO; + } + return [self isEqualToShareVideo:(FBSDKShareVideo *)object]; +} + +- (BOOL)isEqualToShareVideo:(FBSDKShareVideo *)video +{ + return (video && + [FBSDKInternalUtility object:_videoURL isEqualToObject:video.videoURL]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _videoURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_VIDEO_URL_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_videoURL forKey:FBSDK_SHARE_VIDEO_URL_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareVideo *copy = [[FBSDKShareVideo alloc] init]; + copy->_videoURL = [_videoURL copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h new file mode 100644 index 0000000..bead676 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract A model for video content to be shared. + */ +@interface FBSDKShareVideoContent : NSObject + +/*! + @abstract The photo that represents the video. + @return The photo + */ +@property (nonatomic, copy) FBSDKSharePhoto *previewPhoto; + +/*! + @abstract The video to be shared. + @return The video + */ +@property (nonatomic, copy) FBSDKShareVideo *video; + +/*! + @abstract Compares the receiver to another video content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareVideoContent:(FBSDKShareVideoContent *)content; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.m new file mode 100644 index 0000000..90b3938 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.m @@ -0,0 +1,130 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareVideoContent.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareUtility.h" + +#define FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY @"contentURL" +#define FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY @"peopleIDs" +#define FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY @"placeID" +#define FBSDK_SHARE_VIDEO_CONTENT_PREVIEW_PHOTO_KEY @"previewPhoto" +#define FBSDK_SHARE_VIDEO_CONTENT_REF_KEY @"ref" +#define FBSDK_SHARE_VIDEO_CONTENT_VIDEO_KEY @"video" + +@implementation FBSDKShareVideoContent + +#pragma mark - Properties + +@synthesize contentURL = _contentURL; +@synthesize peopleIDs = _peopleIDs; +@synthesize placeID = _placeID; +@synthesize ref = _ref; + +- (void)setPeopleIDs:(NSArray *)peopleIDs +{ + [FBSDKShareUtility assertCollection:peopleIDs ofClass:[NSString class] name:@"peopleIDs"]; + if (![FBSDKInternalUtility object:_peopleIDs isEqualToObject:peopleIDs]) { + _peopleIDs = [peopleIDs copy]; + } +} + +#pragma mark - Equality + +- (NSUInteger)hash +{ + NSUInteger subhashes[] = { + [_contentURL hash], + [_peopleIDs hash], + [_placeID hash], + [_previewPhoto hash], + [_ref hash], + [_video hash], + }; + return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FBSDKShareVideoContent class]]) { + return NO; + } + return [self isEqualToShareVideoContent:(FBSDKShareVideoContent *)object]; +} + +- (BOOL)isEqualToShareVideoContent:(FBSDKShareVideoContent *)content +{ + return (content && + [FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] && + [FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] && + [FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] && + [FBSDKInternalUtility object:_previewPhoto isEqualToObject:content.previewPhoto] && + [FBSDKInternalUtility object:_ref isEqualToObject:content.ref] && + [FBSDKInternalUtility object:_video isEqualToObject:content.video]); +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [self init])) { + _contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY]; + _peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY]; + _placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY]; + _previewPhoto = [decoder decodeObjectOfClass:[FBSDKSharePhoto class] + forKey:FBSDK_SHARE_VIDEO_CONTENT_PREVIEW_PHOTO_KEY]; + _ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_VIDEO_CONTENT_REF_KEY]; + _video = [decoder decodeObjectOfClass:[FBSDKShareVideo class] forKey:FBSDK_SHARE_VIDEO_CONTENT_VIDEO_KEY]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_contentURL forKey:FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY]; + [encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY]; + [encoder encodeObject:_placeID forKey:FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY]; + [encoder encodeObject:_previewPhoto forKey:FBSDK_SHARE_VIDEO_CONTENT_PREVIEW_PHOTO_KEY]; + [encoder encodeObject:_ref forKey:FBSDK_SHARE_VIDEO_CONTENT_REF_KEY]; + [encoder encodeObject:_video forKey:FBSDK_SHARE_VIDEO_CONTENT_VIDEO_KEY]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + FBSDKShareVideoContent *copy = [[FBSDKShareVideoContent alloc] init]; + copy->_contentURL = [_contentURL copy]; + copy->_peopleIDs = [_peopleIDs copy]; + copy->_placeID = [_placeID copy]; + copy->_previewPhoto = [_previewPhoto copy]; + copy->_ref = [_ref copy]; + copy->_video = [_video copy]; + return copy; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h new file mode 100644 index 0000000..d6d373e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h @@ -0,0 +1,110 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKSharingDelegate; + +/*! + @abstract The common interface for components that initiate sharing. + @see FBSDKShareDialog + @see FBSDKMessageDialog + @see FBSDKShareAPI + */ +@protocol FBSDKSharing + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content to be shared. + */ +@property (nonatomic, copy) id shareContent; + +/*! + @abstract A Boolean value that indicates whether the receiver should fail if it finds an error with the share content. + @discussion If NO, the sharer will still be displayed without the data that was mis-configured. For example, an + invalid placeID specified on the shareContent would produce a data error. + */ +@property (nonatomic, assign) BOOL shouldFailOnDataError; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError **)errorRef; + +@end + +/*! + @abstract The common interface for dialogs that initiate sharing. + */ +@protocol FBSDKSharingDialog + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate a share. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see [FBSDKSharing validateWithError:] + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Shows the dialog. + @result YES if the receiver was able to begin sharing, otherwise NO. + */ +- (BOOL)show; + +@end + +/*! + @abstract A delegate for FBSDKSharing. + @discussion The delegate is notified with the results of the sharer as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the sharer may not be able + to distinguish between completion of a share and cancellation. + */ +@protocol FBSDKSharingDelegate + +/*! + @abstract Sent to the delegate when the share completes without error or cancellation. + @param sharer The FBSDKSharing that completed. + @param results The results from the sharer. This may be nil or empty. + */ +- (void)sharer:(id)sharer didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the sharer encounters an error. + @param sharer The FBSDKSharing that completed. + @param error The error. + */ +- (void)sharer:(id)sharer didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the sharer is cancelled. + @param sharer The FBSDKSharing that completed. + */ +- (void)sharerDidCancel:(id)sharer; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h new file mode 100644 index 0000000..a3af423 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The common interface for sharing buttons. + @see FBSDKSendButton + @see FBSDKShareButton + */ +@protocol FBSDKSharingButton + +/*! + @abstract The content to be shared. + */ +@property (nonatomic, copy) id shareContent; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h new file mode 100644 index 0000000..5f70083 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A base interface for content to be shared. + */ +@protocol FBSDKSharingContent + +/*! + @abstract URL for the content being shared. + @discussion This URL will be checked for all link meta tags for linking in platform specific ways. See documentation + for App Links (https://developers.facebook.com/docs/applinks/) + @return URL representation of the content link + */ +@property (nonatomic, copy) NSURL *contentURL; + +/*! + @abstract List of IDs for taggable people to tag with this content. + @description See documentation for Taggable Friends + (https://developers.facebook.com/docs/graph-api/reference/user/taggable_friends) + @return Array of IDs for people to tag (NSString) + */ +@property (nonatomic, copy) NSArray *peopleIDs; + +/*! + @abstract The ID for a place to tag with this content. + @return The ID for the place to tag + */ +@property (nonatomic, copy) NSString *placeID; + +/*! + @abstract A value to be added to the referrer URL when a person follows a link from this shared content on feed. + @return The ref for the content. + */ +@property (nonatomic, copy) NSString *ref; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.h new file mode 100644 index 0000000..06fde34 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKCheckmarkIcon : FBSDKIcon + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.m new file mode 100644 index 0000000..7f4da89 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.m @@ -0,0 +1,43 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKCheckmarkIcon.h" + +@implementation FBSDKCheckmarkIcon + +- (CGPathRef)pathWithSize:(CGSize)size +{ + CGAffineTransform transformValue = CGAffineTransformMakeScale(size.width / 100.0, size.height / 100.0); + CGAffineTransform *transform = &transformValue; + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, transform, 0.0, 50.0); + const CGPoint points[] = { + CGPointMake(12.0, 38.0), + CGPointMake(37.0, 63.0), + CGPointMake(87.0, 13.0), + CGPointMake(99.0, 25.0), + CGPointMake(37.0, 87.0), + CGPointMake(0.0, 48.0), + }; + CGPathAddLines(path, transform, points, sizeof(points) / sizeof(points[0])); + CGPathRef result = CGPathCreateCopy(path); + CGPathRelease(path); + return CFAutorelease(result); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.h new file mode 100644 index 0000000..ad0a20e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKGameRequestFrictionlessRecipientCache : NSObject + +- (BOOL)recipientsAreFrictionless:(id)recipients; +- (void)updateWithResults:(NSDictionary *)results; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.m new file mode 100644 index 0000000..b1551d5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.m @@ -0,0 +1,100 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKGameRequestFrictionlessRecipientCache.h" + +#import + +#import "FBSDKCoreKit+Internal.h" + +@implementation FBSDKGameRequestFrictionlessRecipientCache +{ + NSSet *_recipientIDs; +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + if ((self = [super init])) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_accessTokenDidChangeNotification:) + name:FBSDKAccessTokenDidChangeNotification + object:nil]; + [self _updateCache]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Public API + +- (BOOL)recipientsAreFrictionless:(id)recipients +{ + if (!recipients) { + return NO; + } + NSArray *recipientIDArray = [FBSDKTypeUtility arrayValue:recipients]; + if (!recipientIDArray && [recipients isKindOfClass:[NSString class]]) { + recipientIDArray = [recipients componentsSeparatedByString:@","]; + } + NSSet *recipientIDs = [[NSSet alloc] initWithArray:recipientIDArray]; + return [recipientIDs isSubsetOfSet:_recipientIDs]; +} + +- (void)updateWithResults:(NSDictionary *)results +{ + if ([FBSDKTypeUtility boolValue:results[@"updated_frictionless"]]) { + [self _updateCache]; + } +} + +#pragma mark - Helper Methods + +- (void)_accessTokenDidChangeNotification:(NSNotification *)notification +{ + if (![notification.userInfo[FBSDKAccessTokenDidChangeUserID] boolValue]) { + return; + } + _recipientIDs = nil; + [self _updateCache]; +} + +- (void)_updateCache +{ + if (![FBSDKAccessToken currentAccessToken]) { + _recipientIDs = nil; + } + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me/apprequestformerrecipients" + parameters:@{@"fields":@""} + flags:(FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | + FBSDKGraphRequestFlagDisableErrorRecovery)]; + [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { + if (!error) { + NSArray *items = [FBSDKTypeUtility arrayValue:result[@"data"]]; + NSArray *recipientIDs = [items valueForKey:@"recipient_id"]; + _recipientIDs = [[NSSet alloc] initWithArray:recipientIDs]; + } + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.h new file mode 100644 index 0000000..234c8d6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import + +#import + +FBSDK_EXTERN NSString *const FBSDKLikeActionControllerDidDisableNotification; +FBSDK_EXTERN NSString *const FBSDKLikeActionControllerDidResetNotification; +FBSDK_EXTERN NSString *const FBSDKLikeActionControllerDidUpdateNotification; +FBSDK_EXTERN NSString *const FBSDKLikeActionControllerAnimatedKey; + +@interface FBSDKLikeActionController : NSObject + ++ (BOOL)isDisabled; + +// this method will call beginContentAccess before returning the instance ++ (instancetype)likeActionControllerForObjectID:(NSString *)objectID objectType:(FBSDKLikeObjectType)objectType; + +@property (nonatomic, copy, readonly) NSDate *lastUpdateTime; +@property (nonatomic, copy, readonly) NSString *likeCountString; +@property (nonatomic, copy, readonly) NSString *objectID; +@property (nonatomic, assign, readonly) FBSDKLikeObjectType objectType; +@property (nonatomic, assign, readonly) BOOL objectIsLiked; +@property (nonatomic, copy, readonly) NSString *socialSentence; + +- (void)refresh; +- (void)toggleLikeWithSoundEnabled:(BOOL)soundEnabled analyticsParameters:(NSDictionary *)analyticsParameters fromViewController:(UIViewController *)fromViewController; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.m new file mode 100644 index 0000000..e57d9d0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.m @@ -0,0 +1,1062 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeActionController.h" + +#import + +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLikeActionControllerCache.h" +#import "FBSDKLikeButtonPopWAV.h" +#import "FBSDKLikeDialog.h" + +NSString *const FBSDKLikeActionControllerDidDisableNotification = @"FBSDKLikeActionControllerDidDisableNotification"; +NSString *const FBSDKLikeActionControllerDidResetNotification = @"FBSDKLikeActionControllerDidResetNotification"; +NSString *const FBSDKLikeActionControllerDidUpdateNotification = @"FBSDKLikeActionControllerDidUpdateNotification"; +NSString *const FBSDKLikeActionControllerAnimatedKey = @"animated"; + +#define FBSDK_LIKE_ACTION_CONTROLLER_ANIMATION_DELAY 0.5 +#define FBSDK_LIKE_ACTION_CONTROLLER_SOUND_DELAY 0.15 +#define FBSDK_LIKE_ACTION_CONTROLLER_API_VERSION @"v2.1" + +#define FBSDK_LIKE_ACTION_CONTROLLER_LIKE_PROPERTY_KEY @"like" +#define FBSDK_LIKE_ACTION_CONTROLLER_REFRESH_PROPERTY_KEY @"refresh" + +#define FBSDK_LIKE_ACTION_CONTROLLER_LAST_UPDATE_TIME_KEY @"lastUpdateTime" +#define FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITH_LIKE_KEY @"likeCountStringWithLike" +#define FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITHOUT_LIKE_KEY @"likeCountStringWithoutLike" +#define FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_ID_KEY @"objectID" +#define FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_IS_LIKED_KEY @"objectIsLiked" +#define FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_TYPE_KEY @"objectType" +#define FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITH_LIKE_KEY @"socialSentenceWithLike" +#define FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITHOUT_LIKE_KEY @"socialSentenceWithoutLike" +#define FBSDK_LIKE_ACTION_CONTROLLER_UNLIKE_TOKEN_KEY @"unlikeToken" +#define FBSDK_LIKE_ACTION_CONTROLLER_VERSION_KEY @"version" + +#define FBSDK_LIKE_ACTION_CONTROLLER_VERSION 4 + +typedef NS_ENUM(NSUInteger, FBSDKLikeActionControllerRefreshMode) +{ + FBSDKLikeActionControllerRefreshModeInitial, + FBSDKLikeActionControllerRefreshModeForce, +}; + +typedef NS_ENUM(NSUInteger, FBSDKLikeActionControllerRefreshState) +{ + FBSDKLikeActionControllerRefreshStateNone, + FBSDKLikeActionControllerRefreshStateActive, + FBSDKLikeActionControllerRefreshStateComplete, +}; + +typedef void(^fbsdk_like_action_block)(FBSDKTriStateBOOL objectIsLiked, + NSString *likeCountStringWithLike, + NSString *likeCountStringWithoutLike, + NSString *socialSentenceWithLike, + NSString *socialSentenceWithoutLike, + NSString *unlikeToken, + BOOL likeStateChanged, + BOOL animated); + +typedef void(^fbsdk_like_action_controller_ensure_verified_object_id_completion_block)(NSString *verifiedObjectID); + +@interface FBSDKLikeActionController () +@end + +@implementation FBSDKLikeActionController +{ + FBSDKAccessToken *_accessToken; + NSUInteger _contentAccessCount; + BOOL _contentDiscarded; + NSMapTable *_dialogToAnalyticsParametersMap; + NSMapTable *_dialogToUpdateBlockMap; + NSString *_likeCountStringWithLike; + NSString *_likeCountStringWithoutLike; + BOOL _objectIsLikedIsPending; + BOOL _objectIsLikedOnServer; + BOOL _objectIsPage; + FBSDKLikeActionControllerRefreshState _refreshState; + NSString *_socialSentenceWithLike; + NSString *_socialSentenceWithoutLike; + NSString *_unlikeToken; + NSString *_verifiedObjectID; +} + +#pragma mark - Class Methods + +static BOOL _fbsdkLikeActionControllerDisabled = NO; + ++ (BOOL)isDisabled +{ + return _fbsdkLikeActionControllerDisabled; +} + +static FBSDKLikeActionControllerCache *_cache = nil; + ++ (void)initialize +{ + if (self == [FBSDKLikeActionController class]) { + NSString *accessTokenString = [FBSDKAccessToken currentAccessToken].tokenString; + if (accessTokenString) { + NSURL *fileURL = [self _cacheFileURL]; + NSData *data = [[NSData alloc] initWithContentsOfURL:fileURL]; + if (data) { + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + unarchiver.requiresSecureCoding = YES; + @try { + _cache = [unarchiver decodeObjectOfClass:[FBSDKLikeActionControllerCache class] + forKey:NSKeyedArchiveRootObjectKey]; + } + @catch (NSException *ex) { + // ignore decoding exceptions from previous versions of the archive, etc + } + if (![_cache.accessTokenString isEqualToString:accessTokenString]) { + _cache = nil; + } + } + } + if (!_cache) { + _cache = [[FBSDKLikeActionControllerCache alloc] initWithAccessTokenString:accessTokenString]; + } + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(_accessTokenDidChangeNotification:) + name:FBSDKAccessTokenDidChangeNotification + object:nil]; + [nc addObserver:self + selector:@selector(_applicationWillResignActiveNotification:) + name:UIApplicationWillResignActiveNotification + object:nil]; + } +} + ++ (void)_accessTokenDidChangeNotification:(NSNotification *)notification +{ + NSString *accessTokenString = [FBSDKAccessToken currentAccessToken].tokenString; + if ([accessTokenString isEqualToString:_cache.accessTokenString]) { + return; + } + [_cache resetForAccessTokenString:accessTokenString]; + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKLikeActionControllerDidResetNotification object:nil]; +} + ++ (void)_applicationWillResignActiveNotification:(NSNotification *)notification +{ + NSURL *fileURL = [self _cacheFileURL]; + if (!fileURL) { + return; + } + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:_cache]; + if (data) { + [data writeToURL:fileURL atomically:YES]; + } else { + [[[NSFileManager alloc] init] removeItemAtURL:fileURL error:NULL]; + } +} + ++ (NSURL *)_cacheFileURL +{ + NSURL *directoryURL = [[[NSFileManager alloc] init] URLForDirectory:NSLibraryDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:YES + error:NULL]; + return [directoryURL URLByAppendingPathComponent:@"com-facebook-sdk-like-data"]; +} + + ++ (instancetype)likeActionControllerForObjectID:(NSString *)objectID objectType:(FBSDKLikeObjectType)objectType +{ + if (!objectID) { + return nil; + } + @synchronized(self) { + FBSDKLikeActionController *controller = _cache[objectID]; + FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken]; + if (controller) { + [controller beginContentAccess]; + } else { + controller = [[self alloc] initWithObjectID:objectID objectType:objectType accessToken:accessToken]; + _cache[objectID] = controller; + } + [controller _refreshWithMode:FBSDKLikeActionControllerRefreshModeInitial]; + return controller; + } +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithObjectID:(NSString *)objectID + objectType:(FBSDKLikeObjectType)objectType + accessToken:(FBSDKAccessToken *)accessToken +{ + if ((self = [super init])) { + _objectID = [objectID copy]; + _objectType = objectType; + _accessToken = [accessToken copy]; + + [self _configure]; + } + return self; +} + +- (instancetype)init +{ + return [self initWithObjectID:nil objectType:FBSDKLikeObjectTypeUnknown accessToken:nil]; +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)decoder +{ + if ([decoder decodeIntegerForKey:FBSDK_LIKE_ACTION_CONTROLLER_VERSION_KEY] != FBSDK_LIKE_ACTION_CONTROLLER_VERSION) { + return nil; + } + + NSString *objectID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_ID_KEY]; + if (!objectID) { + return nil; + } + + if ((self = [super init])) { + _objectID = [objectID copy]; + _accessToken = [FBSDKAccessToken currentAccessToken]; + + _lastUpdateTime = [[decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_LIKE_ACTION_CONTROLLER_LAST_UPDATE_TIME_KEY] copy]; + _likeCountStringWithLike = [[decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITH_LIKE_KEY] copy]; + _likeCountStringWithoutLike = [[decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITHOUT_LIKE_KEY] copy]; + _objectIsLiked = [decoder decodeBoolForKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_IS_LIKED_KEY]; + _objectType = [decoder decodeIntegerForKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_TYPE_KEY]; + _socialSentenceWithLike = [[decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITH_LIKE_KEY] copy]; + _socialSentenceWithoutLike = [[decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITHOUT_LIKE_KEY] copy]; + _unlikeToken = [[decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_LIKE_ACTION_CONTROLLER_UNLIKE_TOKEN_KEY] copy]; + + [self _configure]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_lastUpdateTime forKey:FBSDK_LIKE_ACTION_CONTROLLER_LAST_UPDATE_TIME_KEY]; + [coder encodeObject:_likeCountStringWithLike forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITH_LIKE_KEY]; + [coder encodeObject:_likeCountStringWithoutLike + forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_COUNT_STRING_WITHOUT_LIKE_KEY]; + [coder encodeObject:_objectID forKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_ID_KEY]; + [coder encodeBool:_objectIsLiked forKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_IS_LIKED_KEY]; + [coder encodeInteger:_objectType forKey:FBSDK_LIKE_ACTION_CONTROLLER_OBJECT_TYPE_KEY]; + [coder encodeObject:_socialSentenceWithLike forKey:FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITH_LIKE_KEY]; + [coder encodeObject:_socialSentenceWithoutLike forKey:FBSDK_LIKE_ACTION_CONTROLLER_SOCIAL_SENTENCE_WITHOUT_LIKE_KEY]; + [coder encodeObject:_unlikeToken forKey:FBSDK_LIKE_ACTION_CONTROLLER_UNLIKE_TOKEN_KEY]; + [coder encodeInteger:FBSDK_LIKE_ACTION_CONTROLLER_VERSION forKey:FBSDK_LIKE_ACTION_CONTROLLER_VERSION_KEY]; +} + +#pragma mark - Properties + +- (NSString *)likeCountString +{ + return (_objectIsLiked ? _likeCountStringWithLike : _likeCountStringWithoutLike); +} + +- (NSString *)socialSentence +{ + return (_objectIsLiked ? _socialSentenceWithLike : _socialSentenceWithoutLike); +} + +#pragma mark - Public API + +- (void)refresh +{ + [self _refreshWithMode:FBSDKLikeActionControllerRefreshModeForce]; +} + +- (void)toggleLikeWithSoundEnabled:(BOOL)soundEnabled analyticsParameters:(NSDictionary *)analyticsParameters fromViewController:(UIViewController *)fromViewController +{ + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKLikeControlDidTap + valueToSum:nil + parameters:analyticsParameters + accessToken:_accessToken]; + + [self _setExecuting:YES forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_PROPERTY_KEY]; + + BOOL useOGLike = [self _useOGLike]; + BOOL deferred = !useOGLike; + + fbsdk_like_action_block updateBlock = ^(FBSDKTriStateBOOL objectIsLiked, + NSString *likeCountStringWithLike, + NSString *likeCountStringWithoutLike, + NSString *socialSentenceWithLike, + NSString *socialSentenceWithoutLike, + NSString *unlikeToken, + BOOL likeStateChanged, + BOOL animated){ + [self _updateWithObjectIsLiked:objectIsLiked + likeCountStringWithLike:likeCountStringWithLike + likeCountStringWithoutLike:likeCountStringWithoutLike + socialSentenceWithLike:socialSentenceWithLike + socialSentenceWithoutLike:socialSentenceWithoutLike + unlikeToken:unlikeToken + soundEnabled:soundEnabled && likeStateChanged + animated:animated && likeStateChanged + deferred:deferred]; + }; + + BOOL objectIsLiked = !_objectIsLiked; + + // optimistically update if using og.like (FAS will defer the update) + if (useOGLike) { + updateBlock(FBSDKTriStateBOOLFromBOOL(objectIsLiked), + _likeCountStringWithLike, + _likeCountStringWithoutLike, + _socialSentenceWithLike, + _socialSentenceWithoutLike, + _unlikeToken, + YES, + YES); + if (_objectIsLikedIsPending) { + return; + } + } + + if (objectIsLiked) { + if (useOGLike) { + [self _publishLikeWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } else { + [self _presentLikeDialogWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } + } else { + if (useOGLike && _unlikeToken) { + [self _publishUnlikeWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } else { + [self _presentLikeDialogWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } + } +} + +#pragma mark - NSDiscardableContent + +- (BOOL)beginContentAccess +{ + _contentDiscarded = NO; + _contentAccessCount++; + return YES; +} + +- (void)endContentAccess +{ + _contentAccessCount--; +} + +- (void)discardContentIfPossible +{ + if (_contentAccessCount == 0) { + _contentDiscarded = YES; + } +} + +- (BOOL)isContentDiscarded +{ + return _contentDiscarded; +} + +#pragma mark - FBSDKLikeDialogDelegate + +- (void)likeDialog:(FBSDKLikeDialog *)likeDialog didCompleteWithResults:(NSDictionary *)results +{ + FBSDKTriStateBOOL objectIsLiked = FBSDKTriStateBOOLFromNSNumber(results[@"object_is_liked"]); + NSString *likeCountString = [FBSDKTypeUtility stringValue:results[@"like_count_string"]]; + NSString *socialSentence = [FBSDKTypeUtility stringValue:results[@"social_sentence"]]; + NSString *unlikeToken = [FBSDKTypeUtility stringValue:results[@"unlike_token"]]; + BOOL likeStateChanged = ![[FBSDKTypeUtility stringValue:results[@"completionGesture"]] isEqualToString:@"cancel"]; + + fbsdk_like_action_block updateBlock = [_dialogToUpdateBlockMap objectForKey:likeDialog]; + if (updateBlock != NULL) { + // we do not need to specify values for with/without like, since we will fast-app-switch to change + // the value + updateBlock(objectIsLiked, + likeCountString, + likeCountString, + socialSentence, + socialSentence, + unlikeToken, + likeStateChanged, + YES); + } + [self _setExecuting:NO forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_PROPERTY_KEY]; +} + +- (void)likeDialog:(FBSDKLikeDialog *)likeDialog didFailWithError:(NSError *)error +{ + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorUIControlErrors + formatString:@"Like dialog error for %@(%@): %@", _objectID, NSStringFromFBSDKLikeObjectType(_objectType), error]; + + if ([error.userInfo[@"error_reason"] isEqualToString:@"dialog_disabled"]) { + _fbsdkLikeActionControllerDisabled = YES; + + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKLikeControlDidDisable + valueToSum:nil + parameters:[_dialogToAnalyticsParametersMap objectForKey:likeDialog] + accessToken:_accessToken]; + + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKLikeActionControllerDidDisableNotification + object:self + userInfo:nil]; + } else { + FBSDKLikeActionControllerLogError(@"present_dialog", _objectID, _objectType, _accessToken, error); + } + [self _setExecuting:NO forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_PROPERTY_KEY]; +} + +#pragma mark - Helper Methods + +- (void)_configure +{ + NSPointerFunctionsOptions keyOptions = (NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality); + NSPointerFunctionsOptions valueOptions = (NSPointerFunctionsStrongMemory | + NSPointerFunctionsObjectPersonality | + NSPointerFunctionsCopyIn); + _dialogToAnalyticsParametersMap = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; + _dialogToUpdateBlockMap = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; + + _contentAccessCount = 1; +} + +static void FBSDKLikeActionControllerLogError(NSString *currentAction, + NSString *objectID, + FBSDKLikeObjectType objectType, + FBSDKAccessToken *accessToken, + NSError *error) +{ + NSDictionary *parameters = @{ + @"object_id": objectID, + @"object_type": NSStringFromFBSDKLikeObjectType(objectType), + @"current_action": currentAction, + @"error": [error description] ?: @"", + }; + NSString *eventName = ([FBSDKError errorIsNetworkError:error] ? + FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable : + FBSDKAppEventNameFBSDKLikeControlError); + [FBSDKAppEvents logImplicitEvent:eventName + valueToSum:nil + parameters:parameters + accessToken:accessToken]; +} + +typedef void(^fbsdk_like_action_controller_get_engagement_completion_block)(BOOL success, + NSString *likeCountStringWithLike, + NSString *likeCountStringWithoutLike, + NSString *socialSentenceWithLike, + NSString *socialSentenceWithoutLike); +static void FBSDKLikeActionControllerAddGetEngagementRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + FBSDKLikeObjectType objectType, + fbsdk_like_action_controller_get_engagement_completion_block completionHandler) +{ + if (completionHandler == NULL) { + return; + } + NSString *fields = @"engagement.fields(count_string_with_like,count_string_without_like,social_sentence_with_like," + @"social_sentence_without_like)"; + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:objectID + parameters:@{ @"fields": fields } + tokenString:accessToken.tokenString + HTTPMethod:@"GET" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + BOOL success = NO; + NSString *likeCountStringWithLike = nil; + NSString *likeCountStringWithoutLike = nil; + NSString *socialSentenceWithLike = nil; + NSString *socialSentenceWithoutLike = nil; + if (error) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorUIControlErrors + formatString:@"Error fetching engagement for %@ (%@): %@", + objectID, + NSStringFromFBSDKLikeObjectType(objectType), + error]; + FBSDKLikeActionControllerLogError(@"get_engagement", objectID, objectType, accessToken, error); + } else { + success = YES; + result = [FBSDKTypeUtility dictionaryValue:result]; + likeCountStringWithLike = [FBSDKTypeUtility stringValue:[result valueForKeyPath:@"engagement.count_string_with_like"]]; + likeCountStringWithoutLike = [FBSDKTypeUtility stringValue:[result valueForKeyPath:@"engagement.count_string_without_like"]]; + socialSentenceWithLike = [FBSDKTypeUtility stringValue:[result valueForKeyPath:@"engagement.social_sentence_with_like"]]; + socialSentenceWithoutLike = [FBSDKTypeUtility stringValue:[result valueForKeyPath:@"engagement.social_sentence_without_like"]]; + } + completionHandler(success, + likeCountStringWithLike, + likeCountStringWithoutLike, + socialSentenceWithLike, + socialSentenceWithoutLike); + }]; +} + +typedef void(^fbsdk_like_action_controller_get_object_id_completion_block)(BOOL success, + NSString *verifiedObjectID, + BOOL objectIsPage); +static void FBSDKLikeActionControllerAddGetObjectIDRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + fbsdk_like_action_controller_get_object_id_completion_block completionHandler) +{ + if (completionHandler == NULL) { + return; + } + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"" + parameters:@{ + @"fields": @"id", + @"id": objectID, + @"metadata": @"1", + @"type": @"og", + } + tokenString:accessToken.tokenString + HTTPMethod:@"GET" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + result = [FBSDKTypeUtility dictionaryValue:result]; + NSString *verifiedObjectID = [FBSDKTypeUtility stringValue:result[@"id"]]; + BOOL objectIsPage = [FBSDKTypeUtility boolValue:[result valueForKeyPath:@"metadata.type"]]; + completionHandler(verifiedObjectID != nil, verifiedObjectID, objectIsPage); + }]; +} + +static void FBSDKLikeActionControllerAddGetObjectIDWithObjectURLRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + fbsdk_like_action_controller_get_object_id_completion_block completionHandler) +{ + if (completionHandler == NULL) { + return; + } + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"" + parameters:@{ + @"fields": @"og_object.fields(id)", + @"id": objectID, + } + tokenString:accessToken.tokenString + HTTPMethod:@"GET" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + result = [FBSDKTypeUtility dictionaryValue:result]; + NSString *verifiedObjectID = [FBSDKTypeUtility stringValue:[result valueForKeyPath:@"og_object.id"]]; + completionHandler(verifiedObjectID != nil, verifiedObjectID, NO); + }]; +} + +typedef void(^fbsdk_like_action_controller_get_og_object_like_completion_block)(BOOL success, + FBSDKTriStateBOOL objectIsLiked, + NSString *unlikeToken); +static void FBSDKLikeActionControllerAddGetOGObjectLikeRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + FBSDKLikeObjectType objectType, + fbsdk_like_action_controller_get_og_object_like_completion_block completionHandler) +{ + if (completionHandler == NULL) { + return; + } + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me/og.likes" + parameters:@{ + @"fields": @"id,application", + @"object": objectID, + } + tokenString:accessToken.tokenString + HTTPMethod:@"GET" + flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery]; + + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + BOOL success = NO; + FBSDKTriStateBOOL objectIsLiked = FBSDKTriStateBOOLValueUnknown; + NSString *unlikeToken = nil; + if (error) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorUIControlErrors + formatString:@"Error fetching like state for %@(%@): %@", objectID, NSStringFromFBSDKLikeObjectType(objectType), error]; + FBSDKLikeActionControllerLogError(@"get_og_object_like", objectID, objectType, accessToken, error); + } else { + success = YES; + result = [FBSDKTypeUtility dictionaryValue:result]; + NSArray *dataSet = [FBSDKTypeUtility arrayValue:result[@"data"]]; + for (NSDictionary *data in dataSet) { + objectIsLiked = FBSDKTriStateBOOLValueYES; + NSString *applicationID = [FBSDKTypeUtility stringValue:[data valueForKeyPath:@"application.id"]]; + if ([accessToken.appID isEqualToString:applicationID]) { + unlikeToken = [FBSDKTypeUtility stringValue:data[@"id"]]; + break; + } + } + } + completionHandler(success, objectIsLiked, unlikeToken); + }]; +} + +typedef void(^fbsdk_like_action_controller_publish_like_completion_block)(BOOL success, NSString *unlikeToken); +static void FBSDKLikeActionControllerAddPublishLikeRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + FBSDKLikeObjectType objectType, + fbsdk_like_action_controller_publish_like_completion_block completionHandler) +{ + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me/og.likes" + parameters:@{ @"object": objectID } + tokenString:accessToken.tokenString + version:nil + HTTPMethod:@"POST"]; + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + BOOL success = NO; + NSString *unlikeToken = nil; + if (error) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorUIControlErrors + formatString:@"Error liking object %@(%@): %@", objectID, NSStringFromFBSDKLikeObjectType(objectType), error]; + FBSDKLikeActionControllerLogError(@"publish_like", objectID, objectType, accessToken, error); + } else { + success = YES; + result = [FBSDKTypeUtility dictionaryValue:result]; + unlikeToken = [FBSDKTypeUtility stringValue:result[@"id"]]; + } + if (completionHandler != NULL) { + completionHandler(success, unlikeToken); + } + }]; +} + +typedef void(^fbsdk_like_action_controller_publish_unlike_completion_block)(BOOL success); +static void FBSDKLikeActionControllerAddPublishUnlikeRequest(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *unlikeToken, + FBSDKLikeObjectType objectType, + fbsdk_like_action_controller_publish_unlike_completion_block completionHandler) +{ + FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:unlikeToken + parameters:nil + tokenString:accessToken.tokenString + version:nil + HTTPMethod:@"DELETE"]; + [connection addRequest:request completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) { + BOOL success = NO; + if (error) { + [FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorUIControlErrors + formatString:@"Error unliking object with unlike token %@(%@): %@", unlikeToken, NSStringFromFBSDKLikeObjectType(objectType), error]; + FBSDKLikeActionControllerLogError(@"publish_unlike", unlikeToken, objectType, accessToken, error); + } else { + success = YES; + } + if (completionHandler != NULL) { + completionHandler(success); + } + }]; +} + +static void FBSDKLikeActionControllerAddRefreshRequests(FBSDKAccessToken *accessToken, + FBSDKGraphRequestConnection *connection, + NSString *objectID, + FBSDKLikeObjectType objectType, + fbsdk_like_action_block completionHandler) +{ + if (completionHandler == NULL) { + return; + } + __block FBSDKTriStateBOOL objectIsLiked = FBSDKTriStateBOOLValueUnknown; + __block NSString *likeCountStringWithLike = nil; + __block NSString *likeCountStringWithoutLike = nil; + __block NSString *socialSentenceWithLike = nil; + __block NSString *socialSentenceWithoutLike = nil; + __block NSString *unlikeToken = nil; + + void(^handleResults)(void) = ^{ + completionHandler(objectIsLiked, + likeCountStringWithLike, + likeCountStringWithoutLike, + socialSentenceWithLike, + socialSentenceWithoutLike, + unlikeToken, + NO, + NO); + }; + + fbsdk_like_action_controller_get_og_object_like_completion_block getLikeStateCompletionBlock = ^(BOOL success, + FBSDKTriStateBOOL innerObjectIsLiked, + NSString *innerUnlikeToken) { + if (success) { + objectIsLiked = innerObjectIsLiked; + if (innerUnlikeToken) { + unlikeToken = [innerUnlikeToken copy]; + } + } + }; + FBSDKLikeActionControllerAddGetOGObjectLikeRequest(accessToken, + connection, + objectID, + objectType, + getLikeStateCompletionBlock); + + fbsdk_like_action_controller_get_engagement_completion_block engagementCompletionBlock = ^(BOOL success, + NSString *innerLikeCountStringWithLike, + NSString *innerLikeCountStringWithoutLike, + NSString *innerSocialSentenceWithLike, + NSString *innerSocialSentenceWithoutLike) { + if (success) { + // Don't lose cached state if certain properties were not included + likeCountStringWithLike = [innerLikeCountStringWithLike copy]; + likeCountStringWithoutLike = [innerLikeCountStringWithoutLike copy]; + socialSentenceWithLike = [innerSocialSentenceWithLike copy]; + socialSentenceWithoutLike = [innerSocialSentenceWithoutLike copy]; + + handleResults(); + } + }; + FBSDKLikeActionControllerAddGetEngagementRequest(accessToken, + connection, + objectID, + objectType, + engagementCompletionBlock); +} + + +- (void)_ensureVerifiedObjectID:(fbsdk_like_action_controller_ensure_verified_object_id_completion_block)completion +{ + if (completion == NULL) { + return; + } + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [connection overrideVersionPartWith:FBSDK_LIKE_ACTION_CONTROLLER_API_VERSION]; + if ([_objectID rangeOfString:@"://"].location != NSNotFound) { + FBSDKLikeActionControllerAddGetObjectIDWithObjectURLRequest(_accessToken, connection, _objectID, ^(BOOL success, + NSString *innerVerifiedObjectID, + BOOL innerObjectIsPage) { + if (success) { + _verifiedObjectID = [innerVerifiedObjectID copy]; + _objectIsPage = innerObjectIsPage; + } + }); + } + + FBSDKLikeActionControllerAddGetObjectIDRequest(_accessToken, connection, _objectID, ^(BOOL success, + NSString *innerVerifiedObjectID, + BOOL innerObjectIsPage) { + if (success) { + // if this was an URL based request, then we want to use the objectID from that request - this value will just + // be an echo of the URL + if (!_verifiedObjectID) { + _verifiedObjectID = [innerVerifiedObjectID copy]; + } + _objectIsPage = innerObjectIsPage; + } + if (_verifiedObjectID) { + completion(_verifiedObjectID); + } + }); + [connection start]; +} + +- (void)_presentLikeDialogWithUpdateBlock:(fbsdk_like_action_block)updateBlock + analyticsParameters:(NSDictionary *)analyticsParameters + fromViewController:(UIViewController *)fromViewController +{ + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKLikeControlDidPresentDialog + valueToSum:nil + parameters:analyticsParameters + accessToken:_accessToken]; + FBSDKLikeDialog *dialog = [[FBSDKLikeDialog alloc] init]; + dialog.objectID = _objectID; + dialog.objectType = _objectType; + dialog.delegate = self; + dialog.fromViewController = fromViewController; + [_dialogToUpdateBlockMap setObject:updateBlock forKey:dialog]; + [_dialogToAnalyticsParametersMap setObject:analyticsParameters forKey:dialog]; + if (![dialog like]) { + [self _setExecuting:NO forKey:FBSDK_LIKE_ACTION_CONTROLLER_LIKE_PROPERTY_KEY]; + } +} + +- (void)_publishIfNeededWithUpdateBlock:(fbsdk_like_action_block)updateBlock + analyticsParameters:(NSDictionary *)analyticsParameters + fromViewController:(UIViewController *)fromViewController +{ + BOOL objectIsLiked = _objectIsLiked; + if (_objectIsLikedOnServer != objectIsLiked) { + if (objectIsLiked) { + [self _publishLikeWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } else { + [self _publishUnlikeWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } + } +} + +- (void)_publishLikeWithUpdateBlock:(fbsdk_like_action_block)updateBlock + analyticsParameters:(NSDictionary *)analyticsParameters + fromViewController:(UIViewController *)fromViewController +{ + _objectIsLikedIsPending = YES; + [self _ensureVerifiedObjectID:^(NSString *verifiedObjectID) { + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [connection overrideVersionPartWith:FBSDK_LIKE_ACTION_CONTROLLER_API_VERSION]; + fbsdk_like_action_controller_publish_like_completion_block completionHandler = ^(BOOL success, + NSString *unlikeToken) { + _objectIsLikedIsPending = NO; + if (success) { + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKLikeControlDidLike + valueToSum:nil + parameters:analyticsParameters + accessToken:_accessToken]; + _objectIsLikedOnServer = YES; + _unlikeToken = [unlikeToken copy]; + if (updateBlock != NULL) { + updateBlock(FBSDKTriStateBOOLFromBOOL(self.objectIsLiked), + _likeCountStringWithLike, + _likeCountStringWithoutLike, + _socialSentenceWithLike, + _socialSentenceWithoutLike, + _unlikeToken, + NO, + NO); + } + [self _publishIfNeededWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } else { + [self _presentLikeDialogWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } + }; + FBSDKLikeActionControllerAddPublishLikeRequest(_accessToken, + connection, + verifiedObjectID, + _objectType, + completionHandler); + [connection start]; + }]; +} + +- (void)_publishUnlikeWithUpdateBlock:(fbsdk_like_action_block)updateBlock + analyticsParameters:(NSDictionary *)analyticsParameters + fromViewController:(UIViewController *)fromViewController +{ + _objectIsLikedIsPending = YES; + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [connection overrideVersionPartWith:FBSDK_LIKE_ACTION_CONTROLLER_API_VERSION]; + fbsdk_like_action_controller_publish_unlike_completion_block completionHandler = ^(BOOL success) { + _objectIsLikedIsPending = NO; + if (success) { + [FBSDKAppEvents logImplicitEvent:FBSDKAppEventNameFBSDKLikeControlDidUnlike + valueToSum:nil + parameters:analyticsParameters + accessToken:_accessToken]; + _objectIsLikedOnServer = NO; + _unlikeToken = nil; + if (updateBlock != NULL) { + updateBlock(FBSDKTriStateBOOLFromBOOL(self.objectIsLiked), + _likeCountStringWithLike, + _likeCountStringWithoutLike, + _socialSentenceWithLike, + _socialSentenceWithoutLike, + _unlikeToken, + NO, + NO); + } + [self _publishIfNeededWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } else { + [self _presentLikeDialogWithUpdateBlock:updateBlock analyticsParameters:analyticsParameters fromViewController:fromViewController]; + } + }; + FBSDKLikeActionControllerAddPublishUnlikeRequest(_accessToken, + connection, + _unlikeToken, + _objectType, + completionHandler); + [connection start]; +} + +- (void)_refreshWithMode:(FBSDKLikeActionControllerRefreshMode)mode +{ + switch (mode) { + case FBSDKLikeActionControllerRefreshModeForce:{ + // if we're already refreshing, skip + if (_refreshState == FBSDKLikeActionControllerRefreshStateActive) { + return; + } + break; + } + case FBSDKLikeActionControllerRefreshModeInitial:{ + // if we've already started any refresh, skip this + if (_refreshState != FBSDKLikeActionControllerRefreshStateNone) { + return; + } + break; + } + } + + // You must be logged in to fetch the like status + if (!_accessToken) { + return; + } + + [self _setExecuting:YES forKey:FBSDK_LIKE_ACTION_CONTROLLER_REFRESH_PROPERTY_KEY]; + _refreshState = FBSDKLikeActionControllerRefreshStateActive; + + [self _ensureVerifiedObjectID:^(NSString *verifiedObjectID) { + FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init]; + [connection overrideVersionPartWith:FBSDK_LIKE_ACTION_CONTROLLER_API_VERSION]; + FBSDKLikeActionControllerAddRefreshRequests(_accessToken, + connection, + verifiedObjectID, + _objectType, + ^(FBSDKTriStateBOOL objectIsLiked, + NSString *likeCountStringWithLike, + NSString *likeCountStringWithoutLike, + NSString *socialSentenceWithLike, + NSString *socialSentenceWithoutLike, + NSString *unlikeToken, + BOOL likeStateChanged, + BOOL animated) { + [self _updateWithObjectIsLiked:objectIsLiked + likeCountStringWithLike:likeCountStringWithLike + likeCountStringWithoutLike:likeCountStringWithoutLike + socialSentenceWithLike:socialSentenceWithLike + socialSentenceWithoutLike:socialSentenceWithoutLike + unlikeToken:unlikeToken + soundEnabled:NO + animated:NO + deferred:NO]; + [self _setExecuting:NO forKey:FBSDK_LIKE_ACTION_CONTROLLER_REFRESH_PROPERTY_KEY]; + _refreshState = FBSDKLikeActionControllerRefreshStateComplete; + }); + [connection start]; + }]; +} + +- (void)_setExecuting:(BOOL)executing forKey:(NSString *)key +{ + static NSMapTable *_executing = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _executing = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsStrongMemory capacity:0]; + }); + + NSString *objectKey = [NSString stringWithFormat: + @"%@:%@:%@", + _objectID, + NSStringFromFBSDKLikeObjectType(_objectType), + key]; + if (executing) { + [self beginContentAccess]; + [_executing setObject:self forKey:objectKey]; + } else { + [_executing removeObjectForKey:objectKey]; + [self endContentAccess]; + } +} + +- (void)_updateWithObjectIsLiked:(FBSDKTriStateBOOL)objectIsLikedTriState + likeCountStringWithLike:(NSString *)likeCountStringWithLike + likeCountStringWithoutLike:(NSString *)likeCountStringWithoutLike + socialSentenceWithLike:(NSString *)socialSentenceWithLike + socialSentenceWithoutLike:(NSString *)socialSentenceWithoutLike + unlikeToken:(NSString *)unlikeToken + soundEnabled:(BOOL)soundEnabled + animated:(BOOL)animated + deferred:(BOOL)deferred +{ + if (objectIsLikedTriState != FBSDKTriStateBOOLValueUnknown) { + _lastUpdateTime = [NSDate date]; + } + + // This value will not be useable if objectIsLikedTriState is FBSDKTriStateBOOLValueUnknown + BOOL objectIsLiked = BOOLFromFBSDKTriStateBOOL(objectIsLikedTriState, NO); + + // So always check objectIsLikedChanged before using objectIsLiked. + // If the new like state is unknown, we don't consider the state to have changed. + BOOL objectIsLikedChanged = (objectIsLikedTriState != FBSDKTriStateBOOLValueUnknown) && (self.objectIsLiked != objectIsLiked); + + if (!objectIsLikedChanged && + [FBSDKInternalUtility object:_likeCountStringWithLike isEqualToObject:likeCountStringWithLike] && + [FBSDKInternalUtility object:_likeCountStringWithoutLike isEqualToObject:likeCountStringWithoutLike] && + [FBSDKInternalUtility object:_socialSentenceWithLike isEqualToObject:socialSentenceWithLike] && + [FBSDKInternalUtility object:_socialSentenceWithoutLike isEqualToObject:socialSentenceWithoutLike] && + [FBSDKInternalUtility object:_unlikeToken isEqualToObject:unlikeToken]) { + // check if the like state changed and only animate if it did + return; + } + + void(^updateBlock)(void) = ^{ + if (objectIsLikedChanged) { + _objectIsLiked = objectIsLiked; + } + + if (likeCountStringWithLike) { + _likeCountStringWithLike = [likeCountStringWithLike copy]; + } + if (likeCountStringWithoutLike) { + _likeCountStringWithoutLike = [likeCountStringWithoutLike copy]; + } + if (socialSentenceWithLike) { + _socialSentenceWithLike = [socialSentenceWithLike copy]; + } + if (socialSentenceWithoutLike) { + _socialSentenceWithoutLike = [socialSentenceWithoutLike copy]; + } + if (unlikeToken) { + _unlikeToken = [unlikeToken copy]; + } + + // if only meta data changed, don't play the sound + FBSDKLikeButtonPopWAV *likeSound = (objectIsLikedChanged && objectIsLiked && soundEnabled ? [FBSDKLikeButtonPopWAV sharedLoader] : nil); + + void(^notificationBlock)(void) = ^{ + if (likeSound) { + dispatch_time_t soundPopTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(FBSDK_LIKE_ACTION_CONTROLLER_SOUND_DELAY * NSEC_PER_SEC)); + dispatch_after(soundPopTime, dispatch_get_main_queue(), ^(void){ + [likeSound playSound]; + }); + } + NSDictionary *userInfo = @{FBSDKLikeActionControllerAnimatedKey: @(animated)}; + [[NSNotificationCenter defaultCenter] postNotificationName:FBSDKLikeActionControllerDidUpdateNotification + object:self + userInfo:userInfo]; + }; + + notificationBlock(); + }; + + // if only meta data changed, don't defer + if (deferred && objectIsLikedChanged) { + double delayInSeconds = FBSDK_LIKE_ACTION_CONTROLLER_ANIMATION_DELAY; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), updateBlock); + } else { + updateBlock(); + } +} + +- (BOOL)_useOGLike +{ + return (_accessToken && + !_objectIsPage && + _verifiedObjectID && + [_accessToken.permissions containsObject:@"publish_actions"]); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.h new file mode 100644 index 0000000..e1f30c8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKLikeActionControllerCache : NSObject + +- (instancetype)initWithAccessTokenString:(NSString *)accessTokenString NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, copy, readonly) NSString *accessTokenString; + +- (id)objectForKeyedSubscript:(id)key; +- (void)resetForAccessTokenString:(NSString *)accessTokenString; +- (void)setObject:(id)object forKeyedSubscript:(id)key; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.m new file mode 100644 index 0000000..746e819 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.m @@ -0,0 +1,116 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeActionControllerCache.h" + +#import + +#import "FBSDKLikeActionController.h" + +// after 1 day, expire the cached states +#define FBSDK_LIKE_ACTION_CONTROLLER_CACHE_TIMEOUT 60 * 24 + +#define FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ACCESS_TOKEN_KEY @"accessTokenString" +#define FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ITEMS_KEY @"items" + +@implementation FBSDKLikeActionControllerCache +{ + NSString *_accessTokenString; + NSMutableDictionary *_items; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithAccessTokenString:(NSString *)accessTokenString +{ + if ((self = [super init])) { + _accessTokenString = [accessTokenString copy]; + _items = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (instancetype)init +{ + FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAccessTokenString:); + return [self initWithAccessTokenString:nil]; +} + +#pragma mark - NSCoding + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + NSString *accessTokenString = [decoder decodeObjectOfClass:[NSString class] + forKey:FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ACCESS_TOKEN_KEY]; + if ((self = [self initWithAccessTokenString:accessTokenString])) { + NSSet *allowedClasses = [NSSet setWithObjects:[NSDictionary class], [FBSDKLikeActionController class], nil]; + NSDictionary *items = [decoder decodeObjectOfClasses:allowedClasses + forKey:FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ITEMS_KEY]; + _items = [[NSMutableDictionary alloc] initWithDictionary:items]; + [self _prune]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + [encoder encodeObject:_accessTokenString forKey:FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ACCESS_TOKEN_KEY]; + [encoder encodeObject:_items forKey:FBSDK_LIKE_ACTION_CONTROLLER_CACHE_ITEMS_KEY]; +} + +#pragma mark - Public Methods + +- (id)objectForKeyedSubscript:(id)key +{ + return _items[key]; +} + +- (void)resetForAccessTokenString:(NSString *)accessTokenString +{ + _accessTokenString = [accessTokenString copy]; + [_items removeAllObjects]; +} + +- (void)setObject:(id)object forKeyedSubscript:(id)key +{ + _items[key] = object; +} + +#pragma mark - Helper Methods + +- (void)_prune +{ + NSMutableArray *keysToRemove = [[NSMutableArray alloc] init]; + [_items enumerateKeysAndObjectsUsingBlock:^(NSString *objectID, + FBSDKLikeActionController *likeActionController, + BOOL *stop) { + NSDate *lastUpdateTime = likeActionController.lastUpdateTime; + if (!lastUpdateTime || + ([[NSDate date] timeIntervalSinceDate:lastUpdateTime] > FBSDK_LIKE_ACTION_CONTROLLER_CACHE_TIMEOUT)) { + [keysToRemove addObject:objectID]; + } + }]; + [_items removeObjectsForKeys:keysToRemove]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.h new file mode 100644 index 0000000..8ad46b6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKLikeBoxView.h" + +@interface FBSDKLikeBoxBorderView : UIView + +@property (nonatomic, assign) CGFloat borderCornerRadius; +@property (nonatomic, assign) CGFloat borderWidth; +@property (nonatomic, assign) FBSDKLikeBoxCaretPosition caretPosition; +@property (nonatomic, assign, readonly) UIEdgeInsets contentInsets; +@property (nonatomic, strong) UIView *contentView; +@property (nonatomic, strong) UIColor *fillColor; +@property (nonatomic, strong) UIColor *foregroundColor; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.m new file mode 100644 index 0000000..71faf0f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.m @@ -0,0 +1,323 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeBoxBorderView.h" + +#import "FBSDKCoreKit+Internal.h" + +#define FBSDK_LIKE_BOX_BORDER_CARET_WIDTH 6.0 +#define FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT 3.0 +#define FBSDK_LIKE_BOX_BORDER_CARET_PADDING 3.0 +#define FBSDK_LIKE_BOX_BORDER_CONTENT_PADDING 4.0 + +@implementation FBSDKLikeBoxBorderView + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + [self _initializeContent]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) { + [self _initializeContent]; + } + return self; +} + +#pragma mark - Properties + +- (void)setBackgroundColor:(UIColor *)backgroundColor +{ + if (![self.backgroundColor isEqual:backgroundColor]) { + [super setBackgroundColor:backgroundColor]; + [self setNeedsDisplay]; + } +} + +- (void)setBorderCornerRadius:(CGFloat)borderCornerRadius +{ + if (_borderCornerRadius != borderCornerRadius) { + _borderCornerRadius = borderCornerRadius; + [self setNeedsDisplay]; + } +} + +- (void)setBorderWidth:(CGFloat)borderWidth +{ + if (_borderWidth != borderWidth) { + _borderWidth = borderWidth; + [self setNeedsDisplay]; + [self invalidateIntrinsicContentSize]; + } +} + +- (void)setCaretPosition:(FBSDKLikeBoxCaretPosition)caretPosition +{ + if (_caretPosition != caretPosition) { + _caretPosition = caretPosition; + [self setNeedsLayout]; + [self setNeedsDisplay]; + [self invalidateIntrinsicContentSize]; + } +} + +- (UIEdgeInsets)contentInsets +{ + UIEdgeInsets borderInsets = [self _borderInsets]; + return UIEdgeInsetsMake(borderInsets.top + FBSDK_LIKE_BOX_BORDER_CONTENT_PADDING, + borderInsets.left + FBSDK_LIKE_BOX_BORDER_CONTENT_PADDING, + borderInsets.bottom + FBSDK_LIKE_BOX_BORDER_CONTENT_PADDING, + borderInsets.right + FBSDK_LIKE_BOX_BORDER_CONTENT_PADDING); +} + +- (void)setContentView:(UIView *)contentView +{ + if (_contentView != contentView) { + [_contentView removeFromSuperview]; + _contentView = contentView; + [self addSubview:_contentView]; + [self setNeedsLayout]; + [self invalidateIntrinsicContentSize]; + } +} + +- (void)setFillColor:(UIColor *)fillColor +{ + if (![_fillColor isEqual:fillColor]) { + _fillColor = fillColor; + [self setNeedsDisplay]; + } +} + +- (void)setForegroundColor:(UIColor *)foregroundColor +{ + if (![_foregroundColor isEqual:foregroundColor]) { + _foregroundColor = foregroundColor; + [self setNeedsDisplay]; + } +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize +{ + return FBSDKEdgeInsetsOutsetSize(self.contentView.intrinsicContentSize, self.contentInsets); +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + self.contentView.frame = UIEdgeInsetsInsetRect(self.bounds, self.contentInsets); +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + UIEdgeInsets contentInsets = self.contentInsets; + size = FBSDKEdgeInsetsInsetSize(size, contentInsets); + size = [self.contentView sizeThatFits:size]; + size = FBSDKEdgeInsetsOutsetSize(size, contentInsets); + return size; +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + + // read the configuration properties + CGRect bounds = self.bounds; + CGFloat borderWidth = self.borderWidth; + CGFloat borderCornerRadius = self.borderCornerRadius; + CGFloat contentScaleFactor = self.contentScaleFactor; + + // fill the background + if (self.backgroundColor) { + [self.backgroundColor setFill]; + CGContextFillRect(context, bounds); + } + + // configure the colors and lines + [self.fillColor setFill]; + [self.foregroundColor setStroke]; + CGContextSetLineJoin(context, kCGLineJoinRound); + CGContextSetLineWidth(context, borderWidth); + + // get the frame of the box + CGRect borderFrame = UIEdgeInsetsInsetRect(bounds, [self _borderInsets]); + + // define the arcs for the corners + const int start = 0; + const int tangent = 1; + const int end = 2; + CGPoint topLeftArc[3] = { + CGPointMake(CGRectGetMinX(borderFrame) + borderCornerRadius, CGRectGetMinY(borderFrame)), + CGPointMake(CGRectGetMinX(borderFrame), CGRectGetMinY(borderFrame)), + CGPointMake(CGRectGetMinX(borderFrame), CGRectGetMinY(borderFrame) + borderCornerRadius), + }; + CGPoint bottomLeftArc[3] = { + CGPointMake(CGRectGetMinX(borderFrame), CGRectGetMaxY(borderFrame) - borderCornerRadius), + CGPointMake(CGRectGetMinX(borderFrame), CGRectGetMaxY(borderFrame)), + CGPointMake(CGRectGetMinX(borderFrame) + borderCornerRadius, CGRectGetMaxY(borderFrame)), + }; + CGPoint bottomRightArc[3] = { + CGPointMake(CGRectGetMaxX(borderFrame) - borderCornerRadius, CGRectGetMaxY(borderFrame)), + CGPointMake(CGRectGetMaxX(borderFrame), CGRectGetMaxY(borderFrame)), + CGPointMake(CGRectGetMaxX(borderFrame), CGRectGetMaxY(borderFrame) - borderCornerRadius), + }; + CGPoint topRightArc[3] = { + CGPointMake(CGRectGetMaxX(borderFrame), CGRectGetMinY(borderFrame) + borderCornerRadius), + CGPointMake(CGRectGetMaxX(borderFrame), CGRectGetMinY(borderFrame)), + CGPointMake(CGRectGetMaxX(borderFrame) - borderCornerRadius, CGRectGetMinY(borderFrame)), + }; + + // start a path on the context + CGContextBeginPath(context); + + // position the caret and decide which lines to draw + CGPoint caretPoints[3]; + switch (self.caretPosition) { + case FBSDKLikeBoxCaretPositionTop: + CGContextMoveToPoint(context, topRightArc[end].x, topRightArc[end].y); + caretPoints[0] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame) + (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2)), + CGRectGetMinY(borderFrame)); + caretPoints[1] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame)), + CGRectGetMinY(borderFrame) - FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT); + caretPoints[2] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame) - (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2)), + CGRectGetMinY(borderFrame)); + CGContextAddLines(context, caretPoints, sizeof(caretPoints) / sizeof(caretPoints[0])); + CGContextAddArcToPoint(context, topLeftArc[tangent].x, topLeftArc[tangent].y, topLeftArc[end].x, topLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomLeftArc[start].x, bottomLeftArc[start].y); + CGContextAddArcToPoint(context, bottomLeftArc[tangent].x, bottomLeftArc[tangent].y, bottomLeftArc[end].x, bottomLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomRightArc[start].x, bottomRightArc[start].y); + CGContextAddArcToPoint(context, bottomRightArc[tangent].x, bottomRightArc[tangent].y, bottomRightArc[end].x, bottomRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topRightArc[start].x, topRightArc[start].y); + CGContextAddArcToPoint(context, topRightArc[tangent].x, topRightArc[tangent].y, topRightArc[end].x, topRightArc[end].y, borderCornerRadius); + break; + case FBSDKLikeBoxCaretPositionLeft: + CGContextMoveToPoint(context, topLeftArc[end].x, topLeftArc[end].y); + caretPoints[0] = CGPointMake(CGRectGetMinX(borderFrame), + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame) - (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2))); + caretPoints[1] = CGPointMake(CGRectGetMinX(borderFrame) - FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT, + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame))); + caretPoints[2] = CGPointMake(CGRectGetMinX(borderFrame), + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame) + (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2))); + CGContextAddLines(context, caretPoints, sizeof(caretPoints) / sizeof(caretPoints[0])); + CGContextAddArcToPoint(context, bottomLeftArc[tangent].x, bottomLeftArc[tangent].y, bottomLeftArc[end].x, bottomLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomRightArc[start].x, bottomRightArc[start].y); + CGContextAddArcToPoint(context, bottomRightArc[tangent].x, bottomRightArc[tangent].y, bottomRightArc[end].x, bottomRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topRightArc[start].x, topRightArc[start].y); + CGContextAddArcToPoint(context, topRightArc[tangent].x, topRightArc[tangent].y, topRightArc[end].x, topRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topLeftArc[start].x, topLeftArc[start].y); + CGContextAddArcToPoint(context, topLeftArc[tangent].x, topLeftArc[tangent].y, topLeftArc[end].x, topLeftArc[end].y, borderCornerRadius); + break; + case FBSDKLikeBoxCaretPositionBottom: + CGContextMoveToPoint(context, bottomLeftArc[end].x, bottomLeftArc[end].y); + caretPoints[0] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame) - (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2)), + CGRectGetMaxY(borderFrame)); + caretPoints[1] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame)), + CGRectGetMaxY(borderFrame) + FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT); + caretPoints[2] = CGPointMake(FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidX(borderFrame) + (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2)), + CGRectGetMaxY(borderFrame)); + CGContextAddLines(context, caretPoints, sizeof(caretPoints) / sizeof(caretPoints[0])); + CGContextAddArcToPoint(context, bottomRightArc[tangent].x, bottomRightArc[tangent].y, bottomRightArc[end].x, bottomRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topRightArc[start].x, topRightArc[start].y); + CGContextAddArcToPoint(context, topRightArc[tangent].x, topRightArc[tangent].y, topRightArc[end].x, topRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topLeftArc[start].x, topLeftArc[start].y); + CGContextAddArcToPoint(context, topLeftArc[tangent].x, topLeftArc[tangent].y, topLeftArc[end].x, topLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomLeftArc[start].x, bottomLeftArc[start].y); + CGContextAddArcToPoint(context, bottomLeftArc[tangent].x, bottomLeftArc[tangent].y, bottomLeftArc[end].x, bottomLeftArc[end].y, borderCornerRadius); + break; + case FBSDKLikeBoxCaretPositionRight: + CGContextMoveToPoint(context, bottomRightArc[end].x, bottomRightArc[end].y); + caretPoints[0] = CGPointMake(CGRectGetMaxX(borderFrame), + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame) + (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2))); + caretPoints[1] = CGPointMake(CGRectGetMaxX(borderFrame) + FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT, + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame))); + caretPoints[2] = CGPointMake(CGRectGetMaxX(borderFrame), + FBSDKPointsForScreenPixels(floorf, contentScaleFactor, CGRectGetMidY(borderFrame) - (FBSDK_LIKE_BOX_BORDER_CARET_WIDTH / 2))); + CGContextAddLines(context, caretPoints, sizeof(caretPoints) / sizeof(caretPoints[0])); + CGContextAddArcToPoint(context, topRightArc[tangent].x, topRightArc[tangent].y, topRightArc[end].x, topRightArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, topLeftArc[start].x, topLeftArc[start].y); + CGContextAddArcToPoint(context, topLeftArc[tangent].x, topLeftArc[tangent].y, topLeftArc[end].x, topLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomLeftArc[start].x, bottomLeftArc[start].y); + CGContextAddArcToPoint(context, bottomLeftArc[tangent].x, bottomLeftArc[tangent].y, bottomLeftArc[end].x, bottomLeftArc[end].y, borderCornerRadius); + CGContextAddLineToPoint(context, bottomRightArc[start].x, bottomRightArc[start].y); + CGContextAddArcToPoint(context, bottomRightArc[tangent].x, bottomRightArc[tangent].y, bottomRightArc[end].x, bottomRightArc[end].y, borderCornerRadius); + break; + } + + // close and draw now that we have it all + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFillStroke); + + CGContextRestoreGState(context); +} + +#pragma mark - Helper Methods + +- (UIEdgeInsets)_borderInsets +{ + // inset the border bounds by 1/2 of the border width, since it is drawn split between inside and outside of the path + CGFloat scale = self.contentScaleFactor; + CGFloat halfBorderWidth = FBSDKPointsForScreenPixels(ceilf, scale, self.borderWidth / 2); + UIEdgeInsets borderInsets = UIEdgeInsetsMake(halfBorderWidth, halfBorderWidth, halfBorderWidth, halfBorderWidth); + + // adjust the insets for the caret position + switch (self.caretPosition) { + case FBSDKLikeBoxCaretPositionTop:{ + borderInsets.top += FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT + FBSDK_LIKE_BOX_BORDER_CARET_PADDING; + break; + } + case FBSDKLikeBoxCaretPositionLeft:{ + borderInsets.left += FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT + FBSDK_LIKE_BOX_BORDER_CARET_PADDING; + break; + } + case FBSDKLikeBoxCaretPositionBottom:{ + borderInsets.bottom += FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT + FBSDK_LIKE_BOX_BORDER_CARET_PADDING; + break; + } + case FBSDKLikeBoxCaretPositionRight:{ + borderInsets.right += FBSDK_LIKE_BOX_BORDER_CARET_HEIGHT + FBSDK_LIKE_BOX_BORDER_CARET_PADDING; + break; + } + } + + return borderInsets; +} + +- (void)_initializeContent +{ + self.backgroundColor = [UIColor clearColor]; + self.borderCornerRadius = 3.0; + self.borderWidth = 1.0; + self.contentMode = UIViewContentModeRedraw; + self.fillColor = [UIColor whiteColor]; + self.foregroundColor = FBSDKUIColorWithRGB(0x6A, 0x71, 0x80); + self.opaque = NO; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.h new file mode 100644 index 0000000..49b3756 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.h @@ -0,0 +1,43 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKLikeBoxCaretPosition) + + @abstract Specifies the position of the caret relative to the box. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeBoxCaretPosition) +{ + /*! The caret is on the top of the box. */ + FBSDKLikeBoxCaretPositionTop, + /*! The caret is on the left of the box. */ + FBSDKLikeBoxCaretPositionLeft, + /*! The caret is on the bottom of the box. */ + FBSDKLikeBoxCaretPositionBottom, + /*! The caret is on the right of the box. */ + FBSDKLikeBoxCaretPositionRight, +}; + +@interface FBSDKLikeBoxView : UIView + +@property (nonatomic, assign) FBSDKLikeBoxCaretPosition caretPosition; +@property (nonatomic, copy) NSString *text; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.m new file mode 100644 index 0000000..e0afeac --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.m @@ -0,0 +1,108 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeBoxView.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLikeBoxBorderView.h" + +@implementation FBSDKLikeBoxView +{ + FBSDKLikeBoxBorderView *_borderView; + UILabel *_likeCountLabel; +} + +#pragma mark - Object Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + [self _initializeContent]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) { + [self _initializeContent]; + } + return self; +} + +#pragma mark - Properties + +- (void)setCaretPosition:(FBSDKLikeBoxCaretPosition)caretPosition +{ + if (_caretPosition != caretPosition) { + _caretPosition = caretPosition; + _borderView.caretPosition = _caretPosition; + [self setNeedsLayout]; + [self invalidateIntrinsicContentSize]; + } +} + +- (NSString *)text +{ + return _likeCountLabel.text; +} + +- (void)setText:(NSString *)text +{ + if (![_likeCountLabel.text isEqualToString:text]) { + _likeCountLabel.text = text; + [self setNeedsLayout]; + [self invalidateIntrinsicContentSize]; + } +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize +{ + return _borderView.intrinsicContentSize; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect bounds = self.bounds; + _borderView.frame = bounds; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + return [_borderView sizeThatFits:size]; +} + +#pragma mark - Helper Methods + +- (void)_initializeContent +{ + _borderView = [[FBSDKLikeBoxBorderView alloc] initWithFrame:CGRectZero]; + [self addSubview:_borderView]; + + _likeCountLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _likeCountLabel.font = [UIFont systemFontOfSize:11.0]; + _likeCountLabel.textAlignment = NSTextAlignmentCenter; + _likeCountLabel.textColor = FBSDKUIColorWithRGB(0x6A, 0x71, 0x80); + _borderView.contentView = _likeCountLabel; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButton+Internal.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButton+Internal.h new file mode 100644 index 0000000..032d30d --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButton+Internal.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKLikeActionController.h" +#import "FBSDKLikeButton.h" + +@interface FBSDKLikeButton () + +@property (nonatomic, strong, readwrite) FBSDKLikeActionController *likeActionController; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.h new file mode 100644 index 0000000..aa4c1d8 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.h @@ -0,0 +1,24 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKLikeButtonPopWAV : FBSDKAudioResourceLoader +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.m new file mode 100644 index 0000000..c021293 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.m @@ -0,0 +1,36 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeButtonPopWAV.h" + +@implementation FBSDKLikeButtonPopWAV + ++ (NSString *)name +{ + return @"FBSDKLikeButtonPop.wav"; +} + ++ (NSData *)data +{ + const Byte bytes[] = { +0x52, 0x49, 0x46, 0x46, 0xfc, 0x57, 0x02, 0x00, 0x57, 0x41, 0x56, 0x45, 0x4a, 0x55, 0x4e, 0x4b, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x65, 0x78, 0x74, 0x5a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x72, 0x6f, 0x20, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x68, 0x72, 0x72, 0x48, 0x37, 0x38, 0x21, 0x54, 0x66, 0x61, 0x61, 0x61, 0x61, 0x47, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x00, 0x31, 0x35, 0x3a, 0x32, 0x38, 0x3a, 0x30, 0x31, 0xf7, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6d, 0x74, 0x20, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0xee, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x66, 0x10, 0x00, 0x00, 0x00, 0x70, 0xe2, 0xe6, 0xc4, 0xdb, 0x13, 0xcf, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x6c, 0x6d, 0x31, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x80, 0x53, 0x02, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x20, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x19, 0x00, 0x19, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x41, 0x00, 0x41, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x30, 0x00, 0x30, 0x00, 0x20, 0x00, 0x20, 0x00, 0x13, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x06, 0x00, 0x02, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x11, 0x00, 0x11, 0x00, 0x17, 0x00, 0x17, 0x00, 0x18, 0x00, 0x18, 0x00, 0x17, 0x00, 0x17, 0x00, 0x14, 0x00, 0x14, 0x00, 0x17, 0x00, 0x17, 0x00, 0x22, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x21, 0x00, 0x21, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x05, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xca, 0xff, 0xca, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xea, 0xff, 0xea, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x10, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0x17, 0x00, 0x17, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x33, 0x00, 0x11, 0x00, 0x11, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0x02, 0x00, 0x02, 0x00, 0x17, 0x00, 0x17, 0x00, 0x24, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xf0, 0xff, 0xf0, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x41, 0xff, 0x41, 0xff, 0xe7, 0xfe, 0xe7, 0xfe, 0xb8, 0xfe, 0xb8, 0xfe, 0xb2, 0xfe, 0xb2, 0xfe, 0x39, 0xfe, 0x39, 0xfe, 0xb3, 0xfc, 0xb3, 0xfc, 0x5e, 0xfa, 0x5e, 0xfa, 0x25, 0xf8, 0x25, 0xf8, 0x22, 0xf7, 0x22, 0xf7, 0xc1, 0xf7, 0xc1, 0xf7, 0x5e, 0xf9, 0x5e, 0xf9, 0xec, 0xfa, 0xec, 0xfa, 0xb2, 0xfb, 0xb2, 0xfb, 0x96, 0xfb, 0x96, 0xfb, 0x0a, 0xfb, 0x0a, 0xfb, 0x9a, 0xfa, 0x9a, 0xfa, 0x94, 0xfa, 0x94, 0xfa, 0x1b, 0xfb, 0x1b, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0x6f, 0xfc, 0x6f, 0xfc, 0xba, 0xfb, 0xba, 0xfb, 0xbc, 0xf9, 0xbc, 0xf9, 0x08, 0xf7, 0x08, 0xf7, 0xe5, 0xf4, 0xe5, 0xf4, 0x7f, 0xf4, 0x7f, 0xf4, 0xde, 0xf5, 0xde, 0xf5, 0x1e, 0xf8, 0x1e, 0xf8, 0x5a, 0xfa, 0x5a, 0xfa, 0x26, 0xfc, 0x26, 0xfc, 0xca, 0xfd, 0xca, 0xfd, 0xdb, 0xff, 0xdb, 0xff, 0x61, 0x02, 0x61, 0x02, 0xc6, 0x04, 0xc6, 0x04, 0x54, 0x06, 0x54, 0x06, 0xb4, 0x06, 0xb4, 0x06, 0x24, 0x06, 0x24, 0x06, 0x3b, 0x05, 0x3b, 0x05, 0x72, 0x04, 0x72, 0x04, 0x27, 0x04, 0x27, 0x04, 0x8e, 0x04, 0x8e, 0x04, 0x73, 0x05, 0x73, 0x05, 0x7f, 0x06, 0x7f, 0x06, 0x72, 0x07, 0x72, 0x07, 0x28, 0x08, 0x28, 0x08, 0xeb, 0x08, 0xeb, 0x08, 0x57, 0x0a, 0x57, 0x0a, 0x8c, 0x0c, 0x8c, 0x0c, 0x00, 0x0f, 0x00, 0x0f, 0xf6, 0x10, 0xf6, 0x10, 0xf2, 0x11, 0xf2, 0x11, 0x14, 0x12, 0x14, 0x12, 0xfa, 0x11, 0xfa, 0x11, 0x1e, 0x12, 0x1e, 0x12, 0x82, 0x12, 0x82, 0x12, 0xc4, 0x12, 0xc4, 0x12, 0x75, 0x12, 0x75, 0x12, 0x86, 0x11, 0x86, 0x11, 0x35, 0x10, 0x35, 0x10, 0xba, 0x0e, 0xba, 0x0e, 0x62, 0x0d, 0x62, 0x0d, 0x79, 0x0c, 0x79, 0x0c, 0x01, 0x0c, 0x01, 0x0c, 0xcf, 0x0b, 0xcf, 0x0b, 0xa7, 0x0b, 0xa7, 0x0b, 0x27, 0x0b, 0x27, 0x0b, 0x32, 0x0a, 0x32, 0x0a, 0x1d, 0x09, 0x1d, 0x09, 0x35, 0x08, 0x35, 0x08, 0x88, 0x07, 0x88, 0x07, 0xf7, 0x06, 0xf7, 0x06, 0x38, 0x06, 0x38, 0x06, 0x1c, 0x05, 0x1c, 0x05, 0xab, 0x03, 0xab, 0x03, 0xea, 0x01, 0xea, 0x01, 0xd7, 0xff, 0xd7, 0xff, 0x72, 0xfd, 0x72, 0xfd, 0xc3, 0xfa, 0xc3, 0xfa, 0x04, 0xf8, 0x04, 0xf8, 0x88, 0xf5, 0x88, 0xf5, 0x63, 0xf3, 0x63, 0xf3, 0x93, 0xf1, 0x93, 0xf1, 0x18, 0xf0, 0x18, 0xf0, 0xe7, 0xee, 0xe7, 0xee, 0x07, 0xee, 0x07, 0xee, 0x8a, 0xed, 0x8a, 0xed, 0x62, 0xed, 0x62, 0xed, 0x68, 0xed, 0x68, 0xed, 0x87, 0xed, 0x87, 0xed, 0xb5, 0xed, 0xb5, 0xed, 0xde, 0xed, 0xde, 0xed, 0xf0, 0xed, 0xf0, 0xed, 0xe5, 0xed, 0xe5, 0xed, 0xe2, 0xed, 0xe2, 0xed, 0x0a, 0xee, 0x0a, 0xee, 0x63, 0xee, 0x63, 0xee, 0xdb, 0xee, 0xdb, 0xee, 0x47, 0xef, 0x47, 0xef, 0x81, 0xef, 0x81, 0xef, 0xb5, 0xef, 0xb5, 0xef, 0x45, 0xf0, 0x45, 0xf0, 0x7b, 0xf1, 0x7b, 0xf1, 0x6c, 0xf3, 0x6c, 0xf3, 0xf1, 0xf5, 0xf1, 0xf5, 0xbf, 0xf8, 0xbf, 0xf8, 0x86, 0xfb, 0x86, 0xfb, 0x15, 0xfe, 0x15, 0xfe, 0x6c, 0x00, 0x6c, 0x00, 0xb3, 0x02, 0xb3, 0x02, 0x1f, 0x05, 0x1f, 0x05, 0xd0, 0x07, 0xd0, 0x07, 0xad, 0x0a, 0xad, 0x0a, 0x48, 0x0d, 0x48, 0x0d, 0x2a, 0x0f, 0x2a, 0x0f, 0x2c, 0x10, 0x2c, 0x10, 0x83, 0x10, 0x83, 0x10, 0xa3, 0x10, 0xa3, 0x10, 0xf5, 0x10, 0xf5, 0x10, 0x93, 0x11, 0x93, 0x11, 0x47, 0x12, 0x47, 0x12, 0xba, 0x12, 0xba, 0x12, 0xb3, 0x12, 0xb3, 0x12, 0x3d, 0x12, 0x3d, 0x12, 0x9c, 0x11, 0x9c, 0x11, 0x26, 0x11, 0x26, 0x11, 0x20, 0x11, 0x20, 0x11, 0x81, 0x11, 0x81, 0x11, 0xdb, 0x11, 0xdb, 0x11, 0xac, 0x11, 0xac, 0x11, 0x90, 0x10, 0x90, 0x10, 0x86, 0x0e, 0x86, 0x0e, 0x06, 0x0c, 0x06, 0x0c, 0xa0, 0x09, 0xa0, 0x09, 0x8b, 0x07, 0x8b, 0x07, 0x97, 0x05, 0x97, 0x05, 0x5a, 0x03, 0x5a, 0x03, 0x73, 0x00, 0x73, 0x00, 0xe1, 0xfc, 0xe1, 0xfc, 0x09, 0xf9, 0x09, 0xf9, 0x6f, 0xf5, 0x6f, 0xf5, 0x7e, 0xf2, 0x7e, 0xf2, 0x4b, 0xf0, 0x4b, 0xf0, 0x99, 0xee, 0x99, 0xee, 0x07, 0xed, 0x07, 0xed, 0x4f, 0xeb, 0x4f, 0xeb, 0x79, 0xe9, 0x79, 0xe9, 0xd4, 0xe7, 0xd4, 0xe7, 0xcc, 0xe6, 0xcc, 0xe6, 0x81, 0xe6, 0x81, 0xe6, 0xc2, 0xe6, 0xc2, 0xe6, 0x2a, 0xe7, 0x2a, 0xe7, 0x4d, 0xe7, 0x4d, 0xe7, 0x09, 0xe7, 0x09, 0xe7, 0x8b, 0xe6, 0x8b, 0xe6, 0x23, 0xe6, 0x23, 0xe6, 0x17, 0xe6, 0x17, 0xe6, 0x7b, 0xe6, 0x7b, 0xe6, 0x38, 0xe7, 0x38, 0xe7, 0x2b, 0xe8, 0x2b, 0xe8, 0x49, 0xe9, 0x49, 0xe9, 0xa6, 0xea, 0xa6, 0xea, 0x72, 0xec, 0x72, 0xec, 0xc5, 0xee, 0xc5, 0xee, 0x92, 0xf1, 0x92, 0xf1, 0xc2, 0xf4, 0xc2, 0xf4, 0x2b, 0xf8, 0x2b, 0xf8, 0xaa, 0xfb, 0xaa, 0xfb, 0x2d, 0xff, 0x2d, 0xff, 0xa6, 0x02, 0xa6, 0x02, 0xff, 0x05, 0xff, 0x05, 0x23, 0x09, 0x23, 0x09, 0xf9, 0x0b, 0xf9, 0x0b, 0x72, 0x0e, 0x72, 0x0e, 0x92, 0x10, 0x92, 0x10, 0x60, 0x12, 0x60, 0x12, 0xe5, 0x13, 0xe5, 0x13, 0x1b, 0x15, 0x1b, 0x15, 0xf4, 0x15, 0xf4, 0x15, 0x79, 0x16, 0x79, 0x16, 0xc1, 0x16, 0xc1, 0x16, 0xf4, 0x16, 0xf4, 0x16, 0x35, 0x17, 0x35, 0x17, 0x95, 0x17, 0x95, 0x17, 0xfc, 0x17, 0xfc, 0x17, 0x39, 0x18, 0x39, 0x18, 0x1d, 0x18, 0x1d, 0x18, 0x92, 0x17, 0x92, 0x17, 0xa8, 0x16, 0xa8, 0x16, 0x86, 0x15, 0x86, 0x15, 0x41, 0x14, 0x41, 0x14, 0xc8, 0x12, 0xc8, 0x12, 0xeb, 0x10, 0xeb, 0x10, 0x84, 0x0e, 0x84, 0x0e, 0x9e, 0x0b, 0x9e, 0x0b, 0x65, 0x08, 0x65, 0x08, 0x10, 0x05, 0x10, 0x05, 0xc8, 0x01, 0xc8, 0x01, 0x9e, 0xfe, 0x9e, 0xfe, 0x8f, 0xfb, 0x8f, 0xfb, 0x9d, 0xf8, 0x9d, 0xf8, 0xd8, 0xf5, 0xd8, 0xf5, 0x5f, 0xf3, 0x5f, 0xf3, 0x5a, 0xf1, 0x5a, 0xf1, 0xe7, 0xef, 0xe7, 0xef, 0xf7, 0xee, 0xf7, 0xee, 0x62, 0xee, 0x62, 0xee, 0x00, 0xee, 0x00, 0xee, 0xb5, 0xed, 0xb5, 0xed, 0x84, 0xed, 0x84, 0xed, 0x80, 0xed, 0x80, 0xed, 0xb9, 0xed, 0xb9, 0xed, 0x26, 0xee, 0x26, 0xee, 0xa8, 0xee, 0xa8, 0xee, 0x24, 0xef, 0x24, 0xef, 0xa1, 0xef, 0xa1, 0xef, 0x37, 0xf0, 0x37, 0xf0, 0x0d, 0xf1, 0x0d, 0xf1, 0x46, 0xf2, 0x46, 0xf2, 0xe5, 0xf3, 0xe5, 0xf3, 0xd2, 0xf5, 0xd2, 0xf5, 0xf9, 0xf7, 0xf9, 0xf7, 0x59, 0xfa, 0x59, 0xfa, 0xf4, 0xfc, 0xf4, 0xfc, 0xd3, 0xff, 0xd3, 0xff, 0xf3, 0x02, 0xf3, 0x02, 0x35, 0x06, 0x35, 0x06, 0x5f, 0x09, 0x5f, 0x09, 0x36, 0x0c, 0x36, 0x0c, 0x97, 0x0e, 0x97, 0x0e, 0x7b, 0x10, 0x7b, 0x10, 0xf1, 0x11, 0xf1, 0x11, 0x0c, 0x13, 0x0c, 0x13, 0xcf, 0x13, 0xcf, 0x13, 0x2a, 0x14, 0x2a, 0x14, 0x15, 0x14, 0x15, 0x14, 0xa2, 0x13, 0xa2, 0x13, 0xf2, 0x12, 0xf2, 0x12, 0x25, 0x12, 0x25, 0x12, 0x57, 0x11, 0x57, 0x11, 0x81, 0x10, 0x81, 0x10, 0x8b, 0x0f, 0x8b, 0x0f, 0x6e, 0x0e, 0x6e, 0x0e, 0x32, 0x0d, 0x32, 0x0d, 0xe7, 0x0b, 0xe7, 0x0b, 0x9b, 0x0a, 0x9b, 0x0a, 0x4f, 0x09, 0x4f, 0x09, 0xec, 0x07, 0xec, 0x07, 0x50, 0x06, 0x50, 0x06, 0x69, 0x04, 0x69, 0x04, 0x3c, 0x02, 0x3c, 0x02, 0xda, 0xff, 0xda, 0xff, 0x5e, 0xfd, 0x5e, 0xfd, 0xe4, 0xfa, 0xe4, 0xfa, 0x7c, 0xf8, 0x7c, 0xf8, 0x29, 0xf6, 0x29, 0xf6, 0xfc, 0xf3, 0xfc, 0xf3, 0x11, 0xf2, 0x11, 0xf2, 0x88, 0xf0, 0x88, 0xf0, 0x81, 0xef, 0x81, 0xef, 0x01, 0xef, 0x01, 0xef, 0xf0, 0xee, 0xf0, 0xee, 0x2c, 0xef, 0x2c, 0xef, 0xb0, 0xef, 0xb0, 0xef, 0x91, 0xf0, 0x91, 0xf0, 0xe6, 0xf1, 0xe6, 0xf1, 0xa9, 0xf3, 0xa9, 0xf3, 0xb9, 0xf5, 0xb9, 0xf5, 0xde, 0xf7, 0xde, 0xf7, 0xdd, 0xf9, 0xdd, 0xf9, 0x8e, 0xfb, 0x8e, 0xfb, 0xe7, 0xfc, 0xe7, 0xfc, 0xfe, 0xfd, 0xfe, 0xfd, 0xf0, 0xfe, 0xf0, 0xfe, 0xd2, 0xff, 0xd2, 0xff, 0xb0, 0x00, 0xb0, 0x00, 0x89, 0x01, 0x89, 0x01, 0x57, 0x02, 0x57, 0x02, 0x25, 0x03, 0x25, 0x03, 0x1b, 0x04, 0x1b, 0x04, 0x64, 0x05, 0x64, 0x05, 0x0a, 0x07, 0x0a, 0x07, 0xf4, 0x08, 0xf4, 0x08, 0xe4, 0x0a, 0xe4, 0x0a, 0x88, 0x0c, 0x88, 0x0c, 0xbf, 0x0d, 0xbf, 0x0d, 0x7c, 0x0e, 0x7c, 0x0e, 0xd1, 0x0e, 0xd1, 0x0e, 0xca, 0x0e, 0xca, 0x0e, 0x48, 0x0e, 0x48, 0x0e, 0x33, 0x0d, 0x33, 0x0d, 0x8f, 0x0b, 0x8f, 0x0b, 0x74, 0x09, 0x74, 0x09, 0x0f, 0x07, 0x0f, 0x07, 0x97, 0x04, 0x97, 0x04, 0x37, 0x02, 0x37, 0x02, 0x11, 0x00, 0x11, 0x00, 0x42, 0xfe, 0x42, 0xfe, 0xe1, 0xfc, 0xe1, 0xfc, 0xfe, 0xfb, 0xfe, 0xfb, 0x91, 0xfb, 0x91, 0xfb, 0x7d, 0xfb, 0x7d, 0xfb, 0x9b, 0xfb, 0x9b, 0xfb, 0xd4, 0xfb, 0xd4, 0xfb, 0x12, 0xfc, 0x12, 0xfc, 0x39, 0xfc, 0x39, 0xfc, 0x2f, 0xfc, 0x2f, 0xfc, 0xe5, 0xfb, 0xe5, 0xfb, 0x56, 0xfb, 0x56, 0xfb, 0x8f, 0xfa, 0x8f, 0xfa, 0xab, 0xf9, 0xab, 0xf9, 0xc8, 0xf8, 0xc8, 0xf8, 0x02, 0xf8, 0x02, 0xf8, 0x6c, 0xf7, 0x6c, 0xf7, 0x1a, 0xf7, 0x1a, 0xf7, 0x25, 0xf7, 0x25, 0xf7, 0xa0, 0xf7, 0xa0, 0xf7, 0x95, 0xf8, 0x95, 0xf8, 0xf5, 0xf9, 0xf5, 0xf9, 0xa0, 0xfb, 0xa0, 0xfb, 0x76, 0xfd, 0x76, 0xfd, 0x68, 0xff, 0x68, 0xff, 0x62, 0x01, 0x62, 0x01, 0x3d, 0x03, 0x3d, 0x03, 0xbb, 0x04, 0xbb, 0x04, 0xa6, 0x05, 0xa6, 0x05, 0xef, 0x05, 0xef, 0x05, 0xac, 0x05, 0xac, 0x05, 0xfe, 0x04, 0xfe, 0x04, 0x03, 0x04, 0x03, 0x04, 0xc8, 0x02, 0xc8, 0x02, 0x61, 0x01, 0x61, 0x01, 0xf5, 0xff, 0xf5, 0xff, 0xb9, 0xfe, 0xb9, 0xfe, 0xd6, 0xfd, 0xd6, 0xfd, 0x5a, 0xfd, 0x5a, 0xfd, 0x3b, 0xfd, 0x3b, 0xfd, 0x62, 0xfd, 0x62, 0xfd, 0xb8, 0xfd, 0xb8, 0xfd, 0x3a, 0xfe, 0x3a, 0xfe, 0xde, 0xfe, 0xde, 0xfe, 0x87, 0xff, 0x87, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x33, 0x00, 0xc8, 0xff, 0xc8, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x41, 0xfe, 0x41, 0xfe, 0x4a, 0xfd, 0x4a, 0xfd, 0x4b, 0xfc, 0x4b, 0xfc, 0x68, 0xfb, 0x68, 0xfb, 0xd0, 0xfa, 0xd0, 0xfa, 0xb3, 0xfa, 0xb3, 0xfa, 0x2b, 0xfb, 0x2b, 0xfb, 0x38, 0xfc, 0x38, 0xfc, 0xbd, 0xfd, 0xbd, 0xfd, 0x95, 0xff, 0x95, 0xff, 0xa5, 0x01, 0xa5, 0x01, 0xd7, 0x03, 0xd7, 0x03, 0x07, 0x06, 0x07, 0x06, 0x02, 0x08, 0x02, 0x08, 0x9a, 0x09, 0x9a, 0x09, 0xb6, 0x0a, 0xb6, 0x0a, 0x4b, 0x0b, 0x4b, 0x0b, 0x57, 0x0b, 0x57, 0x0b, 0xd9, 0x0a, 0xd9, 0x0a, 0xdb, 0x09, 0xdb, 0x09, 0x7c, 0x08, 0x7c, 0x08, 0xe8, 0x06, 0xe8, 0x06, 0x48, 0x05, 0x48, 0x05, 0xaf, 0x03, 0xaf, 0x03, 0x28, 0x02, 0x28, 0x02, 0xcf, 0x00, 0xcf, 0x00, 0xce, 0xff, 0xce, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0xd1, 0xfe, 0xd1, 0xfe, 0x7c, 0xfe, 0x7c, 0xfe, 0x09, 0xfe, 0x09, 0xfe, 0x76, 0xfd, 0x76, 0xfd, 0xda, 0xfc, 0xda, 0xfc, 0x37, 0xfc, 0x37, 0xfc, 0x68, 0xfb, 0x68, 0xfb, 0x4b, 0xfa, 0x4b, 0xfa, 0xd8, 0xf8, 0xd8, 0xf8, 0x1e, 0xf7, 0x1e, 0xf7, 0x3a, 0xf5, 0x3a, 0xf5, 0x5d, 0xf3, 0x5d, 0xf3, 0xce, 0xf1, 0xce, 0xf1, 0xda, 0xf0, 0xda, 0xf0, 0xba, 0xf0, 0xba, 0xf0, 0x69, 0xf1, 0x69, 0xf1, 0x8d, 0xf2, 0x8d, 0xf2, 0xc6, 0xf3, 0xc6, 0xf3, 0x20, 0xf5, 0x20, 0xf5, 0x11, 0xf7, 0x11, 0xf7, 0xf4, 0xf9, 0xf4, 0xf9, 0x96, 0xfd, 0x96, 0xfd, 0x4d, 0x01, 0x4d, 0x01, 0x79, 0x04, 0x79, 0x04, 0xe9, 0x06, 0xe9, 0x06, 0xd0, 0x08, 0xd0, 0x08, 0x6b, 0x0a, 0x6b, 0x0a, 0xb5, 0x0b, 0xb5, 0x0b, 0x80, 0x0c, 0x80, 0x0c, 0xcb, 0x0c, 0xcb, 0x0c, 0xd4, 0x0c, 0xd4, 0x0c, 0xda, 0x0c, 0xda, 0x0c, 0xdd, 0x0c, 0xdd, 0x0c, 0xae, 0x0c, 0xae, 0x0c, 0x4a, 0x0c, 0x4a, 0x0c, 0xee, 0x0b, 0xee, 0x0b, 0xdf, 0x0b, 0xdf, 0x0b, 0x13, 0x0c, 0x13, 0x0c, 0x26, 0x0c, 0x26, 0x0c, 0xb3, 0x0b, 0xb3, 0x0b, 0xa5, 0x0a, 0xa5, 0x0a, 0x34, 0x09, 0x34, 0x09, 0x7d, 0x07, 0x7d, 0x07, 0x55, 0x05, 0x55, 0x05, 0x7c, 0x02, 0x7c, 0x02, 0xfd, 0xfe, 0xfd, 0xfe, 0x35, 0xfb, 0x35, 0xfb, 0x85, 0xf7, 0x85, 0xf7, 0x10, 0xf4, 0x10, 0xf4, 0xc9, 0xf0, 0xc9, 0xf0, 0xc0, 0xed, 0xc0, 0xed, 0x3b, 0xeb, 0x3b, 0xeb, 0x95, 0xe9, 0x95, 0xe9, 0xf6, 0xe8, 0xf6, 0xe8, 0x3a, 0xe9, 0x3a, 0xe9, 0x2d, 0xea, 0x2d, 0xea, 0xb6, 0xeb, 0xb6, 0xeb, 0xcd, 0xed, 0xcd, 0xed, 0x55, 0xf0, 0x55, 0xf0, 0x13, 0xf3, 0x13, 0xf3, 0xda, 0xf5, 0xda, 0xf5, 0xa6, 0xf8, 0xa6, 0xf8, 0x8d, 0xfb, 0x8d, 0xfb, 0x87, 0xfe, 0x87, 0xfe, 0x5c, 0x01, 0x5c, 0x01, 0xd9, 0x03, 0xd9, 0x03, 0x0b, 0x06, 0x0b, 0x06, 0x38, 0x08, 0x38, 0x08, 0x96, 0x0a, 0x96, 0x0a, 0x14, 0x0d, 0x14, 0x0d, 0x78, 0x0f, 0x78, 0x0f, 0xa7, 0x11, 0xa7, 0x11, 0xae, 0x13, 0xae, 0x13, 0xa2, 0x15, 0xa2, 0x15, 0x72, 0x17, 0x72, 0x17, 0xe1, 0x18, 0xe1, 0x18, 0xae, 0x19, 0xae, 0x19, 0xb8, 0x19, 0xb8, 0x19, 0x03, 0x19, 0x03, 0x19, 0x8f, 0x17, 0x8f, 0x17, 0x4b, 0x15, 0x4b, 0x15, 0x33, 0x12, 0x33, 0x12, 0x68, 0x0e, 0x68, 0x0e, 0x22, 0x0a, 0x22, 0x0a, 0x91, 0x05, 0x91, 0x05, 0xcb, 0x00, 0xcb, 0x00, 0xea, 0xfb, 0xea, 0xfb, 0x1b, 0xf7, 0x1b, 0xf7, 0x9f, 0xf2, 0x9f, 0xf2, 0xa8, 0xee, 0xa8, 0xee, 0x47, 0xeb, 0x47, 0xeb, 0x76, 0xe8, 0x76, 0xe8, 0x3a, 0xe6, 0x3a, 0xe6, 0x9d, 0xe4, 0x9d, 0xe4, 0xaa, 0xe3, 0xaa, 0xe3, 0x51, 0xe3, 0x51, 0xe3, 0x77, 0xe3, 0x77, 0xe3, 0x08, 0xe4, 0x08, 0xe4, 0x02, 0xe5, 0x02, 0xe5, 0x70, 0xe6, 0x70, 0xe6, 0x56, 0xe8, 0x56, 0xe8, 0xb1, 0xea, 0xb1, 0xea, 0x82, 0xed, 0x82, 0xed, 0xd8, 0xf0, 0xd8, 0xf0, 0xba, 0xf4, 0xba, 0xf4, 0x1b, 0xf9, 0x1b, 0xf9, 0xd9, 0xfd, 0xd9, 0xfd, 0xd2, 0x02, 0xd2, 0x02, 0xec, 0x07, 0xec, 0x07, 0x05, 0x0d, 0x05, 0x0d, 0xec, 0x11, 0xec, 0x11, 0x6c, 0x16, 0x6c, 0x16, 0x59, 0x1a, 0x59, 0x1a, 0x93, 0x1d, 0x93, 0x1d, 0x03, 0x20, 0x03, 0x20, 0x96, 0x21, 0x96, 0x21, 0x38, 0x22, 0x38, 0x22, 0xd9, 0x21, 0xd9, 0x21, 0x7f, 0x20, 0x7f, 0x20, 0x44, 0x1e, 0x44, 0x1e, 0x51, 0x1b, 0x51, 0x1b, 0xcf, 0x17, 0xcf, 0x17, 0xe0, 0x13, 0xe0, 0x13, 0xa4, 0x0f, 0xa4, 0x0f, 0x34, 0x0b, 0x34, 0x0b, 0xa9, 0x06, 0xa9, 0x06, 0x13, 0x02, 0x13, 0x02, 0x89, 0xfd, 0x89, 0xfd, 0x21, 0xf9, 0x21, 0xf9, 0xea, 0xf4, 0xea, 0xf4, 0xe9, 0xf0, 0xe9, 0xf0, 0x20, 0xed, 0x20, 0xed, 0x97, 0xe9, 0x97, 0xe9, 0x60, 0xe6, 0x60, 0xe6, 0x9f, 0xe3, 0x9f, 0xe3, 0x70, 0xe1, 0x70, 0xe1, 0xe6, 0xdf, 0xe6, 0xdf, 0x10, 0xdf, 0x10, 0xdf, 0x03, 0xdf, 0x03, 0xdf, 0xd2, 0xdf, 0xd2, 0xdf, 0x85, 0xe1, 0x85, 0xe1, 0x1d, 0xe4, 0x1d, 0xe4, 0x94, 0xe7, 0x94, 0xe7, 0xd8, 0xeb, 0xd8, 0xeb, 0xd0, 0xf0, 0xd0, 0xf0, 0x51, 0xf6, 0x51, 0xf6, 0x25, 0xfc, 0x25, 0xfc, 0x0f, 0x02, 0x0f, 0x02, 0xdb, 0x07, 0xdb, 0x07, 0x5c, 0x0d, 0x5c, 0x0d, 0x6c, 0x12, 0x6c, 0x12, 0xe0, 0x16, 0xe0, 0x16, 0x99, 0x1a, 0x99, 0x1a, 0x81, 0x1d, 0x81, 0x1d, 0x95, 0x1f, 0x95, 0x1f, 0xd7, 0x20, 0xd7, 0x20, 0x48, 0x21, 0x48, 0x21, 0xee, 0x20, 0xee, 0x20, 0xd3, 0x1f, 0xd3, 0x1f, 0x0d, 0x1e, 0x0d, 0x1e, 0xae, 0x1b, 0xae, 0x1b, 0xc5, 0x18, 0xc5, 0x18, 0x5c, 0x15, 0x5c, 0x15, 0x7b, 0x11, 0x7b, 0x11, 0x31, 0x0d, 0x31, 0x0d, 0x92, 0x08, 0x92, 0x08, 0xb2, 0x03, 0xb2, 0x03, 0xa4, 0xfe, 0xa4, 0xfe, 0x80, 0xf9, 0x80, 0xf9, 0x67, 0xf4, 0x67, 0xf4, 0x7f, 0xef, 0x7f, 0xef, 0xef, 0xea, 0xef, 0xea, 0xe2, 0xe6, 0xe2, 0xe6, 0x78, 0xe3, 0x78, 0xe3, 0xd2, 0xe0, 0xd2, 0xe0, 0x0f, 0xdf, 0x0f, 0xdf, 0x40, 0xde, 0x40, 0xde, 0x65, 0xde, 0x65, 0xde, 0x73, 0xdf, 0x73, 0xdf, 0x5c, 0xe1, 0x5c, 0xe1, 0x09, 0xe4, 0x09, 0xe4, 0x62, 0xe7, 0x62, 0xe7, 0x4f, 0xeb, 0x4f, 0xeb, 0xab, 0xef, 0xab, 0xef, 0x53, 0xf4, 0x53, 0xf4, 0x29, 0xf9, 0x29, 0xf9, 0x0e, 0xfe, 0x0e, 0xfe, 0xe3, 0x02, 0xe3, 0x02, 0x8a, 0x07, 0x8a, 0x07, 0xe8, 0x0b, 0xe8, 0x0b, 0xeb, 0x0f, 0xeb, 0x0f, 0x7b, 0x13, 0x7b, 0x13, 0x89, 0x16, 0x89, 0x16, 0x09, 0x19, 0x09, 0x19, 0xf3, 0x1a, 0xf3, 0x1a, 0x3a, 0x1c, 0x3a, 0x1c, 0xcb, 0x1c, 0xcb, 0x1c, 0x9b, 0x1c, 0x9b, 0x1c, 0xa8, 0x1b, 0xa8, 0x1b, 0xf8, 0x19, 0xf8, 0x19, 0x99, 0x17, 0x99, 0x17, 0x9d, 0x14, 0x9d, 0x14, 0x15, 0x11, 0x15, 0x11, 0x13, 0x0d, 0x13, 0x0d, 0xac, 0x08, 0xac, 0x08, 0x09, 0x04, 0x09, 0x04, 0x55, 0xff, 0x55, 0xff, 0xb8, 0xfa, 0xb8, 0xfa, 0x59, 0xf6, 0x59, 0xf6, 0x5a, 0xf2, 0x5a, 0xf2, 0xd4, 0xee, 0xd4, 0xee, 0xe1, 0xeb, 0xe1, 0xeb, 0x95, 0xe9, 0x95, 0xe9, 0xfb, 0xe7, 0xfb, 0xe7, 0x1d, 0xe7, 0x1d, 0xe7, 0x01, 0xe7, 0x01, 0xe7, 0xa4, 0xe7, 0xa4, 0xe7, 0xf6, 0xe8, 0xf6, 0xe8, 0xe1, 0xea, 0xe1, 0xea, 0x50, 0xed, 0x50, 0xed, 0x2d, 0xf0, 0x2d, 0xf0, 0x5e, 0xf3, 0x5e, 0xf3, 0xc7, 0xf6, 0xc7, 0xf6, 0x4d, 0xfa, 0x4d, 0xfa, 0xd9, 0xfd, 0xd9, 0xfd, 0x55, 0x01, 0x55, 0x01, 0xb0, 0x04, 0xb0, 0x04, 0xdd, 0x07, 0xdd, 0x07, 0xc8, 0x0a, 0xc8, 0x0a, 0x5f, 0x0d, 0x5f, 0x0d, 0x94, 0x0f, 0x94, 0x0f, 0x5d, 0x11, 0x5d, 0x11, 0xa4, 0x12, 0xa4, 0x12, 0x5c, 0x13, 0x5c, 0x13, 0x7c, 0x13, 0x7c, 0x13, 0x0a, 0x13, 0x0a, 0x13, 0x0e, 0x12, 0x0e, 0x12, 0x93, 0x10, 0x93, 0x10, 0xa2, 0x0e, 0xa2, 0x0e, 0x3f, 0x0c, 0x3f, 0x0c, 0x75, 0x09, 0x75, 0x09, 0x5d, 0x06, 0x5d, 0x06, 0x19, 0x03, 0x19, 0x03, 0xc4, 0xff, 0xc4, 0xff, 0x7b, 0xfc, 0x7b, 0xfc, 0x5f, 0xf9, 0x5f, 0xf9, 0x8b, 0xf6, 0x8b, 0xf6, 0x1b, 0xf4, 0x1b, 0xf4, 0x1f, 0xf2, 0x1f, 0xf2, 0xa2, 0xf0, 0xa2, 0xf0, 0xa4, 0xef, 0xa4, 0xef, 0x27, 0xef, 0x27, 0xef, 0x31, 0xef, 0x31, 0xef, 0xbd, 0xef, 0xbd, 0xef, 0xbf, 0xf0, 0xbf, 0xf0, 0x29, 0xf2, 0x29, 0xf2, 0xf1, 0xf3, 0xf1, 0xf3, 0x0a, 0xf6, 0x0a, 0xf6, 0x66, 0xf8, 0x66, 0xf8, 0xf4, 0xfa, 0xf4, 0xfa, 0x9d, 0xfd, 0x9d, 0xfd, 0x49, 0x00, 0x49, 0x00, 0xe7, 0x02, 0xe7, 0x02, 0x65, 0x05, 0x65, 0x05, 0xb2, 0x07, 0xb2, 0x07, 0xbb, 0x09, 0xbb, 0x09, 0x75, 0x0b, 0x75, 0x0b, 0xd7, 0x0c, 0xd7, 0x0c, 0xda, 0x0d, 0xda, 0x0d, 0x78, 0x0e, 0x78, 0x0e, 0xa9, 0x0e, 0xa9, 0x0e, 0x6d, 0x0e, 0x6d, 0x0e, 0xc4, 0x0d, 0xc4, 0x0d, 0xb6, 0x0c, 0xb6, 0x0c, 0x4e, 0x0b, 0x4e, 0x0b, 0xa2, 0x09, 0xa2, 0x09, 0xba, 0x07, 0xba, 0x07, 0xa8, 0x05, 0xa8, 0x05, 0x82, 0x03, 0x82, 0x03, 0x5c, 0x01, 0x5c, 0x01, 0x41, 0xff, 0x41, 0xff, 0x3e, 0xfd, 0x3e, 0xfd, 0x65, 0xfb, 0x65, 0xfb, 0xc6, 0xf9, 0xc6, 0xf9, 0x69, 0xf8, 0x69, 0xf8, 0x55, 0xf7, 0x55, 0xf7, 0x8f, 0xf6, 0x8f, 0xf6, 0x15, 0xf6, 0x15, 0xf6, 0xea, 0xf5, 0xea, 0xf5, 0x17, 0xf6, 0x17, 0xf6, 0x99, 0xf6, 0x99, 0xf6, 0x6f, 0xf7, 0x6f, 0xf7, 0x8a, 0xf8, 0x8a, 0xf8, 0xe0, 0xf9, 0xe0, 0xf9, 0x58, 0xfb, 0x58, 0xfb, 0xe7, 0xfc, 0xe7, 0xfc, 0x86, 0xfe, 0x86, 0xfe, 0x2a, 0x00, 0x2a, 0x00, 0xc3, 0x01, 0xc3, 0x01, 0x44, 0x03, 0x44, 0x03, 0x9e, 0x04, 0x9e, 0x04, 0xc3, 0x05, 0xc3, 0x05, 0xaf, 0x06, 0xaf, 0x06, 0x5b, 0x07, 0x5b, 0x07, 0xbe, 0x07, 0xbe, 0x07, 0xd5, 0x07, 0xd5, 0x07, 0xa1, 0x07, 0xa1, 0x07, 0x25, 0x07, 0x25, 0x07, 0x6c, 0x06, 0x6c, 0x06, 0x84, 0x05, 0x84, 0x05, 0x7d, 0x04, 0x7d, 0x04, 0x5d, 0x03, 0x5d, 0x03, 0x2b, 0x02, 0x2b, 0x02, 0xf3, 0x00, 0xf3, 0x00, 0xbd, 0xff, 0xbd, 0xff, 0x91, 0xfe, 0x91, 0xfe, 0x7b, 0xfd, 0x7b, 0xfd, 0x86, 0xfc, 0x86, 0xfc, 0xbb, 0xfb, 0xbb, 0xfb, 0x23, 0xfb, 0x23, 0xfb, 0xc1, 0xfa, 0xc1, 0xfa, 0x8b, 0xfa, 0x8b, 0xfa, 0x76, 0xfa, 0x76, 0xfa, 0x7f, 0xfa, 0x7f, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0x09, 0xfb, 0x09, 0xfb, 0x94, 0xfb, 0x94, 0xfb, 0x47, 0xfc, 0x47, 0xfc, 0x0c, 0xfd, 0x0c, 0xfd, 0xd4, 0xfd, 0xd4, 0xfd, 0xa0, 0xfe, 0xa0, 0xfe, 0x74, 0xff, 0x74, 0xff, 0x56, 0x00, 0x56, 0x00, 0x3b, 0x01, 0x3b, 0x01, 0x13, 0x02, 0x13, 0x02, 0xcc, 0x02, 0xcc, 0x02, 0x5e, 0x03, 0x5e, 0x03, 0xce, 0x03, 0xce, 0x03, 0x17, 0x04, 0x17, 0x04, 0x36, 0x04, 0x36, 0x04, 0x26, 0x04, 0x26, 0x04, 0xec, 0x03, 0xec, 0x03, 0x95, 0x03, 0x95, 0x03, 0x28, 0x03, 0x28, 0x03, 0xab, 0x02, 0xab, 0x02, 0x23, 0x02, 0x23, 0x02, 0x8c, 0x01, 0x8c, 0x01, 0xe8, 0x00, 0xe8, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x85, 0xff, 0x85, 0xff, 0xca, 0xfe, 0xca, 0xfe, 0x0d, 0xfe, 0x0d, 0xfe, 0x59, 0xfd, 0x59, 0xfd, 0xb7, 0xfc, 0xb7, 0xfc, 0x2b, 0xfc, 0x2b, 0xfc, 0xbc, 0xfb, 0xbc, 0xfb, 0x6d, 0xfb, 0x6d, 0xfb, 0x44, 0xfb, 0x44, 0xfb, 0x53, 0xfb, 0x53, 0xfb, 0xa7, 0xfb, 0xa7, 0xfb, 0x3f, 0xfc, 0x3f, 0xfc, 0x0e, 0xfd, 0x0e, 0xfd, 0x00, 0xfe, 0x00, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0xf6, 0xff, 0xf6, 0xff, 0xe0, 0x00, 0xe0, 0x00, 0xb2, 0x01, 0xb2, 0x01, 0x58, 0x02, 0x58, 0x02, 0xbd, 0x02, 0xbd, 0x02, 0xd5, 0x02, 0xd5, 0x02, 0xa5, 0x02, 0xa5, 0x02, 0x3a, 0x02, 0x3a, 0x02, 0xa4, 0x01, 0xa4, 0x01, 0xff, 0x00, 0xff, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0xd6, 0xff, 0xd6, 0xff, 0x73, 0xff, 0x73, 0xff, 0x35, 0xff, 0x35, 0xff, 0x12, 0xff, 0x12, 0xff, 0x01, 0xff, 0x01, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x12, 0xff, 0x12, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0x71, 0xff, 0x71, 0xff, 0x94, 0xff, 0x94, 0xff, 0x91, 0xff, 0x91, 0xff, 0x67, 0xff, 0x67, 0xff, 0x2d, 0xff, 0x2d, 0xff, 0x03, 0xff, 0x03, 0xff, 0xfb, 0xfe, 0xfb, 0xfe, 0x12, 0xff, 0x12, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0x70, 0xff, 0x70, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x40, 0x00, 0x40, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xa0, 0x01, 0xa0, 0x01, 0x7b, 0x02, 0x7b, 0x02, 0xfc, 0x02, 0xfc, 0x02, 0xe0, 0x02, 0xe0, 0x02, 0x47, 0x02, 0x47, 0x02, 0xa9, 0x01, 0xa9, 0x01, 0x87, 0x01, 0x87, 0x01, 0x0b, 0x02, 0x0b, 0x02, 0xe2, 0x02, 0xe2, 0x02, 0x6c, 0x03, 0x6c, 0x03, 0x3d, 0x03, 0x3d, 0x03, 0x5e, 0x02, 0x5e, 0x02, 0x39, 0x01, 0x39, 0x01, 0x4e, 0x00, 0x4e, 0x00, 0xee, 0xff, 0xee, 0xff, 0x19, 0x00, 0x19, 0x00, 0x87, 0x00, 0x87, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x5b, 0xff, 0x5b, 0xff, 0xdf, 0xfd, 0xdf, 0xfd, 0x9c, 0xfc, 0x9c, 0xfc, 0x1e, 0xfc, 0x1e, 0xfc, 0x7e, 0xfc, 0x7e, 0xfc, 0x5d, 0xfd, 0x5d, 0xfd, 0x24, 0xfe, 0x24, 0xfe, 0x69, 0xfe, 0x69, 0xfe, 0x2b, 0xfe, 0x2b, 0xfe, 0xcb, 0xfd, 0xcb, 0xfd, 0xb2, 0xfd, 0xb2, 0xfd, 0x0b, 0xfe, 0x0b, 0xfe, 0xbb, 0xfe, 0xbb, 0xfe, 0x8b, 0xff, 0x8b, 0xff, 0x4c, 0x00, 0x4c, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x27, 0x01, 0x27, 0x01, 0x35, 0x01, 0x35, 0x01, 0x27, 0x01, 0x27, 0x01, 0x27, 0x01, 0x27, 0x01, 0x41, 0x01, 0x41, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x39, 0x01, 0x39, 0x01, 0xfd, 0x00, 0xfd, 0x00, 0xba, 0x00, 0xba, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x03, 0x00, 0x03, 0x00, 0x7b, 0xff, 0x7b, 0xff, 0xf2, 0xfe, 0xf2, 0xfe, 0x9e, 0xfe, 0x9e, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0xc5, 0xfe, 0xc5, 0xfe, 0xf3, 0xfe, 0xf3, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xe8, 0xfe, 0xe8, 0xfe, 0xd2, 0xfe, 0xd2, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0x12, 0xff, 0x12, 0xff, 0x68, 0xff, 0x68, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0x5a, 0x00, 0x5a, 0x00, 0xde, 0x00, 0xde, 0x00, 0x4d, 0x01, 0x4d, 0x01, 0x97, 0x01, 0x97, 0x01, 0xc2, 0x01, 0xc2, 0x01, 0xe9, 0x01, 0xe9, 0x01, 0x22, 0x02, 0x22, 0x02, 0x69, 0x02, 0x69, 0x02, 0xad, 0x02, 0xad, 0x02, 0xda, 0x02, 0xda, 0x02, 0xe2, 0x02, 0xe2, 0x02, 0xbc, 0x02, 0xbc, 0x02, 0x61, 0x02, 0x61, 0x02, 0xd1, 0x01, 0xd1, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x65, 0x00, 0x65, 0x00, 0xcf, 0xff, 0xcf, 0xff, 0x62, 0xff, 0x62, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0xbb, 0xfe, 0xbb, 0xfe, 0x5c, 0xfe, 0x5c, 0xfe, 0xf8, 0xfd, 0xf8, 0xfd, 0xa6, 0xfd, 0xa6, 0xfd, 0x7b, 0xfd, 0x7b, 0xfd, 0x7c, 0xfd, 0x7c, 0xfd, 0xa6, 0xfd, 0xa6, 0xfd, 0xf2, 0xfd, 0xf2, 0xfd, 0x5b, 0xfe, 0x5b, 0xfe, 0xd1, 0xfe, 0xd1, 0xfe, 0x41, 0xff, 0x41, 0xff, 0x98, 0xff, 0x98, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0x01, 0x00, 0x01, 0x00, 0x28, 0x00, 0x28, 0x00, 0x53, 0x00, 0x53, 0x00, 0x86, 0x00, 0x86, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xef, 0x00, 0xef, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x12, 0x01, 0x12, 0x01, 0xff, 0x00, 0xff, 0x00, 0xe8, 0x00, 0xe8, 0x00, 0xda, 0x00, 0xda, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x63, 0x00, 0x63, 0x00, 0x14, 0x00, 0x14, 0x00, 0xb2, 0xff, 0xb2, 0xff, 0x42, 0xff, 0x42, 0xff, 0xca, 0xfe, 0xca, 0xfe, 0x58, 0xfe, 0x58, 0xfe, 0xfa, 0xfd, 0xfa, 0xfd, 0xae, 0xfd, 0xae, 0xfd, 0x6b, 0xfd, 0x6b, 0xfd, 0x33, 0xfd, 0x33, 0xfd, 0x11, 0xfd, 0x11, 0xfd, 0x1a, 0xfd, 0x1a, 0xfd, 0x50, 0xfd, 0x50, 0xfd, 0xac, 0xfd, 0xac, 0xfd, 0x22, 0xfe, 0x22, 0xfe, 0xa9, 0xfe, 0xa9, 0xfe, 0x3d, 0xff, 0x3d, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0x73, 0x00, 0x73, 0x00, 0x03, 0x01, 0x03, 0x01, 0x85, 0x01, 0x85, 0x01, 0xfd, 0x01, 0xfd, 0x01, 0x6f, 0x02, 0x6f, 0x02, 0xd6, 0x02, 0xd6, 0x02, 0x24, 0x03, 0x24, 0x03, 0x4c, 0x03, 0x4c, 0x03, 0x48, 0x03, 0x48, 0x03, 0x23, 0x03, 0x23, 0x03, 0xe5, 0x02, 0xe5, 0x02, 0x94, 0x02, 0x94, 0x02, 0x34, 0x02, 0x34, 0x02, 0xcf, 0x01, 0xcf, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x04, 0x01, 0x04, 0x01, 0x9b, 0x00, 0x9b, 0x00, 0x29, 0x00, 0x29, 0x00, 0xb2, 0xff, 0xb2, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0xde, 0xfe, 0xde, 0xfe, 0x94, 0xfe, 0x94, 0xfe, 0x5a, 0xfe, 0x5a, 0xfe, 0x20, 0xfe, 0x20, 0xfe, 0xe7, 0xfd, 0xe7, 0xfd, 0xb7, 0xfd, 0xb7, 0xfd, 0x9d, 0xfd, 0x9d, 0xfd, 0x9f, 0xfd, 0x9f, 0xfd, 0xb4, 0xfd, 0xb4, 0xfd, 0xd6, 0xfd, 0xd6, 0xfd, 0x04, 0xfe, 0x04, 0xfe, 0x40, 0xfe, 0x40, 0xfe, 0x8d, 0xfe, 0x8d, 0xfe, 0xec, 0xfe, 0xec, 0xfe, 0x5a, 0xff, 0x5a, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0x4a, 0x00, 0x4a, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0x12, 0x01, 0x12, 0x01, 0x4f, 0x01, 0x4f, 0x01, 0x6c, 0x01, 0x6c, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x63, 0x01, 0x63, 0x01, 0x54, 0x01, 0x54, 0x01, 0x45, 0x01, 0x45, 0x01, 0x2f, 0x01, 0x2f, 0x01, 0x11, 0x01, 0x11, 0x01, 0xec, 0x00, 0xec, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x30, 0x00, 0x30, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0x96, 0xff, 0x96, 0xff, 0x68, 0xff, 0x68, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x12, 0xff, 0x12, 0xff, 0xf5, 0xfe, 0xf5, 0xfe, 0xe8, 0xfe, 0xe8, 0xfe, 0xea, 0xfe, 0xea, 0xfe, 0xf4, 0xfe, 0xf4, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x0d, 0xff, 0x0d, 0xff, 0x27, 0xff, 0x27, 0xff, 0x58, 0xff, 0x58, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x4f, 0x00, 0x4f, 0x00, 0x98, 0x00, 0x98, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0x14, 0x01, 0x14, 0x01, 0x50, 0x01, 0x50, 0x01, 0x8e, 0x01, 0x8e, 0x01, 0xcb, 0x01, 0xcb, 0x01, 0x02, 0x02, 0x02, 0x02, 0x2e, 0x02, 0x2e, 0x02, 0x4a, 0x02, 0x4a, 0x02, 0x53, 0x02, 0x53, 0x02, 0x45, 0x02, 0x45, 0x02, 0x27, 0x02, 0x27, 0x02, 0xfc, 0x01, 0xfc, 0x01, 0xc9, 0x01, 0xc9, 0x01, 0x8d, 0x01, 0x8d, 0x01, 0x43, 0x01, 0x43, 0x01, 0xe9, 0x00, 0xe9, 0x00, 0x82, 0x00, 0x82, 0x00, 0x16, 0x00, 0x16, 0x00, 0xad, 0xff, 0xad, 0xff, 0x49, 0xff, 0x49, 0xff, 0xeb, 0xfe, 0xeb, 0xfe, 0x94, 0xfe, 0x94, 0xfe, 0x47, 0xfe, 0x47, 0xfe, 0x04, 0xfe, 0x04, 0xfe, 0xcb, 0xfd, 0xcb, 0xfd, 0x9e, 0xfd, 0x9e, 0xfd, 0x81, 0xfd, 0x81, 0xfd, 0x76, 0xfd, 0x76, 0xfd, 0x80, 0xfd, 0x80, 0xfd, 0x98, 0xfd, 0x98, 0xfd, 0xb9, 0xfd, 0xb9, 0xfd, 0xdf, 0xfd, 0xdf, 0xfd, 0x08, 0xfe, 0x08, 0xfe, 0x36, 0xfe, 0x36, 0xfe, 0x6f, 0xfe, 0x6f, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0xf4, 0xfe, 0xf4, 0xfe, 0x35, 0xff, 0x35, 0xff, 0x70, 0xff, 0x70, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0x27, 0x00, 0x27, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0x06, 0x01, 0x06, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0x8c, 0x01, 0x8c, 0x01, 0xcc, 0x01, 0xcc, 0x01, 0x0c, 0x02, 0x0c, 0x02, 0x42, 0x02, 0x42, 0x02, 0x6e, 0x02, 0x6e, 0x02, 0x8f, 0x02, 0x8f, 0x02, 0x9e, 0x02, 0x9e, 0x02, 0x95, 0x02, 0x95, 0x02, 0x72, 0x02, 0x72, 0x02, 0x3e, 0x02, 0x3e, 0x02, 0x00, 0x02, 0x00, 0x02, 0xbe, 0x01, 0xbe, 0x01, 0x7e, 0x01, 0x7e, 0x01, 0x40, 0x01, 0x40, 0x01, 0x04, 0x01, 0x04, 0x01, 0xc8, 0x00, 0xc8, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x55, 0x00, 0x55, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0xe8, 0xff, 0xe8, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x49, 0xff, 0x49, 0xff, 0x11, 0xff, 0x11, 0xff, 0xd3, 0xfe, 0xd3, 0xfe, 0x90, 0xfe, 0x90, 0xfe, 0x4a, 0xfe, 0x4a, 0xfe, 0x04, 0xfe, 0x04, 0xfe, 0xc4, 0xfd, 0xc4, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x60, 0xfd, 0x60, 0xfd, 0x41, 0xfd, 0x41, 0xfd, 0x31, 0xfd, 0x31, 0xfd, 0x2b, 0xfd, 0x2b, 0xfd, 0x2f, 0xfd, 0x2f, 0xfd, 0x40, 0xfd, 0x40, 0xfd, 0x61, 0xfd, 0x61, 0xfd, 0x94, 0xfd, 0x94, 0xfd, 0xd4, 0xfd, 0xd4, 0xfd, 0x1a, 0xfe, 0x1a, 0xfe, 0x62, 0xfe, 0x62, 0xfe, 0xaa, 0xfe, 0xaa, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe, 0x37, 0xff, 0x37, 0xff, 0x80, 0xff, 0x80, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x48, 0x00, 0x48, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xae, 0x00, 0xae, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x09, 0x01, 0x09, 0x01, 0x39, 0x01, 0x39, 0x01, 0x67, 0x01, 0x67, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0xa7, 0x01, 0xa7, 0x01, 0xbc, 0x01, 0xbc, 0x01, 0xc9, 0x01, 0xc9, 0x01, 0xcd, 0x01, 0xcd, 0x01, 0xc5, 0x01, 0xc5, 0x01, 0xaf, 0x01, 0xaf, 0x01, 0x8a, 0x01, 0x8a, 0x01, 0x57, 0x01, 0x57, 0x01, 0x19, 0x01, 0x19, 0x01, 0xdb, 0x00, 0xdb, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x71, 0x00, 0x71, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x39, 0x00, 0x39, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x92, 0x00, 0x92, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xec, 0x00, 0xec, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x25, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x2b, 0x01, 0x20, 0x01, 0x20, 0x01, 0x06, 0x01, 0x06, 0x01, 0xdd, 0x00, 0xdd, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0x65, 0x00, 0x65, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xce, 0xff, 0xce, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x24, 0xff, 0x24, 0xff, 0xcf, 0xfe, 0xcf, 0xfe, 0x7c, 0xfe, 0x7c, 0xfe, 0x2e, 0xfe, 0x2e, 0xfe, 0xe6, 0xfd, 0xe6, 0xfd, 0xaa, 0xfd, 0xaa, 0xfd, 0x7a, 0xfd, 0x7a, 0xfd, 0x55, 0xfd, 0x55, 0xfd, 0x3c, 0xfd, 0x3c, 0xfd, 0x2c, 0xfd, 0x2c, 0xfd, 0x24, 0xfd, 0x24, 0xfd, 0x29, 0xfd, 0x29, 0xfd, 0x3c, 0xfd, 0x3c, 0xfd, 0x63, 0xfd, 0x63, 0xfd, 0x9d, 0xfd, 0x9d, 0xfd, 0xe7, 0xfd, 0xe7, 0xfd, 0x40, 0xfe, 0x40, 0xfe, 0xa9, 0xfe, 0xa9, 0xfe, 0x24, 0xff, 0x24, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0x53, 0x00, 0x53, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xa9, 0x01, 0xa9, 0x01, 0x4b, 0x02, 0x4b, 0x02, 0xe0, 0x02, 0xe0, 0x02, 0x66, 0x03, 0x66, 0x03, 0xd9, 0x03, 0xd9, 0x03, 0x32, 0x04, 0x32, 0x04, 0x6c, 0x04, 0x6c, 0x04, 0x83, 0x04, 0x83, 0x04, 0x75, 0x04, 0x75, 0x04, 0x45, 0x04, 0x45, 0x04, 0xfa, 0x03, 0xfa, 0x03, 0x97, 0x03, 0x97, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x96, 0x02, 0x96, 0x02, 0xfb, 0x01, 0xfb, 0x01, 0x53, 0x01, 0x53, 0x01, 0x9f, 0x00, 0x9f, 0x00, 0xe5, 0xff, 0xe5, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x7e, 0xfe, 0x7e, 0xfe, 0xd8, 0xfd, 0xd8, 0xfd, 0x3a, 0xfd, 0x3a, 0xfd, 0xa6, 0xfc, 0xa6, 0xfc, 0x21, 0xfc, 0x21, 0xfc, 0xb5, 0xfb, 0xb5, 0xfb, 0x6c, 0xfb, 0x6c, 0xfb, 0x47, 0xfb, 0x47, 0xfb, 0x47, 0xfb, 0x47, 0xfb, 0x6a, 0xfb, 0x6a, 0xfb, 0xaf, 0xfb, 0xaf, 0xfb, 0x17, 0xfc, 0x17, 0xfc, 0xa1, 0xfc, 0xa1, 0xfc, 0x48, 0xfd, 0x48, 0xfd, 0x08, 0xfe, 0x08, 0xfe, 0xda, 0xfe, 0xda, 0xfe, 0xb8, 0xff, 0xb8, 0xff, 0x98, 0x00, 0x98, 0x00, 0x78, 0x01, 0x78, 0x01, 0x52, 0x02, 0x52, 0x02, 0x22, 0x03, 0x22, 0x03, 0xe8, 0x03, 0xe8, 0x03, 0x9b, 0x04, 0x9b, 0x04, 0x33, 0x05, 0x33, 0x05, 0xa6, 0x05, 0xa6, 0x05, 0xf2, 0x05, 0xf2, 0x05, 0x19, 0x06, 0x19, 0x06, 0x1f, 0x06, 0x1f, 0x06, 0x04, 0x06, 0x04, 0x06, 0xc4, 0x05, 0xc4, 0x05, 0x5b, 0x05, 0x5b, 0x05, 0xc7, 0x04, 0xc7, 0x04, 0x0e, 0x04, 0x0e, 0x04, 0x3b, 0x03, 0x3b, 0x03, 0x55, 0x02, 0x55, 0x02, 0x60, 0x01, 0x60, 0x01, 0x61, 0x00, 0x61, 0x00, 0x5a, 0xff, 0x5a, 0xff, 0x4d, 0xfe, 0x4d, 0xfe, 0x47, 0xfd, 0x47, 0xfd, 0x52, 0xfc, 0x52, 0xfc, 0x77, 0xfb, 0x77, 0xfb, 0xb9, 0xfa, 0xb9, 0xfa, 0x1d, 0xfa, 0x1d, 0xfa, 0xa7, 0xf9, 0xa7, 0xf9, 0x57, 0xf9, 0x57, 0xf9, 0x30, 0xf9, 0x30, 0xf9, 0x36, 0xf9, 0x36, 0xf9, 0x69, 0xf9, 0x69, 0xf9, 0xc6, 0xf9, 0xc6, 0xf9, 0x4a, 0xfa, 0x4a, 0xfa, 0xf0, 0xfa, 0xf0, 0xfa, 0xb0, 0xfb, 0xb0, 0xfb, 0x81, 0xfc, 0x81, 0xfc, 0x61, 0xfd, 0x61, 0xfd, 0x4a, 0xfe, 0x4a, 0xfe, 0x3c, 0xff, 0x3c, 0xff, 0x31, 0x00, 0x31, 0x00, 0x23, 0x01, 0x23, 0x01, 0x0f, 0x02, 0x0f, 0x02, 0xf1, 0x02, 0xf1, 0x02, 0xc7, 0x03, 0xc7, 0x03, 0x8d, 0x04, 0x8d, 0x04, 0x3c, 0x05, 0x3c, 0x05, 0xce, 0x05, 0xce, 0x05, 0x3d, 0x06, 0x3d, 0x06, 0x88, 0x06, 0x88, 0x06, 0xae, 0x06, 0xae, 0x06, 0xaf, 0x06, 0xaf, 0x06, 0x87, 0x06, 0x87, 0x06, 0x35, 0x06, 0x35, 0x06, 0xbc, 0x05, 0xbc, 0x05, 0x1d, 0x05, 0x1d, 0x05, 0x5f, 0x04, 0x5f, 0x04, 0x88, 0x03, 0x88, 0x03, 0xa2, 0x02, 0xa2, 0x02, 0xb1, 0x01, 0xb1, 0x01, 0xbe, 0x00, 0xbe, 0x00, 0xd2, 0xff, 0xd2, 0xff, 0xf0, 0xfe, 0xf0, 0xfe, 0x1c, 0xfe, 0x1c, 0xfe, 0x5b, 0xfd, 0x5b, 0xfd, 0xb5, 0xfc, 0xb5, 0xfc, 0x2e, 0xfc, 0x2e, 0xfc, 0xc5, 0xfb, 0xc5, 0xfb, 0x75, 0xfb, 0x75, 0xfb, 0x3d, 0xfb, 0x3d, 0xfb, 0x1d, 0xfb, 0x1d, 0xfb, 0x19, 0xfb, 0x19, 0xfb, 0x31, 0xfb, 0x31, 0xfb, 0x65, 0xfb, 0x65, 0xfb, 0xae, 0xfb, 0xae, 0xfb, 0x06, 0xfc, 0x06, 0xfc, 0x66, 0xfc, 0x66, 0xfc, 0xce, 0xfc, 0xce, 0xfc, 0x41, 0xfd, 0x41, 0xfd, 0xbf, 0xfd, 0xbf, 0xfd, 0x47, 0xfe, 0x47, 0xfe, 0xd0, 0xfe, 0xd0, 0xfe, 0x5b, 0xff, 0x5b, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0x5b, 0x00, 0x5b, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0x1f, 0x01, 0x1f, 0x01, 0x6b, 0x01, 0x6b, 0x01, 0xa9, 0x01, 0xa9, 0x01, 0xda, 0x01, 0xda, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0x0e, 0x02, 0x0e, 0x02, 0x0b, 0x02, 0x0b, 0x02, 0xf9, 0x01, 0xf9, 0x01, 0xda, 0x01, 0xda, 0x01, 0xb4, 0x01, 0xb4, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x60, 0x01, 0x60, 0x01, 0x34, 0x01, 0x34, 0x01, 0x05, 0x01, 0x05, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x62, 0x00, 0x62, 0x00, 0x55, 0x00, 0x55, 0x00, 0x53, 0x00, 0x53, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x63, 0x00, 0x64, 0x00, 0x64, 0x00, 0x64, 0x00, 0x64, 0x00, 0x63, 0x00, 0x63, 0x00, 0x60, 0x00, 0x60, 0x00, 0x56, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0xe9, 0xff, 0xe9, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0x78, 0xff, 0x78, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x0b, 0xff, 0x0b, 0xff, 0xdc, 0xfe, 0xdc, 0xfe, 0xad, 0xfe, 0xad, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0x53, 0xfe, 0x53, 0xfe, 0x2d, 0xfe, 0x2d, 0xfe, 0x11, 0xfe, 0x11, 0xfe, 0xfc, 0xfd, 0xfc, 0xfd, 0xec, 0xfd, 0xec, 0xfd, 0xdf, 0xfd, 0xdf, 0xfd, 0xd3, 0xfd, 0xd3, 0xfd, 0xc9, 0xfd, 0xc9, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xcc, 0xfd, 0xcc, 0xfd, 0xe3, 0xfd, 0xe3, 0xfd, 0x0b, 0xfe, 0x0b, 0xfe, 0x45, 0xfe, 0x45, 0xfe, 0x90, 0xfe, 0x90, 0xfe, 0xe9, 0xfe, 0xe9, 0xfe, 0x53, 0xff, 0x53, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0x50, 0x00, 0x50, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x6c, 0x01, 0x6c, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0x79, 0x02, 0x79, 0x02, 0xea, 0x02, 0xea, 0x02, 0x4b, 0x03, 0x4b, 0x03, 0x98, 0x03, 0x98, 0x03, 0xd1, 0x03, 0xd1, 0x03, 0xf4, 0x03, 0xf4, 0x03, 0x03, 0x04, 0x03, 0x04, 0xfd, 0x03, 0xfd, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xab, 0x03, 0xab, 0x03, 0x5e, 0x03, 0x5e, 0x03, 0xfe, 0x02, 0xfe, 0x02, 0x8c, 0x02, 0x8c, 0x02, 0x09, 0x02, 0x09, 0x02, 0x7b, 0x01, 0x7b, 0x01, 0xe2, 0x00, 0xe2, 0x00, 0x44, 0x00, 0x44, 0x00, 0xa4, 0xff, 0xa4, 0xff, 0x08, 0xff, 0x08, 0xff, 0x74, 0xfe, 0x74, 0xfe, 0xeb, 0xfd, 0xeb, 0xfd, 0x6e, 0xfd, 0x6e, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0x99, 0xfc, 0x99, 0xfc, 0x47, 0xfc, 0x47, 0xfc, 0x0c, 0xfc, 0x0c, 0xfc, 0xec, 0xfb, 0xec, 0xfb, 0xea, 0xfb, 0xea, 0xfb, 0x05, 0xfc, 0x05, 0xfc, 0x38, 0xfc, 0x38, 0xfc, 0x7d, 0xfc, 0x7d, 0xfc, 0xcf, 0xfc, 0xcf, 0xfc, 0x33, 0xfd, 0x33, 0xfd, 0xad, 0xfd, 0xad, 0xfd, 0x3e, 0xfe, 0x3e, 0xfe, 0xe4, 0xfe, 0xe4, 0xfe, 0x97, 0xff, 0x97, 0xff, 0x50, 0x00, 0x50, 0x00, 0x03, 0x01, 0x03, 0x01, 0xa6, 0x01, 0xa6, 0x01, 0x36, 0x02, 0x36, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0x2c, 0x03, 0x2c, 0x03, 0x91, 0x03, 0x91, 0x03, 0xe4, 0x03, 0xe4, 0x03, 0x1d, 0x04, 0x1d, 0x04, 0x35, 0x04, 0x35, 0x04, 0x27, 0x04, 0x27, 0x04, 0xf7, 0x03, 0xf7, 0x03, 0xb1, 0x03, 0xb1, 0x03, 0x5b, 0x03, 0x5b, 0x03, 0xf7, 0x02, 0xf7, 0x02, 0x83, 0x02, 0x83, 0x02, 0xfa, 0x01, 0xfa, 0x01, 0x61, 0x01, 0x61, 0x01, 0xbe, 0x00, 0xbe, 0x00, 0x19, 0x00, 0x19, 0x00, 0x7c, 0xff, 0x7c, 0xff, 0xf0, 0xfe, 0xf0, 0xfe, 0x78, 0xfe, 0x78, 0xfe, 0x14, 0xfe, 0x14, 0xfe, 0xbf, 0xfd, 0xbf, 0xfd, 0x75, 0xfd, 0x75, 0xfd, 0x38, 0xfd, 0x38, 0xfd, 0x0c, 0xfd, 0x0c, 0xfd, 0xf6, 0xfc, 0xf6, 0xfc, 0xf4, 0xfc, 0xf4, 0xfc, 0x06, 0xfd, 0x06, 0xfd, 0x26, 0xfd, 0x26, 0xfd, 0x4e, 0xfd, 0x4e, 0xfd, 0x7d, 0xfd, 0x7d, 0xfd, 0xb4, 0xfd, 0xb4, 0xfd, 0xf7, 0xfd, 0xf7, 0xfd, 0x48, 0xfe, 0x48, 0xfe, 0xaa, 0xfe, 0xaa, 0xfe, 0x1c, 0xff, 0x1c, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x22, 0x00, 0x22, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0x1c, 0x01, 0x1c, 0x01, 0x87, 0x01, 0x87, 0x01, 0xe5, 0x01, 0xe5, 0x01, 0x35, 0x02, 0x35, 0x02, 0x75, 0x02, 0x75, 0x02, 0x9f, 0x02, 0x9f, 0x02, 0xaf, 0x02, 0xaf, 0x02, 0xa3, 0x02, 0xa3, 0x02, 0x7d, 0x02, 0x7d, 0x02, 0x42, 0x02, 0x42, 0x02, 0xf9, 0x01, 0xf9, 0x01, 0xaa, 0x01, 0xaa, 0x01, 0x57, 0x01, 0x57, 0x01, 0x04, 0x01, 0x04, 0x01, 0xad, 0x00, 0xad, 0x00, 0x53, 0x00, 0x53, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0x97, 0xff, 0x97, 0xff, 0x44, 0xff, 0x44, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xc9, 0xfe, 0xc9, 0xfe, 0x9c, 0xfe, 0x9c, 0xfe, 0x76, 0xfe, 0x76, 0xfe, 0x57, 0xfe, 0x57, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0x3a, 0xfe, 0x3a, 0xfe, 0x3d, 0xfe, 0x3d, 0xfe, 0x4a, 0xfe, 0x4a, 0xfe, 0x5b, 0xfe, 0x5b, 0xfe, 0x71, 0xfe, 0x71, 0xfe, 0x8c, 0xfe, 0x8c, 0xfe, 0xac, 0xfe, 0xac, 0xfe, 0xd6, 0xfe, 0xd6, 0xfe, 0x09, 0xff, 0x09, 0xff, 0x48, 0xff, 0x48, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0x25, 0x00, 0x25, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x48, 0x01, 0x48, 0x01, 0xad, 0x01, 0xad, 0x01, 0x07, 0x02, 0x07, 0x02, 0x4f, 0x02, 0x4f, 0x02, 0x82, 0x02, 0x82, 0x02, 0x9e, 0x02, 0x9e, 0x02, 0xa7, 0x02, 0xa7, 0x02, 0xa3, 0x02, 0xa3, 0x02, 0x90, 0x02, 0x90, 0x02, 0x6a, 0x02, 0x6a, 0x02, 0x2f, 0x02, 0x2f, 0x02, 0xe2, 0x01, 0xe2, 0x01, 0x86, 0x01, 0x86, 0x01, 0x24, 0x01, 0x24, 0x01, 0xc4, 0x00, 0xc4, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xcf, 0xff, 0xcf, 0xff, 0x84, 0xff, 0x84, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0xf4, 0xfe, 0xf4, 0xfe, 0xb2, 0xfe, 0xb2, 0xfe, 0x72, 0xfe, 0x72, 0xfe, 0x30, 0xfe, 0x30, 0xfe, 0xeb, 0xfd, 0xeb, 0xfd, 0xa7, 0xfd, 0xa7, 0xfd, 0x67, 0xfd, 0x67, 0xfd, 0x2f, 0xfd, 0x2f, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0xe2, 0xfc, 0xe2, 0xfc, 0xd1, 0xfc, 0xd1, 0xfc, 0xd1, 0xfc, 0xd1, 0xfc, 0xe5, 0xfc, 0xe5, 0xfc, 0x10, 0xfd, 0x10, 0xfd, 0x53, 0xfd, 0x53, 0xfd, 0xab, 0xfd, 0xab, 0xfd, 0x15, 0xfe, 0x15, 0xfe, 0x8a, 0xfe, 0x8a, 0xfe, 0x08, 0xff, 0x08, 0xff, 0x87, 0xff, 0x87, 0xff, 0x04, 0x00, 0x04, 0x00, 0x80, 0x00, 0x80, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x6c, 0x01, 0x6c, 0x01, 0xcf, 0x01, 0xcf, 0x01, 0x1f, 0x02, 0x1f, 0x02, 0x59, 0x02, 0x59, 0x02, 0x81, 0x02, 0x81, 0x02, 0x99, 0x02, 0x99, 0x02, 0xa5, 0x02, 0xa5, 0x02, 0xa8, 0x02, 0xa8, 0x02, 0x9e, 0x02, 0x9e, 0x02, 0x87, 0x02, 0x87, 0x02, 0x65, 0x02, 0x65, 0x02, 0x3b, 0x02, 0x3b, 0x02, 0x0d, 0x02, 0x0d, 0x02, 0xd9, 0x01, 0xd9, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0x5e, 0x01, 0x5e, 0x01, 0x11, 0x01, 0x11, 0x01, 0xba, 0x00, 0xba, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x41, 0xff, 0x41, 0xff, 0xea, 0xfe, 0xea, 0xfe, 0x95, 0xfe, 0x95, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0xf7, 0xfd, 0xf7, 0xfd, 0xba, 0xfd, 0xba, 0xfd, 0x92, 0xfd, 0x92, 0xfd, 0x87, 0xfd, 0x87, 0xfd, 0x97, 0xfd, 0x97, 0xfd, 0xb8, 0xfd, 0xb8, 0xfd, 0xe5, 0xfd, 0xe5, 0xfd, 0x19, 0xfe, 0x19, 0xfe, 0x53, 0xfe, 0x53, 0xfe, 0x94, 0xfe, 0x94, 0xfe, 0xdb, 0xfe, 0xdb, 0xfe, 0x28, 0xff, 0x28, 0xff, 0x77, 0xff, 0x77, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2e, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x69, 0x00, 0x69, 0x00, 0x84, 0x00, 0x84, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xda, 0x00, 0xda, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x04, 0x01, 0x04, 0x01, 0x14, 0x01, 0x14, 0x01, 0x24, 0x01, 0x24, 0x01, 0x34, 0x01, 0x34, 0x01, 0x40, 0x01, 0x40, 0x01, 0x45, 0x01, 0x45, 0x01, 0x40, 0x01, 0x40, 0x01, 0x30, 0x01, 0x30, 0x01, 0x18, 0x01, 0x18, 0x01, 0xfb, 0x00, 0xfb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x81, 0x00, 0x81, 0x00, 0x69, 0x00, 0x69, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x64, 0x00, 0x73, 0x00, 0x73, 0x00, 0x83, 0x00, 0x83, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x55, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x19, 0x00, 0x19, 0x00, 0xeb, 0xff, 0xeb, 0xff, 0xac, 0xff, 0xac, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x0c, 0xff, 0x0c, 0xff, 0xbd, 0xfe, 0xbd, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0x3e, 0xfe, 0x3e, 0xfe, 0x10, 0xfe, 0x10, 0xfe, 0xeb, 0xfd, 0xeb, 0xfd, 0xce, 0xfd, 0xce, 0xfd, 0xb9, 0xfd, 0xb9, 0xfd, 0xad, 0xfd, 0xad, 0xfd, 0xac, 0xfd, 0xac, 0xfd, 0xb6, 0xfd, 0xb6, 0xfd, 0xce, 0xfd, 0xce, 0xfd, 0xf1, 0xfd, 0xf1, 0xfd, 0x1a, 0xfe, 0x1a, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x73, 0xfe, 0x73, 0xfe, 0xa2, 0xfe, 0xa2, 0xfe, 0xd4, 0xfe, 0xd4, 0xfe, 0x07, 0xff, 0x07, 0xff, 0x3e, 0xff, 0x3e, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0x26, 0x00, 0x26, 0x00, 0x85, 0x00, 0x85, 0x00, 0xe4, 0x00, 0xe4, 0x00, 0x3e, 0x01, 0x3e, 0x01, 0x93, 0x01, 0x93, 0x01, 0xe3, 0x01, 0xe3, 0x01, 0x2c, 0x02, 0x2c, 0x02, 0x6e, 0x02, 0x6e, 0x02, 0xa5, 0x02, 0xa5, 0x02, 0xd0, 0x02, 0xd0, 0x02, 0xea, 0x02, 0xea, 0x02, 0xf0, 0x02, 0xf0, 0x02, 0xe8, 0x02, 0xe8, 0x02, 0xd5, 0x02, 0xd5, 0x02, 0xc0, 0x02, 0xc0, 0x02, 0xad, 0x02, 0xad, 0x02, 0x9d, 0x02, 0x9d, 0x02, 0x8b, 0x02, 0x8b, 0x02, 0x76, 0x02, 0x76, 0x02, 0x5f, 0x02, 0x5f, 0x02, 0x48, 0x02, 0x48, 0x02, 0x32, 0x02, 0x32, 0x02, 0x1b, 0x02, 0x1b, 0x02, 0xff, 0x01, 0xff, 0x01, 0xdb, 0x01, 0xdb, 0x01, 0xae, 0x01, 0xae, 0x01, 0x75, 0x01, 0x75, 0x01, 0x37, 0x01, 0x37, 0x01, 0xf5, 0x00, 0xf5, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0x79, 0x00, 0x79, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x03, 0x00, 0xc7, 0xff, 0xc7, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x54, 0xff, 0x54, 0xff, 0x22, 0xff, 0x22, 0xff, 0xf2, 0xfe, 0xf2, 0xfe, 0xbf, 0xfe, 0xbf, 0xfe, 0x85, 0xfe, 0x85, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0xf9, 0xfd, 0xf9, 0xfd, 0xad, 0xfd, 0xad, 0xfd, 0x63, 0xfd, 0x63, 0xfd, 0x20, 0xfd, 0x20, 0xfd, 0xe3, 0xfc, 0xe3, 0xfc, 0xa9, 0xfc, 0xa9, 0xfc, 0x73, 0xfc, 0x73, 0xfc, 0x45, 0xfc, 0x45, 0xfc, 0x24, 0xfc, 0x24, 0xfc, 0x15, 0xfc, 0x15, 0xfc, 0x1b, 0xfc, 0x1b, 0xfc, 0x35, 0xfc, 0x35, 0xfc, 0x61, 0xfc, 0x61, 0xfc, 0x9c, 0xfc, 0x9c, 0xfc, 0xe5, 0xfc, 0xe5, 0xfc, 0x3c, 0xfd, 0x3c, 0xfd, 0x9f, 0xfd, 0x9f, 0xfd, 0x11, 0xfe, 0x11, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x15, 0xff, 0x15, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x29, 0x00, 0x29, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0x32, 0x01, 0x32, 0x01, 0xae, 0x01, 0xae, 0x01, 0x22, 0x02, 0x22, 0x02, 0x8e, 0x02, 0x8e, 0x02, 0xef, 0x02, 0xef, 0x02, 0x3f, 0x03, 0x3f, 0x03, 0x82, 0x03, 0x82, 0x03, 0xbb, 0x03, 0xbb, 0x03, 0xe9, 0x03, 0xe9, 0x03, 0x0c, 0x04, 0x0c, 0x04, 0x1e, 0x04, 0x1e, 0x04, 0x1f, 0x04, 0x1f, 0x04, 0x0a, 0x04, 0x0a, 0x04, 0xde, 0x03, 0xde, 0x03, 0x9c, 0x03, 0x9c, 0x03, 0x4a, 0x03, 0x4a, 0x03, 0xed, 0x02, 0xed, 0x02, 0x88, 0x02, 0x88, 0x02, 0x19, 0x02, 0x19, 0x02, 0xa0, 0x01, 0xa0, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x94, 0x00, 0x94, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x86, 0xff, 0x86, 0xff, 0x0e, 0xff, 0x0e, 0xff, 0xa3, 0xfe, 0xa3, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0xf5, 0xfd, 0xf5, 0xfd, 0xae, 0xfd, 0xae, 0xfd, 0x73, 0xfd, 0x73, 0xfd, 0x45, 0xfd, 0x45, 0xfd, 0x22, 0xfd, 0x22, 0xfd, 0x0d, 0xfd, 0x0d, 0xfd, 0x05, 0xfd, 0x05, 0xfd, 0x07, 0xfd, 0x07, 0xfd, 0x11, 0xfd, 0x11, 0xfd, 0x21, 0xfd, 0x21, 0xfd, 0x3b, 0xfd, 0x3b, 0xfd, 0x5e, 0xfd, 0x5e, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0x0b, 0xfe, 0x0b, 0xfe, 0x5c, 0xfe, 0x5c, 0xfe, 0xb3, 0xfe, 0xb3, 0xfe, 0x0d, 0xff, 0x0d, 0xff, 0x65, 0xff, 0x65, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0x16, 0x00, 0x16, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0xc4, 0x00, 0xc4, 0x00, 0x10, 0x01, 0x10, 0x01, 0x4e, 0x01, 0x4e, 0x01, 0x7f, 0x01, 0x7f, 0x01, 0xa0, 0x01, 0xa0, 0x01, 0xb0, 0x01, 0xb0, 0x01, 0xae, 0x01, 0xae, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x7e, 0x01, 0x7e, 0x01, 0x58, 0x01, 0x58, 0x01, 0x27, 0x01, 0x27, 0x01, 0xf1, 0x00, 0xf1, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x41, 0x00, 0x41, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xd9, 0xff, 0xd9, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0x80, 0xff, 0x80, 0xff, 0x5c, 0xff, 0x5c, 0xff, 0x40, 0xff, 0x40, 0xff, 0x2b, 0xff, 0x2b, 0xff, 0x17, 0xff, 0x17, 0xff, 0x04, 0xff, 0x04, 0xff, 0xf3, 0xfe, 0xf3, 0xfe, 0xe4, 0xfe, 0xe4, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0xdc, 0xfe, 0xdc, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0xee, 0xfe, 0xee, 0xfe, 0x01, 0xff, 0x01, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x45, 0xff, 0x45, 0xff, 0x79, 0xff, 0x79, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x47, 0x00, 0x47, 0x00, 0x90, 0x00, 0x90, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x18, 0x01, 0x18, 0x01, 0x53, 0x01, 0x53, 0x01, 0x8a, 0x01, 0x8a, 0x01, 0xb8, 0x01, 0xb8, 0x01, 0xda, 0x01, 0xda, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf7, 0x01, 0xf7, 0x01, 0xef, 0x01, 0xef, 0x01, 0xe2, 0x01, 0xe2, 0x01, 0xd2, 0x01, 0xd2, 0x01, 0xbc, 0x01, 0xbc, 0x01, 0x9c, 0x01, 0x9c, 0x01, 0x73, 0x01, 0x73, 0x01, 0x44, 0x01, 0x44, 0x01, 0x13, 0x01, 0x13, 0x01, 0xe2, 0x00, 0xe2, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0x77, 0x00, 0x77, 0x00, 0x38, 0x00, 0x38, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0xab, 0xff, 0xab, 0xff, 0x62, 0xff, 0x62, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0xd7, 0xfe, 0xd7, 0xfe, 0x96, 0xfe, 0x96, 0xfe, 0x5a, 0xfe, 0x5a, 0xfe, 0x22, 0xfe, 0x22, 0xfe, 0xf2, 0xfd, 0xf2, 0xfd, 0xcb, 0xfd, 0xcb, 0xfd, 0xb1, 0xfd, 0xb1, 0xfd, 0xa4, 0xfd, 0xa4, 0xfd, 0xa6, 0xfd, 0xa6, 0xfd, 0xb6, 0xfd, 0xb6, 0xfd, 0xd0, 0xfd, 0xd0, 0xfd, 0xf5, 0xfd, 0xf5, 0xfd, 0x24, 0xfe, 0x24, 0xfe, 0x5b, 0xfe, 0x5b, 0xfe, 0x9a, 0xfe, 0x9a, 0xfe, 0xe2, 0xfe, 0xe2, 0xfe, 0x30, 0xff, 0x30, 0xff, 0x82, 0xff, 0x82, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0x3b, 0x00, 0x3b, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0x14, 0x01, 0x14, 0x01, 0x82, 0x01, 0x82, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x46, 0x02, 0x46, 0x02, 0x99, 0x02, 0x99, 0x02, 0xdd, 0x02, 0xdd, 0x02, 0x11, 0x03, 0x11, 0x03, 0x32, 0x03, 0x32, 0x03, 0x3c, 0x03, 0x3c, 0x03, 0x30, 0x03, 0x30, 0x03, 0x0a, 0x03, 0x0a, 0x03, 0xcf, 0x02, 0xcf, 0x02, 0x83, 0x02, 0x83, 0x02, 0x2d, 0x02, 0x2d, 0x02, 0xd3, 0x01, 0xd3, 0x01, 0x76, 0x01, 0x76, 0x01, 0x16, 0x01, 0x16, 0x01, 0xb3, 0x00, 0xb3, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xe7, 0xff, 0xe7, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x18, 0xff, 0x18, 0xff, 0xb2, 0xfe, 0xb2, 0xfe, 0x50, 0xfe, 0x50, 0xfe, 0xf2, 0xfd, 0xf2, 0xfd, 0x97, 0xfd, 0x97, 0xfd, 0x42, 0xfd, 0x42, 0xfd, 0xf8, 0xfc, 0xf8, 0xfc, 0xbc, 0xfc, 0xbc, 0xfc, 0x93, 0xfc, 0x93, 0xfc, 0x81, 0xfc, 0x81, 0xfc, 0x85, 0xfc, 0x85, 0xfc, 0xa0, 0xfc, 0xa0, 0xfc, 0xcd, 0xfc, 0xcd, 0xfc, 0x09, 0xfd, 0x09, 0xfd, 0x54, 0xfd, 0x54, 0xfd, 0xaf, 0xfd, 0xaf, 0xfd, 0x1a, 0xfe, 0x1a, 0xfe, 0x8f, 0xfe, 0x8f, 0xfe, 0x0b, 0xff, 0x0b, 0xff, 0x88, 0xff, 0x88, 0xff, 0x02, 0x00, 0x02, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0xf4, 0x00, 0xf4, 0x00, 0x6f, 0x01, 0x6f, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x58, 0x02, 0x58, 0x02, 0xb6, 0x02, 0xb6, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0x2b, 0x03, 0x2b, 0x03, 0x46, 0x03, 0x46, 0x03, 0x53, 0x03, 0x53, 0x03, 0x56, 0x03, 0x56, 0x03, 0x4e, 0x03, 0x4e, 0x03, 0x36, 0x03, 0x36, 0x03, 0x0c, 0x03, 0x0c, 0x03, 0xd2, 0x02, 0xd2, 0x02, 0x8b, 0x02, 0x8b, 0x02, 0x3f, 0x02, 0x3f, 0x02, 0xf2, 0x01, 0xf2, 0x01, 0xa6, 0x01, 0xa6, 0x01, 0x5a, 0x01, 0x5a, 0x01, 0x07, 0x01, 0x07, 0x01, 0xa6, 0x00, 0xa6, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0xc7, 0xff, 0xc7, 0xff, 0x55, 0xff, 0x55, 0xff, 0xe7, 0xfe, 0xe7, 0xfe, 0x80, 0xfe, 0x80, 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0xc3, 0xfd, 0xc3, 0xfd, 0x70, 0xfd, 0x70, 0xfd, 0x2d, 0xfd, 0x2d, 0xfd, 0xfe, 0xfc, 0xfe, 0xfc, 0xe6, 0xfc, 0xe6, 0xfc, 0xe5, 0xfc, 0xe5, 0xfc, 0xf8, 0xfc, 0xf8, 0xfc, 0x19, 0xfd, 0x19, 0xfd, 0x45, 0xfd, 0x45, 0xfd, 0x7a, 0xfd, 0x7a, 0xfd, 0xb6, 0xfd, 0xb6, 0xfd, 0xf3, 0xfd, 0xf3, 0xfd, 0x35, 0xfe, 0x35, 0xfe, 0x7b, 0xfe, 0x7b, 0xfe, 0xc6, 0xfe, 0xc6, 0xfe, 0x0f, 0xff, 0x0f, 0xff, 0x56, 0xff, 0x56, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0x32, 0x00, 0x32, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0x1a, 0x01, 0x1a, 0x01, 0x6e, 0x01, 0x6e, 0x01, 0xc3, 0x01, 0xc3, 0x01, 0x14, 0x02, 0x14, 0x02, 0x60, 0x02, 0x60, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xde, 0x02, 0xde, 0x02, 0x0e, 0x03, 0x0e, 0x03, 0x31, 0x03, 0x31, 0x03, 0x45, 0x03, 0x45, 0x03, 0x46, 0x03, 0x46, 0x03, 0x33, 0x03, 0x33, 0x03, 0x0a, 0x03, 0x0a, 0x03, 0xce, 0x02, 0xce, 0x02, 0x86, 0x02, 0x86, 0x02, 0x32, 0x02, 0x32, 0x02, 0xd7, 0x01, 0xd7, 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xa2, 0x00, 0xa2, 0x00, 0x38, 0x00, 0x38, 0x00, 0xce, 0xff, 0xce, 0xff, 0x66, 0xff, 0x66, 0xff, 0x03, 0xff, 0x03, 0xff, 0xa4, 0xfe, 0xa4, 0xfe, 0x48, 0xfe, 0x48, 0xfe, 0xef, 0xfd, 0xef, 0xfd, 0x95, 0xfd, 0x95, 0xfd, 0x3c, 0xfd, 0x3c, 0xfd, 0xe5, 0xfc, 0xe5, 0xfc, 0x94, 0xfc, 0x94, 0xfc, 0x4f, 0xfc, 0x4f, 0xfc, 0x15, 0xfc, 0x15, 0xfc, 0xe8, 0xfb, 0xe8, 0xfb, 0xcc, 0xfb, 0xcc, 0xfb, 0xc3, 0xfb, 0xc3, 0xfb, 0xcf, 0xfb, 0xcf, 0xfb, 0xf2, 0xfb, 0xf2, 0xfb, 0x2f, 0xfc, 0x2f, 0xfc, 0x84, 0xfc, 0x84, 0xfc, 0xee, 0xfc, 0xee, 0xfc, 0x67, 0xfd, 0x67, 0xfd, 0xee, 0xfd, 0xee, 0xfd, 0x81, 0xfe, 0x81, 0xfe, 0x1f, 0xff, 0x1f, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0x6d, 0x00, 0x6d, 0x00, 0x13, 0x01, 0x13, 0x01, 0xb1, 0x01, 0xb1, 0x01, 0x42, 0x02, 0x42, 0x02, 0xc6, 0x02, 0xc6, 0x02, 0x3a, 0x03, 0x3a, 0x03, 0x9e, 0x03, 0x9e, 0x03, 0xf3, 0x03, 0xf3, 0x03, 0x38, 0x04, 0x38, 0x04, 0x6a, 0x04, 0x6a, 0x04, 0x89, 0x04, 0x89, 0x04, 0x95, 0x04, 0x95, 0x04, 0x8e, 0x04, 0x8e, 0x04, 0x78, 0x04, 0x78, 0x04, 0x51, 0x04, 0x51, 0x04, 0x19, 0x04, 0x19, 0x04, 0xcd, 0x03, 0xcd, 0x03, 0x6d, 0x03, 0x6d, 0x03, 0xf9, 0x02, 0xf9, 0x02, 0x73, 0x02, 0x73, 0x02, 0xde, 0x01, 0xde, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x97, 0x00, 0x97, 0x00, 0xe8, 0xff, 0xe8, 0xff, 0x36, 0xff, 0x36, 0xff, 0x88, 0xfe, 0x88, 0xfe, 0xe1, 0xfd, 0xe1, 0xfd, 0x47, 0xfd, 0x47, 0xfd, 0xc0, 0xfc, 0xc0, 0xfc, 0x51, 0xfc, 0x51, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0xcc, 0xfb, 0xcc, 0xfb, 0xaf, 0xfb, 0xaf, 0xfb, 0xa9, 0xfb, 0xa9, 0xfb, 0xb9, 0xfb, 0xb9, 0xfb, 0xe0, 0xfb, 0xe0, 0xfb, 0x1a, 0xfc, 0x1a, 0xfc, 0x66, 0xfc, 0x66, 0xfc, 0xc0, 0xfc, 0xc0, 0xfc, 0x23, 0xfd, 0x23, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0xfc, 0xfd, 0xfc, 0xfd, 0x73, 0xfe, 0x73, 0xfe, 0xf2, 0xfe, 0xf2, 0xfe, 0x75, 0xff, 0x75, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x80, 0x00, 0x80, 0x00, 0x05, 0x01, 0x05, 0x01, 0x86, 0x01, 0x86, 0x01, 0xfd, 0x01, 0xfd, 0x01, 0x67, 0x02, 0x67, 0x02, 0xc2, 0x02, 0xc2, 0x02, 0x0c, 0x03, 0x0c, 0x03, 0x43, 0x03, 0x43, 0x03, 0x60, 0x03, 0x60, 0x03, 0x64, 0x03, 0x64, 0x03, 0x4a, 0x03, 0x4a, 0x03, 0x16, 0x03, 0x16, 0x03, 0xc9, 0x02, 0xc9, 0x02, 0x64, 0x02, 0x64, 0x02, 0xeb, 0x01, 0xeb, 0x01, 0x62, 0x01, 0x62, 0x01, 0xd0, 0x00, 0xd0, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xae, 0xff, 0xae, 0xff, 0x29, 0xff, 0x29, 0xff, 0xae, 0xfe, 0xae, 0xfe, 0x40, 0xfe, 0x40, 0xfe, 0xe2, 0xfd, 0xe2, 0xfd, 0x96, 0xfd, 0x96, 0xfd, 0x5a, 0xfd, 0x5a, 0xfd, 0x2d, 0xfd, 0x2d, 0xfd, 0x12, 0xfd, 0x12, 0xfd, 0x0c, 0xfd, 0x0c, 0xfd, 0x1b, 0xfd, 0x1b, 0xfd, 0x3c, 0xfd, 0x3c, 0xfd, 0x70, 0xfd, 0x70, 0xfd, 0xb4, 0xfd, 0xb4, 0xfd, 0x08, 0xfe, 0x08, 0xfe, 0x6b, 0xfe, 0x6b, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0x5a, 0xff, 0x5a, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0x6a, 0x00, 0x6a, 0x00, 0xf5, 0x00, 0xf5, 0x00, 0x7f, 0x01, 0x7f, 0x01, 0x01, 0x02, 0x01, 0x02, 0x76, 0x02, 0x76, 0x02, 0xdd, 0x02, 0xdd, 0x02, 0x35, 0x03, 0x35, 0x03, 0x7d, 0x03, 0x7d, 0x03, 0xaf, 0x03, 0xaf, 0x03, 0xcb, 0x03, 0xcb, 0x03, 0xcf, 0x03, 0xcf, 0x03, 0xbb, 0x03, 0xbb, 0x03, 0x93, 0x03, 0x93, 0x03, 0x59, 0x03, 0x59, 0x03, 0x0b, 0x03, 0x0b, 0x03, 0xaa, 0x02, 0xaa, 0x02, 0x39, 0x02, 0x39, 0x02, 0xb9, 0x01, 0xb9, 0x01, 0x2d, 0x01, 0x2d, 0x01, 0x99, 0x00, 0x99, 0x00, 0x02, 0x00, 0x02, 0x00, 0x6d, 0xff, 0x6d, 0xff, 0xe0, 0xfe, 0xe0, 0xfe, 0x59, 0xfe, 0x59, 0xfe, 0xd9, 0xfd, 0xd9, 0xfd, 0x64, 0xfd, 0x64, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xa7, 0xfc, 0xa7, 0xfc, 0x69, 0xfc, 0x69, 0xfc, 0x47, 0xfc, 0x47, 0xfc, 0x41, 0xfc, 0x41, 0xfc, 0x56, 0xfc, 0x56, 0xfc, 0x83, 0xfc, 0x83, 0xfc, 0xc5, 0xfc, 0xc5, 0xfc, 0x1b, 0xfd, 0x1b, 0xfd, 0x84, 0xfd, 0x84, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0x88, 0xfe, 0x88, 0xfe, 0x1a, 0xff, 0x1a, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0x3e, 0x00, 0x3e, 0x00, 0xc6, 0x00, 0xc6, 0x00, 0x43, 0x01, 0x43, 0x01, 0xb3, 0x01, 0xb3, 0x01, 0x14, 0x02, 0x14, 0x02, 0x65, 0x02, 0x65, 0x02, 0xa7, 0x02, 0xa7, 0x02, 0xd8, 0x02, 0xd8, 0x02, 0xf9, 0x02, 0xf9, 0x02, 0x06, 0x03, 0x06, 0x03, 0x03, 0x03, 0x03, 0x03, 0xf0, 0x02, 0xf0, 0x02, 0xcf, 0x02, 0xcf, 0x02, 0xa2, 0x02, 0xa2, 0x02, 0x68, 0x02, 0x68, 0x02, 0x26, 0x02, 0x26, 0x02, 0xd9, 0x01, 0xd9, 0x01, 0x81, 0x01, 0x81, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0xad, 0x00, 0xad, 0x00, 0x37, 0x00, 0x37, 0x00, 0xbf, 0xff, 0xbf, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0xe2, 0xfe, 0xe2, 0xfe, 0x84, 0xfe, 0x84, 0xfe, 0x32, 0xfe, 0x32, 0xfe, 0xed, 0xfd, 0xed, 0xfd, 0xb3, 0xfd, 0xb3, 0xfd, 0x89, 0xfd, 0x89, 0xfd, 0x70, 0xfd, 0x70, 0xfd, 0x6b, 0xfd, 0x6b, 0xfd, 0x7b, 0xfd, 0x7b, 0xfd, 0x9e, 0xfd, 0x9e, 0xfd, 0xcc, 0xfd, 0xcc, 0xfd, 0x00, 0xfe, 0x00, 0xfe, 0x36, 0xfe, 0x36, 0xfe, 0x6f, 0xfe, 0x6f, 0xfe, 0xab, 0xfe, 0xab, 0xfe, 0xea, 0xfe, 0xea, 0xfe, 0x2a, 0xff, 0x2a, 0xff, 0x67, 0xff, 0x67, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0x09, 0x00, 0x09, 0x00, 0x26, 0x00, 0x26, 0x00, 0x43, 0x00, 0x43, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x75, 0x00, 0x75, 0x00, 0x86, 0x00, 0x86, 0x00, 0x93, 0x00, 0x93, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xe5, 0x00, 0xe5, 0x00, 0xec, 0x00, 0xec, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0xf7, 0x00, 0xf7, 0x00, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x11, 0x01, 0x20, 0x01, 0x20, 0x01, 0x2b, 0x01, 0x2b, 0x01, 0x32, 0x01, 0x32, 0x01, 0x37, 0x01, 0x37, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x48, 0x01, 0x48, 0x01, 0x56, 0x01, 0x56, 0x01, 0x62, 0x01, 0x62, 0x01, 0x68, 0x01, 0x68, 0x01, 0x62, 0x01, 0x62, 0x01, 0x4e, 0x01, 0x4e, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0x04, 0x01, 0x04, 0x01, 0xd2, 0x00, 0xd2, 0x00, 0x96, 0x00, 0x96, 0x00, 0x50, 0x00, 0x50, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0xd8, 0xfe, 0xd8, 0xfe, 0x72, 0xfe, 0x72, 0xfe, 0x10, 0xfe, 0x10, 0xfe, 0xb4, 0xfd, 0xb4, 0xfd, 0x5f, 0xfd, 0x5f, 0xfd, 0x16, 0xfd, 0x16, 0xfd, 0xdb, 0xfc, 0xdb, 0xfc, 0xb3, 0xfc, 0xb3, 0xfc, 0x9f, 0xfc, 0x9f, 0xfc, 0xa1, 0xfc, 0xa1, 0xfc, 0xb6, 0xfc, 0xb6, 0xfc, 0xe0, 0xfc, 0xe0, 0xfc, 0x1e, 0xfd, 0x1e, 0xfd, 0x6f, 0xfd, 0x6f, 0xfd, 0xd0, 0xfd, 0xd0, 0xfd, 0x3b, 0xfe, 0x3b, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0x2b, 0xff, 0x2b, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0x2a, 0x00, 0x2a, 0x00, 0xab, 0x00, 0xab, 0x00, 0x2d, 0x01, 0x2d, 0x01, 0xac, 0x01, 0xac, 0x01, 0x23, 0x02, 0x23, 0x02, 0x91, 0x02, 0x91, 0x02, 0xf2, 0x02, 0xf2, 0x02, 0x46, 0x03, 0x46, 0x03, 0x8c, 0x03, 0x8c, 0x03, 0xc4, 0x03, 0xc4, 0x03, 0xea, 0x03, 0xea, 0x03, 0xfb, 0x03, 0xfb, 0x03, 0xf3, 0x03, 0xf3, 0x03, 0xd2, 0x03, 0xd2, 0x03, 0x99, 0x03, 0x99, 0x03, 0x49, 0x03, 0x49, 0x03, 0xe6, 0x02, 0xe6, 0x02, 0x70, 0x02, 0x70, 0x02, 0xe7, 0x01, 0xe7, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0xa2, 0x00, 0xa2, 0x00, 0xf1, 0xff, 0xf1, 0xff, 0x41, 0xff, 0x41, 0xff, 0x9d, 0xfe, 0x9d, 0xfe, 0x09, 0xfe, 0x09, 0xfe, 0x82, 0xfd, 0x82, 0xfd, 0x08, 0xfd, 0x08, 0xfd, 0x9e, 0xfc, 0x9e, 0xfc, 0x48, 0xfc, 0x48, 0xfc, 0x09, 0xfc, 0x09, 0xfc, 0xe8, 0xfb, 0xe8, 0xfb, 0xe4, 0xfb, 0xe4, 0xfb, 0xf9, 0xfb, 0xf9, 0xfb, 0x24, 0xfc, 0x24, 0xfc, 0x5f, 0xfc, 0x5f, 0xfc, 0xac, 0xfc, 0xac, 0xfc, 0x08, 0xfd, 0x08, 0xfd, 0x78, 0xfd, 0x78, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0x81, 0xfe, 0x81, 0xfe, 0x15, 0xff, 0x15, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0x3a, 0x00, 0x3a, 0x00, 0xc7, 0x00, 0xc7, 0x00, 0x51, 0x01, 0x51, 0x01, 0xd5, 0x01, 0xd5, 0x01, 0x4c, 0x02, 0x4c, 0x02, 0xb2, 0x02, 0xb2, 0x02, 0x03, 0x03, 0x03, 0x03, 0x40, 0x03, 0x40, 0x03, 0x66, 0x03, 0x66, 0x03, 0x78, 0x03, 0x78, 0x03, 0x77, 0x03, 0x77, 0x03, 0x64, 0x03, 0x64, 0x03, 0x3d, 0x03, 0x3d, 0x03, 0x01, 0x03, 0x01, 0x03, 0xb1, 0x02, 0xb1, 0x02, 0x4f, 0x02, 0x4f, 0x02, 0xe1, 0x01, 0xe1, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0xff, 0x00, 0xff, 0x00, 0x91, 0x00, 0x91, 0x00, 0x25, 0x00, 0x25, 0x00, 0xb8, 0xff, 0xb8, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0xf0, 0xfe, 0xf0, 0xfe, 0x9f, 0xfe, 0x9f, 0xfe, 0x5f, 0xfe, 0x5f, 0xfe, 0x31, 0xfe, 0x31, 0xfe, 0x14, 0xfe, 0x14, 0xfe, 0x03, 0xfe, 0x03, 0xfe, 0xfb, 0xfd, 0xfb, 0xfd, 0xfb, 0xfd, 0xfb, 0xfd, 0x04, 0xfe, 0x04, 0xfe, 0x19, 0xfe, 0x19, 0xfe, 0x3c, 0xfe, 0x3c, 0xfe, 0x70, 0xfe, 0x70, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0x3f, 0xff, 0x3f, 0xff, 0x88, 0xff, 0x88, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0x20, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x0b, 0x01, 0x0b, 0x01, 0x4f, 0x01, 0x4f, 0x01, 0x87, 0x01, 0x87, 0x01, 0xac, 0x01, 0xac, 0x01, 0xbd, 0x01, 0xbd, 0x01, 0xbd, 0x01, 0xbd, 0x01, 0xad, 0x01, 0xad, 0x01, 0x8e, 0x01, 0x8e, 0x01, 0x5e, 0x01, 0x5e, 0x01, 0x1f, 0x01, 0x1f, 0x01, 0xd7, 0x00, 0xd7, 0x00, 0x87, 0x00, 0x87, 0x00, 0x32, 0x00, 0x32, 0x00, 0xdc, 0xff, 0xdc, 0xff, 0x87, 0xff, 0x87, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0xf9, 0xfe, 0xf9, 0xfe, 0xc6, 0xfe, 0xc6, 0xfe, 0xa0, 0xfe, 0xa0, 0xfe, 0x89, 0xfe, 0x89, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0x8a, 0xfe, 0x8a, 0xfe, 0x9e, 0xfe, 0x9e, 0xfe, 0xbb, 0xfe, 0xbb, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0x0e, 0xff, 0x0e, 0xff, 0x41, 0xff, 0x41, 0xff, 0x79, 0xff, 0x79, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0x31, 0x00, 0x31, 0x00, 0x71, 0x00, 0x71, 0x00, 0xad, 0x00, 0xad, 0x00, 0xe8, 0x00, 0xe8, 0x00, 0x1e, 0x01, 0x1e, 0x01, 0x4d, 0x01, 0x4d, 0x01, 0x72, 0x01, 0x72, 0x01, 0x88, 0x01, 0x88, 0x01, 0x8e, 0x01, 0x8e, 0x01, 0x83, 0x01, 0x83, 0x01, 0x68, 0x01, 0x68, 0x01, 0x40, 0x01, 0x40, 0x01, 0x0a, 0x01, 0x0a, 0x01, 0xc9, 0x00, 0xc9, 0x00, 0x81, 0x00, 0x81, 0x00, 0x34, 0x00, 0x34, 0x00, 0xe2, 0xff, 0xe2, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0x38, 0xff, 0x38, 0xff, 0xe6, 0xfe, 0xe6, 0xfe, 0x9d, 0xfe, 0x9d, 0xfe, 0x5e, 0xfe, 0x5e, 0xfe, 0x2f, 0xfe, 0x2f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe, 0xfa, 0xfd, 0xfa, 0xfd, 0xf4, 0xfd, 0xf4, 0xfd, 0xfa, 0xfd, 0xfa, 0xfd, 0x0e, 0xfe, 0x0e, 0xfe, 0x32, 0xfe, 0x32, 0xfe, 0x67, 0xfe, 0x67, 0xfe, 0xad, 0xfe, 0xad, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0x55, 0xff, 0x55, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x70, 0x00, 0x70, 0x00, 0xce, 0x00, 0xce, 0x00, 0x28, 0x01, 0x28, 0x01, 0x7a, 0x01, 0x7a, 0x01, 0xc2, 0x01, 0xc2, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0x29, 0x02, 0x29, 0x02, 0x47, 0x02, 0x47, 0x02, 0x58, 0x02, 0x58, 0x02, 0x5b, 0x02, 0x5b, 0x02, 0x4d, 0x02, 0x4d, 0x02, 0x31, 0x02, 0x31, 0x02, 0x05, 0x02, 0x05, 0x02, 0xca, 0x01, 0xca, 0x01, 0x81, 0x01, 0x81, 0x01, 0x2c, 0x01, 0x2c, 0x01, 0xd1, 0x00, 0xd1, 0x00, 0x73, 0x00, 0x73, 0x00, 0x11, 0x00, 0x11, 0x00, 0xad, 0xff, 0xad, 0xff, 0x4a, 0xff, 0x4a, 0xff, 0xed, 0xfe, 0xed, 0xfe, 0x9b, 0xfe, 0x9b, 0xfe, 0x58, 0xfe, 0x58, 0xfe, 0x24, 0xfe, 0x24, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0xef, 0xfd, 0xef, 0xfd, 0xeb, 0xfd, 0xeb, 0xfd, 0xf4, 0xfd, 0xf4, 0xfd, 0x09, 0xfe, 0x09, 0xfe, 0x28, 0xfe, 0x28, 0xfe, 0x54, 0xfe, 0x54, 0xfe, 0x8b, 0xfe, 0x8b, 0xfe, 0xce, 0xfe, 0xce, 0xfe, 0x15, 0xff, 0x15, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xed, 0xff, 0xed, 0xff, 0x2f, 0x00, 0x2f, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0xa8, 0x00, 0xa8, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x08, 0x01, 0x08, 0x01, 0x2a, 0x01, 0x2a, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x44, 0x01, 0x44, 0x01, 0x3b, 0x01, 0x3b, 0x01, 0x28, 0x01, 0x28, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0xee, 0x00, 0xee, 0x00, 0xca, 0x00, 0xca, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x71, 0x00, 0x71, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xd9, 0xff, 0xd9, 0xff, 0xab, 0xff, 0xab, 0xff, 0x82, 0xff, 0x82, 0xff, 0x62, 0xff, 0x62, 0xff, 0x47, 0xff, 0x47, 0xff, 0x31, 0xff, 0x31, 0xff, 0x22, 0xff, 0x22, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0x24, 0xff, 0x24, 0xff, 0x39, 0xff, 0x39, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x89, 0xff, 0x89, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x41, 0x00, 0x85, 0x00, 0x85, 0x00, 0xc8, 0x00, 0xc8, 0x00, 0x06, 0x01, 0x06, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x6c, 0x01, 0x6c, 0x01, 0x8e, 0x01, 0x8e, 0x01, 0xa2, 0x01, 0xa2, 0x01, 0xa8, 0x01, 0xa8, 0x01, 0xa5, 0x01, 0xa5, 0x01, 0x99, 0x01, 0x99, 0x01, 0x81, 0x01, 0x81, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x2f, 0x01, 0x2f, 0x01, 0xf4, 0x00, 0xf4, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x64, 0x00, 0x64, 0x00, 0x17, 0x00, 0x17, 0x00, 0xc8, 0xff, 0xc8, 0xff, 0x79, 0xff, 0x79, 0xff, 0x28, 0xff, 0x28, 0xff, 0xd8, 0xfe, 0xd8, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x4e, 0xfe, 0x4e, 0xfe, 0x1c, 0xfe, 0x1c, 0xfe, 0xf8, 0xfd, 0xf8, 0xfd, 0xe2, 0xfd, 0xe2, 0xfd, 0xda, 0xfd, 0xda, 0xfd, 0xe0, 0xfd, 0xe0, 0xfd, 0xf4, 0xfd, 0xf4, 0xfd, 0x14, 0xfe, 0x14, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0x82, 0xfe, 0x82, 0xfe, 0xcc, 0xfe, 0xcc, 0xfe, 0x1f, 0xff, 0x1f, 0xff, 0x75, 0xff, 0x75, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0x23, 0x00, 0x23, 0x00, 0x77, 0x00, 0x77, 0x00, 0xc7, 0x00, 0xc7, 0x00, 0x12, 0x01, 0x12, 0x01, 0x53, 0x01, 0x53, 0x01, 0x8d, 0x01, 0x8d, 0x01, 0xbc, 0x01, 0xbc, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf7, 0x01, 0xf7, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0xf5, 0x01, 0xf5, 0x01, 0xdc, 0x01, 0xdc, 0x01, 0xb5, 0x01, 0xb5, 0x01, 0x85, 0x01, 0x85, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0xc7, 0x00, 0xc7, 0x00, 0x81, 0x00, 0x81, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x37, 0xff, 0x37, 0xff, 0x16, 0xff, 0x16, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xee, 0xfe, 0xee, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xee, 0xfe, 0xee, 0xfe, 0xf5, 0xfe, 0xf5, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0x06, 0xff, 0x06, 0xff, 0x12, 0xff, 0x12, 0xff, 0x22, 0xff, 0x22, 0xff, 0x34, 0xff, 0x34, 0xff, 0x49, 0xff, 0x49, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x73, 0xff, 0x73, 0xff, 0x85, 0xff, 0x85, 0xff, 0x95, 0xff, 0x95, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xac, 0xff, 0xac, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x15, 0x00, 0x15, 0x00, 0x31, 0x00, 0x31, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x68, 0x00, 0x68, 0x00, 0x85, 0x00, 0x85, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xca, 0x00, 0xca, 0x00, 0xce, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x83, 0x00, 0x83, 0x00, 0x67, 0x00, 0x67, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x35, 0x00, 0x35, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xce, 0xff, 0xce, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x15, 0x00, 0x22, 0x00, 0x22, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x69, 0x00, 0x71, 0x00, 0x71, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x42, 0x00, 0x24, 0x00, 0x24, 0x00, 0x02, 0x00, 0x02, 0x00, 0xdc, 0xff, 0xdc, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x62, 0xff, 0x62, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x16, 0xff, 0x16, 0xff, 0xf9, 0xfe, 0xf9, 0xfe, 0xe2, 0xfe, 0xe2, 0xfe, 0xd3, 0xfe, 0xd3, 0xfe, 0xcd, 0xfe, 0xcd, 0xfe, 0xd1, 0xfe, 0xd1, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xfc, 0xfe, 0xfc, 0xfe, 0x20, 0xff, 0x20, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x82, 0xff, 0x82, 0xff, 0xba, 0xff, 0xba, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x3e, 0x00, 0x3e, 0x00, 0x86, 0x00, 0x86, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x0d, 0x01, 0x0d, 0x01, 0x44, 0x01, 0x44, 0x01, 0x71, 0x01, 0x71, 0x01, 0x94, 0x01, 0x94, 0x01, 0xae, 0x01, 0xae, 0x01, 0xbc, 0x01, 0xbc, 0x01, 0xbe, 0x01, 0xbe, 0x01, 0xb3, 0x01, 0xb3, 0x01, 0x98, 0x01, 0x98, 0x01, 0x70, 0x01, 0x70, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x02, 0x01, 0x02, 0x01, 0xc1, 0x00, 0xc1, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0xda, 0xff, 0xda, 0xff, 0x83, 0xff, 0x83, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0xd6, 0xfe, 0xd6, 0xfe, 0x88, 0xfe, 0x88, 0xfe, 0x41, 0xfe, 0x41, 0xfe, 0x03, 0xfe, 0x03, 0xfe, 0xd1, 0xfd, 0xd1, 0xfd, 0xae, 0xfd, 0xae, 0xfd, 0x9b, 0xfd, 0x9b, 0xfd, 0x9d, 0xfd, 0x9d, 0xfd, 0xb4, 0xfd, 0xb4, 0xfd, 0xe1, 0xfd, 0xe1, 0xfd, 0x23, 0xfe, 0x23, 0xfe, 0x74, 0xfe, 0x74, 0xfe, 0xd1, 0xfe, 0xd1, 0xfe, 0x38, 0xff, 0x38, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x92, 0x00, 0x92, 0x00, 0x05, 0x01, 0x05, 0x01, 0x70, 0x01, 0x70, 0x01, 0xce, 0x01, 0xce, 0x01, 0x1d, 0x02, 0x1d, 0x02, 0x5c, 0x02, 0x5c, 0x02, 0x8b, 0x02, 0x8b, 0x02, 0xa9, 0x02, 0xa9, 0x02, 0xb6, 0x02, 0xb6, 0x02, 0xb1, 0x02, 0xb1, 0x02, 0x99, 0x02, 0x99, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x32, 0x02, 0x32, 0x02, 0xe9, 0x01, 0xe9, 0x01, 0x95, 0x01, 0x95, 0x01, 0x33, 0x01, 0x33, 0x01, 0xc5, 0x00, 0xc5, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0xcf, 0xff, 0xcf, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0xcd, 0xfe, 0xcd, 0xfe, 0x52, 0xfe, 0x52, 0xfe, 0xe1, 0xfd, 0xe1, 0xfd, 0x7a, 0xfd, 0x7a, 0xfd, 0x22, 0xfd, 0x22, 0xfd, 0xd7, 0xfc, 0xd7, 0xfc, 0x9c, 0xfc, 0x9c, 0xfc, 0x75, 0xfc, 0x75, 0xfc, 0x61, 0xfc, 0x61, 0xfc, 0x63, 0xfc, 0x63, 0xfc, 0x79, 0xfc, 0x79, 0xfc, 0xa3, 0xfc, 0xa3, 0xfc, 0xe2, 0xfc, 0xe2, 0xfc, 0x35, 0xfd, 0x35, 0xfd, 0x9b, 0xfd, 0x9b, 0xfd, 0x10, 0xfe, 0x10, 0xfe, 0x95, 0xfe, 0x95, 0xfe, 0x23, 0xff, 0x23, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0x4c, 0x00, 0x4c, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x6f, 0x01, 0x6f, 0x01, 0xf2, 0x01, 0xf2, 0x01, 0x68, 0x02, 0x68, 0x02, 0xcd, 0x02, 0xcd, 0x02, 0x21, 0x03, 0x21, 0x03, 0x60, 0x03, 0x60, 0x03, 0x8d, 0x03, 0x8d, 0x03, 0xa7, 0x03, 0xa7, 0x03, 0xaf, 0x03, 0xaf, 0x03, 0xa6, 0x03, 0xa6, 0x03, 0x8a, 0x03, 0x8a, 0x03, 0x5f, 0x03, 0x5f, 0x03, 0x26, 0x03, 0x26, 0x03, 0xde, 0x02, 0xde, 0x02, 0x89, 0x02, 0x89, 0x02, 0x29, 0x02, 0x29, 0x02, 0xbe, 0x01, 0xbe, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0xc5, 0xff, 0xc5, 0xff, 0x3e, 0xff, 0x3e, 0xff, 0xbb, 0xfe, 0xbb, 0xfe, 0x3b, 0xfe, 0x3b, 0xfe, 0xc6, 0xfd, 0xc6, 0xfd, 0x5e, 0xfd, 0x5e, 0xfd, 0x05, 0xfd, 0x05, 0xfd, 0xbe, 0xfc, 0xbe, 0xfc, 0x8c, 0xfc, 0x8c, 0xfc, 0x70, 0xfc, 0x70, 0xfc, 0x67, 0xfc, 0x67, 0xfc, 0x77, 0xfc, 0x77, 0xfc, 0x9c, 0xfc, 0x9c, 0xfc, 0xd6, 0xfc, 0xd6, 0xfc, 0x21, 0xfd, 0x21, 0xfd, 0x7c, 0xfd, 0x7c, 0xfd, 0xe6, 0xfd, 0xe6, 0xfd, 0x59, 0xfe, 0x59, 0xfe, 0xd0, 0xfe, 0xd0, 0xfe, 0x49, 0xff, 0x49, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0x35, 0x00, 0x35, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x14, 0x01, 0x14, 0x01, 0x7d, 0x01, 0x7d, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0x3c, 0x02, 0x3c, 0x02, 0x91, 0x02, 0x91, 0x02, 0xde, 0x02, 0xde, 0x02, 0x20, 0x03, 0x20, 0x03, 0x55, 0x03, 0x55, 0x03, 0x7f, 0x03, 0x7f, 0x03, 0x9a, 0x03, 0x9a, 0x03, 0xa4, 0x03, 0xa4, 0x03, 0x99, 0x03, 0x99, 0x03, 0x78, 0x03, 0x78, 0x03, 0x43, 0x03, 0x43, 0x03, 0xfa, 0x02, 0xfa, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x34, 0x02, 0x34, 0x02, 0xba, 0x01, 0xba, 0x01, 0x34, 0x01, 0x34, 0x01, 0xa8, 0x00, 0xa8, 0x00, 0x19, 0x00, 0x19, 0x00, 0x8d, 0xff, 0x8d, 0xff, 0x08, 0xff, 0x08, 0xff, 0x8b, 0xfe, 0x8b, 0xfe, 0x1d, 0xfe, 0x1d, 0xfe, 0xbc, 0xfd, 0xbc, 0xfd, 0x6b, 0xfd, 0x6b, 0xfd, 0x2a, 0xfd, 0x2a, 0xfd, 0xf5, 0xfc, 0xf5, 0xfc, 0xcd, 0xfc, 0xcd, 0xfc, 0xb2, 0xfc, 0xb2, 0xfc, 0xa4, 0xfc, 0xa4, 0xfc, 0xa1, 0xfc, 0xa1, 0xfc, 0xab, 0xfc, 0xab, 0xfc, 0xbf, 0xfc, 0xbf, 0xfc, 0xe1, 0xfc, 0xe1, 0xfc, 0x14, 0xfd, 0x14, 0xfd, 0x55, 0xfd, 0x55, 0xfd, 0xa4, 0xfd, 0xa4, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0x62, 0xfe, 0x62, 0xfe, 0xcd, 0xfe, 0xcd, 0xfe, 0x3e, 0xff, 0x3e, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0x2c, 0x00, 0x2c, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x0d, 0x01, 0x0d, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0xc3, 0x01, 0xc3, 0x01, 0x06, 0x02, 0x06, 0x02, 0x3a, 0x02, 0x3a, 0x02, 0x5b, 0x02, 0x5b, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6f, 0x02, 0x6f, 0x02, 0x62, 0x02, 0x62, 0x02, 0x4c, 0x02, 0x4c, 0x02, 0x2a, 0x02, 0x2a, 0x02, 0x02, 0x02, 0x02, 0x02, 0xd1, 0x01, 0xd1, 0x01, 0x9c, 0x01, 0x9c, 0x01, 0x63, 0x01, 0x63, 0x01, 0x24, 0x01, 0x24, 0x01, 0xe4, 0x00, 0xe4, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0x68, 0x00, 0x68, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0xf8, 0xff, 0xf8, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x74, 0xff, 0x74, 0xff, 0x54, 0xff, 0x54, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x2b, 0xff, 0x2b, 0xff, 0x22, 0xff, 0x22, 0xff, 0x20, 0xff, 0x20, 0xff, 0x24, 0xff, 0x24, 0xff, 0x30, 0xff, 0x30, 0xff, 0x43, 0xff, 0x43, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x77, 0xff, 0x77, 0xff, 0x99, 0xff, 0x99, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0x09, 0x00, 0x09, 0x00, 0x25, 0x00, 0x25, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x57, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x53, 0x00, 0x53, 0x00, 0x42, 0x00, 0x42, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xee, 0xff, 0xee, 0xff, 0xce, 0xff, 0xce, 0xff, 0xac, 0xff, 0xac, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x70, 0xff, 0x70, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x4c, 0xff, 0x4c, 0xff, 0x43, 0xff, 0x43, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0x43, 0xff, 0x43, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x6f, 0xff, 0x6f, 0xff, 0x84, 0xff, 0x84, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x23, 0x00, 0x23, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x72, 0x00, 0x72, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0xc1, 0x00, 0xc1, 0x00, 0xe6, 0x00, 0xe6, 0x00, 0x05, 0x01, 0x05, 0x01, 0x1b, 0x01, 0x1b, 0x01, 0x2a, 0x01, 0x2a, 0x01, 0x2f, 0x01, 0x2f, 0x01, 0x2c, 0x01, 0x2c, 0x01, 0x21, 0x01, 0x21, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0xf6, 0x00, 0xf6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xb2, 0x00, 0xb2, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x32, 0x00, 0x32, 0x00, 0x08, 0x00, 0x08, 0x00, 0xde, 0xff, 0xde, 0xff, 0xba, 0xff, 0xba, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x82, 0xff, 0x82, 0xff, 0x6f, 0xff, 0x6f, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x52, 0xff, 0x52, 0xff, 0x4a, 0xff, 0x4a, 0xff, 0x48, 0xff, 0x48, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x51, 0xff, 0x51, 0xff, 0x58, 0xff, 0x58, 0xff, 0x61, 0xff, 0x61, 0xff, 0x6f, 0xff, 0x6f, 0xff, 0x80, 0xff, 0x80, 0xff, 0x96, 0xff, 0x96, 0xff, 0xac, 0xff, 0xac, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x18, 0x00, 0x18, 0x00, 0x37, 0x00, 0x37, 0x00, 0x54, 0x00, 0x54, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x81, 0x00, 0x81, 0x00, 0x92, 0x00, 0x92, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x93, 0x00, 0x93, 0x00, 0x84, 0x00, 0x84, 0x00, 0x74, 0x00, 0x74, 0x00, 0x62, 0x00, 0x62, 0x00, 0x50, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x28, 0x00, 0x28, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xef, 0xff, 0xea, 0xff, 0xea, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x01, 0x00, 0x01, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x12, 0x00, 0x13, 0x00, 0x13, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x03, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xab, 0xff, 0xab, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x96, 0xff, 0x96, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x75, 0xff, 0x75, 0xff, 0x6e, 0xff, 0x6e, 0xff, 0x67, 0xff, 0x67, 0xff, 0x61, 0xff, 0x61, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x63, 0xff, 0x63, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x52, 0x00, 0x52, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x82, 0x00, 0x82, 0x00, 0x93, 0x00, 0x93, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xad, 0x00, 0xad, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x99, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x79, 0x00, 0x79, 0x00, 0x64, 0x00, 0x64, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xef, 0xff, 0xef, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xae, 0xff, 0xae, 0xff, 0x90, 0xff, 0x90, 0xff, 0x73, 0xff, 0x73, 0xff, 0x59, 0xff, 0x59, 0xff, 0x45, 0xff, 0x45, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x39, 0xff, 0x39, 0xff, 0x41, 0xff, 0x41, 0xff, 0x52, 0xff, 0x52, 0xff, 0x68, 0xff, 0x68, 0xff, 0x85, 0xff, 0x85, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xce, 0xff, 0xce, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x24, 0x00, 0x24, 0x00, 0x53, 0x00, 0x53, 0x00, 0x82, 0x00, 0x82, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0x14, 0x01, 0x14, 0x01, 0x2a, 0x01, 0x2a, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x39, 0x01, 0x39, 0x01, 0x28, 0x01, 0x28, 0x01, 0x0e, 0x01, 0x0e, 0x01, 0xec, 0x00, 0xec, 0x00, 0xc4, 0x00, 0xc4, 0x00, 0x93, 0x00, 0x93, 0x00, 0x58, 0x00, 0x58, 0x00, 0x17, 0x00, 0x17, 0x00, 0xcf, 0xff, 0xcf, 0xff, 0x81, 0xff, 0x81, 0xff, 0x33, 0xff, 0x33, 0xff, 0xe9, 0xfe, 0xe9, 0xfe, 0xa1, 0xfe, 0xa1, 0xfe, 0x5b, 0xfe, 0x5b, 0xfe, 0x1a, 0xfe, 0x1a, 0xfe, 0xe2, 0xfd, 0xe2, 0xfd, 0xb5, 0xfd, 0xb5, 0xfd, 0x95, 0xfd, 0x95, 0xfd, 0x86, 0xfd, 0x86, 0xfd, 0x8a, 0xfd, 0x8a, 0xfd, 0xa0, 0xfd, 0xa0, 0xfd, 0xc7, 0xfd, 0xc7, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0x43, 0xfe, 0x43, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0xf7, 0xfe, 0xf7, 0xfe, 0x5e, 0xff, 0x5e, 0xff, 0xca, 0xff, 0xca, 0xff, 0x35, 0x00, 0x35, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x00, 0x01, 0x00, 0x01, 0x5b, 0x01, 0x5b, 0x01, 0xab, 0x01, 0xab, 0x01, 0xf0, 0x01, 0xf0, 0x01, 0x29, 0x02, 0x29, 0x02, 0x56, 0x02, 0x56, 0x02, 0x76, 0x02, 0x76, 0x02, 0x8a, 0x02, 0x8a, 0x02, 0x92, 0x02, 0x92, 0x02, 0x8c, 0x02, 0x8c, 0x02, 0x7a, 0x02, 0x7a, 0x02, 0x5c, 0x02, 0x5c, 0x02, 0x2f, 0x02, 0x2f, 0x02, 0xf2, 0x01, 0xf2, 0x01, 0xa8, 0x01, 0xa8, 0x01, 0x52, 0x01, 0x52, 0x01, 0xf3, 0x00, 0xf3, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x24, 0x00, 0x24, 0x00, 0xb7, 0xff, 0xb7, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0xe6, 0xfe, 0xe6, 0xfe, 0x8c, 0xfe, 0x8c, 0xfe, 0x42, 0xfe, 0x42, 0xfe, 0x0a, 0xfe, 0x0a, 0xfe, 0xe7, 0xfd, 0xe7, 0xfd, 0xda, 0xfd, 0xda, 0xfd, 0xdf, 0xfd, 0xdf, 0xfd, 0xf9, 0xfd, 0xf9, 0xfd, 0x26, 0xfe, 0x26, 0xfe, 0x63, 0xfe, 0x63, 0xfe, 0xad, 0xfe, 0xad, 0xfe, 0x02, 0xff, 0x02, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0xba, 0xff, 0xba, 0xff, 0x11, 0x00, 0x11, 0x00, 0x64, 0x00, 0x64, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xf1, 0x00, 0xf1, 0x00, 0x2b, 0x01, 0x2b, 0x01, 0x5c, 0x01, 0x5c, 0x01, 0x80, 0x01, 0x80, 0x01, 0x98, 0x01, 0x98, 0x01, 0xa2, 0x01, 0xa2, 0x01, 0x9e, 0x01, 0x9e, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x6b, 0x01, 0x6b, 0x01, 0x40, 0x01, 0x40, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0x84, 0x00, 0x84, 0x00, 0x31, 0x00, 0x31, 0x00, 0xd9, 0xff, 0xd9, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x28, 0xff, 0x28, 0xff, 0xd6, 0xfe, 0xd6, 0xfe, 0x8b, 0xfe, 0x8b, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x09, 0xfe, 0x09, 0xfe, 0xdb, 0xfd, 0xdb, 0xfd, 0xba, 0xfd, 0xba, 0xfd, 0xaa, 0xfd, 0xaa, 0xfd, 0xad, 0xfd, 0xad, 0xfd, 0xc3, 0xfd, 0xc3, 0xfd, 0xeb, 0xfd, 0xeb, 0xfd, 0x24, 0xfe, 0x24, 0xfe, 0x6d, 0xfe, 0x6d, 0xfe, 0xc4, 0xfe, 0xc4, 0xfe, 0x25, 0xff, 0x25, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x6d, 0x00, 0x6d, 0x00, 0xda, 0x00, 0xda, 0x00, 0x3d, 0x01, 0x3d, 0x01, 0x97, 0x01, 0x97, 0x01, 0xe7, 0x01, 0xe7, 0x01, 0x2b, 0x02, 0x2b, 0x02, 0x60, 0x02, 0x60, 0x02, 0x83, 0x02, 0x83, 0x02, 0x95, 0x02, 0x95, 0x02, 0x94, 0x02, 0x94, 0x02, 0x81, 0x02, 0x81, 0x02, 0x5d, 0x02, 0x5d, 0x02, 0x2b, 0x02, 0x2b, 0x02, 0xec, 0x01, 0xec, 0x01, 0xa4, 0x01, 0xa4, 0x01, 0x55, 0x01, 0x55, 0x01, 0xff, 0x00, 0xff, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x44, 0x00, 0x44, 0x00, 0xe7, 0xff, 0xe7, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x32, 0xff, 0x32, 0xff, 0xdf, 0xfe, 0xdf, 0xfe, 0x92, 0xfe, 0x92, 0xfe, 0x4e, 0xfe, 0x4e, 0xfe, 0x15, 0xfe, 0x15, 0xfe, 0xe6, 0xfd, 0xe6, 0xfd, 0xc4, 0xfd, 0xc4, 0xfd, 0xad, 0xfd, 0xad, 0xfd, 0xa3, 0xfd, 0xa3, 0xfd, 0xa9, 0xfd, 0xa9, 0xfd, 0xc0, 0xfd, 0xc0, 0xfd, 0xe8, 0xfd, 0xe8, 0xfd, 0x20, 0xfe, 0x20, 0xfe, 0x6a, 0xfe, 0x6a, 0xfe, 0xc4, 0xfe, 0xc4, 0xfe, 0x2a, 0xff, 0x2a, 0xff, 0x96, 0xff, 0x96, 0xff, 0x04, 0x00, 0x04, 0x00, 0x71, 0x00, 0x71, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x3d, 0x01, 0x3d, 0x01, 0x93, 0x01, 0x93, 0x01, 0xdd, 0x01, 0xdd, 0x01, 0x16, 0x02, 0x16, 0x02, 0x3c, 0x02, 0x3c, 0x02, 0x4f, 0x02, 0x4f, 0x02, 0x53, 0x02, 0x53, 0x02, 0x48, 0x02, 0x48, 0x02, 0x2e, 0x02, 0x2e, 0x02, 0x0a, 0x02, 0x0a, 0x02, 0xde, 0x01, 0xde, 0x01, 0xaa, 0x01, 0xaa, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0xe9, 0x00, 0xe9, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x15, 0x00, 0x15, 0x00, 0xce, 0xff, 0xce, 0xff, 0x87, 0xff, 0x87, 0xff, 0x40, 0xff, 0x40, 0xff, 0xfa, 0xfe, 0xfa, 0xfe, 0xb7, 0xfe, 0xb7, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0x3d, 0xfe, 0x3d, 0xfe, 0x0a, 0xfe, 0x0a, 0xfe, 0xe1, 0xfd, 0xe1, 0xfd, 0xc3, 0xfd, 0xc3, 0xfd, 0xb5, 0xfd, 0xb5, 0xfd, 0xb6, 0xfd, 0xb6, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xe4, 0xfd, 0xe4, 0xfd, 0x11, 0xfe, 0x11, 0xfe, 0x4e, 0xfe, 0x4e, 0xfe, 0x98, 0xfe, 0x98, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0x39, 0xff, 0x39, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0x32, 0x00, 0x32, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xf6, 0x00, 0xf6, 0x00, 0x26, 0x01, 0x26, 0x01, 0x4f, 0x01, 0x4f, 0x01, 0x70, 0x01, 0x70, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0xae, 0x01, 0xae, 0x01, 0xb9, 0x01, 0xb9, 0x01, 0xc2, 0x01, 0xc2, 0x01, 0xc6, 0x01, 0xc6, 0x01, 0xc4, 0x01, 0xc4, 0x01, 0xbc, 0x01, 0xbc, 0x01, 0xaa, 0x01, 0xaa, 0x01, 0x93, 0x01, 0x93, 0x01, 0x75, 0x01, 0x75, 0x01, 0x52, 0x01, 0x52, 0x01, 0x29, 0x01, 0x29, 0x01, 0xfa, 0x00, 0xfa, 0x00, 0xc6, 0x00, 0xc6, 0x00, 0x90, 0x00, 0x90, 0x00, 0x58, 0x00, 0x58, 0x00, 0x21, 0x00, 0x21, 0x00, 0xec, 0xff, 0xec, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0x88, 0xff, 0x88, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x04, 0xff, 0x04, 0xff, 0xf2, 0xfe, 0xf2, 0xfe, 0xe5, 0xfe, 0xe5, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xdf, 0xfe, 0xdf, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0xe6, 0xfe, 0xe6, 0xfe, 0xec, 0xfe, 0xec, 0xfe, 0xf4, 0xfe, 0xf4, 0xfe, 0xfc, 0xfe, 0xfc, 0xfe, 0x06, 0xff, 0x06, 0xff, 0x10, 0xff, 0x10, 0xff, 0x19, 0xff, 0x19, 0xff, 0x24, 0xff, 0x24, 0xff, 0x32, 0xff, 0x32, 0xff, 0x42, 0xff, 0x42, 0xff, 0x53, 0xff, 0x53, 0xff, 0x65, 0xff, 0x65, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x92, 0xff, 0x92, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x27, 0x00, 0x27, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x60, 0x00, 0x60, 0x00, 0x67, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x74, 0x00, 0x78, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x80, 0x00, 0x84, 0x00, 0x84, 0x00, 0x89, 0x00, 0x89, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x82, 0x00, 0x82, 0x00, 0x72, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x47, 0x00, 0x47, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xff, 0xec, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0x95, 0xff, 0x95, 0xff, 0x84, 0xff, 0x84, 0xff, 0x75, 0xff, 0x75, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x64, 0xff, 0x64, 0xff, 0x60, 0xff, 0x60, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x54, 0xff, 0x54, 0xff, 0x50, 0xff, 0x50, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x46, 0xff, 0x46, 0xff, 0x43, 0xff, 0x43, 0xff, 0x43, 0xff, 0x43, 0xff, 0x49, 0xff, 0x49, 0xff, 0x53, 0xff, 0x53, 0xff, 0x60, 0xff, 0x60, 0xff, 0x71, 0xff, 0x71, 0xff, 0x89, 0xff, 0x89, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x24, 0x00, 0x24, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x77, 0x00, 0x77, 0x00, 0x99, 0x00, 0x99, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xe7, 0x00, 0xe7, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xff, 0x00, 0xff, 0x00, 0x05, 0x01, 0x05, 0x01, 0x09, 0x01, 0x09, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x09, 0x01, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0xf6, 0x00, 0xf6, 0x00, 0xe6, 0x00, 0xe6, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0x89, 0x00, 0x89, 0x00, 0x59, 0x00, 0x59, 0x00, 0x21, 0x00, 0x21, 0x00, 0xe5, 0xff, 0xe5, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x69, 0xff, 0x69, 0xff, 0x2c, 0xff, 0x2c, 0xff, 0xf3, 0xfe, 0xf3, 0xfe, 0xbd, 0xfe, 0xbd, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x69, 0xfe, 0x69, 0xfe, 0x4d, 0xfe, 0x4d, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3c, 0xfe, 0x3c, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0x52, 0xfe, 0x52, 0xfe, 0x6a, 0xfe, 0x6a, 0xfe, 0x89, 0xfe, 0x89, 0xfe, 0xb1, 0xfe, 0xb1, 0xfe, 0xe2, 0xfe, 0xe2, 0xfe, 0x17, 0xff, 0x17, 0xff, 0x53, 0xff, 0x53, 0xff, 0x94, 0xff, 0x94, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0x1b, 0x00, 0x1b, 0x00, 0x60, 0x00, 0x60, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xee, 0x00, 0xee, 0x00, 0x31, 0x01, 0x31, 0x01, 0x70, 0x01, 0x70, 0x01, 0xac, 0x01, 0xac, 0x01, 0xe5, 0x01, 0xe5, 0x01, 0x17, 0x02, 0x17, 0x02, 0x3c, 0x02, 0x3c, 0x02, 0x53, 0x02, 0x53, 0x02, 0x5d, 0x02, 0x5d, 0x02, 0x57, 0x02, 0x57, 0x02, 0x41, 0x02, 0x41, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0xe9, 0x01, 0xe9, 0x01, 0xa8, 0x01, 0xa8, 0x01, 0x5b, 0x01, 0x5b, 0x01, 0x03, 0x01, 0x03, 0x01, 0xa4, 0x00, 0xa4, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0xd8, 0xff, 0xd8, 0xff, 0x71, 0xff, 0x71, 0xff, 0x0e, 0xff, 0x0e, 0xff, 0xb0, 0xfe, 0xb0, 0xfe, 0x5a, 0xfe, 0x5a, 0xfe, 0x0c, 0xfe, 0x0c, 0xfe, 0xcd, 0xfd, 0xcd, 0xfd, 0x9f, 0xfd, 0x9f, 0xfd, 0x7f, 0xfd, 0x7f, 0xfd, 0x71, 0xfd, 0x71, 0xfd, 0x73, 0xfd, 0x73, 0xfd, 0x82, 0xfd, 0x82, 0xfd, 0x9e, 0xfd, 0x9e, 0xfd, 0xc7, 0xfd, 0xc7, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0x42, 0xfe, 0x42, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0xe2, 0xfe, 0xe2, 0xfe, 0x3b, 0xff, 0x3b, 0xff, 0x98, 0xff, 0x98, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x59, 0x00, 0x59, 0x00, 0xba, 0x00, 0xba, 0x00, 0x1a, 0x01, 0x1a, 0x01, 0x74, 0x01, 0x74, 0x01, 0xc6, 0x01, 0xc6, 0x01, 0x0d, 0x02, 0x0d, 0x02, 0x48, 0x02, 0x48, 0x02, 0x78, 0x02, 0x78, 0x02, 0x98, 0x02, 0x98, 0x02, 0xa9, 0x02, 0xa9, 0x02, 0xa9, 0x02, 0xa9, 0x02, 0x9b, 0x02, 0x9b, 0x02, 0x7d, 0x02, 0x7d, 0x02, 0x4f, 0x02, 0x4f, 0x02, 0x10, 0x02, 0x10, 0x02, 0xc3, 0x01, 0xc3, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x12, 0x01, 0x12, 0x01, 0xb2, 0x00, 0xb2, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0xe5, 0xff, 0xe5, 0xff, 0x84, 0xff, 0x84, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0xd6, 0xfe, 0xd6, 0xfe, 0x8a, 0xfe, 0x8a, 0xfe, 0x49, 0xfe, 0x49, 0xfe, 0x15, 0xfe, 0x15, 0xfe, 0xef, 0xfd, 0xef, 0xfd, 0xd6, 0xfd, 0xd6, 0xfd, 0xca, 0xfd, 0xca, 0xfd, 0xc9, 0xfd, 0xc9, 0xfd, 0xd4, 0xfd, 0xd4, 0xfd, 0xe6, 0xfd, 0xe6, 0xfd, 0x03, 0xfe, 0x03, 0xfe, 0x29, 0xfe, 0x29, 0xfe, 0x57, 0xfe, 0x57, 0xfe, 0x8d, 0xfe, 0x8d, 0xfe, 0xc8, 0xfe, 0xc8, 0xfe, 0x06, 0xff, 0x06, 0xff, 0x46, 0xff, 0x46, 0xff, 0x87, 0xff, 0x87, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0x07, 0x00, 0x07, 0x00, 0x41, 0x00, 0x41, 0x00, 0x77, 0x00, 0x77, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xed, 0x00, 0xed, 0x00, 0x03, 0x01, 0x03, 0x01, 0x10, 0x01, 0x10, 0x01, 0x15, 0x01, 0x15, 0x01, 0x13, 0x01, 0x13, 0x01, 0x0a, 0x01, 0x0a, 0x01, 0xfb, 0x00, 0xfb, 0x00, 0xe6, 0x00, 0xe6, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0x94, 0x00, 0x94, 0x00, 0x78, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x37, 0x00, 0x37, 0x00, 0x35, 0x00, 0x35, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x71, 0x00, 0x71, 0x00, 0x85, 0x00, 0x85, 0x00, 0x97, 0x00, 0x97, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xd2, 0x00, 0xd2, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xca, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x99, 0x00, 0x99, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x58, 0x00, 0x58, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0x86, 0xff, 0x86, 0xff, 0x47, 0xff, 0x47, 0xff, 0x06, 0xff, 0x06, 0xff, 0xc6, 0xfe, 0xc6, 0xfe, 0x88, 0xfe, 0x88, 0xfe, 0x51, 0xfe, 0x51, 0xfe, 0x23, 0xfe, 0x23, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xe5, 0xfd, 0xe5, 0xfd, 0xd6, 0xfd, 0xd6, 0xfd, 0xd4, 0xfd, 0xd4, 0xfd, 0xdd, 0xfd, 0xdd, 0xfd, 0xf5, 0xfd, 0xf5, 0xfd, 0x18, 0xfe, 0x18, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x7d, 0xfe, 0x7d, 0xfe, 0xba, 0xfe, 0xba, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x43, 0xff, 0x43, 0xff, 0x87, 0xff, 0x87, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x51, 0x00, 0x51, 0x00, 0x90, 0x00, 0x90, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xfb, 0x00, 0xfb, 0x00, 0x26, 0x01, 0x26, 0x01, 0x4c, 0x01, 0x4c, 0x01, 0x6b, 0x01, 0x6b, 0x01, 0x83, 0x01, 0x83, 0x01, 0x91, 0x01, 0x91, 0x01, 0x95, 0x01, 0x95, 0x01, 0x90, 0x01, 0x90, 0x01, 0x84, 0x01, 0x84, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x52, 0x01, 0x52, 0x01, 0x2f, 0x01, 0x2f, 0x01, 0x08, 0x01, 0x08, 0x01, 0xde, 0x00, 0xde, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0x81, 0x00, 0x81, 0x00, 0x54, 0x00, 0x54, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xef, 0xff, 0xef, 0xff, 0xda, 0xff, 0xda, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xca, 0xff, 0xca, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x29, 0x00, 0x29, 0x00, 0x31, 0x00, 0x31, 0x00, 0x33, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x24, 0x00, 0x16, 0x00, 0x16, 0x00, 0x02, 0x00, 0x02, 0x00, 0xea, 0xff, 0xea, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0x85, 0xff, 0x85, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x38, 0xff, 0x38, 0xff, 0x13, 0xff, 0x13, 0xff, 0xef, 0xfe, 0xef, 0xfe, 0xcc, 0xfe, 0xcc, 0xfe, 0xac, 0xfe, 0xac, 0xfe, 0x91, 0xfe, 0x91, 0xfe, 0x7a, 0xfe, 0x7a, 0xfe, 0x66, 0xfe, 0x66, 0xfe, 0x59, 0xfe, 0x59, 0xfe, 0x54, 0xfe, 0x54, 0xfe, 0x55, 0xfe, 0x55, 0xfe, 0x60, 0xfe, 0x60, 0xfe, 0x76, 0xfe, 0x76, 0xfe, 0x96, 0xfe, 0x96, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe, 0x2b, 0xff, 0x2b, 0xff, 0x70, 0xff, 0x70, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0x08, 0x01, 0x08, 0x01, 0x5a, 0x01, 0x5a, 0x01, 0xa7, 0x01, 0xa7, 0x01, 0xec, 0x01, 0xec, 0x01, 0x27, 0x02, 0x27, 0x02, 0x57, 0x02, 0x57, 0x02, 0x7e, 0x02, 0x7e, 0x02, 0x9a, 0x02, 0x9a, 0x02, 0xa8, 0x02, 0xa8, 0x02, 0xa8, 0x02, 0xa8, 0x02, 0x99, 0x02, 0x99, 0x02, 0x7c, 0x02, 0x7c, 0x02, 0x52, 0x02, 0x52, 0x02, 0x1a, 0x02, 0x1a, 0x02, 0xdb, 0x01, 0xdb, 0x01, 0x95, 0x01, 0x95, 0x01, 0x49, 0x01, 0x49, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x47, 0xff, 0x47, 0xff, 0xf9, 0xfe, 0xf9, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0x6b, 0xfe, 0x6b, 0xfe, 0x2d, 0xfe, 0x2d, 0xfe, 0xf4, 0xfd, 0xf4, 0xfd, 0xc3, 0xfd, 0xc3, 0xfd, 0x9d, 0xfd, 0x9d, 0xfd, 0x86, 0xfd, 0x86, 0xfd, 0x7c, 0xfd, 0x7c, 0xfd, 0x7c, 0xfd, 0x7c, 0xfd, 0x89, 0xfd, 0x89, 0xfd, 0xa2, 0xfd, 0xa2, 0xfd, 0xc7, 0xfd, 0xc7, 0xfd, 0xf7, 0xfd, 0xf7, 0xfd, 0x30, 0xfe, 0x30, 0xfe, 0x72, 0xfe, 0x72, 0xfe, 0xb8, 0xfe, 0xb8, 0xfe, 0x00, 0xff, 0x00, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x96, 0xff, 0x96, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0x30, 0x00, 0x30, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0x12, 0x01, 0x12, 0x01, 0x50, 0x01, 0x50, 0x01, 0x86, 0x01, 0x86, 0x01, 0xb6, 0x01, 0xb6, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0x02, 0x02, 0x02, 0x02, 0x1d, 0x02, 0x1d, 0x02, 0x2d, 0x02, 0x2d, 0x02, 0x34, 0x02, 0x34, 0x02, 0x2f, 0x02, 0x2f, 0x02, 0x21, 0x02, 0x21, 0x02, 0x0b, 0x02, 0x0b, 0x02, 0xec, 0x01, 0xec, 0x01, 0xc4, 0x01, 0xc4, 0x01, 0x98, 0x01, 0x98, 0x01, 0x67, 0x01, 0x67, 0x01, 0x30, 0x01, 0x30, 0x01, 0xf3, 0x00, 0xf3, 0x00, 0xb2, 0x00, 0xb2, 0x00, 0x70, 0x00, 0x70, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0xee, 0xff, 0xee, 0xff, 0xac, 0xff, 0xac, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x28, 0xff, 0x28, 0xff, 0xe8, 0xfe, 0xe8, 0xfe, 0xad, 0xfe, 0xad, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x1b, 0xfe, 0x1b, 0xfe, 0xf9, 0xfd, 0xf9, 0xfd, 0xde, 0xfd, 0xde, 0xfd, 0xca, 0xfd, 0xca, 0xfd, 0xc2, 0xfd, 0xc2, 0xfd, 0xc5, 0xfd, 0xc5, 0xfd, 0xd6, 0xfd, 0xd6, 0xfd, 0xf3, 0xfd, 0xf3, 0xfd, 0x19, 0xfe, 0x19, 0xfe, 0x48, 0xfe, 0x48, 0xfe, 0x81, 0xfe, 0x81, 0xfe, 0xc4, 0xfe, 0xc4, 0xfe, 0x10, 0xff, 0x10, 0xff, 0x65, 0xff, 0x65, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0x1b, 0x00, 0x1b, 0x00, 0x78, 0x00, 0x78, 0x00, 0xd2, 0x00, 0xd2, 0x00, 0x27, 0x01, 0x27, 0x01, 0x78, 0x01, 0x78, 0x01, 0xc2, 0x01, 0xc2, 0x01, 0x04, 0x02, 0x04, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x6a, 0x02, 0x6a, 0x02, 0x8c, 0x02, 0x8c, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xb3, 0x02, 0xb3, 0x02, 0xb9, 0x02, 0xb9, 0x02, 0xb5, 0x02, 0xb5, 0x02, 0xa5, 0x02, 0xa5, 0x02, 0x88, 0x02, 0x88, 0x02, 0x61, 0x02, 0x61, 0x02, 0x2e, 0x02, 0x2e, 0x02, 0xf0, 0x01, 0xf0, 0x01, 0xa7, 0x01, 0xa7, 0x01, 0x55, 0x01, 0x55, 0x01, 0xfc, 0x00, 0xfc, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x35, 0x00, 0x35, 0x00, 0xc9, 0xff, 0xc9, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0xf1, 0xfe, 0xf1, 0xfe, 0x89, 0xfe, 0x89, 0xfe, 0x28, 0xfe, 0x28, 0xfe, 0xd1, 0xfd, 0xd1, 0xfd, 0x89, 0xfd, 0x89, 0xfd, 0x4f, 0xfd, 0x4f, 0xfd, 0x24, 0xfd, 0x24, 0xfd, 0x08, 0xfd, 0x08, 0xfd, 0xfb, 0xfc, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x0b, 0xfd, 0x0b, 0xfd, 0x29, 0xfd, 0x29, 0xfd, 0x53, 0xfd, 0x53, 0xfd, 0x89, 0xfd, 0x89, 0xfd, 0xc9, 0xfd, 0xc9, 0xfd, 0x10, 0xfe, 0x10, 0xfe, 0x5c, 0xfe, 0x5c, 0xfe, 0xae, 0xfe, 0xae, 0xfe, 0x01, 0xff, 0x01, 0xff, 0x55, 0xff, 0x55, 0xff, 0xad, 0xff, 0xad, 0xff, 0x07, 0x00, 0x07, 0x00, 0x60, 0x00, 0x60, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0b, 0x01, 0x0b, 0x01, 0x5b, 0x01, 0x5b, 0x01, 0xa5, 0x01, 0xa5, 0x01, 0xe6, 0x01, 0xe6, 0x01, 0x1f, 0x02, 0x1f, 0x02, 0x4d, 0x02, 0x4d, 0x02, 0x6f, 0x02, 0x6f, 0x02, 0x85, 0x02, 0x85, 0x02, 0x8e, 0x02, 0x8e, 0x02, 0x89, 0x02, 0x89, 0x02, 0x76, 0x02, 0x76, 0x02, 0x55, 0x02, 0x55, 0x02, 0x28, 0x02, 0x28, 0x02, 0xf2, 0x01, 0xf2, 0x01, 0xb1, 0x01, 0xb1, 0x01, 0x68, 0x01, 0x68, 0x01, 0x1b, 0x01, 0x1b, 0x01, 0xcd, 0x00, 0xcd, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0xe5, 0xff, 0xe5, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x28, 0xff, 0x28, 0xff, 0xf7, 0xfe, 0xf7, 0xfe, 0xce, 0xfe, 0xce, 0xfe, 0xab, 0xfe, 0xab, 0xfe, 0x90, 0xfe, 0x90, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0x73, 0xfe, 0x73, 0xfe, 0x6f, 0xfe, 0x6f, 0xfe, 0x71, 0xfe, 0x71, 0xfe, 0x7b, 0xfe, 0x7b, 0xfe, 0x8b, 0xfe, 0x8b, 0xfe, 0xa0, 0xfe, 0xa0, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0x06, 0xff, 0x06, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xec, 0xff, 0xec, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0xa8, 0x00, 0xa8, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xed, 0x00, 0xed, 0x00, 0x00, 0x01, 0x00, 0x01, 0x08, 0x01, 0x08, 0x01, 0x06, 0x01, 0x06, 0x01, 0xfa, 0x00, 0xfa, 0x00, 0xe5, 0x00, 0xe5, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x81, 0x00, 0x81, 0x00, 0x59, 0x00, 0x59, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x05, 0x00, 0x05, 0x00, 0xdf, 0xff, 0xdf, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x76, 0xff, 0x76, 0xff, 0x68, 0xff, 0x68, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x53, 0xff, 0x53, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0x50, 0xff, 0x50, 0xff, 0x56, 0xff, 0x56, 0xff, 0x60, 0xff, 0x60, 0xff, 0x6d, 0xff, 0x6d, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x95, 0xff, 0x95, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0x1e, 0x00, 0x1e, 0x00, 0x49, 0x00, 0x49, 0x00, 0x76, 0x00, 0x76, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xc8, 0x00, 0xc8, 0x00, 0xe9, 0x00, 0xe9, 0x00, 0x00, 0x01, 0x00, 0x01, 0x0e, 0x01, 0x0e, 0x01, 0x11, 0x01, 0x11, 0x01, 0x07, 0x01, 0x07, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xce, 0x00, 0xce, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x17, 0x00, 0x17, 0x00, 0xe1, 0xff, 0xe1, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x84, 0xff, 0x84, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x40, 0xff, 0x40, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x18, 0xff, 0x18, 0xff, 0x0b, 0xff, 0x0b, 0xff, 0x03, 0xff, 0x03, 0xff, 0x02, 0xff, 0x02, 0xff, 0x07, 0xff, 0x07, 0xff, 0x10, 0xff, 0x10, 0xff, 0x20, 0xff, 0x20, 0xff, 0x36, 0xff, 0x36, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x6e, 0xff, 0x6e, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0x16, 0x00, 0x16, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x17, 0x01, 0x17, 0x01, 0x2d, 0x01, 0x2d, 0x01, 0x38, 0x01, 0x38, 0x01, 0x38, 0x01, 0x38, 0x01, 0x2c, 0x01, 0x2c, 0x01, 0x12, 0x01, 0x12, 0x01, 0xef, 0x00, 0xef, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x51, 0x00, 0x51, 0x00, 0x18, 0x00, 0x18, 0x00, 0xe1, 0xff, 0xe1, 0xff, 0xad, 0xff, 0xad, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x55, 0xff, 0x55, 0xff, 0x34, 0xff, 0x34, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x0d, 0xff, 0x0d, 0xff, 0x09, 0xff, 0x09, 0xff, 0x0a, 0xff, 0x0a, 0xff, 0x11, 0xff, 0x11, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x30, 0xff, 0x30, 0xff, 0x49, 0xff, 0x49, 0xff, 0x65, 0xff, 0x65, 0xff, 0x85, 0xff, 0x85, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x28, 0x00, 0x28, 0x00, 0x58, 0x00, 0x58, 0x00, 0x89, 0x00, 0x89, 0x00, 0xba, 0x00, 0xba, 0x00, 0xe7, 0x00, 0xe7, 0x00, 0x11, 0x01, 0x11, 0x01, 0x35, 0x01, 0x35, 0x01, 0x50, 0x01, 0x50, 0x01, 0x61, 0x01, 0x61, 0x01, 0x66, 0x01, 0x66, 0x01, 0x60, 0x01, 0x60, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0x27, 0x01, 0x27, 0x01, 0xf9, 0x00, 0xf9, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0x85, 0x00, 0x85, 0x00, 0x44, 0x00, 0x44, 0x00, 0x03, 0x00, 0x03, 0x00, 0xc3, 0xff, 0xc3, 0xff, 0x86, 0xff, 0x86, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0xf5, 0xfe, 0xf5, 0xfe, 0xcf, 0xfe, 0xcf, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0x86, 0xfe, 0x86, 0xfe, 0x7c, 0xfe, 0x7c, 0xfe, 0x79, 0xfe, 0x79, 0xfe, 0x7d, 0xfe, 0x7d, 0xfe, 0x87, 0xfe, 0x87, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0xaf, 0xfe, 0xaf, 0xfe, 0xcf, 0xfe, 0xcf, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0x24, 0xff, 0x24, 0xff, 0x58, 0xff, 0x58, 0xff, 0x92, 0xff, 0x92, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x48, 0x00, 0x48, 0x00, 0x82, 0x00, 0x82, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xe7, 0x00, 0xe7, 0x00, 0x11, 0x01, 0x11, 0x01, 0x31, 0x01, 0x31, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0x5c, 0x01, 0x5c, 0x01, 0x64, 0x01, 0x64, 0x01, 0x65, 0x01, 0x65, 0x01, 0x60, 0x01, 0x60, 0x01, 0x57, 0x01, 0x57, 0x01, 0x45, 0x01, 0x45, 0x01, 0x2b, 0x01, 0x2b, 0x01, 0x0a, 0x01, 0x0a, 0x01, 0xe6, 0x00, 0xe6, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x98, 0x00, 0x98, 0x00, 0x71, 0x00, 0x71, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x25, 0x00, 0x25, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe2, 0xff, 0xe2, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xac, 0xff, 0xac, 0xff, 0x98, 0xff, 0x98, 0xff, 0x88, 0xff, 0x88, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0x71, 0xff, 0x71, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x68, 0xff, 0x68, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x72, 0xff, 0x72, 0xff, 0x79, 0xff, 0x79, 0xff, 0x81, 0xff, 0x81, 0xff, 0x89, 0xff, 0x89, 0xff, 0x91, 0xff, 0x91, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xad, 0xff, 0xad, 0xff, 0xae, 0xff, 0xae, 0xff, 0xac, 0xff, 0xac, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x93, 0xff, 0x93, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x89, 0xff, 0x89, 0xff, 0x88, 0xff, 0x88, 0xff, 0x87, 0xff, 0x87, 0xff, 0x89, 0xff, 0x89, 0xff, 0x90, 0xff, 0x90, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x10, 0x00, 0x10, 0x00, 0x28, 0x00, 0x28, 0x00, 0x42, 0x00, 0x42, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x01, 0x00, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0x36, 0x01, 0x36, 0x01, 0x48, 0x01, 0x48, 0x01, 0x54, 0x01, 0x54, 0x01, 0x59, 0x01, 0x59, 0x01, 0x54, 0x01, 0x54, 0x01, 0x45, 0x01, 0x45, 0x01, 0x2d, 0x01, 0x2d, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xe4, 0x00, 0xe4, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xd3, 0xff, 0xd3, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x6c, 0xff, 0x6c, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x12, 0xff, 0x12, 0xff, 0xee, 0xfe, 0xee, 0xfe, 0xce, 0xfe, 0xce, 0xfe, 0xb2, 0xfe, 0xb2, 0xfe, 0x99, 0xfe, 0x99, 0xfe, 0x86, 0xfe, 0x86, 0xfe, 0x7a, 0xfe, 0x7a, 0xfe, 0x72, 0xfe, 0x72, 0xfe, 0x71, 0xfe, 0x71, 0xfe, 0x7a, 0xfe, 0x7a, 0xfe, 0x8c, 0xfe, 0x8c, 0xfe, 0xa6, 0xfe, 0xa6, 0xfe, 0xc9, 0xfe, 0xc9, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe, 0x1e, 0xff, 0x1e, 0xff, 0x54, 0xff, 0x54, 0xff, 0x91, 0xff, 0x91, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0x19, 0x00, 0x19, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0x10, 0x01, 0x10, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x62, 0x01, 0x62, 0x01, 0x7b, 0x01, 0x7b, 0x01, 0x89, 0x01, 0x89, 0x01, 0x8d, 0x01, 0x8d, 0x01, 0x88, 0x01, 0x88, 0x01, 0x7f, 0x01, 0x7f, 0x01, 0x70, 0x01, 0x70, 0x01, 0x5a, 0x01, 0x5a, 0x01, 0x3f, 0x01, 0x3f, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0xfa, 0x00, 0xfa, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xab, 0x00, 0xab, 0x00, 0x81, 0x00, 0x81, 0x00, 0x54, 0x00, 0x54, 0x00, 0x23, 0x00, 0x23, 0x00, 0xf0, 0xff, 0xf0, 0xff, 0xba, 0xff, 0xba, 0xff, 0x83, 0xff, 0x83, 0xff, 0x50, 0xff, 0x50, 0xff, 0x23, 0xff, 0x23, 0xff, 0xfd, 0xfe, 0xfd, 0xfe, 0xda, 0xfe, 0xda, 0xfe, 0xbd, 0xfe, 0xbd, 0xfe, 0xa7, 0xfe, 0xa7, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0x8f, 0xfe, 0x8f, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x95, 0xfe, 0x95, 0xfe, 0xa3, 0xfe, 0xa3, 0xfe, 0xb8, 0xfe, 0xb8, 0xfe, 0xd3, 0xfe, 0xd3, 0xfe, 0xf3, 0xfe, 0xf3, 0xfe, 0x18, 0xff, 0x18, 0xff, 0x40, 0xff, 0x40, 0xff, 0x69, 0xff, 0x69, 0xff, 0x92, 0xff, 0x92, 0xff, 0xba, 0xff, 0xba, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x33, 0x00, 0x33, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x82, 0x00, 0x82, 0x00, 0xa8, 0x00, 0xa8, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0xec, 0x00, 0xec, 0x00, 0x07, 0x01, 0x07, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x30, 0x01, 0x30, 0x01, 0x3f, 0x01, 0x3f, 0x01, 0x47, 0x01, 0x47, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0x47, 0x01, 0x47, 0x01, 0x38, 0x01, 0x38, 0x01, 0x20, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0xe0, 0x00, 0xe0, 0x00, 0xba, 0x00, 0xba, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x60, 0x00, 0x60, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xca, 0xff, 0xca, 0xff, 0x99, 0xff, 0x99, 0xff, 0x6c, 0xff, 0x6c, 0xff, 0x42, 0xff, 0x42, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0xfb, 0xfe, 0xfb, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xcd, 0xfe, 0xcd, 0xfe, 0xc2, 0xfe, 0xc2, 0xfe, 0xbe, 0xfe, 0xbe, 0xfe, 0xc2, 0xfe, 0xc2, 0xfe, 0xcf, 0xfe, 0xcf, 0xfe, 0xe3, 0xfe, 0xe3, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x21, 0xff, 0x21, 0xff, 0x48, 0xff, 0x48, 0xff, 0x73, 0xff, 0x73, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0x09, 0x00, 0x09, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xfb, 0x00, 0xfb, 0x00, 0x21, 0x01, 0x21, 0x01, 0x41, 0x01, 0x41, 0x01, 0x5a, 0x01, 0x5a, 0x01, 0x6b, 0x01, 0x6b, 0x01, 0x74, 0x01, 0x74, 0x01, 0x75, 0x01, 0x75, 0x01, 0x6c, 0x01, 0x6c, 0x01, 0x57, 0x01, 0x57, 0x01, 0x36, 0x01, 0x36, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0xda, 0x00, 0xda, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0xda, 0xff, 0xda, 0xff, 0x92, 0xff, 0x92, 0xff, 0x4a, 0xff, 0x4a, 0xff, 0x06, 0xff, 0x06, 0xff, 0xcc, 0xfe, 0xcc, 0xfe, 0x97, 0xfe, 0x97, 0xfe, 0x6b, 0xfe, 0x6b, 0xfe, 0x49, 0xfe, 0x49, 0xfe, 0x33, 0xfe, 0x33, 0xfe, 0x2a, 0xfe, 0x2a, 0xfe, 0x2b, 0xfe, 0x2b, 0xfe, 0x39, 0xfe, 0x39, 0xfe, 0x54, 0xfe, 0x54, 0xfe, 0x7e, 0xfe, 0x7e, 0xfe, 0xb2, 0xfe, 0xb2, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe, 0x34, 0xff, 0x34, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0xba, 0x00, 0xba, 0x00, 0x03, 0x01, 0x03, 0x01, 0x45, 0x01, 0x45, 0x01, 0x80, 0x01, 0x80, 0x01, 0xb4, 0x01, 0xb4, 0x01, 0xdd, 0x01, 0xdd, 0x01, 0xfb, 0x01, 0xfb, 0x01, 0x0c, 0x02, 0x0c, 0x02, 0x10, 0x02, 0x10, 0x02, 0x07, 0x02, 0x07, 0x02, 0xf2, 0x01, 0xf2, 0x01, 0xd1, 0x01, 0xd1, 0x01, 0xa4, 0x01, 0xa4, 0x01, 0x6e, 0x01, 0x6e, 0x01, 0x2d, 0x01, 0x2d, 0x01, 0xe4, 0x00, 0xe4, 0x00, 0x94, 0x00, 0x94, 0x00, 0x40, 0x00, 0x40, 0x00, 0xeb, 0xff, 0xeb, 0xff, 0x96, 0xff, 0x96, 0xff, 0x44, 0xff, 0x44, 0xff, 0xf6, 0xfe, 0xf6, 0xfe, 0xac, 0xfe, 0xac, 0xfe, 0x6a, 0xfe, 0x6a, 0xfe, 0x33, 0xfe, 0x33, 0xfe, 0x09, 0xfe, 0x09, 0xfe, 0xeb, 0xfd, 0xeb, 0xfd, 0xda, 0xfd, 0xda, 0xfd, 0xd6, 0xfd, 0xd6, 0xfd, 0xe0, 0xfd, 0xe0, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0x1b, 0xfe, 0x1b, 0xfe, 0x4e, 0xfe, 0x4e, 0xfe, 0x8b, 0xfe, 0x8b, 0xfe, 0xd0, 0xfe, 0xd0, 0xfe, 0x17, 0xff, 0x17, 0xff, 0x62, 0xff, 0x62, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x00, 0x4a, 0x00, 0x91, 0x00, 0x91, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x3c, 0x01, 0x3c, 0x01, 0x61, 0x01, 0x61, 0x01, 0x7f, 0x01, 0x7f, 0x01, 0x94, 0x01, 0x94, 0x01, 0x9e, 0x01, 0x9e, 0x01, 0xa2, 0x01, 0xa2, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0x92, 0x01, 0x92, 0x01, 0x7a, 0x01, 0x7a, 0x01, 0x59, 0x01, 0x59, 0x01, 0x31, 0x01, 0x31, 0x01, 0x05, 0x01, 0x05, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x39, 0x00, 0x39, 0x00, 0x05, 0x00, 0x05, 0x00, 0xd3, 0xff, 0xd3, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0x80, 0xff, 0x80, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x43, 0xff, 0x43, 0xff, 0x32, 0xff, 0x32, 0xff, 0x29, 0xff, 0x29, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x31, 0xff, 0x31, 0xff, 0x41, 0xff, 0x41, 0xff, 0x56, 0xff, 0x56, 0xff, 0x71, 0xff, 0x71, 0xff, 0x91, 0xff, 0x91, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x16, 0x00, 0x16, 0x00, 0x34, 0x00, 0x34, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x62, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x74, 0x00, 0x73, 0x00, 0x73, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x65, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x51, 0x00, 0x51, 0x00, 0x40, 0x00, 0x40, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x16, 0x00, 0x16, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x92, 0xff, 0x92, 0xff, 0x74, 0xff, 0x74, 0xff, 0x57, 0xff, 0x57, 0xff, 0x40, 0xff, 0x40, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x14, 0xff, 0x14, 0xff, 0x10, 0xff, 0x10, 0xff, 0x15, 0xff, 0x15, 0xff, 0x22, 0xff, 0x22, 0xff, 0x37, 0xff, 0x37, 0xff, 0x53, 0xff, 0x53, 0xff, 0x74, 0xff, 0x74, 0xff, 0x98, 0xff, 0x98, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0x15, 0x00, 0x15, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0xb2, 0x00, 0xb2, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x19, 0x01, 0x19, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0x3c, 0x01, 0x3c, 0x01, 0x47, 0x01, 0x47, 0x01, 0x4e, 0x01, 0x4e, 0x01, 0x4f, 0x01, 0x4f, 0x01, 0x4b, 0x01, 0x4b, 0x01, 0x40, 0x01, 0x40, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0x16, 0x01, 0x16, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xad, 0x00, 0xad, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x14, 0x00, 0x14, 0x00, 0xdf, 0xff, 0xdf, 0xff, 0xab, 0xff, 0xab, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x4c, 0xff, 0x4c, 0xff, 0x21, 0xff, 0x21, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xc7, 0xfe, 0xc7, 0xfe, 0xb2, 0xfe, 0xb2, 0xfe, 0xa4, 0xfe, 0xa4, 0xfe, 0x9f, 0xfe, 0x9f, 0xfe, 0xa4, 0xfe, 0xa4, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0xc0, 0xfe, 0xc0, 0xfe, 0xd3, 0xfe, 0xd3, 0xfe, 0xe8, 0xfe, 0xe8, 0xfe, 0x02, 0xff, 0x02, 0xff, 0x22, 0xff, 0x22, 0xff, 0x43, 0xff, 0x43, 0xff, 0x66, 0xff, 0x66, 0xff, 0x88, 0xff, 0x88, 0xff, 0xab, 0xff, 0xab, 0xff, 0xce, 0xff, 0xce, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0x14, 0x00, 0x14, 0x00, 0x36, 0x00, 0x36, 0x00, 0x53, 0x00, 0x53, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x87, 0x00, 0x87, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0x92, 0x00, 0x92, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x57, 0x00, 0x57, 0x00, 0x44, 0x00, 0x44, 0x00, 0x34, 0x00, 0x34, 0x00, 0x28, 0x00, 0x28, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x18, 0x00, 0x15, 0x00, 0x15, 0x00, 0x16, 0x00, 0x16, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x19, 0x00, 0x19, 0x00, 0x17, 0x00, 0x17, 0x00, 0x11, 0x00, 0x11, 0x00, 0x09, 0x00, 0x09, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xad, 0xff, 0xad, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xae, 0xff, 0xae, 0xff, 0xae, 0xff, 0xae, 0xff, 0xad, 0xff, 0xad, 0xff, 0xab, 0xff, 0xab, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xac, 0xff, 0xac, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xee, 0xff, 0xee, 0xff, 0x05, 0x00, 0x05, 0x00, 0x20, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x77, 0x00, 0x77, 0x00, 0x90, 0x00, 0x90, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x74, 0x00, 0x57, 0x00, 0x57, 0x00, 0x35, 0x00, 0x35, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xe6, 0xff, 0xe6, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x62, 0xff, 0x62, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x35, 0xff, 0x35, 0xff, 0x23, 0xff, 0x23, 0xff, 0x14, 0xff, 0x14, 0xff, 0x07, 0xff, 0x07, 0xff, 0xfc, 0xfe, 0xfc, 0xfe, 0xf3, 0xfe, 0xf3, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xed, 0xfe, 0xf5, 0xfe, 0xf5, 0xfe, 0x03, 0xff, 0x03, 0xff, 0x17, 0xff, 0x17, 0xff, 0x33, 0xff, 0x33, 0xff, 0x54, 0xff, 0x54, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0x23, 0x00, 0x23, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x92, 0x00, 0x92, 0x00, 0xc4, 0x00, 0xc4, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0x1b, 0x01, 0x1b, 0x01, 0x39, 0x01, 0x39, 0x01, 0x4c, 0x01, 0x4c, 0x01, 0x56, 0x01, 0x56, 0x01, 0x58, 0x01, 0x58, 0x01, 0x55, 0x01, 0x55, 0x01, 0x4c, 0x01, 0x4c, 0x01, 0x3f, 0x01, 0x3f, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0x17, 0x01, 0x17, 0x01, 0xfc, 0x00, 0xfc, 0x00, 0xda, 0x00, 0xda, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0x88, 0x00, 0x88, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x27, 0x00, 0x27, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x58, 0xff, 0x58, 0xff, 0x28, 0xff, 0x28, 0xff, 0xfd, 0xfe, 0xfd, 0xfe, 0xd9, 0xfe, 0xd9, 0xfe, 0xbf, 0xfe, 0xbf, 0xfe, 0xb0, 0xfe, 0xb0, 0xfe, 0xae, 0xfe, 0xae, 0xfe, 0xb5, 0xfe, 0xb5, 0xfe, 0xc3, 0xfe, 0xc3, 0xfe, 0xd9, 0xfe, 0xd9, 0xfe, 0xfb, 0xfe, 0xfb, 0xfe, 0x24, 0xff, 0x24, 0xff, 0x53, 0xff, 0x53, 0xff, 0x86, 0xff, 0x86, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x2a, 0x00, 0x2a, 0x00, 0x61, 0x00, 0x61, 0x00, 0x94, 0x00, 0x94, 0x00, 0xc1, 0x00, 0xc1, 0x00, 0xe8, 0x00, 0xe8, 0x00, 0x09, 0x01, 0x09, 0x01, 0x24, 0x01, 0x24, 0x01, 0x37, 0x01, 0x37, 0x01, 0x41, 0x01, 0x41, 0x01, 0x45, 0x01, 0x45, 0x01, 0x43, 0x01, 0x43, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x30, 0x01, 0x30, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0xff, 0x00, 0xff, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x42, 0x00, 0x42, 0x00, 0x06, 0x00, 0x06, 0x00, 0xc5, 0xff, 0xc5, 0xff, 0x82, 0xff, 0x82, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x03, 0xff, 0x03, 0xff, 0xcf, 0xfe, 0xcf, 0xfe, 0xa3, 0xfe, 0xa3, 0xfe, 0x7d, 0xfe, 0x7d, 0xfe, 0x61, 0xfe, 0x61, 0xfe, 0x4d, 0xfe, 0x4d, 0xfe, 0x44, 0xfe, 0x44, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x54, 0xfe, 0x54, 0xfe, 0x6c, 0xfe, 0x6c, 0xfe, 0x8c, 0xfe, 0x8c, 0xfe, 0xb4, 0xfe, 0xb4, 0xfe, 0xe3, 0xfe, 0xe3, 0xfe, 0x19, 0xff, 0x19, 0xff, 0x53, 0xff, 0x53, 0xff, 0x92, 0xff, 0x92, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0x14, 0x00, 0x14, 0x00, 0x57, 0x00, 0x57, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0xde, 0x00, 0xde, 0x00, 0x1f, 0x01, 0x1f, 0x01, 0x5d, 0x01, 0x5d, 0x01, 0x96, 0x01, 0x96, 0x01, 0xcb, 0x01, 0xcb, 0x01, 0xf9, 0x01, 0xf9, 0x01, 0x1d, 0x02, 0x1d, 0x02, 0x35, 0x02, 0x35, 0x02, 0x41, 0x02, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x02, 0x30, 0x02, 0x30, 0x02, 0x13, 0x02, 0x13, 0x02, 0xe9, 0x01, 0xe9, 0x01, 0xb3, 0x01, 0xb3, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x24, 0x01, 0x24, 0x01, 0xd2, 0x00, 0xd2, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x29, 0x00, 0x29, 0x00, 0xd5, 0xff, 0xd5, 0xff, 0x84, 0xff, 0x84, 0xff, 0x36, 0xff, 0x36, 0xff, 0xec, 0xfe, 0xec, 0xfe, 0xab, 0xfe, 0xab, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0x4c, 0xfe, 0x4c, 0xfe, 0x2b, 0xfe, 0x2b, 0xfe, 0x12, 0xfe, 0x12, 0xfe, 0x02, 0xfe, 0x02, 0xfe, 0xf9, 0xfd, 0xf9, 0xfd, 0xf6, 0xfd, 0xf6, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0b, 0xfe, 0x0b, 0xfe, 0x21, 0xfe, 0x21, 0xfe, 0x40, 0xfe, 0x40, 0xfe, 0x6c, 0xfe, 0x6c, 0xfe, 0xa1, 0xfe, 0xa1, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0x20, 0xff, 0x20, 0xff, 0x67, 0xff, 0x67, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x91, 0x00, 0x91, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0x0a, 0x01, 0x0a, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x67, 0x01, 0x67, 0x01, 0x84, 0x01, 0x84, 0x01, 0x96, 0x01, 0x96, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0x9f, 0x01, 0x95, 0x01, 0x95, 0x01, 0x85, 0x01, 0x85, 0x01, 0x70, 0x01, 0x70, 0x01, 0x54, 0x01, 0x54, 0x01, 0x31, 0x01, 0x31, 0x01, 0x0a, 0x01, 0x0a, 0x01, 0xe0, 0x00, 0xe0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x19, 0x00, 0x19, 0x00, 0xe6, 0xff, 0xe6, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0x85, 0xff, 0x85, 0xff, 0x58, 0xff, 0x58, 0xff, 0x2d, 0xff, 0x2d, 0xff, 0x09, 0xff, 0x09, 0xff, 0xed, 0xfe, 0xed, 0xfe, 0xd7, 0xfe, 0xd7, 0xfe, 0xc7, 0xfe, 0xc7, 0xfe, 0xbc, 0xfe, 0xbc, 0xfe, 0xb8, 0xfe, 0xb8, 0xfe, 0xb7, 0xfe, 0xb7, 0xfe, 0xbf, 0xfe, 0xbf, 0xfe, 0xd3, 0xfe, 0xd3, 0xfe, 0xee, 0xfe, 0xee, 0xfe, 0x10, 0xff, 0x10, 0xff, 0x35, 0xff, 0x35, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0x24, 0x00, 0x24, 0x00, 0x55, 0x00, 0x55, 0x00, 0x80, 0x00, 0x80, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xe4, 0x00, 0xe4, 0x00, 0xfb, 0x00, 0xfb, 0x00, 0x0d, 0x01, 0x0d, 0x01, 0x17, 0x01, 0x17, 0x01, 0x19, 0x01, 0x19, 0x01, 0x16, 0x01, 0x16, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0xfd, 0x00, 0xfd, 0x00, 0xe9, 0x00, 0xe9, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0x90, 0x00, 0x90, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x42, 0x00, 0x42, 0x00, 0x16, 0x00, 0x16, 0x00, 0xe7, 0xff, 0xe7, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x63, 0xff, 0x63, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x01, 0xff, 0x01, 0xff, 0xec, 0xfe, 0xec, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0xee, 0xfe, 0xee, 0xfe, 0x01, 0xff, 0x01, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0x3e, 0xff, 0x3e, 0xff, 0x67, 0xff, 0x67, 0xff, 0x95, 0xff, 0x95, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0x22, 0x00, 0x22, 0x00, 0x53, 0x00, 0x53, 0x00, 0x84, 0x00, 0x84, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xde, 0x00, 0xde, 0x00, 0x03, 0x01, 0x03, 0x01, 0x21, 0x01, 0x21, 0x01, 0x36, 0x01, 0x36, 0x01, 0x41, 0x01, 0x41, 0x01, 0x44, 0x01, 0x44, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x2b, 0x01, 0x2b, 0x01, 0x11, 0x01, 0x11, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0x92, 0x00, 0x92, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0xdd, 0xff, 0xdd, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x65, 0xff, 0x65, 0xff, 0x30, 0xff, 0x30, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xd6, 0xfe, 0xd6, 0xfe, 0xb4, 0xfe, 0xb4, 0xfe, 0x9c, 0xfe, 0x9c, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x8a, 0xfe, 0x8a, 0xfe, 0x8e, 0xfe, 0x8e, 0xfe, 0x9e, 0xfe, 0x9e, 0xfe, 0xb8, 0xfe, 0xb8, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0x0b, 0xff, 0x0b, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0xba, 0xff, 0xba, 0xff, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x46, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0xd2, 0x00, 0xd2, 0x00, 0x0f, 0x01, 0x0f, 0x01, 0x48, 0x01, 0x48, 0x01, 0x7a, 0x01, 0x7a, 0x01, 0xa5, 0x01, 0xa5, 0x01, 0xc7, 0x01, 0xc7, 0x01, 0xdc, 0x01, 0xdc, 0x01, 0xe5, 0x01, 0xe5, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xce, 0x01, 0xce, 0x01, 0xaf, 0x01, 0xaf, 0x01, 0x84, 0x01, 0x84, 0x01, 0x4e, 0x01, 0x4e, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0xca, 0x00, 0xca, 0x00, 0x80, 0x00, 0x80, 0x00, 0x31, 0x00, 0x31, 0x00, 0xdf, 0xff, 0xdf, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0xf1, 0xfe, 0xf1, 0xfe, 0xb1, 0xfe, 0xb1, 0xfe, 0x7d, 0xfe, 0x7d, 0xfe, 0x54, 0xfe, 0x54, 0xfe, 0x36, 0xfe, 0x36, 0xfe, 0x25, 0xfe, 0x25, 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x22, 0xfe, 0x22, 0xfe, 0x30, 0xfe, 0x30, 0xfe, 0x4d, 0xfe, 0x4d, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0xa7, 0xfe, 0xa7, 0xfe, 0xdc, 0xfe, 0xdc, 0xfe, 0x14, 0xff, 0x14, 0xff, 0x51, 0xff, 0x51, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0x07, 0x00, 0x07, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0xe8, 0x00, 0xe8, 0x00, 0x11, 0x01, 0x11, 0x01, 0x32, 0x01, 0x32, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0x59, 0x01, 0x59, 0x01, 0x62, 0x01, 0x62, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x52, 0x01, 0x52, 0x01, 0x39, 0x01, 0x39, 0x01, 0x18, 0x01, 0x18, 0x01, 0xf1, 0x00, 0xf1, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0x97, 0x00, 0x97, 0x00, 0x65, 0x00, 0x65, 0x00, 0x33, 0x00, 0x33, 0x00, 0x05, 0x00, 0x05, 0x00, 0xda, 0xff, 0xda, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0x93, 0xff, 0x93, 0xff, 0x79, 0xff, 0x79, 0xff, 0x63, 0xff, 0x63, 0xff, 0x54, 0xff, 0x54, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x48, 0xff, 0x48, 0xff, 0x46, 0xff, 0x46, 0xff, 0x47, 0xff, 0x47, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x74, 0xff, 0x74, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xea, 0xff, 0xea, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x86, 0x00, 0x86, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0xad, 0x00, 0xad, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xab, 0x00, 0xab, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x85, 0x00, 0x85, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xe9, 0xff, 0xe9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0x81, 0xff, 0x81, 0xff, 0x61, 0xff, 0x61, 0xff, 0x43, 0xff, 0x43, 0xff, 0x27, 0xff, 0x27, 0xff, 0x11, 0xff, 0x11, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xe1, 0xfe, 0xe1, 0xfe, 0xe9, 0xfe, 0xe9, 0xfe, 0xf9, 0xfe, 0xf9, 0xfe, 0x10, 0xff, 0x10, 0xff, 0x2d, 0xff, 0x2d, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0x73, 0xff, 0x73, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0x22, 0x00, 0x22, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x77, 0x00, 0x77, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xdf, 0x00, 0xdf, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x12, 0x01, 0x12, 0x01, 0x25, 0x01, 0x25, 0x01, 0x34, 0x01, 0x34, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x43, 0x01, 0x43, 0x01, 0x46, 0x01, 0x46, 0x01, 0x45, 0x01, 0x45, 0x01, 0x40, 0x01, 0x40, 0x01, 0x37, 0x01, 0x37, 0x01, 0x28, 0x01, 0x28, 0x01, 0x14, 0x01, 0x14, 0x01, 0xfb, 0x00, 0xfb, 0x00, 0xdf, 0x00, 0xdf, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x98, 0x00, 0x98, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x43, 0x00, 0x43, 0x00, 0x18, 0x00, 0x18, 0x00, 0xec, 0xff, 0xec, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0x94, 0xff, 0x94, 0xff, 0x6c, 0xff, 0x6c, 0xff, 0x45, 0xff, 0x45, 0xff, 0x22, 0xff, 0x22, 0xff, 0x05, 0xff, 0x05, 0xff, 0xec, 0xfe, 0xec, 0xfe, 0xd8, 0xfe, 0xd8, 0xfe, 0xc8, 0xfe, 0xc8, 0xfe, 0xbd, 0xfe, 0xbd, 0xfe, 0xb7, 0xfe, 0xb7, 0xfe, 0xb6, 0xfe, 0xb6, 0xfe, 0xb9, 0xfe, 0xb9, 0xfe, 0xc1, 0xfe, 0xc1, 0xfe, 0xce, 0xfe, 0xce, 0xfe, 0xdd, 0xfe, 0xdd, 0xfe, 0xef, 0xfe, 0xef, 0xfe, 0x06, 0xff, 0x06, 0xff, 0x20, 0xff, 0x20, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x64, 0xff, 0x64, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0x16, 0x00, 0x16, 0x00, 0x47, 0x00, 0x47, 0x00, 0x79, 0x00, 0x79, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0x1b, 0x01, 0x1b, 0x01, 0x35, 0x01, 0x35, 0x01, 0x48, 0x01, 0x48, 0x01, 0x52, 0x01, 0x52, 0x01, 0x53, 0x01, 0x53, 0x01, 0x4c, 0x01, 0x4c, 0x01, 0x40, 0x01, 0x40, 0x01, 0x2e, 0x01, 0x2e, 0x01, 0x19, 0x01, 0x19, 0x01, 0x01, 0x01, 0x01, 0x01, 0xe8, 0x00, 0xe8, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0xae, 0x00, 0xae, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x69, 0x00, 0x69, 0x00, 0x46, 0x00, 0x46, 0x00, 0x20, 0x00, 0x20, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x6c, 0xff, 0x6c, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x33, 0xff, 0x33, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x0d, 0xff, 0x0d, 0xff, 0x05, 0xff, 0x05, 0xff, 0x03, 0xff, 0x03, 0xff, 0x09, 0xff, 0x09, 0xff, 0x12, 0xff, 0x12, 0xff, 0x1e, 0xff, 0x1e, 0xff, 0x2c, 0xff, 0x2c, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x53, 0xff, 0x53, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x85, 0xff, 0x85, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x37, 0x00, 0x40, 0x00, 0x40, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x53, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x60, 0x00, 0x61, 0x00, 0x61, 0x00, 0x62, 0x00, 0x62, 0x00, 0x62, 0x00, 0x62, 0x00, 0x62, 0x00, 0x62, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x56, 0x00, 0x56, 0x00, 0x51, 0x00, 0x51, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x52, 0x00, 0x53, 0x00, 0x53, 0x00, 0x50, 0x00, 0x50, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x50, 0x00, 0x51, 0x00, 0x51, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xce, 0xff, 0xce, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x81, 0xff, 0x81, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x59, 0xff, 0x59, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x47, 0xff, 0x47, 0xff, 0x45, 0xff, 0x45, 0xff, 0x46, 0xff, 0x46, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x91, 0xff, 0x91, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xda, 0xff, 0xda, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x14, 0x00, 0x14, 0x00, 0x31, 0x00, 0x31, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x68, 0x00, 0x68, 0x00, 0x84, 0x00, 0x84, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd2, 0x00, 0xda, 0x00, 0xda, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xab, 0x00, 0xab, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x45, 0x00, 0x45, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xca, 0xff, 0xca, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x42, 0xff, 0x42, 0xff, 0x2f, 0xff, 0x2f, 0xff, 0x22, 0xff, 0x22, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0x24, 0xff, 0x24, 0xff, 0x34, 0xff, 0x34, 0xff, 0x4a, 0xff, 0x4a, 0xff, 0x64, 0xff, 0x64, 0xff, 0x84, 0xff, 0x84, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xce, 0xff, 0xce, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x43, 0x00, 0x43, 0x00, 0x66, 0x00, 0x66, 0x00, 0x86, 0x00, 0x86, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xb8, 0x00, 0xb8, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xca, 0x00, 0xca, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x73, 0x00, 0x73, 0x00, 0x56, 0x00, 0x56, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x21, 0x00, 0x21, 0x00, 0x07, 0x00, 0x07, 0x00, 0xed, 0xff, 0xed, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0x9c, 0xff, 0x9c, 0xff, 0x96, 0xff, 0x96, 0xff, 0x92, 0xff, 0x92, 0xff, 0x93, 0xff, 0x93, 0xff, 0x99, 0xff, 0x99, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xed, 0xff, 0xed, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x29, 0x00, 0x32, 0x00, 0x32, 0x00, 0x36, 0x00, 0x36, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x73, 0xff, 0x73, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x66, 0xff, 0x66, 0xff, 0x69, 0xff, 0x69, 0xff, 0x73, 0xff, 0x73, 0xff, 0x82, 0xff, 0x82, 0xff, 0x95, 0xff, 0x95, 0xff, 0xac, 0xff, 0xac, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1d, 0x00, 0x1d, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x54, 0x00, 0x54, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x82, 0x00, 0x82, 0x00, 0x98, 0x00, 0x98, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xb2, 0x00, 0xb2, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x70, 0x00, 0x70, 0x00, 0x52, 0x00, 0x52, 0x00, 0x30, 0x00, 0x30, 0x00, 0x08, 0x00, 0x08, 0x00, 0xde, 0xff, 0xde, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0x89, 0xff, 0x89, 0xff, 0x64, 0xff, 0x64, 0xff, 0x46, 0xff, 0x46, 0xff, 0x31, 0xff, 0x31, 0xff, 0x22, 0xff, 0x22, 0xff, 0x1a, 0xff, 0x1a, 0xff, 0x19, 0xff, 0x19, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x42, 0xff, 0x42, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0x0e, 0x00, 0x0e, 0x00, 0x34, 0x00, 0x34, 0x00, 0x56, 0x00, 0x56, 0x00, 0x72, 0x00, 0x72, 0x00, 0x87, 0x00, 0x87, 0x00, 0x99, 0x00, 0x99, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xab, 0x00, 0xab, 0x00, 0xab, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0x98, 0x00, 0x98, 0x00, 0x89, 0x00, 0x89, 0x00, 0x77, 0x00, 0x77, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x45, 0x00, 0x45, 0x00, 0x26, 0x00, 0x26, 0x00, 0x02, 0x00, 0x02, 0x00, 0xde, 0xff, 0xde, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0x95, 0xff, 0x95, 0xff, 0x74, 0xff, 0x74, 0xff, 0x54, 0xff, 0x54, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x29, 0xff, 0x29, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x18, 0xff, 0x18, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x2d, 0xff, 0x2d, 0xff, 0x43, 0xff, 0x43, 0xff, 0x60, 0xff, 0x60, 0xff, 0x83, 0xff, 0x83, 0xff, 0xac, 0xff, 0xac, 0xff, 0xda, 0xff, 0xda, 0xff, 0x09, 0x00, 0x09, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x68, 0x00, 0x68, 0x00, 0x92, 0x00, 0x92, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xe9, 0x00, 0xe9, 0x00, 0xf7, 0x00, 0xf7, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xe9, 0x00, 0xe9, 0x00, 0xd2, 0x00, 0xd2, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0x92, 0x00, 0x92, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x42, 0x00, 0x16, 0x00, 0x16, 0x00, 0xe8, 0xff, 0xe8, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x69, 0xff, 0x69, 0xff, 0x4a, 0xff, 0x4a, 0xff, 0x31, 0xff, 0x31, 0xff, 0x1e, 0xff, 0x1e, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x07, 0xff, 0x07, 0xff, 0x06, 0xff, 0x06, 0xff, 0x0e, 0xff, 0x0e, 0xff, 0x1e, 0xff, 0x1e, 0xff, 0x35, 0xff, 0x35, 0xff, 0x53, 0xff, 0x53, 0xff, 0x73, 0xff, 0x73, 0xff, 0x95, 0xff, 0x95, 0xff, 0xba, 0xff, 0xba, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x35, 0x00, 0x35, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x81, 0x00, 0x81, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xda, 0x00, 0xda, 0x00, 0xe1, 0x00, 0xe1, 0x00, 0xdf, 0x00, 0xdf, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xc7, 0x00, 0xc7, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x90, 0x00, 0x90, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x48, 0x00, 0x48, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x79, 0xff, 0x79, 0xff, 0x59, 0xff, 0x59, 0xff, 0x40, 0xff, 0x40, 0xff, 0x30, 0xff, 0x30, 0xff, 0x24, 0xff, 0x24, 0xff, 0x21, 0xff, 0x21, 0xff, 0x25, 0xff, 0x25, 0xff, 0x30, 0xff, 0x30, 0xff, 0x42, 0xff, 0x42, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x76, 0xff, 0x76, 0xff, 0x96, 0xff, 0x96, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0x06, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x55, 0x00, 0x55, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xeb, 0x00, 0xeb, 0x00, 0xf9, 0x00, 0xf9, 0x00, 0x00, 0x01, 0x00, 0x01, 0xff, 0x00, 0xff, 0x00, 0xf6, 0x00, 0xf6, 0x00, 0xe5, 0x00, 0xe5, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x84, 0x00, 0x84, 0x00, 0x57, 0x00, 0x57, 0x00, 0x28, 0x00, 0x28, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x42, 0xff, 0x42, 0xff, 0x2f, 0xff, 0x2f, 0xff, 0x23, 0xff, 0x23, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x28, 0xff, 0x28, 0xff, 0x38, 0xff, 0x38, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0x67, 0xff, 0x67, 0xff, 0x83, 0xff, 0x83, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0x10, 0x00, 0x10, 0x00, 0x36, 0x00, 0x36, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0xca, 0x00, 0xca, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x95, 0x00, 0x73, 0x00, 0x73, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0xf0, 0xff, 0xf0, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x63, 0xff, 0x63, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x36, 0xff, 0x36, 0xff, 0x37, 0xff, 0x37, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0x64, 0xff, 0x64, 0xff, 0x81, 0xff, 0x81, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xee, 0xff, 0xee, 0xff, 0x15, 0x00, 0x15, 0x00, 0x38, 0x00, 0x38, 0x00, 0x58, 0x00, 0x58, 0x00, 0x75, 0x00, 0x75, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xae, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xac, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x72, 0x00, 0x72, 0x00, 0x51, 0x00, 0x51, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x05, 0x00, 0xdc, 0xff, 0xdc, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0x87, 0xff, 0x87, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x0a, 0xff, 0x0a, 0xff, 0xfb, 0xfe, 0xfb, 0xfe, 0xf5, 0xfe, 0xf5, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0x00, 0xff, 0x00, 0xff, 0x13, 0xff, 0x13, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x50, 0xff, 0x50, 0xff, 0x78, 0xff, 0x78, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xda, 0xff, 0xda, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x71, 0x00, 0x71, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xf1, 0x00, 0xf1, 0x00, 0x10, 0x01, 0x10, 0x01, 0x29, 0x01, 0x29, 0x01, 0x38, 0x01, 0x38, 0x01, 0x3f, 0x01, 0x3f, 0x01, 0x3e, 0x01, 0x3e, 0x01, 0x31, 0x01, 0x31, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x01, 0x01, 0x01, 0x01, 0xe3, 0x00, 0xe3, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x75, 0x00, 0x75, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xad, 0xff, 0xad, 0xff, 0x89, 0xff, 0x89, 0xff, 0x69, 0xff, 0x69, 0xff, 0x50, 0xff, 0x50, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x27, 0xff, 0x27, 0xff, 0x27, 0xff, 0x27, 0xff, 0x2f, 0xff, 0x2f, 0xff, 0x3c, 0xff, 0x3c, 0xff, 0x50, 0xff, 0x50, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x89, 0xff, 0x89, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0x01, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x41, 0x00, 0x41, 0x00, 0x44, 0x00, 0x44, 0x00, 0x41, 0x00, 0x41, 0x00, 0x39, 0x00, 0x39, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x16, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x69, 0xff, 0x69, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x53, 0xff, 0x53, 0xff, 0x53, 0xff, 0x53, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x68, 0xff, 0x68, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x95, 0xff, 0x95, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0x07, 0x00, 0x07, 0x00, 0x32, 0x00, 0x32, 0x00, 0x60, 0x00, 0x60, 0x00, 0x90, 0x00, 0x90, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xec, 0x00, 0xec, 0x00, 0x13, 0x01, 0x13, 0x01, 0x35, 0x01, 0x35, 0x01, 0x4f, 0x01, 0x4f, 0x01, 0x5f, 0x01, 0x5f, 0x01, 0x67, 0x01, 0x67, 0x01, 0x66, 0x01, 0x66, 0x01, 0x5b, 0x01, 0x5b, 0x01, 0x45, 0x01, 0x45, 0x01, 0x25, 0x01, 0x25, 0x01, 0xfe, 0x00, 0xfe, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x60, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0xdb, 0xff, 0xdb, 0xff, 0x95, 0xff, 0x95, 0xff, 0x52, 0xff, 0x52, 0xff, 0x12, 0xff, 0x12, 0xff, 0xd7, 0xfe, 0xd7, 0xfe, 0xa1, 0xfe, 0xa1, 0xfe, 0x78, 0xfe, 0x78, 0xfe, 0x5a, 0xfe, 0x5a, 0xfe, 0x46, 0xfe, 0x46, 0xfe, 0x3b, 0xfe, 0x3b, 0xfe, 0x3c, 0xfe, 0x3c, 0xfe, 0x4b, 0xfe, 0x4b, 0xfe, 0x65, 0xfe, 0x65, 0xfe, 0x8b, 0xfe, 0x8b, 0xfe, 0xbc, 0xfe, 0xbc, 0xfe, 0xf5, 0xfe, 0xf5, 0xfe, 0x35, 0xff, 0x35, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0x13, 0x00, 0x13, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xee, 0x00, 0xee, 0x00, 0x2c, 0x01, 0x2c, 0x01, 0x64, 0x01, 0x64, 0x01, 0x92, 0x01, 0x92, 0x01, 0xb6, 0x01, 0xb6, 0x01, 0xce, 0x01, 0xce, 0x01, 0xd9, 0x01, 0xd9, 0x01, 0xd7, 0x01, 0xd7, 0x01, 0xc8, 0x01, 0xc8, 0x01, 0xad, 0x01, 0xad, 0x01, 0x86, 0x01, 0x86, 0x01, 0x55, 0x01, 0x55, 0x01, 0x1a, 0x01, 0x1a, 0x01, 0xdb, 0x00, 0xdb, 0x00, 0x98, 0x00, 0x98, 0x00, 0x51, 0x00, 0x51, 0x00, 0x06, 0x00, 0x06, 0x00, 0xbb, 0xff, 0xbb, 0xff, 0x77, 0xff, 0x77, 0xff, 0x39, 0xff, 0x39, 0xff, 0x02, 0xff, 0x02, 0xff, 0xd0, 0xfe, 0xd0, 0xfe, 0xa5, 0xfe, 0xa5, 0xfe, 0x81, 0xfe, 0x81, 0xfe, 0x66, 0xfe, 0x66, 0xfe, 0x55, 0xfe, 0x55, 0xfe, 0x52, 0xfe, 0x52, 0xfe, 0x59, 0xfe, 0x59, 0xfe, 0x6b, 0xfe, 0x6b, 0xfe, 0x87, 0xfe, 0x87, 0xfe, 0xab, 0xfe, 0xab, 0xfe, 0xd7, 0xfe, 0xd7, 0xfe, 0x0c, 0xff, 0x0c, 0xff, 0x4c, 0xff, 0x4c, 0xff, 0x91, 0xff, 0x91, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0x1b, 0x00, 0x1b, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x34, 0x01, 0x34, 0x01, 0x50, 0x01, 0x50, 0x01, 0x61, 0x01, 0x61, 0x01, 0x69, 0x01, 0x69, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x63, 0x01, 0x63, 0x01, 0x53, 0x01, 0x53, 0x01, 0x3c, 0x01, 0x3c, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0xf8, 0x00, 0xf8, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x36, 0x00, 0x36, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0x90, 0xff, 0x90, 0xff, 0x5c, 0xff, 0x5c, 0xff, 0x2e, 0xff, 0x2e, 0xff, 0x08, 0xff, 0x08, 0xff, 0xe9, 0xfe, 0xe9, 0xfe, 0xd5, 0xfe, 0xd5, 0xfe, 0xcb, 0xfe, 0xcb, 0xfe, 0xc9, 0xfe, 0xc9, 0xfe, 0xce, 0xfe, 0xce, 0xfe, 0xd9, 0xfe, 0xd9, 0xfe, 0xec, 0xfe, 0xec, 0xfe, 0x05, 0xff, 0x05, 0xff, 0x27, 0xff, 0x27, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0xad, 0xff, 0xad, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0x15, 0x00, 0x15, 0x00, 0x47, 0x00, 0x47, 0x00, 0x76, 0x00, 0x76, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xc6, 0x00, 0xc6, 0x00, 0xe5, 0x00, 0xe5, 0x00, 0xff, 0x00, 0xff, 0x00, 0x14, 0x01, 0x14, 0x01, 0x20, 0x01, 0x20, 0x01, 0x24, 0x01, 0x24, 0x01, 0x1e, 0x01, 0x1e, 0x01, 0x11, 0x01, 0x11, 0x01, 0xfd, 0x00, 0xfd, 0x00, 0xe5, 0x00, 0xe5, 0x00, 0xca, 0x00, 0xca, 0x00, 0xac, 0x00, 0xac, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x66, 0x00, 0x66, 0x00, 0x40, 0x00, 0x40, 0x00, 0x19, 0x00, 0x19, 0x00, 0xf1, 0xff, 0xf1, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0x82, 0xff, 0x82, 0xff, 0x63, 0xff, 0x63, 0xff, 0x49, 0xff, 0x49, 0xff, 0x34, 0xff, 0x34, 0xff, 0x24, 0xff, 0x24, 0xff, 0x1a, 0xff, 0x1a, 0xff, 0x17, 0xff, 0x17, 0xff, 0x1d, 0xff, 0x1d, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x40, 0xff, 0x40, 0xff, 0x57, 0xff, 0x57, 0xff, 0x70, 0xff, 0x70, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xca, 0xff, 0xca, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0x05, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x36, 0x00, 0x48, 0x00, 0x48, 0x00, 0x57, 0x00, 0x57, 0x00, 0x62, 0x00, 0x62, 0x00, 0x68, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x66, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x54, 0x00, 0x49, 0x00, 0x49, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x33, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x11, 0x00, 0x07, 0x00, 0x07, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x01, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x24, 0x00, 0x28, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x29, 0x00, 0x29, 0x00, 0x26, 0x00, 0x26, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xea, 0xff, 0xea, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x07, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x14, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x21, 0x00, 0x21, 0x00, 0x23, 0x00, 0x23, 0x00, 0x24, 0x00, 0x24, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x03, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xed, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x17, 0x00, 0x25, 0x00, 0x25, 0x00, 0x32, 0x00, 0x32, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x56, 0x00, 0x56, 0x00, 0x59, 0x00, 0x59, 0x00, 0x58, 0x00, 0x58, 0x00, 0x54, 0x00, 0x54, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x41, 0x00, 0x41, 0x00, 0x31, 0x00, 0x31, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x06, 0x00, 0x06, 0x00, 0xef, 0xff, 0xef, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x79, 0xff, 0x79, 0xff, 0x6d, 0xff, 0x6d, 0xff, 0x67, 0xff, 0x67, 0xff, 0x66, 0xff, 0x66, 0xff, 0x68, 0xff, 0x68, 0xff, 0x70, 0xff, 0x70, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x88, 0xff, 0x88, 0xff, 0x99, 0xff, 0x99, 0xff, 0xae, 0xff, 0xae, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x39, 0x00, 0x39, 0x00, 0x54, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x87, 0x00, 0x87, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xba, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0x99, 0x00, 0x99, 0x00, 0x80, 0x00, 0x80, 0x00, 0x64, 0x00, 0x64, 0x00, 0x45, 0x00, 0x45, 0x00, 0x22, 0x00, 0x22, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0x96, 0xff, 0x96, 0xff, 0x79, 0xff, 0x79, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x47, 0xff, 0x47, 0xff, 0x34, 0xff, 0x34, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x26, 0xff, 0x26, 0xff, 0x27, 0xff, 0x27, 0xff, 0x2f, 0xff, 0x2f, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x60, 0xff, 0x60, 0xff, 0x79, 0xff, 0x79, 0xff, 0x96, 0xff, 0x96, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x15, 0x00, 0x27, 0x00, 0x27, 0x00, 0x35, 0x00, 0x35, 0x00, 0x40, 0x00, 0x40, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x48, 0x00, 0x48, 0x00, 0x45, 0x00, 0x45, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x35, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x28, 0x00, 0x20, 0x00, 0x20, 0x00, 0x19, 0x00, 0x19, 0x00, 0x12, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xed, 0xff, 0xee, 0xff, 0xee, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x40, 0x00, 0x52, 0x00, 0x52, 0x00, 0x63, 0x00, 0x63, 0x00, 0x70, 0x00, 0x70, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x83, 0x00, 0x83, 0x00, 0x80, 0x00, 0x80, 0x00, 0x76, 0x00, 0x76, 0x00, 0x66, 0x00, 0x66, 0x00, 0x51, 0x00, 0x51, 0x00, 0x38, 0x00, 0x38, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x91, 0xff, 0x91, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x68, 0xff, 0x68, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x4e, 0xff, 0x4e, 0xff, 0x46, 0xff, 0x46, 0xff, 0x43, 0xff, 0x43, 0xff, 0x44, 0xff, 0x44, 0xff, 0x49, 0xff, 0x49, 0xff, 0x52, 0xff, 0x52, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x6e, 0xff, 0x6e, 0xff, 0x81, 0xff, 0x81, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xda, 0xff, 0xda, 0xff, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x27, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x74, 0x00, 0x98, 0x00, 0x98, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xe9, 0x00, 0xe9, 0x00, 0xf6, 0x00, 0xf6, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0xf7, 0x00, 0xf7, 0x00, 0xed, 0x00, 0xed, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xc4, 0x00, 0xc4, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x51, 0x00, 0x51, 0x00, 0x24, 0x00, 0x24, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x79, 0xff, 0x79, 0xff, 0x57, 0xff, 0x57, 0xff, 0x38, 0xff, 0x38, 0xff, 0x1e, 0xff, 0x1e, 0xff, 0x0a, 0xff, 0x0a, 0xff, 0xfa, 0xfe, 0xfa, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0x02, 0xff, 0x02, 0xff, 0x13, 0xff, 0x13, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x47, 0xff, 0x47, 0xff, 0x67, 0xff, 0x67, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0xae, 0xff, 0xae, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x2c, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x84, 0x00, 0x84, 0x00, 0xad, 0x00, 0xad, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xf1, 0x00, 0xf1, 0x00, 0x0d, 0x01, 0x0d, 0x01, 0x23, 0x01, 0x23, 0x01, 0x34, 0x01, 0x34, 0x01, 0x3d, 0x01, 0x3d, 0x01, 0x3f, 0x01, 0x3f, 0x01, 0x3b, 0x01, 0x3b, 0x01, 0x30, 0x01, 0x30, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x03, 0x01, 0x03, 0x01, 0xe4, 0x00, 0xe4, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x78, 0x00, 0x78, 0x00, 0x50, 0x00, 0x50, 0x00, 0x26, 0x00, 0x26, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xad, 0xff, 0xad, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x50, 0xff, 0x50, 0xff, 0x36, 0xff, 0x36, 0xff, 0x20, 0xff, 0x20, 0xff, 0x0d, 0xff, 0x0d, 0xff, 0x00, 0xff, 0x00, 0xff, 0xf8, 0xfe, 0xf8, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0xf6, 0xfe, 0xfb, 0xfe, 0xfb, 0xfe, 0x05, 0xff, 0x05, 0xff, 0x12, 0xff, 0x12, 0xff, 0x24, 0xff, 0x24, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x59, 0xff, 0x59, 0xff, 0x78, 0xff, 0x78, 0xff, 0x99, 0xff, 0x99, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0x03, 0x00, 0x03, 0x00, 0x26, 0x00, 0x26, 0x00, 0x48, 0x00, 0x48, 0x00, 0x65, 0x00, 0x65, 0x00, 0x80, 0x00, 0x80, 0x00, 0x96, 0x00, 0x96, 0x00, 0xa8, 0x00, 0xa8, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0xc7, 0x00, 0xc6, 0x00, 0xc6, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x68, 0x00, 0x68, 0x00, 0x54, 0x00, 0x54, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x25, 0x00, 0x25, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0xff, 0xf8, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xce, 0xff, 0xce, 0xff, 0xba, 0xff, 0xba, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x95, 0xff, 0x95, 0xff, 0x85, 0xff, 0x85, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x75, 0xff, 0x75, 0xff, 0x72, 0xff, 0x72, 0xff, 0x70, 0xff, 0x70, 0xff, 0x72, 0xff, 0x72, 0xff, 0x78, 0xff, 0x78, 0xff, 0x81, 0xff, 0x81, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x97, 0xff, 0x97, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x34, 0x00, 0x34, 0x00, 0x48, 0x00, 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x99, 0x00, 0x99, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa8, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x93, 0x00, 0x93, 0x00, 0x86, 0x00, 0x86, 0x00, 0x77, 0x00, 0x77, 0x00, 0x67, 0x00, 0x67, 0x00, 0x55, 0x00, 0x55, 0x00, 0x41, 0x00, 0x41, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x15, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x85, 0xff, 0x85, 0xff, 0x72, 0xff, 0x72, 0xff, 0x61, 0xff, 0x61, 0xff, 0x53, 0xff, 0x53, 0xff, 0x48, 0xff, 0x48, 0xff, 0x40, 0xff, 0x40, 0xff, 0x3a, 0xff, 0x3a, 0xff, 0x37, 0xff, 0x37, 0xff, 0x38, 0xff, 0x38, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x4c, 0xff, 0x4c, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x76, 0xff, 0x76, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xba, 0xff, 0xba, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x67, 0x00, 0x67, 0x00, 0x80, 0x00, 0x80, 0x00, 0x97, 0x00, 0x97, 0x00, 0xae, 0x00, 0xae, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xe4, 0x00, 0xe4, 0x00, 0xea, 0x00, 0xea, 0x00, 0xee, 0x00, 0xee, 0x00, 0xee, 0x00, 0xee, 0x00, 0xe8, 0x00, 0xe8, 0x00, 0xde, 0x00, 0xde, 0x00, 0xce, 0x00, 0xce, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x81, 0x00, 0x62, 0x00, 0x62, 0x00, 0x40, 0x00, 0x40, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x83, 0xff, 0x83, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x53, 0xff, 0x53, 0xff, 0x40, 0xff, 0x40, 0xff, 0x2f, 0xff, 0x2f, 0xff, 0x23, 0xff, 0x23, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x19, 0xff, 0x19, 0xff, 0x1b, 0xff, 0x1b, 0xff, 0x20, 0xff, 0x20, 0xff, 0x2b, 0xff, 0x2b, 0xff, 0x3b, 0xff, 0x3b, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x64, 0xff, 0x64, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x96, 0xff, 0x96, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0x01, 0x00, 0x01, 0x00, 0x26, 0x00, 0x26, 0x00, 0x46, 0x00, 0x46, 0x00, 0x62, 0x00, 0x62, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x92, 0x00, 0x92, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xba, 0x00, 0xad, 0x00, 0xad, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x78, 0x00, 0x78, 0x00, 0x63, 0x00, 0x63, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x39, 0x00, 0x39, 0x00, 0x24, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0x97, 0xff, 0x97, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x82, 0xff, 0x82, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0x80, 0xff, 0x80, 0xff, 0x86, 0xff, 0x86, 0xff, 0x90, 0xff, 0x90, 0xff, 0x9c, 0xff, 0x9c, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x15, 0x00, 0x15, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x15, 0x00, 0x15, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x46, 0x00, 0x46, 0x00, 0x40, 0x00, 0x40, 0x00, 0x37, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x25, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x11, 0x00, 0x06, 0x00, 0x06, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x98, 0xff, 0x98, 0xff, 0x95, 0xff, 0x95, 0xff, 0x98, 0xff, 0x98, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x24, 0x00, 0x24, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x56, 0x00, 0x60, 0x00, 0x60, 0x00, 0x65, 0x00, 0x65, 0x00, 0x69, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x68, 0x00, 0x68, 0x00, 0x66, 0x00, 0x66, 0x00, 0x63, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x51, 0x00, 0x51, 0x00, 0x46, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x21, 0x00, 0x21, 0x00, 0x13, 0x00, 0x13, 0x00, 0x07, 0x00, 0x07, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xad, 0xff, 0xad, 0xff, 0xac, 0xff, 0xac, 0xff, 0xac, 0xff, 0xac, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x06, 0x00, 0x06, 0x00, 0x14, 0x00, 0x14, 0x00, 0x23, 0x00, 0x23, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x57, 0x00, 0x61, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x83, 0x00, 0x85, 0x00, 0x85, 0x00, 0x82, 0x00, 0x82, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x61, 0x00, 0x54, 0x00, 0x54, 0x00, 0x46, 0x00, 0x46, 0x00, 0x36, 0x00, 0x36, 0x00, 0x26, 0x00, 0x26, 0x00, 0x15, 0x00, 0x15, 0x00, 0x05, 0x00, 0x05, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xad, 0xff, 0xad, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xad, 0xff, 0xad, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x05, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x18, 0x00, 0x21, 0x00, 0x21, 0x00, 0x24, 0x00, 0x24, 0x00, 0x23, 0x00, 0x23, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x16, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x04, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xca, 0xff, 0xca, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x07, 0x00, 0x07, 0x00, 0x19, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x66, 0x00, 0x66, 0x00, 0x72, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x82, 0x00, 0x82, 0x00, 0x86, 0x00, 0x86, 0x00, 0x89, 0x00, 0x89, 0x00, 0x89, 0x00, 0x89, 0x00, 0x87, 0x00, 0x87, 0x00, 0x83, 0x00, 0x83, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x77, 0x00, 0x77, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x35, 0x00, 0x20, 0x00, 0x20, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0x98, 0xff, 0x98, 0xff, 0x81, 0xff, 0x81, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x52, 0xff, 0x52, 0xff, 0x3d, 0xff, 0x3d, 0xff, 0x2b, 0xff, 0x2b, 0xff, 0x1f, 0xff, 0x1f, 0xff, 0x17, 0xff, 0x17, 0xff, 0x16, 0xff, 0x16, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0x27, 0xff, 0x27, 0xff, 0x37, 0xff, 0x37, 0xff, 0x48, 0xff, 0x48, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x78, 0xff, 0x78, 0xff, 0x96, 0xff, 0x96, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0x10, 0x00, 0x10, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x47, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x73, 0x00, 0x73, 0x00, 0x85, 0x00, 0x85, 0x00, 0x93, 0x00, 0x93, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xba, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x77, 0x00, 0x77, 0x00, 0x61, 0x00, 0x61, 0x00, 0x49, 0x00, 0x49, 0x00, 0x30, 0x00, 0x30, 0x00, 0x14, 0x00, 0x14, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xde, 0xff, 0xde, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x92, 0xff, 0x92, 0xff, 0x87, 0xff, 0x87, 0xff, 0x80, 0xff, 0x80, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x85, 0xff, 0x85, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0x98, 0xff, 0x98, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x06, 0x00, 0x06, 0x00, 0x16, 0x00, 0x16, 0x00, 0x24, 0x00, 0x24, 0x00, 0x32, 0x00, 0x32, 0x00, 0x40, 0x00, 0x40, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x61, 0x00, 0x61, 0x00, 0x61, 0x00, 0x61, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x57, 0x00, 0x57, 0x00, 0x52, 0x00, 0x52, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x22, 0x00, 0x22, 0x00, 0x15, 0x00, 0x15, 0x00, 0x08, 0x00, 0x08, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xed, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x9c, 0xff, 0x9c, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x97, 0xff, 0x97, 0xff, 0x96, 0xff, 0x96, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xad, 0xff, 0xad, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x23, 0x00, 0x23, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x51, 0x00, 0x51, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x83, 0x00, 0x83, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0xae, 0x00, 0xae, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xca, 0x00, 0xca, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xc4, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x71, 0x00, 0x71, 0x00, 0x52, 0x00, 0x52, 0x00, 0x32, 0x00, 0x32, 0x00, 0x11, 0x00, 0x11, 0x00, 0xef, 0xff, 0xef, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x84, 0xff, 0x84, 0xff, 0x63, 0xff, 0x63, 0xff, 0x43, 0xff, 0x43, 0xff, 0x26, 0xff, 0x26, 0xff, 0x0d, 0xff, 0x0d, 0xff, 0xf6, 0xfe, 0xf6, 0xfe, 0xe6, 0xfe, 0xe6, 0xfe, 0xdb, 0xfe, 0xdb, 0xfe, 0xd4, 0xfe, 0xd4, 0xfe, 0xd3, 0xfe, 0xd3, 0xfe, 0xda, 0xfe, 0xda, 0xfe, 0xe9, 0xfe, 0xe9, 0xfe, 0xfd, 0xfe, 0xfd, 0xfe, 0x17, 0xff, 0x17, 0xff, 0x34, 0xff, 0x34, 0xff, 0x56, 0xff, 0x56, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xce, 0xff, 0xce, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x25, 0x00, 0x25, 0x00, 0x50, 0x00, 0x50, 0x00, 0x78, 0x00, 0x78, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf9, 0x00, 0xf9, 0x00, 0x0a, 0x01, 0x0a, 0x01, 0x16, 0x01, 0x16, 0x01, 0x1a, 0x01, 0x1a, 0x01, 0x18, 0x01, 0x18, 0x01, 0x13, 0x01, 0x13, 0x01, 0x07, 0x01, 0x07, 0x01, 0xf6, 0x00, 0xf6, 0x00, 0xdf, 0x00, 0xdf, 0x00, 0xc6, 0x00, 0xc6, 0x00, 0xab, 0x00, 0xab, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x62, 0x00, 0x62, 0x00, 0x37, 0x00, 0x37, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xe1, 0xff, 0xe1, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0x98, 0xff, 0x98, 0xff, 0x78, 0xff, 0x78, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x29, 0xff, 0x29, 0xff, 0x18, 0xff, 0x18, 0xff, 0x0c, 0xff, 0x0c, 0xff, 0x04, 0xff, 0x04, 0xff, 0x02, 0xff, 0x02, 0xff, 0x08, 0xff, 0x08, 0xff, 0x17, 0xff, 0x17, 0xff, 0x2a, 0xff, 0x2a, 0xff, 0x40, 0xff, 0x40, 0xff, 0x58, 0xff, 0x58, 0xff, 0x73, 0xff, 0x73, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0xab, 0xff, 0xab, 0xff, 0xca, 0xff, 0xca, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0x08, 0x00, 0x08, 0x00, 0x25, 0x00, 0x25, 0x00, 0x43, 0x00, 0x43, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x75, 0x00, 0x75, 0x00, 0x89, 0x00, 0x89, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xc7, 0x00, 0xc7, 0x00, 0xca, 0x00, 0xca, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x94, 0x00, 0x94, 0x00, 0x82, 0x00, 0x82, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x54, 0x00, 0x54, 0x00, 0x39, 0x00, 0x39, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x01, 0x00, 0x01, 0x00, 0xe2, 0xff, 0xe2, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0x85, 0xff, 0x85, 0xff, 0x68, 0xff, 0x68, 0xff, 0x4c, 0xff, 0x4c, 0xff, 0x34, 0xff, 0x34, 0xff, 0x21, 0xff, 0x21, 0xff, 0x13, 0xff, 0x13, 0xff, 0x08, 0xff, 0x08, 0xff, 0x03, 0xff, 0x03, 0xff, 0x01, 0xff, 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x03, 0xff, 0x03, 0xff, 0x0a, 0xff, 0x0a, 0xff, 0x15, 0xff, 0x15, 0xff, 0x23, 0xff, 0x23, 0xff, 0x36, 0xff, 0x36, 0xff, 0x4d, 0xff, 0x4d, 0xff, 0x68, 0xff, 0x68, 0xff, 0x85, 0xff, 0x85, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x32, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x85, 0x00, 0x85, 0x00, 0xac, 0x00, 0xac, 0x00, 0xce, 0x00, 0xce, 0x00, 0xed, 0x00, 0xed, 0x00, 0x0b, 0x01, 0x0b, 0x01, 0x27, 0x01, 0x27, 0x01, 0x41, 0x01, 0x41, 0x01, 0x57, 0x01, 0x57, 0x01, 0x66, 0x01, 0x66, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x6f, 0x01, 0x66, 0x01, 0x66, 0x01, 0x59, 0x01, 0x59, 0x01, 0x48, 0x01, 0x48, 0x01, 0x31, 0x01, 0x31, 0x01, 0x16, 0x01, 0x16, 0x01, 0xf5, 0x00, 0xf5, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x74, 0x00, 0x74, 0x00, 0x43, 0x00, 0x43, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xda, 0xff, 0xda, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0x74, 0xff, 0x74, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0x0b, 0xff, 0x0b, 0xff, 0xdd, 0xfe, 0xdd, 0xfe, 0xb6, 0xfe, 0xb6, 0xfe, 0x95, 0xfe, 0x95, 0xfe, 0x77, 0xfe, 0x77, 0xfe, 0x5f, 0xfe, 0x5f, 0xfe, 0x4e, 0xfe, 0x4e, 0xfe, 0x43, 0xfe, 0x43, 0xfe, 0x3d, 0xfe, 0x3d, 0xfe, 0x41, 0xfe, 0x41, 0xfe, 0x4c, 0xfe, 0x4c, 0xfe, 0x5f, 0xfe, 0x5f, 0xfe, 0x7a, 0xfe, 0x7a, 0xfe, 0x9e, 0xfe, 0x9e, 0xfe, 0xcb, 0xfe, 0xcb, 0xfe, 0xfc, 0xfe, 0xfc, 0xfe, 0x31, 0xff, 0x31, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0x27, 0x00, 0x27, 0x00, 0x65, 0x00, 0x65, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x12, 0x01, 0x12, 0x01, 0x43, 0x01, 0x43, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x8e, 0x01, 0x8e, 0x01, 0xa9, 0x01, 0xa9, 0x01, 0xbe, 0x01, 0xbe, 0x01, 0xcb, 0x01, 0xcb, 0x01, 0xd0, 0x01, 0xd0, 0x01, 0xcd, 0x01, 0xcd, 0x01, 0xc1, 0x01, 0xc1, 0x01, 0xad, 0x01, 0xad, 0x01, 0x91, 0x01, 0x91, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0x42, 0x01, 0x42, 0x01, 0x11, 0x01, 0x11, 0x01, 0xda, 0x00, 0xda, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x66, 0x00, 0x66, 0x00, 0x29, 0x00, 0x29, 0x00, 0xee, 0xff, 0xee, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x45, 0xff, 0x45, 0xff, 0x14, 0xff, 0x14, 0xff, 0xea, 0xfe, 0xea, 0xfe, 0xc8, 0xfe, 0xc8, 0xfe, 0xad, 0xfe, 0xad, 0xfe, 0x9d, 0xfe, 0x9d, 0xfe, 0x94, 0xfe, 0x94, 0xfe, 0x8f, 0xfe, 0x8f, 0xfe, 0x91, 0xfe, 0x91, 0xfe, 0x9e, 0xfe, 0x9e, 0xfe, 0xb4, 0xfe, 0xb4, 0xfe, 0xcd, 0xfe, 0xcd, 0xfe, 0xeb, 0xfe, 0xeb, 0xfe, 0x0c, 0xff, 0x0c, 0xff, 0x30, 0xff, 0x30, 0xff, 0x55, 0xff, 0x55, 0xff, 0x79, 0xff, 0x79, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0x1c, 0x00, 0x1c, 0x00, 0x45, 0x00, 0x45, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xdf, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xba, 0x00, 0xba, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0x95, 0x00, 0x95, 0x00, 0x80, 0x00, 0x80, 0x00, 0x69, 0x00, 0x69, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x37, 0x00, 0x37, 0x00, 0x22, 0x00, 0x22, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xee, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xce, 0xff, 0xce, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xee, 0xff, 0xee, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x02, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x10, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x20, 0x00, 0x20, 0x00, 0x23, 0x00, 0x23, 0x00, 0x25, 0x00, 0x25, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x09, 0x00, 0x09, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xed, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0x01, 0x00, 0x01, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x11, 0x00, 0x19, 0x00, 0x19, 0x00, 0x21, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x35, 0x00, 0x40, 0x00, 0x40, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x66, 0x00, 0x66, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x76, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x81, 0x00, 0x80, 0x00, 0x80, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x74, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x63, 0x00, 0x63, 0x00, 0x57, 0x00, 0x57, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x39, 0x00, 0x39, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0xef, 0xff, 0xef, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x97, 0xff, 0x97, 0xff, 0x92, 0xff, 0x92, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x88, 0xff, 0x88, 0xff, 0x84, 0xff, 0x84, 0xff, 0x83, 0xff, 0x83, 0xff, 0x84, 0xff, 0x84, 0xff, 0x89, 0xff, 0x89, 0xff, 0x92, 0xff, 0x92, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xab, 0xff, 0xab, 0xff, 0xba, 0xff, 0xba, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x0e, 0x00, 0x0e, 0x00, 0x21, 0x00, 0x21, 0x00, 0x33, 0x00, 0x33, 0x00, 0x42, 0x00, 0x42, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x60, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x52, 0x00, 0x52, 0x00, 0x47, 0x00, 0x47, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x30, 0x00, 0x30, 0x00, 0x22, 0x00, 0x22, 0x00, 0x14, 0x00, 0x14, 0x00, 0x04, 0x00, 0x04, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xca, 0xff, 0xca, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xae, 0xff, 0xae, 0xff, 0xad, 0xff, 0xad, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x28, 0x00, 0x28, 0x00, 0x31, 0x00, 0x31, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x46, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x49, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x20, 0x00, 0x20, 0x00, 0x14, 0x00, 0x14, 0x00, 0x06, 0x00, 0x06, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xca, 0xff, 0xca, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xda, 0xff, 0xda, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x03, 0x00, 0x03, 0x00, 0x10, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x29, 0x00, 0x29, 0x00, 0x32, 0x00, 0x32, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x45, 0x00, 0x45, 0x00, 0x49, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x49, 0x00, 0x49, 0x00, 0x44, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x32, 0x00, 0x32, 0x00, 0x23, 0x00, 0x23, 0x00, 0x10, 0x00, 0x10, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xad, 0xff, 0xad, 0xff, 0xac, 0xff, 0xac, 0xff, 0xab, 0xff, 0xab, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0x06, 0x00, 0x06, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x35, 0x00, 0x35, 0x00, 0x46, 0x00, 0x46, 0x00, 0x54, 0x00, 0x54, 0x00, 0x62, 0x00, 0x62, 0x00, 0x73, 0x00, 0x73, 0x00, 0x81, 0x00, 0x81, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x92, 0x00, 0x91, 0x00, 0x91, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x85, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x71, 0x00, 0x71, 0x00, 0x62, 0x00, 0x62, 0x00, 0x51, 0x00, 0x51, 0x00, 0x41, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x07, 0x00, 0x07, 0x00, 0xf0, 0xff, 0xf0, 0xff, 0xda, 0xff, 0xda, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0x91, 0xff, 0x91, 0xff, 0x83, 0xff, 0x83, 0xff, 0x77, 0xff, 0x77, 0xff, 0x6e, 0xff, 0x6e, 0xff, 0x67, 0xff, 0x67, 0xff, 0x62, 0xff, 0x62, 0xff, 0x63, 0xff, 0x63, 0xff, 0x69, 0xff, 0x69, 0xff, 0x6f, 0xff, 0x6f, 0xff, 0x76, 0xff, 0x76, 0xff, 0x80, 0xff, 0x80, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xed, 0xff, 0xed, 0xff, 0x06, 0x00, 0x06, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x32, 0x00, 0x32, 0x00, 0x44, 0x00, 0x44, 0x00, 0x55, 0x00, 0x55, 0x00, 0x67, 0x00, 0x67, 0x00, 0x78, 0x00, 0x78, 0x00, 0x86, 0x00, 0x86, 0x00, 0x91, 0x00, 0x91, 0x00, 0x98, 0x00, 0x98, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x93, 0x00, 0x85, 0x00, 0x85, 0x00, 0x76, 0x00, 0x76, 0x00, 0x65, 0x00, 0x65, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x38, 0x00, 0x38, 0x00, 0x20, 0x00, 0x20, 0x00, 0x07, 0x00, 0x07, 0x00, 0xec, 0xff, 0xec, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0x99, 0xff, 0x99, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x89, 0xff, 0x89, 0xff, 0x85, 0xff, 0x85, 0xff, 0x81, 0xff, 0x81, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x80, 0xff, 0x80, 0xff, 0x85, 0xff, 0x85, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x95, 0xff, 0x95, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0xad, 0xff, 0xad, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xde, 0xff, 0xde, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x05, 0x00, 0x05, 0x00, 0x18, 0x00, 0x18, 0x00, 0x28, 0x00, 0x28, 0x00, 0x36, 0x00, 0x36, 0x00, 0x43, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x65, 0x00, 0x65, 0x00, 0x65, 0x00, 0x66, 0x00, 0x66, 0x00, 0x63, 0x00, 0x63, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x57, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x48, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x07, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x14, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x22, 0x00, 0x28, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x33, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x44, 0x00, 0x46, 0x00, 0x46, 0x00, 0x44, 0x00, 0x44, 0x00, 0x40, 0x00, 0x40, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x22, 0x00, 0x22, 0x00, 0x16, 0x00, 0x16, 0x00, 0x09, 0x00, 0x09, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xad, 0xff, 0xad, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x7c, 0xff, 0x7c, 0xff, 0x6f, 0xff, 0x6f, 0xff, 0x66, 0xff, 0x66, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x65, 0xff, 0x65, 0xff, 0x70, 0xff, 0x70, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xba, 0xff, 0xba, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xee, 0xff, 0xee, 0xff, 0x0e, 0x00, 0x0e, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x68, 0x00, 0x68, 0x00, 0x83, 0x00, 0x83, 0x00, 0x99, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xb8, 0x00, 0xb8, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc8, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x75, 0x00, 0x75, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x40, 0x00, 0x40, 0x00, 0x23, 0x00, 0x23, 0x00, 0x06, 0x00, 0x06, 0x00, 0xe6, 0xff, 0xe6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x74, 0xff, 0x74, 0xff, 0x60, 0xff, 0x60, 0xff, 0x51, 0xff, 0x51, 0xff, 0x48, 0xff, 0x48, 0xff, 0x44, 0xff, 0x44, 0xff, 0x43, 0xff, 0x43, 0xff, 0x48, 0xff, 0x48, 0xff, 0x53, 0xff, 0x53, 0xff, 0x65, 0xff, 0x65, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x95, 0xff, 0x95, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x19, 0x00, 0x30, 0x00, 0x30, 0x00, 0x45, 0x00, 0x45, 0x00, 0x55, 0x00, 0x55, 0x00, 0x63, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x72, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x60, 0x00, 0x60, 0x00, 0x55, 0x00, 0x55, 0x00, 0x48, 0x00, 0x48, 0x00, 0x38, 0x00, 0x38, 0x00, 0x27, 0x00, 0x27, 0x00, 0x16, 0x00, 0x16, 0x00, 0x03, 0x00, 0x03, 0x00, 0xed, 0xff, 0xed, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0x97, 0xff, 0x97, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x84, 0xff, 0x84, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x86, 0xff, 0x86, 0xff, 0x90, 0xff, 0x90, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0x01, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x51, 0x00, 0x51, 0x00, 0x67, 0x00, 0x67, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x57, 0x00, 0x57, 0x00, 0x41, 0x00, 0x41, 0x00, 0x26, 0x00, 0x26, 0x00, 0x09, 0x00, 0x09, 0x00, 0xee, 0xff, 0xee, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x93, 0xff, 0x93, 0xff, 0x81, 0xff, 0x81, 0xff, 0x73, 0xff, 0x73, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x64, 0xff, 0x64, 0xff, 0x62, 0xff, 0x62, 0xff, 0x66, 0xff, 0x66, 0xff, 0x73, 0xff, 0x73, 0xff, 0x85, 0xff, 0x85, 0xff, 0x99, 0xff, 0x99, 0xff, 0xae, 0xff, 0xae, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xde, 0xff, 0xde, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x12, 0x00, 0x12, 0x00, 0x29, 0x00, 0x29, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x66, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x64, 0x00, 0x64, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x52, 0x00, 0x52, 0x00, 0x44, 0x00, 0x44, 0x00, 0x33, 0x00, 0x33, 0x00, 0x20, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0x99, 0xff, 0x99, 0xff, 0x86, 0xff, 0x86, 0xff, 0x75, 0xff, 0x75, 0xff, 0x68, 0xff, 0x68, 0xff, 0x60, 0xff, 0x60, 0xff, 0x5e, 0xff, 0x5e, 0xff, 0x62, 0xff, 0x62, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x74, 0xff, 0x74, 0xff, 0x82, 0xff, 0x82, 0xff, 0x92, 0xff, 0x92, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0x02, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x52, 0x00, 0x52, 0x00, 0x64, 0x00, 0x64, 0x00, 0x77, 0x00, 0x77, 0x00, 0x88, 0x00, 0x88, 0x00, 0x97, 0x00, 0x97, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb8, 0x00, 0xb8, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x45, 0x00, 0x45, 0x00, 0x29, 0x00, 0x29, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xf2, 0xff, 0xf2, 0xff, 0xda, 0xff, 0xda, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x77, 0xff, 0x77, 0xff, 0x62, 0xff, 0x62, 0xff, 0x50, 0xff, 0x50, 0xff, 0x41, 0xff, 0x41, 0xff, 0x34, 0xff, 0x34, 0xff, 0x29, 0xff, 0x29, 0xff, 0x1e, 0xff, 0x1e, 0xff, 0x19, 0xff, 0x19, 0xff, 0x19, 0xff, 0x19, 0xff, 0x1c, 0xff, 0x1c, 0xff, 0x23, 0xff, 0x23, 0xff, 0x30, 0xff, 0x30, 0xff, 0x43, 0xff, 0x43, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x75, 0xff, 0x75, 0xff, 0x91, 0xff, 0x91, 0xff, 0xad, 0xff, 0xad, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x66, 0x00, 0x66, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x97, 0x00, 0x97, 0x00, 0xab, 0x00, 0xab, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xca, 0x00, 0xca, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xda, 0x00, 0xda, 0x00, 0xde, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xcf, 0x00, 0xc2, 0x00, 0xc2, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x97, 0x00, 0x97, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x64, 0x00, 0x64, 0x00, 0x49, 0x00, 0x49, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x12, 0x00, 0x12, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x79, 0xff, 0x79, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x61, 0xff, 0x61, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x59, 0xff, 0x59, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x60, 0xff, 0x60, 0xff, 0x6a, 0xff, 0x6a, 0xff, 0x75, 0xff, 0x75, 0xff, 0x84, 0xff, 0x84, 0xff, 0x96, 0xff, 0x96, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xec, 0xff, 0xec, 0xff, 0x04, 0x00, 0x04, 0x00, 0x19, 0x00, 0x19, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x48, 0x00, 0x52, 0x00, 0x52, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x61, 0x00, 0x61, 0x00, 0x68, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x67, 0x00, 0x67, 0x00, 0x63, 0x00, 0x63, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x52, 0x00, 0x52, 0x00, 0x48, 0x00, 0x48, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x16, 0x00, 0x02, 0x00, 0x02, 0x00, 0xef, 0xff, 0xef, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xab, 0xff, 0xab, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x99, 0xff, 0x99, 0xff, 0x92, 0xff, 0x92, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x88, 0xff, 0x88, 0xff, 0x87, 0xff, 0x87, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x91, 0xff, 0x91, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x06, 0x00, 0x06, 0x00, 0x14, 0x00, 0x14, 0x00, 0x23, 0x00, 0x23, 0x00, 0x32, 0x00, 0x32, 0x00, 0x41, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x62, 0x00, 0x62, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x70, 0x00, 0x70, 0x00, 0x74, 0x00, 0x74, 0x00, 0x76, 0x00, 0x76, 0x00, 0x72, 0x00, 0x72, 0x00, 0x69, 0x00, 0x69, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x15, 0x00, 0x15, 0x00, 0x03, 0x00, 0x03, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x03, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x12, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x18, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x00, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x52, 0x00, 0x54, 0x00, 0x54, 0x00, 0x52, 0x00, 0x52, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x42, 0x00, 0x37, 0x00, 0x37, 0x00, 0x27, 0x00, 0x27, 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xce, 0xff, 0xce, 0xff, 0xda, 0xff, 0xda, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x00, 0x11, 0x00, 0x24, 0x00, 0x24, 0x00, 0x36, 0x00, 0x36, 0x00, 0x46, 0x00, 0x46, 0x00, 0x54, 0x00, 0x54, 0x00, 0x60, 0x00, 0x60, 0x00, 0x69, 0x00, 0x69, 0x00, 0x72, 0x00, 0x72, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, 0x00, 0x79, 0x00, 0x77, 0x00, 0x77, 0x00, 0x74, 0x00, 0x74, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x28, 0x00, 0x28, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xff, 0xec, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xad, 0xff, 0xad, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x91, 0xff, 0x91, 0xff, 0x85, 0xff, 0x85, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x76, 0xff, 0x76, 0xff, 0x75, 0xff, 0x75, 0xff, 0x79, 0xff, 0x79, 0xff, 0x80, 0xff, 0x80, 0xff, 0x88, 0xff, 0x88, 0xff, 0x92, 0xff, 0x92, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xad, 0xff, 0xad, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xef, 0xff, 0xef, 0xff, 0x03, 0x00, 0x03, 0x00, 0x14, 0x00, 0x14, 0x00, 0x25, 0x00, 0x25, 0x00, 0x32, 0x00, 0x32, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x47, 0x00, 0x50, 0x00, 0x50, 0x00, 0x56, 0x00, 0x56, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x64, 0x00, 0x64, 0x00, 0x67, 0x00, 0x67, 0x00, 0x65, 0x00, 0x65, 0x00, 0x61, 0x00, 0x61, 0x00, 0x59, 0x00, 0x59, 0x00, 0x50, 0x00, 0x50, 0x00, 0x48, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x35, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x10, 0x00, 0x10, 0x00, 0x09, 0x00, 0x09, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xee, 0xff, 0xee, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xda, 0xff, 0xda, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x07, 0x00, 0x07, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x26, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, 0x00, 0x34, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x06, 0x00, 0x06, 0x00, 0xf8, 0xff, 0xf8, 0xff, 0xea, 0xff, 0xea, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0x02, 0x00, 0x02, 0x00, 0x14, 0x00, 0x14, 0x00, 0x24, 0x00, 0x24, 0x00, 0x31, 0x00, 0x31, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x46, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x51, 0x00, 0x55, 0x00, 0x55, 0x00, 0x57, 0x00, 0x57, 0x00, 0x54, 0x00, 0x54, 0x00, 0x50, 0x00, 0x50, 0x00, 0x48, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x22, 0x00, 0x22, 0x00, 0x14, 0x00, 0x14, 0x00, 0x04, 0x00, 0x04, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xac, 0xff, 0xac, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x91, 0xff, 0x91, 0xff, 0x86, 0xff, 0x86, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x79, 0xff, 0x79, 0xff, 0x79, 0xff, 0x79, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x84, 0xff, 0x84, 0xff, 0x90, 0xff, 0x90, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xde, 0xff, 0xde, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x21, 0x00, 0x34, 0x00, 0x34, 0x00, 0x46, 0x00, 0x46, 0x00, 0x59, 0x00, 0x59, 0x00, 0x67, 0x00, 0x67, 0x00, 0x73, 0x00, 0x73, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x85, 0x00, 0x85, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x73, 0x00, 0x73, 0x00, 0x65, 0x00, 0x65, 0x00, 0x54, 0x00, 0x54, 0x00, 0x45, 0x00, 0x45, 0x00, 0x36, 0x00, 0x36, 0x00, 0x26, 0x00, 0x26, 0x00, 0x13, 0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0xef, 0xff, 0xef, 0xff, 0xde, 0xff, 0xde, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xae, 0xff, 0xae, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x97, 0xff, 0x97, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x88, 0xff, 0x88, 0xff, 0x83, 0xff, 0x83, 0xff, 0x84, 0xff, 0x84, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x95, 0xff, 0x95, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0xad, 0xff, 0xad, 0xff, 0xba, 0xff, 0xba, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x09, 0x00, 0x09, 0x00, 0x18, 0x00, 0x18, 0x00, 0x26, 0x00, 0x26, 0x00, 0x31, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x42, 0x00, 0x42, 0x00, 0x46, 0x00, 0x46, 0x00, 0x47, 0x00, 0x47, 0x00, 0x47, 0x00, 0x47, 0x00, 0x49, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x48, 0x00, 0x48, 0x00, 0x46, 0x00, 0x46, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xee, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xce, 0xff, 0xce, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xca, 0xff, 0xca, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x11, 0x00, 0x16, 0x00, 0x16, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x21, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x17, 0x00, 0x11, 0x00, 0x11, 0x00, 0x09, 0x00, 0x09, 0x00, 0x03, 0x00, 0x03, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x05, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x12, 0x00, 0x13, 0x00, 0x13, 0x00, 0x14, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x14, 0x00, 0x14, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xed, 0xff, 0xed, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x11, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x20, 0x00, 0x20, 0x00, 0x27, 0x00, 0x27, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x33, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x31, 0x00, 0x31, 0x00, 0x28, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x12, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xda, 0xff, 0xda, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x08, 0x00, 0x08, 0x00, 0x19, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x86, 0x00, 0x86, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x92, 0x00, 0x94, 0x00, 0x94, 0x00, 0x91, 0x00, 0x91, 0x00, 0x8a, 0x00, 0x8a, 0x00, 0x80, 0x00, 0x80, 0x00, 0x73, 0x00, 0x73, 0x00, 0x64, 0x00, 0x64, 0x00, 0x52, 0x00, 0x52, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x02, 0x00, 0x02, 0x00, 0xeb, 0xff, 0xeb, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xba, 0xff, 0xba, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0x95, 0xff, 0x95, 0xff, 0x87, 0xff, 0x87, 0xff, 0x79, 0xff, 0x79, 0xff, 0x6d, 0xff, 0x6d, 0xff, 0x68, 0xff, 0x68, 0xff, 0x69, 0xff, 0x69, 0xff, 0x6e, 0xff, 0x6e, 0xff, 0x75, 0xff, 0x75, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xea, 0xff, 0xea, 0xff, 0x02, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x35, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x66, 0x00, 0x66, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0x98, 0x00, 0x98, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x43, 0x00, 0x43, 0x00, 0x28, 0x00, 0x28, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x60, 0xff, 0x60, 0xff, 0x5a, 0xff, 0x5a, 0xff, 0x57, 0xff, 0x57, 0xff, 0x59, 0xff, 0x59, 0xff, 0x62, 0xff, 0x62, 0xff, 0x71, 0xff, 0x71, 0xff, 0x83, 0xff, 0x83, 0xff, 0x95, 0xff, 0x95, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x27, 0x00, 0x27, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x55, 0x00, 0x55, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x88, 0x00, 0x88, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x52, 0x00, 0x52, 0x00, 0x35, 0x00, 0x35, 0x00, 0x19, 0x00, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x6b, 0xff, 0x6b, 0xff, 0x5d, 0xff, 0x5d, 0xff, 0x50, 0xff, 0x50, 0xff, 0x48, 0xff, 0x48, 0xff, 0x49, 0xff, 0x49, 0xff, 0x4f, 0xff, 0x4f, 0xff, 0x5b, 0xff, 0x5b, 0xff, 0x69, 0xff, 0x69, 0xff, 0x78, 0xff, 0x78, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x1d, 0x00, 0x1d, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x58, 0x00, 0x58, 0x00, 0x72, 0x00, 0x72, 0x00, 0x88, 0x00, 0x88, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb6, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb8, 0x00, 0xb5, 0x00, 0xb5, 0x00, 0xae, 0x00, 0xae, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x67, 0x00, 0x67, 0x00, 0x51, 0x00, 0x51, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x26, 0x00, 0x26, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xf1, 0xff, 0xf1, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xba, 0xff, 0xba, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x77, 0xff, 0x77, 0xff, 0x68, 0xff, 0x68, 0xff, 0x5c, 0xff, 0x5c, 0xff, 0x52, 0xff, 0x52, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x48, 0xff, 0x48, 0xff, 0x4b, 0xff, 0x4b, 0xff, 0x51, 0xff, 0x51, 0xff, 0x5c, 0xff, 0x5c, 0xff, 0x69, 0xff, 0x69, 0xff, 0x79, 0xff, 0x79, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xba, 0xff, 0xba, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0x0e, 0x00, 0x0e, 0x00, 0x28, 0x00, 0x28, 0x00, 0x41, 0x00, 0x41, 0x00, 0x59, 0x00, 0x59, 0x00, 0x71, 0x00, 0x71, 0x00, 0x85, 0x00, 0x85, 0x00, 0x95, 0x00, 0x95, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xac, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x98, 0x00, 0x88, 0x00, 0x88, 0x00, 0x77, 0x00, 0x77, 0x00, 0x65, 0x00, 0x65, 0x00, 0x52, 0x00, 0x52, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x23, 0x00, 0x23, 0x00, 0x09, 0x00, 0x09, 0x00, 0xee, 0xff, 0xee, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x91, 0xff, 0x91, 0xff, 0x89, 0xff, 0x89, 0xff, 0x87, 0xff, 0x87, 0xff, 0x86, 0xff, 0x86, 0xff, 0x84, 0xff, 0x84, 0xff, 0x83, 0xff, 0x83, 0xff, 0x86, 0xff, 0x86, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x98, 0xff, 0x98, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xed, 0xff, 0xed, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x29, 0x00, 0x29, 0x00, 0x33, 0x00, 0x33, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x33, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x24, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x16, 0x00, 0x16, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x07, 0x00, 0x07, 0x00, 0x10, 0x00, 0x10, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x24, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x37, 0x00, 0x35, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x05, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x03, 0x00, 0x03, 0x00, 0x11, 0x00, 0x11, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x28, 0x00, 0x28, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x43, 0x00, 0x43, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x53, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x54, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x43, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xec, 0xff, 0xec, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x0d, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x31, 0x00, 0x31, 0x00, 0x41, 0x00, 0x41, 0x00, 0x51, 0x00, 0x51, 0x00, 0x60, 0x00, 0x60, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x8c, 0x00, 0x88, 0x00, 0x88, 0x00, 0x80, 0x00, 0x80, 0x00, 0x75, 0x00, 0x75, 0x00, 0x65, 0x00, 0x65, 0x00, 0x52, 0x00, 0x52, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x21, 0x00, 0x21, 0x00, 0x07, 0x00, 0x07, 0x00, 0xed, 0xff, 0xed, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x70, 0xff, 0x70, 0xff, 0x68, 0xff, 0x68, 0xff, 0x64, 0xff, 0x64, 0xff, 0x62, 0xff, 0x62, 0xff, 0x65, 0xff, 0x65, 0xff, 0x6c, 0xff, 0x6c, 0xff, 0x79, 0xff, 0x79, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x9c, 0xff, 0x9c, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xef, 0xff, 0xef, 0xff, 0x07, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x35, 0x00, 0x35, 0x00, 0x49, 0x00, 0x49, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x70, 0x00, 0x70, 0x00, 0x81, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x8e, 0x00, 0x96, 0x00, 0x96, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x98, 0x00, 0x92, 0x00, 0x92, 0x00, 0x89, 0x00, 0x89, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x02, 0x00, 0x02, 0x00, 0xed, 0xff, 0xed, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0x90, 0xff, 0x90, 0xff, 0x83, 0xff, 0x83, 0xff, 0x7b, 0xff, 0x7b, 0xff, 0x76, 0xff, 0x76, 0xff, 0x76, 0xff, 0x76, 0xff, 0x77, 0xff, 0x77, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x99, 0xff, 0x99, 0xff, 0xab, 0xff, 0xab, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0x08, 0x00, 0x08, 0x00, 0x18, 0x00, 0x18, 0x00, 0x25, 0x00, 0x25, 0x00, 0x31, 0x00, 0x31, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x47, 0x00, 0x47, 0x00, 0x50, 0x00, 0x50, 0x00, 0x55, 0x00, 0x55, 0x00, 0x57, 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x59, 0x00, 0x59, 0x00, 0x57, 0x00, 0x57, 0x00, 0x52, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x41, 0x00, 0x35, 0x00, 0x35, 0x00, 0x29, 0x00, 0x29, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xea, 0xff, 0xea, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x01, 0x00, 0x01, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x17, 0x00, 0x17, 0x00, 0x23, 0x00, 0x23, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x45, 0x00, 0x45, 0x00, 0x48, 0x00, 0x48, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x48, 0x00, 0x48, 0x00, 0x43, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x39, 0x00, 0x36, 0x00, 0x36, 0x00, 0x32, 0x00, 0x32, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x17, 0x00, 0x17, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x04, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xed, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xba, 0xff, 0xba, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x93, 0xff, 0x93, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x91, 0xff, 0x91, 0xff, 0x90, 0xff, 0x90, 0xff, 0x90, 0xff, 0x90, 0xff, 0x91, 0xff, 0x91, 0xff, 0x96, 0xff, 0x96, 0xff, 0xa0, 0xff, 0xa0, 0xff, 0xae, 0xff, 0xae, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xca, 0xff, 0xca, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xea, 0xff, 0xea, 0xff, 0x01, 0x00, 0x01, 0x00, 0x18, 0x00, 0x18, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x66, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x73, 0x00, 0x76, 0x00, 0x76, 0x00, 0x75, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x62, 0x00, 0x62, 0x00, 0x58, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xee, 0xff, 0xee, 0xff, 0xde, 0xff, 0xde, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x91, 0xff, 0x91, 0xff, 0x8d, 0xff, 0x8d, 0xff, 0x8c, 0xff, 0x8c, 0xff, 0x8f, 0xff, 0x8f, 0xff, 0x93, 0xff, 0x93, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0x03, 0x00, 0x03, 0x00, 0x13, 0x00, 0x13, 0x00, 0x22, 0x00, 0x22, 0x00, 0x31, 0x00, 0x31, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x45, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x46, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xee, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x0a, 0x00, 0x0a, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x64, 0x00, 0x64, 0x00, 0x69, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x68, 0x00, 0x68, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x47, 0x00, 0x47, 0x00, 0x34, 0x00, 0x34, 0x00, 0x24, 0x00, 0x24, 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0xed, 0xff, 0xed, 0xff, 0xda, 0xff, 0xda, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xba, 0xff, 0xba, 0xff, 0xae, 0xff, 0xae, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x95, 0xff, 0x95, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x89, 0xff, 0x89, 0xff, 0x89, 0xff, 0x89, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x8e, 0xff, 0x8e, 0xff, 0x93, 0xff, 0x93, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xca, 0xff, 0xca, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x13, 0x00, 0x13, 0x00, 0x26, 0x00, 0x26, 0x00, 0x37, 0x00, 0x37, 0x00, 0x47, 0x00, 0x47, 0x00, 0x58, 0x00, 0x58, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x77, 0x00, 0x77, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x80, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x75, 0x00, 0x71, 0x00, 0x71, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x32, 0x00, 0x25, 0x00, 0x25, 0x00, 0x16, 0x00, 0x16, 0x00, 0x07, 0x00, 0x07, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x99, 0xff, 0x99, 0xff, 0x99, 0xff, 0x99, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x05, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x37, 0x00, 0x37, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x37, 0x00, 0x37, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x35, 0x00, 0x35, 0x00, 0x30, 0x00, 0x30, 0x00, 0x27, 0x00, 0x27, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x16, 0x00, 0x16, 0x00, 0x13, 0x00, 0x13, 0x00, 0x12, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x09, 0x00, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xde, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xda, 0xff, 0xda, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xda, 0xff, 0xda, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x05, 0x00, 0x05, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x34, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x39, 0x00, 0x39, 0x00, 0x33, 0x00, 0x33, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x26, 0x00, 0x26, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x15, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x09, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xee, 0xff, 0xee, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x23, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x35, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x48, 0x00, 0x48, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x48, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x33, 0x00, 0x26, 0x00, 0x26, 0x00, 0x18, 0x00, 0x18, 0x00, 0x06, 0x00, 0x06, 0x00, 0xf4, 0xff, 0xf4, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xaa, 0xff, 0xaa, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x15, 0x00, 0x22, 0x00, 0x22, 0x00, 0x30, 0x00, 0x30, 0x00, 0x40, 0x00, 0x40, 0x00, 0x51, 0x00, 0x51, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x66, 0x00, 0x66, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x67, 0x00, 0x67, 0x00, 0x60, 0x00, 0x60, 0x00, 0x59, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x44, 0x00, 0x44, 0x00, 0x39, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x14, 0x00, 0x09, 0x00, 0x09, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xed, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0x97, 0xff, 0x97, 0xff, 0x85, 0xff, 0x85, 0xff, 0x74, 0xff, 0x74, 0xff, 0x69, 0xff, 0x69, 0xff, 0x63, 0xff, 0x63, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x5f, 0xff, 0x62, 0xff, 0x62, 0xff, 0x69, 0xff, 0x69, 0xff, 0x73, 0xff, 0x73, 0xff, 0x81, 0xff, 0x81, 0xff, 0x93, 0xff, 0x93, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xee, 0xff, 0xee, 0xff, 0x07, 0x00, 0x07, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x42, 0x00, 0x42, 0x00, 0x55, 0x00, 0x55, 0x00, 0x67, 0x00, 0x67, 0x00, 0x76, 0x00, 0x76, 0x00, 0x84, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x8d, 0x00, 0x95, 0x00, 0x95, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x9f, 0x00, 0x9f, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x96, 0x00, 0x88, 0x00, 0x88, 0x00, 0x75, 0x00, 0x75, 0x00, 0x61, 0x00, 0x61, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x25, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0x97, 0xff, 0x97, 0xff, 0x89, 0xff, 0x89, 0xff, 0x80, 0xff, 0x80, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x79, 0xff, 0x79, 0xff, 0x7a, 0xff, 0x7a, 0xff, 0x7d, 0xff, 0x7d, 0xff, 0x82, 0xff, 0x82, 0xff, 0x89, 0xff, 0x89, 0xff, 0x91, 0xff, 0x91, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0xac, 0xff, 0xac, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x0c, 0x00, 0x0c, 0x00, 0x20, 0x00, 0x20, 0x00, 0x31, 0x00, 0x31, 0x00, 0x40, 0x00, 0x40, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x60, 0x00, 0x60, 0x00, 0x65, 0x00, 0x65, 0x00, 0x67, 0x00, 0x67, 0x00, 0x66, 0x00, 0x66, 0x00, 0x62, 0x00, 0x62, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x54, 0x00, 0x54, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x24, 0x00, 0x24, 0x00, 0x16, 0x00, 0x16, 0x00, 0x06, 0x00, 0x06, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xac, 0xff, 0xac, 0xff, 0xae, 0xff, 0xae, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xda, 0xff, 0xda, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x02, 0x00, 0x02, 0x00, 0x10, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x35, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x51, 0x00, 0x51, 0x00, 0x56, 0x00, 0x56, 0x00, 0x58, 0x00, 0x58, 0x00, 0x55, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x10, 0x00, 0x03, 0x00, 0x03, 0x00, 0xf5, 0xff, 0xf5, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xed, 0xff, 0xed, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x08, 0x00, 0x08, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x20, 0x00, 0x20, 0x00, 0x25, 0x00, 0x25, 0x00, 0x29, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x26, 0x00, 0x26, 0x00, 0x20, 0x00, 0x20, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x05, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x03, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x21, 0x00, 0x26, 0x00, 0x26, 0x00, 0x29, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x29, 0x00, 0x29, 0x00, 0x27, 0x00, 0x27, 0x00, 0x24, 0x00, 0x24, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xed, 0xff, 0xed, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xda, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xed, 0xff, 0xed, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x27, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x22, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x05, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x23, 0x00, 0x28, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x31, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x33, 0x00, 0x33, 0x00, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x27, 0x00, 0x27, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xec, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xca, 0xff, 0xca, 0xff, 0xca, 0xff, 0xca, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xee, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x03, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x14, 0x00, 0x14, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x21, 0x00, 0x21, 0x00, 0x24, 0x00, 0x24, 0x00, 0x26, 0x00, 0x26, 0x00, 0x29, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x28, 0x00, 0x26, 0x00, 0x26, 0x00, 0x26, 0x00, 0x26, 0x00, 0x25, 0x00, 0x25, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfa, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xee, 0xff, 0xee, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xee, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x08, 0x00, 0x08, 0x00, 0x17, 0x00, 0x17, 0x00, 0x28, 0x00, 0x28, 0x00, 0x39, 0x00, 0x39, 0x00, 0x49, 0x00, 0x49, 0x00, 0x57, 0x00, 0x57, 0x00, 0x62, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x75, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x78, 0x00, 0x71, 0x00, 0x71, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x60, 0x00, 0x60, 0x00, 0x55, 0x00, 0x55, 0x00, 0x49, 0x00, 0x49, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xed, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xa8, 0xff, 0xa8, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0x99, 0xff, 0x99, 0xff, 0x98, 0xff, 0x98, 0xff, 0x9a, 0xff, 0x9a, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x04, 0x00, 0x04, 0x00, 0x14, 0x00, 0x14, 0x00, 0x24, 0x00, 0x24, 0x00, 0x32, 0x00, 0x32, 0x00, 0x40, 0x00, 0x40, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x62, 0x00, 0x62, 0x00, 0x69, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x65, 0x00, 0x65, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x43, 0x00, 0x43, 0x00, 0x38, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xb4, 0xff, 0xb4, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xb2, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x09, 0x00, 0x05, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfc, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x11, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xed, 0xff, 0xed, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xca, 0xff, 0xca, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x06, 0x00, 0x06, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x54, 0x00, 0x54, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x64, 0x00, 0x67, 0x00, 0x67, 0x00, 0x68, 0x00, 0x68, 0x00, 0x65, 0x00, 0x65, 0x00, 0x61, 0x00, 0x61, 0x00, 0x5a, 0x00, 0x5a, 0x00, 0x54, 0x00, 0x54, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x45, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xb9, 0xff, 0xb9, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xa2, 0xff, 0xa2, 0xff, 0xa3, 0xff, 0xa3, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xac, 0xff, 0xac, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0x06, 0x00, 0x06, 0x00, 0x12, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x28, 0x00, 0x28, 0x00, 0x32, 0x00, 0x32, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x42, 0x00, 0x42, 0x00, 0x49, 0x00, 0x49, 0x00, 0x50, 0x00, 0x50, 0x00, 0x58, 0x00, 0x58, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x58, 0x00, 0x58, 0x00, 0x55, 0x00, 0x55, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x45, 0x00, 0x39, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xec, 0xff, 0xec, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xba, 0xff, 0xba, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xa7, 0xff, 0xa7, 0xff, 0xa1, 0xff, 0xa1, 0xff, 0x9c, 0xff, 0x9c, 0xff, 0x98, 0xff, 0x98, 0xff, 0x93, 0xff, 0x93, 0xff, 0x92, 0xff, 0x92, 0xff, 0x97, 0xff, 0x97, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x06, 0x00, 0x06, 0x00, 0x17, 0x00, 0x17, 0x00, 0x27, 0x00, 0x27, 0x00, 0x39, 0x00, 0x39, 0x00, 0x48, 0x00, 0x48, 0x00, 0x54, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x64, 0x00, 0x64, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x71, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x69, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x50, 0x00, 0x41, 0x00, 0x41, 0x00, 0x32, 0x00, 0x32, 0x00, 0x21, 0x00, 0x21, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xb8, 0xff, 0xb8, 0xff, 0xab, 0xff, 0xab, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x91, 0xff, 0x91, 0xff, 0x88, 0xff, 0x88, 0xff, 0x83, 0xff, 0x83, 0xff, 0x82, 0xff, 0x82, 0xff, 0x86, 0xff, 0x86, 0xff, 0x8b, 0xff, 0x8b, 0xff, 0x92, 0xff, 0x92, 0xff, 0x9f, 0xff, 0x9f, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x08, 0x00, 0x08, 0x00, 0x15, 0x00, 0x15, 0x00, 0x21, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x37, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x48, 0x00, 0x48, 0x00, 0x50, 0x00, 0x50, 0x00, 0x56, 0x00, 0x56, 0x00, 0x58, 0x00, 0x58, 0x00, 0x57, 0x00, 0x57, 0x00, 0x55, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x43, 0x00, 0x43, 0x00, 0x34, 0x00, 0x34, 0x00, 0x24, 0x00, 0x24, 0x00, 0x15, 0x00, 0x15, 0x00, 0x04, 0x00, 0x04, 0x00, 0xf2, 0xff, 0xf2, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xbc, 0xff, 0xbc, 0xff, 0xb3, 0xff, 0xb3, 0xff, 0xab, 0xff, 0xab, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0x98, 0xff, 0x98, 0xff, 0x95, 0xff, 0x95, 0xff, 0x96, 0xff, 0x96, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xb1, 0xff, 0xb1, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0x09, 0x00, 0x09, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x40, 0x00, 0x40, 0x00, 0x50, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x64, 0x00, 0x69, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x69, 0x00, 0x64, 0x00, 0x64, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x54, 0x00, 0x54, 0x00, 0x49, 0x00, 0x49, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x31, 0x00, 0x31, 0x00, 0x24, 0x00, 0x24, 0x00, 0x17, 0x00, 0x17, 0x00, 0x08, 0x00, 0x08, 0x00, 0xf9, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xec, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xca, 0xff, 0xca, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xb7, 0xff, 0xb7, 0xff, 0xb0, 0xff, 0xb0, 0xff, 0xab, 0xff, 0xab, 0xff, 0xa5, 0xff, 0xa5, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xa6, 0xff, 0xa6, 0xff, 0xa9, 0xff, 0xa9, 0xff, 0xaf, 0xff, 0xaf, 0xff, 0xb6, 0xff, 0xb6, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xce, 0xff, 0xce, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x08, 0x00, 0x08, 0x00, 0x15, 0x00, 0x15, 0x00, 0x21, 0x00, 0x21, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x37, 0x00, 0x37, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x46, 0x00, 0x46, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x52, 0x00, 0x54, 0x00, 0x54, 0x00, 0x53, 0x00, 0x53, 0x00, 0x51, 0x00, 0x51, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x43, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x21, 0x00, 0x21, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xed, 0xff, 0xed, 0xff, 0xec, 0xff, 0xec, 0xff, 0xee, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xef, 0xff, 0xec, 0xff, 0xec, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0x01, 0x00, 0x01, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x20, 0x00, 0x24, 0x00, 0x24, 0x00, 0x27, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x28, 0x00, 0x28, 0x00, 0x27, 0x00, 0x27, 0x00, 0x26, 0x00, 0x26, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x05, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xce, 0xff, 0xce, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xbe, 0xff, 0xbe, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xca, 0xff, 0xca, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x14, 0x00, 0x19, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x21, 0x00, 0x21, 0x00, 0x26, 0x00, 0x26, 0x00, 0x28, 0x00, 0x28, 0x00, 0x27, 0x00, 0x27, 0x00, 0x26, 0x00, 0x26, 0x00, 0x25, 0x00, 0x25, 0x00, 0x23, 0x00, 0x23, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x19, 0x00, 0x19, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xda, 0xff, 0xda, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0x10, 0x00, 0x10, 0x00, 0x16, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x26, 0x00, 0x26, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x35, 0x00, 0x37, 0x00, 0x37, 0x00, 0x36, 0x00, 0x36, 0x00, 0x31, 0x00, 0x31, 0x00, 0x29, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x17, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xd6, 0xff, 0xd6, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xed, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0x02, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x27, 0x00, 0x27, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x31, 0x00, 0x32, 0x00, 0x32, 0x00, 0x33, 0x00, 0x33, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x27, 0x00, 0x27, 0x00, 0x22, 0x00, 0x22, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x17, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x04, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xee, 0xff, 0xee, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd8, 0xff, 0xd8, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc2, 0xff, 0xc2, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xc5, 0xff, 0xc5, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0x03, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x19, 0x00, 0x22, 0x00, 0x22, 0x00, 0x29, 0x00, 0x29, 0x00, 0x30, 0x00, 0x30, 0x00, 0x35, 0x00, 0x35, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x41, 0x00, 0x41, 0x00, 0x43, 0x00, 0x43, 0x00, 0x45, 0x00, 0x45, 0x00, 0x45, 0x00, 0x45, 0x00, 0x44, 0x00, 0x44, 0x00, 0x43, 0x00, 0x43, 0x00, 0x43, 0x00, 0x43, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x34, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x23, 0x00, 0x19, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xed, 0xff, 0xde, 0xff, 0xde, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc6, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xca, 0xff, 0xca, 0xff, 0xce, 0xff, 0xce, 0xff, 0xd3, 0xff, 0xd3, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xea, 0xff, 0xea, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x02, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x21, 0x00, 0x24, 0x00, 0x24, 0x00, 0x27, 0x00, 0x27, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x28, 0x00, 0x23, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x17, 0x00, 0x12, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xec, 0xff, 0xec, 0xff, 0xee, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x09, 0x00, 0x10, 0x00, 0x10, 0x00, 0x15, 0x00, 0x15, 0x00, 0x18, 0x00, 0x18, 0x00, 0x19, 0x00, 0x19, 0x00, 0x18, 0x00, 0x18, 0x00, 0x17, 0x00, 0x17, 0x00, 0x16, 0x00, 0x16, 0x00, 0x14, 0x00, 0x14, 0x00, 0x13, 0x00, 0x13, 0x00, 0x13, 0x00, 0x13, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x00, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xef, 0xff, 0xef, 0xff, 0xed, 0xff, 0xed, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xde, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe3, 0xff, 0xe3, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xea, 0xff, 0xea, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x00, 0x03, 0x00, 0xfb, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xc8, 0xff, 0xc8, 0xff, 0xca, 0xff, 0xca, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xd9, 0xff, 0xd9, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x01, 0x00, 0x01, 0x00, 0x09, 0x00, 0x09, 0x00, 0x14, 0x00, 0x14, 0x00, 0x23, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x25, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x13, 0x00, 0x13, 0x00, 0x08, 0x00, 0x08, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xef, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xd5, 0xff, 0xd5, 0xff, 0xce, 0xff, 0xce, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xcc, 0xff, 0xcf, 0xff, 0xcf, 0xff, 0xd0, 0xff, 0xd0, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xd4, 0xff, 0xd4, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x07, 0x00, 0x07, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x14, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x16, 0x00, 0x16, 0x00, 0x11, 0x00, 0x11, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xed, 0xff, 0xed, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xea, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe5, 0xff, 0xe5, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xca, 0xff, 0xca, 0xff, 0xd1, 0xff, 0xd1, 0xff, 0xde, 0xff, 0xde, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x2d, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x47, 0x00, 0x47, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x55, 0x00, 0x55, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x58, 0x00, 0x58, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x45, 0x00, 0x41, 0x00, 0x41, 0x00, 0x42, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x42, 0x00, 0x49, 0x00, 0x49, 0x00, 0x42, 0x00, 0x42, 0x00, 0x39, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x33, 0x00, 0x28, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x08, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xea, 0xff, 0xea, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0x04, 0x00, 0x04, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x28, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x59, 0x00, 0x59, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x75, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x66, 0x00, 0x74, 0x00, 0x74, 0x00, 0x87, 0x00, 0x87, 0x00, 0x81, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x69, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x65, 0x00, 0x51, 0x00, 0x51, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x50, 0x00, 0x45, 0x00, 0x45, 0x00, 0x37, 0x00, 0x37, 0x00, 0x21, 0x00, 0x21, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x15, 0x00, 0xfd, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xee, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xec, 0xff, 0xec, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0x05, 0x00, 0x05, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0x0b, 0x00, 0x0b, 0x00, 0x24, 0x00, 0x24, 0x00, 0x25, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x57, 0x00, 0x39, 0x00, 0x39, 0x00, 0x35, 0x00, 0x35, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x4e, 0x00, 0x4e, 0x00, 0x84, 0x00, 0x84, 0x00, 0xde, 0x00, 0xde, 0x00, 0xab, 0x00, 0xab, 0x00, 0x89, 0xff, 0x89, 0xff, 0x52, 0xfd, 0x52, 0xfd, 0xba, 0xfa, 0xba, 0xfa, 0x11, 0xfa, 0x11, 0xfa, 0x79, 0xfc, 0x79, 0xfc, 0x96, 0xff, 0x96, 0xff, 0xee, 0x00, 0xee, 0x00, 0x69, 0x00, 0x69, 0x00, 0x63, 0xfe, 0x63, 0xfe, 0xa0, 0xfb, 0xa0, 0xfb, 0xdd, 0xf9, 0xdd, 0xf9, 0x58, 0xf9, 0x58, 0xf9, 0xec, 0xf8, 0xed, 0xf8, 0x22, 0xf9, 0x22, 0xf9, 0x2b, 0xfb, 0x2b, 0xfb, 0x4b, 0xfe, 0x4b, 0xfe, 0xaa, 0x00, 0xaa, 0x00, 0x0c, 0x01, 0x0c, 0x01, 0x5a, 0xff, 0x5a, 0xff, 0xcc, 0xfc, 0xcc, 0xfc, 0x43, 0xfb, 0x44, 0xfb, 0x0b, 0xfc, 0x0b, 0xfc, 0xb1, 0xfe, 0xb2, 0xfe, 0x15, 0x01, 0x15, 0x01, 0x81, 0x01, 0x81, 0x01, 0x2d, 0x00, 0x2d, 0x00, 0x02, 0xfe, 0x02, 0xfe, 0xdd, 0xfb, 0xdd, 0xfb, 0xed, 0xfa, 0xed, 0xfa, 0x80, 0xfb, 0x81, 0xfb, 0x7f, 0xfc, 0x7f, 0xfc, 0x1a, 0xfd, 0x1a, 0xfd, 0x75, 0xfd, 0x75, 0xfd, 0x8c, 0xfd, 0x8c, 0xfd, 0x22, 0xfd, 0x22, 0xfd, 0xa2, 0xfc, 0xa2, 0xfc, 0xf1, 0xfc, 0xf1, 0xfc, 0x38, 0xfe, 0x38, 0xfe, 0xcb, 0xff, 0xcb, 0xff, 0x06, 0x01, 0x07, 0x01, 0x92, 0x01, 0x92, 0x01, 0x93, 0x01, 0x93, 0x01, 0x11, 0x02, 0x11, 0x02, 0xc7, 0x03, 0xc7, 0x03, 0xdb, 0x05, 0xdb, 0x05, 0x16, 0x07, 0x16, 0x07, 0x51, 0x07, 0x51, 0x07, 0x18, 0x07, 0x18, 0x07, 0xfa, 0x06, 0xfa, 0x06, 0x08, 0x07, 0x08, 0x07, 0xf5, 0x06, 0xf5, 0x06, 0xd8, 0x06, 0xd8, 0x06, 0x09, 0x07, 0x09, 0x07, 0x4c, 0x07, 0x4c, 0x07, 0xff, 0x06, 0xff, 0x06, 0x8c, 0x05, 0x8b, 0x05, 0xfa, 0x02, 0xfa, 0x02, 0xa8, 0x00, 0xa8, 0x00, 0x29, 0x00, 0x28, 0x00, 0x52, 0x01, 0x51, 0x01, 0xa4, 0x02, 0xa3, 0x02, 0x03, 0x03, 0x02, 0x03, 0x4e, 0x02, 0x4d, 0x02, 0x10, 0x01, 0x10, 0x01, 0xe1, 0xff, 0xe1, 0xff, 0x2d, 0xff, 0x2d, 0xff, 0x64, 0xff, 0x64, 0xff, 0x9d, 0x00, 0x9d, 0x00, 0x6c, 0x02, 0x6c, 0x02, 0x44, 0x04, 0x43, 0x04, 0x7c, 0x05, 0x7c, 0x05, 0xb4, 0x05, 0xb3, 0x05, 0x75, 0x05, 0x74, 0x05, 0x84, 0x05, 0x83, 0x05, 0x16, 0x06, 0x16, 0x06, 0x35, 0x07, 0x35, 0x07, 0xcb, 0x08, 0xcb, 0x08, 0x6a, 0x0a, 0x6a, 0x0a, 0xaa, 0x0b, 0xa9, 0x0b, 0x4b, 0x0c, 0x4b, 0x0c, 0x50, 0x0c, 0x4f, 0x0c, 0x34, 0x0c, 0x34, 0x0c, 0x6c, 0x0c, 0x6b, 0x0c, 0xfc, 0x0c, 0xfc, 0x0c, 0x99, 0x0d, 0x99, 0x0d, 0x9b, 0x0d, 0x9a, 0x0d, 0x7c, 0x0c, 0x7b, 0x0c, 0x8e, 0x0a, 0x8e, 0x0a, 0x64, 0x08, 0x64, 0x08, 0x4f, 0x06, 0x4e, 0x06, 0xe7, 0x04, 0xe6, 0x04, 0x8f, 0x04, 0x8f, 0x04, 0x8b, 0x04, 0x8a, 0x04, 0xb7, 0x03, 0xb6, 0x03, 0xa6, 0x01, 0xa6, 0x01, 0xb9, 0xfe, 0xb9, 0xfe, 0xe5, 0xfb, 0xe5, 0xfb, 0x3f, 0xfa, 0x3e, 0xfa, 0x23, 0xfa, 0x23, 0xfa, 0x03, 0xfb, 0x02, 0xfb, 0xf5, 0xfb, 0xf4, 0xfb, 0x3b, 0xfc, 0x3a, 0xfc, 0x7b, 0xfb, 0x7a, 0xfb, 0xc9, 0xf9, 0xc8, 0xf9, 0xaf, 0xf7, 0xaf, 0xf7, 0x22, 0xf6, 0x21, 0xf6, 0xe7, 0xf5, 0xe6, 0xf5, 0xfc, 0xf6, 0xfb, 0xf6, 0x97, 0xf8, 0x97, 0xf8, 0xc5, 0xf9, 0xc5, 0xf9, 0xf9, 0xf9, 0xf8, 0xf9, 0x40, 0xf9, 0x40, 0xf9, 0x35, 0xf8, 0x35, 0xf8, 0x8b, 0xf7, 0x8b, 0xf7, 0x9b, 0xf7, 0x9b, 0xf7, 0x33, 0xf8, 0x33, 0xf8, 0xd7, 0xf8, 0xd7, 0xf8, 0xf0, 0xf8, 0xf1, 0xf8, 0x09, 0xf8, 0x0a, 0xf8, 0x77, 0xf6, 0x78, 0xf6, 0x48, 0xf5, 0x49, 0xf5, 0x5a, 0xf5, 0x5b, 0xf5, 0xb5, 0xf6, 0xb6, 0xf6, 0x89, 0xf8, 0x8a, 0xf8, 0xa0, 0xf9, 0xa1, 0xf9, 0x5a, 0xf9, 0x5b, 0xf9, 0x24, 0xf8, 0x25, 0xf8, 0xe7, 0xf6, 0xe8, 0xf6, 0x6f, 0xf6, 0x70, 0xf6, 0x1c, 0xf7, 0x1d, 0xf7, 0xa8, 0xf8, 0xa9, 0xf8, 0x5a, 0xfa, 0x5a, 0xfa, 0x8d, 0xfb, 0x8d, 0xfb, 0xeb, 0xfb, 0xeb, 0xfb, 0x7b, 0xfb, 0x7b, 0xfb, 0xb2, 0xfa, 0xb2, 0xfa, 0x2c, 0xfa, 0x2c, 0xfa, 0x48, 0xfa, 0x48, 0xfa, 0x1a, 0xfb, 0x19, 0xfb, 0x7e, 0xfc, 0x7d, 0xfc, 0x12, 0xfe, 0x11, 0xfe, 0x50, 0xff, 0x4f, 0xff, 0xe2, 0xff, 0xe1, 0xff, 0xec, 0xff, 0xea, 0xff, 0xea, 0xff, 0xe9, 0xff, 0x55, 0x00, 0x54, 0x00, 0x3a, 0x01, 0x39, 0x01, 0x2f, 0x02, 0x2d, 0x02, 0x9d, 0x02, 0x9b, 0x02, 0x4c, 0x02, 0x4d, 0x02, 0xaf, 0x01, 0xb6, 0x01, 0x7d, 0x01, 0x8b, 0x01, 0x0a, 0x02, 0x1e, 0x02, 0x2a, 0x03, 0x3f, 0x03, 0x6b, 0x04, 0x7d, 0x04, 0x3f, 0x05, 0x4b, 0x05, 0x34, 0x05, 0x3a, 0x05, 0x4e, 0x04, 0x4f, 0x04, 0x0d, 0x03, 0x0e, 0x03, 0xfe, 0x01, 0x05, 0x02, 0x7e, 0x01, 0x8e, 0x01, 0xb3, 0x01, 0xcb, 0x01, 0x63, 0x02, 0x7e, 0x02, 0x00, 0x03, 0x18, 0x03, 0x13, 0x03, 0x21, 0x03, 0x86, 0x02, 0x87, 0x02, 0x78, 0x01, 0x6f, 0x01, 0x22, 0x00, 0x13, 0x00, 0xeb, 0xfe, 0xdb, 0xfe, 0x3e, 0xfe, 0x32, 0xfe, 0x1c, 0xfe, 0x14, 0xfe, 0x26, 0xfe, 0x20, 0xfe, 0x08, 0xfe, 0x00, 0xfe, 0x9a, 0xfd, 0x90, 0xfd, 0xe8, 0xfc, 0xdb, 0xfc, 0x36, 0xfc, 0x29, 0xfc, 0xc0, 0xfb, 0xb7, 0xfb, 0x75, 0xfb, 0x74, 0xfb, 0x18, 0xfb, 0x1e, 0xfb, 0x8c, 0xfa, 0x97, 0xfa, 0xd2, 0xf9, 0xde, 0xf9, 0x07, 0xf9, 0x11, 0xf9, 0x76, 0xf8, 0x7d, 0xf8, 0x62, 0xf8, 0x66, 0xf8, 0xc7, 0xf8, 0xc9, 0xf8, 0x64, 0xf9, 0x65, 0xf9, 0xe0, 0xf9, 0xde, 0xf9, 0xed, 0xf9, 0xe9, 0xf9, 0x75, 0xf9, 0x6c, 0xf9, 0xaa, 0xf8, 0x9b, 0xf8, 0xfb, 0xf7, 0xe8, 0xf7, 0xd5, 0xf7, 0xbe, 0xf7, 0x56, 0xf8, 0x3a, 0xf8, 0x55, 0xf9, 0x35, 0xf9, 0x8a, 0xfa, 0x66, 0xfa, 0x92, 0xfb, 0x6b, 0xfb, 0x20, 0xfc, 0xf7, 0xfb, 0x40, 0xfc, 0x17, 0xfc, 0x47, 0xfc, 0x20, 0xfc, 0x6b, 0xfc, 0x48, 0xfc, 0xc4, 0xfc, 0xa6, 0xfc, 0x60, 0xfd, 0x48, 0xfd, 0x21, 0xfe, 0x12, 0xfe, 0xe4, 0xfe, 0xe0, 0xfe, 0xaa, 0xff, 0xb0, 0xff, 0x78, 0x00, 0x86, 0x00, 0x42, 0x01, 0x56, 0x01, 0x06, 0x02, 0x1f, 0x02, 0xc5, 0x02, 0xe1, 0x02, 0x66, 0x03, 0x87, 0x03, 0xd0, 0x03, 0xf6, 0x03, 0x03, 0x04, 0x2c, 0x04, 0x1d, 0x04, 0x49, 0x04, 0x56, 0x04, 0x86, 0x04, 0xdd, 0x04, 0x13, 0x05, 0xbd, 0x05, 0xf3, 0x05, 0xcd, 0x06, 0xfd, 0x06, 0xbc, 0x07, 0xe1, 0x07, 0x3f, 0x08, 0x59, 0x08, 0x57, 0x08, 0x6c, 0x08, 0x2f, 0x08, 0x47, 0x08, 0xff, 0x07, 0x1e, 0x08, 0x02, 0x08, 0x24, 0x08, 0x5a, 0x08, 0x78, 0x08, 0xf5, 0x08, 0x0a, 0x09, 0xa0, 0x09, 0xa9, 0x09, 0x29, 0x0a, 0x27, 0x0a, 0x69, 0x0a, 0x61, 0x0a, 0x4d, 0x0a, 0x48, 0x0a, 0xe5, 0x09, 0xeb, 0x09, 0x4f, 0x09, 0x61, 0x09, 0xa2, 0x08, 0xbd, 0x08, 0xf5, 0x07, 0x10, 0x08, 0x65, 0x07, 0x75, 0x07, 0x09, 0x07, 0x0a, 0x07, 0xda, 0x06, 0xd1, 0x06, 0xb4, 0x06, 0xac, 0x06, 0x6e, 0x06, 0x6d, 0x06, 0xf4, 0x05, 0xfd, 0x05, 0x43, 0x05, 0x54, 0x05, 0x67, 0x04, 0x7a, 0x04, 0x76, 0x03, 0x83, 0x03, 0x7e, 0x02, 0x81, 0x02, 0x99, 0x01, 0x8f, 0x01, 0xe5, 0x00, 0xd2, 0x00, 0x71, 0x00, 0x5e, 0x00, 0x2c, 0x00, 0x24, 0x00, 0xe8, 0xff, 0xf0, 0xff, 0x83, 0xff, 0x93, 0xff, 0xfd, 0xfe, 0x0a, 0xff, 0x5c, 0xfe, 0x5c, 0xfe, 0xad, 0xfd, 0x9c, 0xfd, 0xff, 0xfc, 0xe2, 0xfc, 0x5e, 0xfc, 0x3f, 0xfc, 0xd9, 0xfb, 0xbe, 0xfb, 0x91, 0xfb, 0x7b, 0xfb, 0x93, 0xfb, 0x7c, 0xfb, 0xc1, 0xfb, 0xa2, 0xfb, 0xf8, 0xfb, 0xcb, 0xfb, 0x0d, 0xfc, 0xd1, 0xfb, 0xe4, 0xfb, 0x9a, 0xfb, 0x93, 0xfb, 0x3e, 0xfb, 0x40, 0xfb, 0xe3, 0xfa, 0xf9, 0xfa, 0x98, 0xfa, 0xda, 0xfa, 0x76, 0xfa, 0xf9, 0xfa, 0x92, 0xfa, 0x4b, 0xfb, 0xe2, 0xfa, 0xc6, 0xfb, 0x5e, 0xfb, 0x55, 0xfc, 0xf3, 0xfb, 0xc9, 0xfc, 0x70, 0xfc, 0x01, 0xfd, 0xb0, 0xfc, 0x0d, 0xfd, 0xc1, 0xfc, 0x13, 0xfd, 0xc8, 0xfc, 0x33, 0xfd, 0xeb, 0xfc, 0x76, 0xfd, 0x36, 0xfd, 0xc5, 0xfd, 0x95, 0xfd, 0x1b, 0xfe, 0xfc, 0xfd, 0x8c, 0xfe, 0x7c, 0xfe, 0x23, 0xff, 0x1a, 0xff, 0xcd, 0xff, 0xc6, 0xff, 0x62, 0x00, 0x55, 0x00, 0xbb, 0x00, 0xa6, 0x00, 0xde, 0x00, 0xc0, 0x00, 0xfb, 0x00, 0xd8, 0x00, 0x35, 0x01, 0x13, 0x01, 0x90, 0x01, 0x6e, 0x01, 0xfe, 0x01, 0xd7, 0x01, 0x8b, 0x02, 0x58, 0x02, 0x46, 0x03, 0x02, 0x03, 0x21, 0x04, 0xcc, 0x03, 0xf1, 0x04, 0x90, 0x04, 0x7a, 0x05, 0x12, 0x05, 0xa2, 0x05, 0x35, 0x05, 0x9a, 0x05, 0x2a, 0x05, 0xac, 0x05, 0x3b, 0x05, 0xf3, 0x05, 0x84, 0x05, 0x5f, 0x06, 0xf9, 0x05, 0xd8, 0x06, 0x80, 0x06, 0x42, 0x07, 0xfd, 0x06, 0x97, 0x07, 0x62, 0x07, 0xd6, 0x07, 0xaf, 0x07, 0xe7, 0x07, 0xca, 0x07, 0xbb, 0x07, 0xa8, 0x07, 0x67, 0x07, 0x62, 0x07, 0x00, 0x07, 0x0f, 0x07, 0x93, 0x06, 0xc0, 0x06, 0x2c, 0x06, 0x7f, 0x06, 0xca, 0x05, 0x49, 0x06, 0x6d, 0x05, 0x17, 0x06, 0x1a, 0x05, 0xe6, 0x05, 0xbc, 0x04, 0x9c, 0x05, 0x35, 0x04, 0x1e, 0x05, 0x83, 0x03, 0x71, 0x04, 0xad, 0x02, 0xa8, 0x03, 0xc9, 0x01, 0xdb, 0x02, 0xf9, 0x00, 0x27, 0x02, 0x47, 0x00, 0x8b, 0x01, 0xa7, 0xff, 0xf6, 0x00, 0x1a, 0xff, 0x65, 0x00, 0x9f, 0xfe, 0xdd, 0xff, 0x21, 0xfe, 0x50, 0xff, 0x94, 0xfd, 0xb7, 0xfe, 0xf3, 0xfc, 0x11, 0xfe, 0x3b, 0xfc, 0x5c, 0xfd, 0x78, 0xfb, 0xa1, 0xfc, 0xc2, 0xfa, 0xf3, 0xfb, 0x2e, 0xfa, 0x62, 0xfb, 0xd0, 0xf9, 0xf9, 0xfa, 0xa7, 0xf9, 0xba, 0xfa, 0x9b, 0xf9, 0x95, 0xfa, 0x8b, 0xf9, 0x70, 0xfa, 0x5f, 0xf9, 0x38, 0xfa, 0x16, 0xf9, 0xe5, 0xf9, 0xc8, 0xf8, 0x88, 0xf9, 0x90, 0xf8, 0x39, 0xf9, 0x72, 0xf8, 0x01, 0xf9, 0x71, 0xf8, 0xeb, 0xf8, 0x98, 0xf8, 0x01, 0xf9, 0xeb, 0xf8, 0x43, 0xf9, 0x5b, 0xf9, 0x9b, 0xf9, 0xd1, 0xf9, 0xee, 0xf9, 0x3a, 0xfa, 0x2b, 0xfa, 0x8c, 0xfa, 0x4c, 0xfa, 0xcd, 0xfa, 0x5c, 0xfa, 0x11, 0xfb, 0x74, 0xfa, 0x5f, 0xfb, 0xa5, 0xfa, 0xc1, 0xfb, 0xf5, 0xfa, 0x3b, 0xfc, 0x65, 0xfb, 0xcf, 0xfc, 0xf1, 0xfb, 0x73, 0xfd, 0x8a, 0xfc, 0x19, 0xfe, 0x20, 0xfd, 0xae, 0xfe, 0xa6, 0xfd, 0x26, 0xff, 0x14, 0xfe, 0x84, 0xff, 0x71, 0xfe, 0xd3, 0xff, 0xc8, 0xfe, 0x28, 0x00, 0x2b, 0xff, 0x99, 0x00, 0xac, 0xff, 0x26, 0x01, 0x47, 0x00, 0xca, 0x01, 0xf2, 0x00, 0x76, 0x02, 0x9c, 0x01, 0x12, 0x03, 0x33, 0x02, 0x98, 0x03, 0xb3, 0x02, 0x02, 0x04, 0x1c, 0x03, 0x51, 0x04, 0x6b, 0x03, 0x8d, 0x04, 0xa6, 0x03, 0xc9, 0x04, 0xd8, 0x03, 0x18, 0x05, 0x10, 0x04, 0x83, 0x05, 0x5c, 0x04, 0xfe, 0x05, 0xb6, 0x04, 0x72, 0x06, 0x0f, 0x05, 0xc8, 0x06, 0x57, 0x05, 0xfa, 0x06, 0x84, 0x05, 0x0e, 0x07, 0x95, 0x05, 0x05, 0x07, 0x86, 0x05, 0xe8, 0x06, 0x5f, 0x05, 0xbe, 0x06, 0x2e, 0x05, 0x92, 0x06, 0xfd, 0x04, 0x6f, 0x06, 0xe1, 0x04, 0x5c, 0x06, 0xdd, 0x04, 0x46, 0x06, 0xe1, 0x04, 0x1a, 0x06, 0xd8, 0x04, 0xd1, 0x05, 0xb9, 0x04, 0x65, 0x05, 0x79, 0x04, 0xd1, 0x04, 0x15, 0x04, 0x26, 0x04, 0x9e, 0x03, 0x74, 0x03, 0x25, 0x03, 0xcb, 0x02, 0xb7, 0x02, 0x3c, 0x02, 0x5f, 0x02, 0xc0, 0x01, 0x16, 0x02, 0x44, 0x01, 0xc7, 0x01, 0xbd, 0x00, 0x6a, 0x01, 0x28, 0x00, 0xfe, 0x00, 0x84, 0xff, 0x7f, 0x00, 0xd7, 0xfe, 0xf0, 0xff, 0x26, 0xfe, 0x54, 0xff, 0x79, 0xfd, 0xb1, 0xfe, 0xe1, 0xfc, 0x17, 0xfe, 0x63, 0xfc, 0x8e, 0xfd, 0xf3, 0xfb, 0x0f, 0xfd, 0x87, 0xfb, 0x95, 0xfc, 0x1e, 0xfb, 0x21, 0xfc, 0xb8, 0xfa, 0xb2, 0xfb, 0x57, 0xfa, 0x46, 0xfb, 0xfa, 0xf9, 0xda, 0xfa, 0x9c, 0xf9, 0x68, 0xfa, 0x43, 0xf9, 0xf3, 0xf9, 0xfb, 0xf8, 0x8d, 0xf9, 0xd1, 0xf8, 0x47, 0xf9, 0xc6, 0xf8, 0x2c, 0xf9, 0xd5, 0xf8, 0x3b, 0xf9, 0xea, 0xf8, 0x60, 0xf9, 0xf5, 0xf8, 0x83, 0xf9, 0xf4, 0xf8, 0x9d, 0xf9, 0xef, 0xf8, 0xb0, 0xf9, 0xeb, 0xf8, 0xc1, 0xf9, 0xf2, 0xf8, 0xdb, 0xf9, 0x13, 0xf9, 0x0e, 0xfa, 0x50, 0xf9, 0x5d, 0xfa, 0xa3, 0xf9, 0xc5, 0xfa, 0x0c, 0xfa, 0x45, 0xfb, 0x81, 0xfa, 0xd0, 0xfb, 0xf8, 0xfa, 0x57, 0xfc, 0x6e, 0xfb, 0xd1, 0xfc, 0xe3, 0xfb, 0x40, 0xfd, 0x58, 0xfc, 0xaa, 0xfd, 0xd2, 0xfc, 0x16, 0xfe, 0x54, 0xfd, 0x88, 0xfe, 0xe0, 0xfd, 0xfe, 0xfe, 0x76, 0xfe, 0x76, 0xff, 0x14, 0xff, 0xf2, 0xff, 0xb5, 0xff, 0x70, 0x00, 0x52, 0x00, 0xed, 0x00, 0xe2, 0x00, 0x63, 0x01, 0x5e, 0x01, 0xc8, 0x01, 0xc6, 0x01, 0x1a, 0x02, 0x1c, 0x02, 0x5c, 0x02, 0x6d, 0x02, 0x96, 0x02, 0xc8, 0x02, 0xd5, 0x02, 0x33, 0x03, 0x21, 0x03, 0xa3, 0x03, 0x79, 0x03, 0x0c, 0x04, 0xd5, 0x03, 0x61, 0x04, 0x2b, 0x04, 0x95, 0x04, 0x6a, 0x04, 0xa4, 0x04, 0x89, 0x04, 0x9d, 0x04, 0x8f, 0x04, 0x93, 0x04, 0x8e, 0x04, 0x86, 0x04, 0x8a, 0x04, 0x77, 0x04, 0x84, 0x04, 0x6f, 0x04, 0x84, 0x04, 0x6c, 0x04, 0x86, 0x04, 0x67, 0x04, 0x85, 0x04, 0x5d, 0x04, 0x7c, 0x04, 0x40, 0x04, 0x63, 0x04, 0x08, 0x04, 0x32, 0x04, 0xbc, 0x03, 0xed, 0x03, 0x6b, 0x03, 0xa1, 0x03, 0x1f, 0x03, 0x56, 0x03, 0xdd, 0x02, 0x0f, 0x03, 0xa4, 0x02, 0xcc, 0x02, 0x6d, 0x02, 0x87, 0x02, 0x34, 0x02, 0x3d, 0x02, 0xef, 0x01, 0xe8, 0x01, 0x95, 0x01, 0x81, 0x01, 0x27, 0x01, 0x0c, 0x01, 0xaf, 0x00, 0x92, 0x00, 0x34, 0x00, 0x19, 0x00, 0xc1, 0xff, 0xa2, 0xff, 0x5f, 0xff, 0x35, 0xff, 0x08, 0xff, 0xca, 0xfe, 0xb4, 0xfe, 0x5e, 0xfe, 0x64, 0xfe, 0xf8, 0xfd, 0x18, 0xfe, 0x9a, 0xfd, 0xc8, 0xfd, 0x3b, 0xfd, 0x74, 0xfd, 0xd9, 0xfc, 0x1e, 0xfd, 0x76, 0xfc, 0xc3, 0xfc, 0x0e, 0xfc, 0x69, 0xfc, 0xa9, 0xfb, 0x1d, 0xfc, 0x50, 0xfb, 0xe7, 0xfb, 0x0a, 0xfb, 0xcc, 0xfb, 0xdc, 0xfa, 0xc9, 0xfb, 0xc5, 0xfa, 0xd2, 0xfb, 0xbd, 0xfa, 0xdd, 0xfb, 0xbb, 0xfa, 0xdd, 0xfb, 0xb2, 0xfa, 0xcd, 0xfb, 0x9b, 0xfa, 0xbc, 0xfb, 0x85, 0xfa, 0xb7, 0xfb, 0x80, 0xfa, 0xbe, 0xfb, 0x8c, 0xfa, 0xcf, 0xfb, 0xa4, 0xfa, 0xeb, 0xfb, 0xc7, 0xfa, 0x10, 0xfc, 0xee, 0xfa, 0x39, 0xfc, 0x14, 0xfb, 0x65, 0xfc, 0x42, 0xfb, 0x96, 0xfc, 0x80, 0xfb, 0xc0, 0xfc, 0xc5, 0xfb, 0xe8, 0xfc, 0x0e, 0xfc, 0x1a, 0xfd, 0x5f, 0xfc, 0x5f, 0xfd, 0xb8, 0xfc, 0xb1, 0xfd, 0x12, 0xfd, 0x0e, 0xfe, 0x6a, 0xfd, 0x79, 0xfe, 0xc9, 0xfd, 0xea, 0xfe, 0x2e, 0xfe, 0x5a, 0xff, 0x97, 0xfe, 0xcb, 0xff, 0x0d, 0xff, 0x39, 0x00, 0x8d, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x06, 0x01, 0x7d, 0x00, 0x75, 0x01, 0xec, 0x00, 0xee, 0x01, 0x59, 0x01, 0x71, 0x02, 0xc8, 0x01, 0xf7, 0x02, 0x3d, 0x02, 0x7b, 0x03, 0xb6, 0x02, 0xf3, 0x03, 0x27, 0x03, 0x56, 0x04, 0x85, 0x03, 0xa9, 0x04, 0xd2, 0x03, 0xf1, 0x04, 0x0c, 0x04, 0x2b, 0x05, 0x31, 0x04, 0x5f, 0x05, 0x49, 0x04, 0x9b, 0x05, 0x6c, 0x04, 0xdf, 0x05, 0xa0, 0x04, 0x1d, 0x06, 0xda, 0x04, 0x51, 0x06, 0x14, 0x05, 0x78, 0x06, 0x44, 0x05, 0x88, 0x06, 0x5d, 0x05, 0x85, 0x06, 0x62, 0x05, 0x76, 0x06, 0x5f, 0x05, 0x5c, 0x06, 0x58, 0x05, 0x39, 0x06, 0x4e, 0x05, 0x14, 0x06, 0x46, 0x05, 0xe8, 0x05, 0x3e, 0x05, 0xab, 0x05, 0x2c, 0x05, 0x63, 0x05, 0x14, 0x05, 0x19, 0x05, 0xfc, 0x04, 0xca, 0x04, 0xdd, 0x04, 0x75, 0x04, 0xb4, 0x04, 0x19, 0x04, 0x82, 0x04, 0xb2, 0x03, 0x46, 0x04, 0x3d, 0x03, 0xfd, 0x03, 0xbb, 0x02, 0xa9, 0x03, 0x3a, 0x02, 0x56, 0x03, 0xc2, 0x01, 0x0b, 0x03, 0x5d, 0x01, 0xcb, 0x02, 0x03, 0x01, 0x8a, 0x02, 0xaa, 0x00, 0x38, 0x02, 0x42, 0x00, 0xc9, 0x01, 0xbe, 0xff, 0x3f, 0x01, 0x26, 0xff, 0xac, 0x00, 0x90, 0xfe, 0x27, 0x00, 0x08, 0xfe, 0xb6, 0xff, 0x97, 0xfd, 0x58, 0xff, 0x44, 0xfd, 0x0e, 0xff, 0x02, 0xfd, 0xcc, 0xfe, 0xc0, 0xfc, 0x84, 0xfe, 0x73, 0xfc, 0x2c, 0xfe, 0x1c, 0xfc, 0xc8, 0xfd, 0xb9, 0xfb, 0x5d, 0xfd, 0x53, 0xfb, 0xfe, 0xfc, 0xfd, 0xfa, 0xc0, 0xfc, 0xbc, 0xfa, 0x9e, 0xfc, 0x92, 0xfa, 0x8d, 0xfc, 0x85, 0xfa, 0x86, 0xfc, 0x8f, 0xfa, 0x84, 0xfc, 0x97, 0xfa, 0x7c, 0xfc, 0x96, 0xfa, 0x72, 0xfc, 0x8e, 0xfa, 0x70, 0xfc, 0x88, 0xfa, 0x77, 0xfc, 0x8d, 0xfa, 0x86, 0xfc, 0xaa, 0xfa, 0xa3, 0xfc, 0xe0, 0xfa, 0xcb, 0xfc, 0x24, 0xfb, 0xf9, 0xfc, 0x6f, 0xfb, 0x2c, 0xfd, 0xb7, 0xfb, 0x61, 0xfd, 0xf8, 0xfb, 0x98, 0xfd, 0x33, 0xfc, 0xcd, 0xfd, 0x6c, 0xfc, 0xfb, 0xfd, 0xa9, 0xfc, 0x1c, 0xfe, 0xec, 0xfc, 0x31, 0xfe, 0x2f, 0xfd, 0x3c, 0xfe, 0x70, 0xfd, 0x46, 0xfe, 0xb4, 0xfd, 0x60, 0xfe, 0xff, 0xfd, 0x90, 0xfe, 0x56, 0xfe, 0xd5, 0xfe, 0xb0, 0xfe, 0x21, 0xff, 0x04, 0xff, 0x64, 0xff, 0x49, 0xff, 0x91, 0xff, 0x80, 0xff, 0xa7, 0xff, 0xb5, 0xff, 0xb5, 0xff, 0xf1, 0xff, 0xc8, 0xff, 0x38, 0x00, 0xf1, 0xff, 0x86, 0x00, 0x31, 0x00, 0xd1, 0x00, 0x7d, 0x00, 0x13, 0x01, 0xc0, 0x00, 0x4d, 0x01, 0xf0, 0x00, 0x7e, 0x01, 0x0a, 0x01, 0xa5, 0x01, 0x17, 0x01, 0xc7, 0x01, 0x28, 0x01, 0xe9, 0x01, 0x44, 0x01, 0x12, 0x02, 0x6a, 0x01, 0x41, 0x02, 0x96, 0x01, 0x76, 0x02, 0xc3, 0x01, 0xa1, 0x02, 0xea, 0x01, 0xbe, 0x02, 0x0c, 0x02, 0xcd, 0x02, 0x27, 0x02, 0xd6, 0x02, 0x3b, 0x02, 0xde, 0x02, 0x49, 0x02, 0xe7, 0x02, 0x52, 0x02, 0xef, 0x02, 0x58, 0x02, 0xef, 0x02, 0x50, 0x02, 0xe1, 0x02, 0x37, 0x02, 0xc4, 0x02, 0x11, 0x02, 0xa8, 0x02, 0xf2, 0x01, 0x93, 0x02, 0xe6, 0x01, 0x85, 0x02, 0xeb, 0x01, 0x79, 0x02, 0xf5, 0x01, 0x60, 0x02, 0xec, 0x01, 0x2a, 0x02, 0xc0, 0x01, 0xd5, 0x01, 0x72, 0x01, 0x6d, 0x01, 0x15, 0x01, 0xff, 0x00, 0xb8, 0x00, 0x98, 0x00, 0x65, 0x00, 0x46, 0x00, 0x28, 0x00, 0x0a, 0x00, 0xff, 0xff, 0xd3, 0xff, 0xd9, 0xff, 0x92, 0xff, 0xa9, 0xff, 0x3a, 0xff, 0x66, 0xff, 0xca, 0xfe, 0x10, 0xff, 0x50, 0xfe, 0xb6, 0xfe, 0xe3, 0xfd, 0x6d, 0xfe, 0x94, 0xfd, 0x3a, 0xfe, 0x5e, 0xfd, 0x0f, 0xfe, 0x3e, 0xfd, 0xe6, 0xfd, 0x29, 0xfd, 0xbb, 0xfd, 0x16, 0xfd, 0x8e, 0xfd, 0x02, 0xfd, 0x66, 0xfd, 0xea, 0xfc, 0x41, 0xfd, 0xd2, 0xfc, 0x1d, 0xfd, 0xbf, 0xfc, 0xf3, 0xfc, 0xb5, 0xfc, 0xc4, 0xfc, 0xb7, 0xfc, 0x94, 0xfc, 0xcf, 0xfc, 0x70, 0xfc, 0xf9, 0xfc, 0x5d, 0xfc, 0x30, 0xfd, 0x5c, 0xfc, 0x6a, 0xfd, 0x68, 0xfc, 0xa0, 0xfd, 0x77, 0xfc, 0xcf, 0xfd, 0x81, 0xfc, 0xfa, 0xfd, 0x80, 0xfc, 0x23, 0xfe, 0x73, 0xfc, 0x49, 0xfe, 0x5d, 0xfc, 0x6c, 0xfe, 0x4a, 0xfc, 0x91, 0xfe, 0x4b, 0xfc, 0xc2, 0xfe, 0x68, 0xfc, 0x06, 0xff, 0x9d, 0xfc, 0x5c, 0xff, 0xde, 0xfc, 0xba, 0xff, 0x1b, 0xfd, 0x0d, 0x00, 0x49, 0xfd, 0x54, 0x00, 0x74, 0xfd, 0x91, 0x00, 0xa9, 0xfd, 0xd0, 0x00, 0xf2, 0xfd, 0x19, 0x01, 0x50, 0xfe, 0x75, 0x01, 0xc1, 0xfe, 0xe4, 0x01, 0x3c, 0xff, 0x57, 0x02, 0xb1, 0xff, 0xc2, 0x02, 0x16, 0x00, 0x1b, 0x03, 0x69, 0x00, 0x5f, 0x03, 0xb1, 0x00, 0x95, 0x03, 0xfa, 0x00, 0xbf, 0x03, 0x4c, 0x01, 0xe5, 0x03, 0xa7, 0x01, 0x17, 0x04, 0x0b, 0x02, 0x57, 0x04, 0x6f, 0x02, 0x9b, 0x04, 0xc8, 0x02, 0xd8, 0x04, 0x13, 0x03, 0x00, 0x05, 0x4d, 0x03, 0x0e, 0x05, 0x78, 0x03, 0x0b, 0x05, 0x9e, 0x03, 0x09, 0x05, 0xcf, 0x03, 0x0d, 0x05, 0x0a, 0x04, 0x11, 0x05, 0x47, 0x04, 0x0c, 0x05, 0x78, 0x04, 0xf5, 0x04, 0x90, 0x04, 0xcc, 0x04, 0x90, 0x04, 0x99, 0x04, 0x80, 0x04, 0x67, 0x04, 0x71, 0x04, 0x3f, 0x04, 0x6f, 0x04, 0x20, 0x04, 0x78, 0x04, 0xfd, 0x03, 0x82, 0x04, 0xcb, 0x03, 0x7e, 0x04, 0x87, 0x03, 0x66, 0x04, 0x37, 0x03, 0x41, 0x04, 0xe8, 0x02, 0x19, 0x04, 0xa5, 0x02, 0xf5, 0x03, 0x69, 0x02, 0xd3, 0x03, 0x28, 0x02, 0xa6, 0x03, 0xe5, 0x01, 0x70, 0x03, 0xa4, 0x01, 0x3b, 0x03, 0x5a, 0x01, 0x01, 0x03, 0x05, 0x01, 0xc4, 0x02, 0xaa, 0x00, 0x87, 0x02, 0x4f, 0x00, 0x4c, 0x02, 0xfa, 0xff, 0x15, 0x02, 0xab, 0xff, 0xde, 0x01, 0x5a, 0xff, 0xa0, 0x01, 0xf9, 0xfe, 0x52, 0x01, 0x8d, 0xfe, 0xfa, 0x00, 0x27, 0xfe, 0xa6, 0x00, 0xcf, 0xfd, 0x61, 0x00, 0x89, 0xfd, 0x2b, 0x00, 0x4c, 0xfd, 0xfb, 0xff, 0x0b, 0xfd, 0xc4, 0xff, 0xc1, 0xfc, 0x83, 0xff, 0x79, 0xfc, 0x3f, 0xff, 0x3b, 0xfc, 0x00, 0xff, 0x0e, 0xfc, 0xcc, 0xfe, 0xf7, 0xfb, 0xa9, 0xfe, 0xe9, 0xfb, 0x8d, 0xfe, 0xd4, 0xfb, 0x68, 0xfe, 0xb3, 0xfb, 0x34, 0xfe, 0x8a, 0xfb, 0xf3, 0xfd, 0x68, 0xfb, 0xb4, 0xfd, 0x5f, 0xfb, 0x88, 0xfd, 0x75, 0xfb, 0x78, 0xfd, 0x9f, 0xfb, 0x78, 0xfd, 0xcf, 0xfb, 0x76, 0xfd, 0x01, 0xfc, 0x6c, 0xfd, 0x2c, 0xfc, 0x55, 0xfd, 0x50, 0xfc, 0x30, 0xfd, 0x75, 0xfc, 0x08, 0xfd, 0xa5, 0xfc, 0xe3, 0xfc, 0xe8, 0xfc, 0xcd, 0xfc, 0x41, 0xfd, 0xcc, 0xfc, 0xb0, 0xfd, 0xe7, 0xfc, 0x28, 0xfe, 0x16, 0xfd, 0x9b, 0xfe, 0x4a, 0xfd, 0xfd, 0xfe, 0x70, 0xfd, 0x4f, 0xff, 0x81, 0xfd, 0x97, 0xff, 0x88, 0xfd, 0xe6, 0xff, 0x97, 0xfd, 0x47, 0x00, 0xc0, 0xfd, 0xb8, 0x00, 0x0c, 0xfe, 0x2a, 0x01, 0x72, 0xfe, 0x85, 0x01, 0xd6, 0xfe, 0xbd, 0x01, 0x28, 0xff, 0xdb, 0x01, 0x6b, 0xff, 0xed, 0x01, 0xa7, 0xff, 0x00, 0x02, 0xe5, 0xff, 0x1d, 0x02, 0x2c, 0x00, 0x40, 0x02, 0x7d, 0x00, 0x61, 0x02, 0xd3, 0x00, 0x81, 0x02, 0x2e, 0x01, 0xa0, 0x02, 0x90, 0x01, 0xb7, 0x02, 0xec, 0x01, 0xc2, 0x02, 0x33, 0x02, 0xc9, 0x02, 0x67, 0x02, 0xd5, 0x02, 0x94, 0x02, 0xe7, 0x02, 0xbd, 0x02, 0xfc, 0x02, 0xe1, 0x02, 0x0f, 0x03, 0x01, 0x03, 0x1b, 0x03, 0x1d, 0x03, 0x21, 0x03, 0x33, 0x03, 0x1f, 0x03, 0x41, 0x03, 0x1c, 0x03, 0x4d, 0x03, 0x1b, 0x03, 0x5a, 0x03, 0x19, 0x03, 0x63, 0x03, 0x0f, 0x03, 0x69, 0x03, 0xf6, 0x02, 0x68, 0x03, 0xc7, 0x02, 0x56, 0x03, 0x84, 0x02, 0x31, 0x03, 0x36, 0x02, 0x01, 0x03, 0xec, 0x01, 0xd6, 0x02, 0xb3, 0x01, 0xbb, 0x02, 0x81, 0x01, 0xa9, 0x02, 0x48, 0x01, 0x93, 0x02, 0xff, 0x00, 0x6d, 0x02, 0xa5, 0x00, 0x33, 0x02, 0x3b, 0x00, 0xe7, 0x01, 0xcd, 0xff, 0x94, 0x01, 0x63, 0xff, 0x42, 0x01, 0xfe, 0xfe, 0xef, 0x00, 0x9e, 0xfe, 0x9b, 0x00, 0x47, 0xfe, 0x4a, 0x00, 0xf9, 0xfd, 0xfa, 0xff, 0xaf, 0xfd, 0xa8, 0xff, 0x6a, 0xfd, 0x54, 0xff, 0x2d, 0xfd, 0xfe, 0xfe, 0xf4, 0xfc, 0x9f, 0xfe, 0xbe, 0xfc, 0x3c, 0xfe, 0x92, 0xfc, 0xe0, 0xfd, 0x71, 0xfc, 0x8e, 0xfd, 0x53, 0xfc, 0x40, 0xfd, 0x3d, 0xfc, 0xf3, 0xfc, 0x36, 0xfc, 0xae, 0xfc, 0x40, 0xfc, 0x74, 0xfc, 0x53, 0xfc, 0x47, 0xfc, 0x68, 0xfc, 0x26, 0xfc, 0x7c, 0xfc, 0x08, 0xfc, 0x88, 0xfc, 0xe6, 0xfb, 0x8f, 0xfc, 0xc0, 0xfb, 0x9f, 0xfc, 0xa5, 0xfb, 0xbf, 0xfc, 0x9e, 0xfb, 0xe7, 0xfc, 0xa9, 0xfb, 0x14, 0xfd, 0xc2, 0xfb, 0x48, 0xfd, 0xee, 0xfb, 0x7a, 0xfd, 0x2a, 0xfc, 0xa3, 0xfd, 0x6e, 0xfc, 0xc3, 0xfd, 0xb2, 0xfc, 0xe3, 0xfd, 0xf4, 0xfc, 0x03, 0xfe, 0x31, 0xfd, 0x22, 0xfe, 0x6b, 0xfd, 0x47, 0xfe, 0xb1, 0xfd, 0x71, 0xfe, 0x0b, 0xfe, 0x95, 0xfe, 0x6b, 0xfe, 0xb8, 0xfe, 0xcb, 0xfe, 0xe8, 0xfe, 0x2d, 0xff, 0x27, 0xff, 0x8c, 0xff, 0x6d, 0xff, 0xde, 0xff, 0xb6, 0xff, 0x26, 0x00, 0xfe, 0xff, 0x64, 0x00, 0x3d, 0x00, 0x9a, 0x00, 0x77, 0x00, 0xcf, 0x00, 0xb7, 0x00, 0x0e, 0x01, 0xff, 0x00, 0x57, 0x01, 0x4c, 0x01, 0x9e, 0x01, 0x9e, 0x01, 0xde, 0x01, 0xf3, 0x01, 0x0e, 0x02, 0x3f, 0x02, 0x2f, 0x02, 0x7e, 0x02, 0x4b, 0x02, 0xa9, 0x02, 0x6b, 0x02, 0xc5, 0x02, 0x92, 0x02, 0xdb, 0x02, 0xc1, 0x02, 0xf6, 0x02, 0xf7, 0x02, 0x1a, 0x03, 0x31, 0x03, 0x44, 0x03, 0x70, 0x03, 0x68, 0x03, 0xad, 0x03, 0x7c, 0x03, 0xe1, 0x03, 0x80, 0x03, 0x03, 0x04, 0x73, 0x03, 0x11, 0x04, 0x54, 0x03, 0x0e, 0x04, 0x24, 0x03, 0x02, 0x04, 0xe8, 0x02, 0xf5, 0x03, 0xa4, 0x02, 0xe8, 0x03, 0x60, 0x02, 0xd8, 0x03, 0x20, 0x02, 0xbf, 0x03, 0xe1, 0x01, 0x94, 0x03, 0x9f, 0x01, 0x53, 0x03, 0x5a, 0x01, 0x04, 0x03, 0x17, 0x01, 0xb3, 0x02, 0xd7, 0x00, 0x6a, 0x02, 0x94, 0x00, 0x28, 0x02, 0x48, 0x00, 0xe4, 0x01, 0xf3, 0xff, 0x97, 0x01, 0x9b, 0xff, 0x3d, 0x01, 0x46, 0xff, 0xd5, 0x00, 0xfd, 0xfe, 0x64, 0x00, 0xc3, 0xfe, 0xf2, 0xff, 0x93, 0xfe, 0x85, 0xff, 0x62, 0xfe, 0x1d, 0xff, 0x2b, 0xfe, 0xbd, 0xfe, 0xf0, 0xfd, 0x63, 0xfe, 0xb6, 0xfd, 0x0e, 0xfe, 0x83, 0xfd, 0xb7, 0xfd, 0x61, 0xfd, 0x62, 0xfd, 0x4f, 0xfd, 0x12, 0xfd, 0x47, 0xfd, 0xc7, 0xfc, 0x44, 0xfd, 0x83, 0xfc, 0x44, 0xfd, 0x47, 0xfc, 0x41, 0xfd, 0x12, 0xfc, 0x3c, 0xfd, 0xe2, 0xfb, 0x3a, 0xfd, 0xb8, 0xfb, 0x39, 0xfd, 0x98, 0xfb, 0x35, 0xfd, 0x7e, 0xfb, 0x2e, 0xfd, 0x67, 0xfb, 0x2b, 0xfd, 0x56, 0xfb, 0x32, 0xfd, 0x50, 0xfb, 0x42, 0xfd, 0x53, 0xfb, 0x5f, 0xfd, 0x63, 0xfb, 0x87, 0xfd, 0x83, 0xfb, 0xb1, 0xfd, 0xaa, 0xfb, 0xd8, 0xfd, 0xcf, 0xfb, 0xfe, 0xfd, 0xf2, 0xfb, 0x24, 0xfe, 0x16, 0xfc, 0x47, 0xfe, 0x39, 0xfc, 0x6c, 0xfe, 0x5e, 0xfc, 0x9b, 0xfe, 0x8e, 0xfc, 0xd4, 0xfe, 0xc5, 0xfc, 0x0d, 0xff, 0xfa, 0xfc, 0x45, 0xff, 0x2c, 0xfd, 0x7f, 0xff, 0x61, 0xfd, 0xbc, 0xff, 0x9a, 0xfd, 0x01, 0x00, 0xdb, 0xfd, 0x4e, 0x00, 0x24, 0xfe, 0x98, 0x00, 0x6d, 0xfe, 0xd6, 0x00, 0xad, 0xfe, 0x08, 0x01, 0xe5, 0xfe, 0x31, 0x01, 0x1e, 0xff, 0x58, 0x01, 0x5d, 0xff, 0x89, 0x01, 0xa6, 0xff, 0xc7, 0x01, 0xf8, 0xff, 0x0e, 0x02, 0x4b, 0x00, 0x55, 0x02, 0x99, 0x00, 0x91, 0x02, 0xe0, 0x00, 0xbf, 0x02, 0x21, 0x01, 0xd9, 0x02, 0x5c, 0x01, 0xe7, 0x02, 0x8f, 0x01, 0xed, 0x02, 0xb8, 0x01, 0xf8, 0x02, 0xd9, 0x01, 0x0e, 0x03, 0xf9, 0x01, 0x2c, 0x03, 0x18, 0x02, 0x49, 0x03, 0x38, 0x02, 0x5a, 0x03, 0x56, 0x02, 0x56, 0x03, 0x69, 0x02, 0x3d, 0x03, 0x6f, 0x02, 0x1c, 0x03, 0x72, 0x02, 0x02, 0x03, 0x79, 0x02, 0xed, 0x02, 0x82, 0x02, 0xdb, 0x02, 0x86, 0x02, 0xcc, 0x02, 0x84, 0x02, 0xbb, 0x02, 0x7e, 0x02, 0xa5, 0x02, 0x73, 0x02, 0x89, 0x02, 0x67, 0x02, 0x66, 0x02, 0x58, 0x02, 0x3c, 0x02, 0x43, 0x02, 0x0d, 0x02, 0x27, 0x02, 0xda, 0x01, 0x05, 0x02, 0xa2, 0x01, 0xdf, 0x01, 0x64, 0x01, 0xb4, 0x01, 0x24, 0x01, 0x81, 0x01, 0xe3, 0x00, 0x44, 0x01, 0xa4, 0x00, 0x02, 0x01, 0x68, 0x00, 0xc2, 0x00, 0x2c, 0x00, 0x88, 0x00, 0xeb, 0xff, 0x50, 0x00, 0xa6, 0xff, 0x1a, 0x00, 0x5d, 0xff, 0xe3, 0xff, 0x0e, 0xff, 0xa3, 0xff, 0xba, 0xfe, 0x5d, 0xff, 0x64, 0xfe, 0x11, 0xff, 0x15, 0xfe, 0xcc, 0xfe, 0xd3, 0xfd, 0x98, 0xfe, 0x9d, 0xfd, 0x79, 0xfe, 0x6e, 0xfd, 0x69, 0xfe, 0x3f, 0xfd, 0x5c, 0xfe, 0x11, 0xfd, 0x48, 0xfe, 0xe5, 0xfc, 0x2a, 0xfe, 0xc5, 0xfc, 0x0a, 0xfe, 0xb8, 0xfc, 0xf5, 0xfd, 0xbe, 0xfc, 0xf0, 0xfd, 0xcb, 0xfc, 0xf9, 0xfd, 0xe1, 0xfc, 0x13, 0xfe, 0x01, 0xfd, 0x39, 0xfe, 0x29, 0xfd, 0x63, 0xfe, 0x5d, 0xfd, 0x89, 0xfe, 0x9f, 0xfd, 0xb0, 0xfe, 0xe7, 0xfd, 0xd5, 0xfe, 0x27, 0xfe, 0xf8, 0xfe, 0x5f, 0xfe, 0x1c, 0xff, 0x8e, 0xfe, 0x43, 0xff, 0xb9, 0xfe, 0x6c, 0xff, 0xe5, 0xfe, 0x97, 0xff, 0x1a, 0xff, 0xc6, 0xff, 0x5c, 0xff, 0xfc, 0xff, 0xa8, 0xff, 0x36, 0x00, 0xf6, 0xff, 0x72, 0x00, 0x3a, 0x00, 0xaf, 0x00, 0x70, 0x00, 0xed, 0x00, 0x99, 0x00, 0x28, 0x01, 0xbd, 0x00, 0x5e, 0x01, 0xe4, 0x00, 0x8c, 0x01, 0x14, 0x01, 0xb5, 0x01, 0x4f, 0x01, 0xe0, 0x01, 0x8e, 0x01, 0x12, 0x02, 0xcf, 0x01, 0x4c, 0x02, 0x09, 0x02, 0x85, 0x02, 0x32, 0x02, 0xb2, 0x02, 0x4f, 0x02, 0xd0, 0x02, 0x67, 0x02, 0xe5, 0x02, 0x83, 0x02, 0xf8, 0x02, 0xa5, 0x02, 0x0e, 0x03, 0xca, 0x02, 0x25, 0x03, 0xe8, 0x02, 0x34, 0x03, 0xfe, 0x02, 0x38, 0x03, 0x0e, 0x03, 0x37, 0x03, 0x19, 0x03, 0x34, 0x03, 0x1c, 0x03, 0x2e, 0x03, 0x14, 0x03, 0x21, 0x03, 0xfe, 0x02, 0x07, 0x03, 0xdd, 0x02, 0xe0, 0x02, 0xb6, 0x02, 0xb2, 0x02, 0x92, 0x02, 0x8a, 0x02, 0x71, 0x02, 0x67, 0x02, 0x56, 0x02, 0x46, 0x02, 0x44, 0x02, 0x27, 0x02, 0x32, 0x02, 0x09, 0x02, 0x16, 0x02, 0xed, 0x01, 0xee, 0x01, 0xd3, 0x01, 0xb7, 0x01, 0xb3, 0x01, 0x74, 0x01, 0x87, 0x01, 0x30, 0x01, 0x50, 0x01, 0xf1, 0x00, 0x18, 0x01, 0xbd, 0x00, 0xe9, 0x00, 0x90, 0x00, 0xc2, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x39, 0x00, 0x7f, 0x00, 0x08, 0x00, 0x59, 0x00, 0xd2, 0xff, 0x2c, 0x00, 0x99, 0xff, 0xf8, 0xff, 0x62, 0xff, 0xbf, 0xff, 0x30, 0xff, 0x83, 0xff, 0x0a, 0xff, 0x4b, 0xff, 0xf1, 0xfe, 0x1d, 0xff, 0xe1, 0xfe, 0xf8, 0xfe, 0xd4, 0xfe, 0xd9, 0xfe, 0xc5, 0xfe, 0xbc, 0xfe, 0xb3, 0xfe, 0x9e, 0xfe, 0x9a, 0xfe, 0x80, 0xfe, 0x7c, 0xfe, 0x60, 0xfe, 0x5d, 0xfe, 0x43, 0xfe, 0x3d, 0xfe, 0x28, 0xfe, 0x1c, 0xfe, 0x0c, 0xfe, 0xfb, 0xfd, 0xf2, 0xfd, 0xdb, 0xfd, 0xdb, 0xfd, 0xb7, 0xfd, 0xc4, 0xfd, 0x8e, 0xfd, 0xad, 0xfd, 0x69, 0xfd, 0x9f, 0xfd, 0x4e, 0xfd, 0x9f, 0xfd, 0x39, 0xfd, 0xaa, 0xfd, 0x23, 0xfd, 0xbf, 0xfd, 0x08, 0xfd, 0xd6, 0xfd, 0xed, 0xfc, 0xe9, 0xfd, 0xe0, 0xfc, 0xfc, 0xfd, 0xeb, 0xfc, 0x18, 0xfe, 0x09, 0xfd, 0x40, 0xfe, 0x2f, 0xfd, 0x74, 0xfe, 0x50, 0xfd, 0xa9, 0xfe, 0x6c, 0xfd, 0xdb, 0xfe, 0x91, 0xfd, 0x08, 0xff, 0xc3, 0xfd, 0x37, 0xff, 0x03, 0xfe, 0x6d, 0xff, 0x49, 0xfe, 0xad, 0xff, 0x8e, 0xfe, 0xef, 0xff, 0xcd, 0xfe, 0x29, 0x00, 0x05, 0xff, 0x58, 0x00, 0x40, 0xff, 0x81, 0x00, 0x7f, 0xff, 0xab, 0x00, 0xc3, 0xff, 0xd7, 0x00, 0x09, 0x00, 0x00, 0x01, 0x4b, 0x00, 0x19, 0x01, 0x7f, 0x00, 0x1c, 0x01, 0xa2, 0x00, 0x14, 0x01, 0xc0, 0x00, 0x10, 0x01, 0xdd, 0x00, 0x14, 0x01, 0xf9, 0x00, 0x17, 0x01, 0x17, 0x01, 0x15, 0x01, 0x3a, 0x01, 0x10, 0x01, 0x5e, 0x01, 0x06, 0x01, 0x7c, 0x01, 0x00, 0x01, 0x96, 0x01, 0x01, 0x01, 0xa7, 0x01, 0x05, 0x01, 0xaf, 0x01, 0x07, 0x01, 0xad, 0x01, 0x08, 0x01, 0xaa, 0x01, 0x08, 0x01, 0xa7, 0x01, 0x04, 0x01, 0x9e, 0x01, 0xf7, 0x00, 0x90, 0x01, 0xe4, 0x00, 0x7f, 0x01, 0xd1, 0x00, 0x6a, 0x01, 0xc1, 0x00, 0x52, 0x01, 0xb6, 0x00, 0x39, 0x01, 0xa9, 0x00, 0x1e, 0x01, 0x95, 0x00, 0xff, 0x00, 0x73, 0x00, 0xd9, 0x00, 0x44, 0x00, 0xb1, 0x00, 0x0f, 0x00, 0x89, 0x00, 0xd7, 0xff, 0x62, 0x00, 0xa1, 0xff, 0x41, 0x00, 0x70, 0xff, 0x27, 0x00, 0x46, 0xff, 0x0f, 0x00, 0x21, 0xff, 0xf7, 0xff, 0xff, 0xfe, 0xe0, 0xff, 0xde, 0xfe, 0xc6, 0xff, 0xb8, 0xfe, 0xa9, 0xff, 0x8e, 0xfe, 0x8e, 0xff, 0x6b, 0xfe, 0x75, 0xff, 0x51, 0xfe, 0x5d, 0xff, 0x3a, 0xfe, 0x40, 0xff, 0x1e, 0xfe, 0x22, 0xff, 0x01, 0xfe, 0x02, 0xff, 0xe5, 0xfd, 0xd9, 0xfe, 0xcd, 0xfd, 0xa9, 0xfe, 0xbf, 0xfd, 0x77, 0xfe, 0xb6, 0xfd, 0x47, 0xfe, 0xab, 0xfd, 0x1a, 0xfe, 0x96, 0xfd, 0xf5, 0xfd, 0x80, 0xfd, 0xdc, 0xfd, 0x70, 0xfd, 0xc9, 0xfd, 0x69, 0xfd, 0xc0, 0xfd, 0x73, 0xfd, 0xc5, 0xfd, 0x8f, 0xfd, 0xd2, 0xfd, 0xb9, 0xfd, 0xdd, 0xfd, 0xe1, 0xfd, 0xe0, 0xfd, 0xff, 0xfd, 0xda, 0xfd, 0x0f, 0xfe, 0xca, 0xfd, 0x13, 0xfe, 0xb7, 0xfd, 0x15, 0xfe, 0xa7, 0xfd, 0x22, 0xfe, 0xa4, 0xfd, 0x43, 0xfe, 0xae, 0xfd, 0x77, 0xfe, 0xbd, 0xfd, 0xb1, 0xfe, 0xcf, 0xfd, 0xef, 0xfe, 0xe9, 0xfd, 0x2e, 0xff, 0x06, 0xfe, 0x68, 0xff, 0x20, 0xfe, 0x96, 0xff, 0x3b, 0xfe, 0xc0, 0xff, 0x5d, 0xfe, 0xf0, 0xff, 0x83, 0xfe, 0x29, 0x00, 0xb2, 0xfe, 0x6d, 0x00, 0xec, 0xfe, 0xb6, 0x00, 0x2b, 0xff, 0xf9, 0x00, 0x66, 0xff, 0x2f, 0x01, 0x9e, 0xff, 0x5f, 0x01, 0xd6, 0xff, 0x8e, 0x01, 0x11, 0x00, 0xbf, 0x01, 0x4f, 0x00, 0xf1, 0x01, 0x8c, 0x00, 0x1d, 0x02, 0xc3, 0x00, 0x3d, 0x02, 0xf1, 0x00, 0x52, 0x02, 0x1b, 0x01, 0x63, 0x02, 0x4c, 0x01, 0x7a, 0x02, 0x8c, 0x01, 0x9d, 0x02, 0xd3, 0x01, 0xc4, 0x02, 0x11, 0x02, 0xe2, 0x02, 0x3e, 0x02, 0xef, 0x02, 0x58, 0x02, 0xe9, 0x02, 0x68, 0x02, 0xd8, 0x02, 0x7a, 0x02, 0xc3, 0x02, 0x96, 0x02, 0xb5, 0x02, 0xb1, 0x02, 0xa7, 0x02, 0xc3, 0x02, 0x96, 0x02, 0xd0, 0x02, 0x86, 0x02, 0xda, 0x02, 0x74, 0x02, 0xe4, 0x02, 0x5f, 0x02, 0xf4, 0x02, 0x4a, 0x02, 0x05, 0x03, 0x33, 0x02, 0x09, 0x03, 0x16, 0x02, 0xfc, 0x02, 0xf1, 0x01, 0xe4, 0x02, 0xcb, 0x01, 0xbf, 0x02, 0x9f, 0x01, 0x93, 0x02, 0x6f, 0x01, 0x67, 0x02, 0x3f, 0x01, 0x3c, 0x02, 0x0e, 0x01, 0x0e, 0x02, 0xd6, 0x00, 0xd6, 0x01, 0x96, 0x00, 0x96, 0x01, 0x57, 0x00, 0x4f, 0x01, 0x1e, 0x00, 0x01, 0x01, 0xeb, 0xff, 0xb2, 0x00, 0xbc, 0xff, 0x64, 0x00, 0x87, 0xff, 0x1e, 0x00, 0x4f, 0xff, 0xe2, 0xff, 0x17, 0xff, 0xac, 0xff, 0xe2, 0xfe, 0x77, 0xff, 0xb0, 0xfe, 0x3d, 0xff, 0x83, 0xfe, 0xfa, 0xfe, 0x56, 0xfe, 0xaf, 0xfe, 0x27, 0xfe, 0x68, 0xfe, 0xff, 0xfd, 0x2d, 0xfe, 0xde, 0xfd, 0x00, 0xfe, 0xc4, 0xfd, 0xde, 0xfd, 0xb0, 0xfd, 0xbf, 0xfd, 0xa0, 0xfd, 0x9b, 0xfd, 0x90, 0xfd, 0x79, 0xfd, 0x85, 0xfd, 0x5f, 0xfd, 0x82, 0xfd, 0x50, 0xfd, 0x83, 0xfd, 0x4d, 0xfd, 0x86, 0xfd, 0x53, 0xfd, 0x8f, 0xfd, 0x61, 0xfd, 0xa5, 0xfd, 0x6e, 0xfd, 0xc4, 0xfd, 0x7c, 0xfd, 0xed, 0xfd, 0x8b, 0xfd, 0x17, 0xfe, 0x97, 0xfd, 0x3a, 0xfe, 0xaa, 0xfd, 0x58, 0xfe, 0xc7, 0xfd, 0x76, 0xfe, 0xe9, 0xfd, 0x97, 0xfe, 0x12, 0xfe, 0xc1, 0xfe, 0x3a, 0xfe, 0xf1, 0xfe, 0x5b, 0xfe, 0x1e, 0xff, 0x73, 0xfe, 0x43, 0xff, 0x8b, 0xfe, 0x62, 0xff, 0xa9, 0xfe, 0x7e, 0xff, 0xd2, 0xfe, 0x98, 0xff, 0x0b, 0xff, 0xba, 0xff, 0x4e, 0xff, 0xe6, 0xff, 0x97, 0xff, 0x1a, 0x00, 0xdd, 0xff, 0x51, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x47, 0x00, 0x97, 0x00, 0x72, 0x00, 0xa1, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xf0, 0x00, 0xbe, 0x00, 0x48, 0x01, 0xdf, 0x00, 0xa5, 0x01, 0x08, 0x01, 0xf9, 0x01, 0x2f, 0x01, 0x43, 0x02, 0x4d, 0x01, 0x85, 0x02, 0x65, 0x01, 0xc4, 0x02, 0x78, 0x01, 0x03, 0x03, 0x8a, 0x01, 0x3d, 0x03, 0x95, 0x01, 0x6d, 0x03, 0x98, 0x01, 0x92, 0x03, 0x98, 0x01, 0xb1, 0x03, 0x96, 0x01, 0xd0, 0x03, 0x92, 0x01, 0xed, 0x03, 0x8b, 0x01, 0x09, 0x04, 0x7e, 0x01, 0x1d, 0x04, 0x66, 0x01, 0x25, 0x04, 0x44, 0x01, 0x23, 0x04, 0x1d, 0x01, 0x1a, 0x04, 0xf6, 0x00, 0x0a, 0x04, 0xce, 0x00, 0xf2, 0x03, 0xa2, 0x00, 0xd1, 0x03, 0x70, 0x00, 0xac, 0x03, 0x39, 0x00, 0x89, 0x03, 0x05, 0x00, 0x66, 0x03, 0xd4, 0xff, 0x3d, 0x03, 0xa4, 0xff, 0x08, 0x03, 0x73, 0xff, 0xc0, 0x02, 0x3d, 0xff, 0x6b, 0x02, 0xff, 0xfe, 0x13, 0x02, 0xbf, 0xfe, 0xc0, 0x01, 0x7e, 0xfe, 0x6f, 0x01, 0x41, 0xfe, 0x19, 0x01, 0x09, 0xfe, 0xbf, 0x00, 0xdb, 0xfd, 0x60, 0x00, 0xb9, 0xfd, 0xfe, 0xff, 0x9e, 0xfd, 0x9a, 0xff, 0x82, 0xfd, 0x38, 0xff, 0x61, 0xfd, 0xda, 0xfe, 0x3d, 0xfd, 0x81, 0xfe, 0x1a, 0xfd, 0x31, 0xfe, 0x00, 0xfd, 0xe9, 0xfd, 0xf3, 0xfc, 0xa3, 0xfd, 0xf3, 0xfc, 0x5e, 0xfd, 0xfa, 0xfc, 0x1b, 0xfd, 0x05, 0xfd, 0xdf, 0xfc, 0x10, 0xfd, 0xaf, 0xfc, 0x1a, 0xfd, 0x8b, 0xfc, 0x26, 0xfd, 0x74, 0xfc, 0x37, 0xfd, 0x64, 0xfc, 0x52, 0xfd, 0x52, 0xfc, 0x71, 0xfd, 0x3c, 0xfc, 0x95, 0xfd, 0x29, 0xfc, 0xbe, 0xfd, 0x1e, 0xfc, 0xeb, 0xfd, 0x22, 0xfc, 0x1d, 0xfe, 0x37, 0xfc, 0x57, 0xfe, 0x5d, 0xfc, 0x9c, 0xfe, 0x8a, 0xfc, 0xe7, 0xfe, 0xb1, 0xfc, 0x31, 0xff, 0xce, 0xfc, 0x73, 0xff, 0xe4, 0xfc, 0xaf, 0xff, 0xfe, 0xfc, 0xe9, 0xff, 0x25, 0xfd, 0x27, 0x00, 0x5c, 0xfd, 0x6c, 0x00, 0x9f, 0xfd, 0xbb, 0x00, 0xe9, 0xfd, 0x13, 0x01, 0x36, 0xfe, 0x72, 0x01, 0x86, 0xfe, 0xd2, 0x01, 0xd8, 0xfe, 0x29, 0x02, 0x2a, 0xff, 0x70, 0x02, 0x7e, 0xff, 0xab, 0x02, 0xd6, 0xff, 0xe4, 0x02, 0x34, 0x00, 0x20, 0x03, 0x93, 0x00, 0x5b, 0x03, 0xea, 0x00, 0x91, 0x03, 0x35, 0x01, 0xbd, 0x03, 0x77, 0x01, 0xdd, 0x03, 0xb7, 0x01, 0xf1, 0x03, 0xf9, 0x01, 0xf6, 0x03, 0x3a, 0x02, 0xee, 0x03, 0x74, 0x02, 0xda, 0x03, 0xa3, 0x02, 0xc1, 0x03, 0xc8, 0x02, 0xa7, 0x03, 0xea, 0x02, 0x8d, 0x03, 0x0e, 0x03, 0x73, 0x03, 0x2e, 0x03, 0x4f, 0x03, 0x43, 0x03, 0x20, 0x03, 0x50, 0x03, 0xed, 0x02, 0x56, 0x03, 0xba, 0x02, 0x55, 0x03, 0x86, 0x02, 0x4c, 0x03, 0x51, 0x02, 0x3b, 0x03, 0x18, 0x02, 0x21, 0x03, 0xda, 0x01, 0x02, 0x03, 0x99, 0x01, 0xe3, 0x02, 0x5b, 0x01, 0xc2, 0x02, 0x1f, 0x01, 0x9b, 0x02, 0xe4, 0x00, 0x6d, 0x02, 0xa8, 0x00, 0x37, 0x02, 0x68, 0x00, 0x01, 0x02, 0x2a, 0x00, 0xd1, 0x01, 0xf0, 0xff, 0xa9, 0x01, 0xbc, 0xff, 0x85, 0x01, 0x8e, 0xff, 0x5c, 0x01, 0x64, 0xff, 0x24, 0x01, 0x37, 0xff, 0xdf, 0x00, 0x05, 0xff, 0x97, 0x00, 0xd3, 0xfe, 0x58, 0x00, 0xa8, 0xfe, 0x20, 0x00, 0x81, 0xfe, 0xf5, 0xff, 0x66, 0xfe, 0xd3, 0xff, 0x59, 0xfe, 0xac, 0xff, 0x4f, 0xfe, 0x78, 0xff, 0x43, 0xfe, 0x37, 0xff, 0x3b, 0xfe, 0xed, 0xfe, 0x38, 0xfe, 0x9f, 0xfe, 0x37, 0xfe, 0x5c, 0xfe, 0x3b, 0xfe, 0x2a, 0xfe, 0x43, 0xfe, 0x03, 0xfe, 0x4b, 0xfe, 0xdf, 0xfd, 0x56, 0xfe, 0xb8, 0xfd, 0x6a, 0xfe, 0x86, 0xfd, 0x83, 0xfe, 0x4d, 0xfd, 0x9c, 0xfe, 0x16, 0xfd, 0xb6, 0xfe, 0xe9, 0xfc, 0xd2, 0xfe, 0xcf, 0xfc, 0xf6, 0xfe, 0xc6, 0xfc, 0x1c, 0xff, 0xc7, 0xfc, 0x3f, 0xff, 0xcd, 0xfc, 0x5f, 0xff, 0xd3, 0xfc, 0x7c, 0xff, 0xd4, 0xfc, 0x99, 0xff, 0xd5, 0xfc, 0xba, 0xff, 0xe1, 0xfc, 0xe2, 0xff, 0xfe, 0xfc, 0x14, 0x00, 0x2a, 0xfd, 0x4e, 0x00, 0x60, 0xfd, 0x8b, 0x00, 0x98, 0xfd, 0xc8, 0x00, 0xc7, 0xfd, 0xfc, 0x00, 0xef, 0xfd, 0x2a, 0x01, 0x19, 0xfe, 0x5a, 0x01, 0x41, 0xfe, 0x89, 0x01, 0x6a, 0xfe, 0xb7, 0x01, 0x97, 0xfe, 0xe8, 0x01, 0xc5, 0xfe, 0x17, 0x02, 0xf4, 0xfe, 0x42, 0x02, 0x22, 0xff, 0x66, 0x02, 0x54, 0xff, 0x86, 0x02, 0x86, 0xff, 0x9e, 0x02, 0xb5, 0xff, 0xac, 0x02, 0xe1, 0xff, 0xb3, 0x02, 0x0b, 0x00, 0xb6, 0x02, 0x38, 0x00, 0xbc, 0x02, 0x68, 0x00, 0xc0, 0x02, 0x9b, 0x00, 0xbf, 0x02, 0xd2, 0x00, 0xb3, 0x02, 0x0a, 0x01, 0x9a, 0x02, 0x3f, 0x01, 0x77, 0x02, 0x6c, 0x01, 0x4e, 0x02, 0x94, 0x01, 0x29, 0x02, 0xba, 0x01, 0x08, 0x02, 0xe2, 0x01, 0xe9, 0x01, 0x10, 0x02, 0xc8, 0x01, 0x40, 0x02, 0xa3, 0x01, 0x69, 0x02, 0x76, 0x01, 0x86, 0x02, 0x40, 0x01, 0x97, 0x02, 0x0a, 0x01, 0x9a, 0x02, 0xd2, 0x00, 0x93, 0x02, 0x9d, 0x00, 0x87, 0x02, 0x6a, 0x00, 0x7b, 0x02, 0x38, 0x00, 0x72, 0x02, 0x03, 0x00, 0x6c, 0x02, 0xcf, 0xff, 0x62, 0x02, 0x9b, 0xff, 0x4e, 0x02, 0x66, 0xff, 0x2d, 0x02, 0x31, 0xff, 0x00, 0x02, 0xfa, 0xfe, 0xcb, 0x01, 0xbf, 0xfe, 0x92, 0x01, 0x82, 0xfe, 0x5b, 0x01, 0x45, 0xfe, 0x29, 0x01, 0x09, 0xfe, 0xfb, 0x00, 0xcf, 0xfd, 0xd1, 0x00, 0x9d, 0xfd, 0xaa, 0x00, 0x78, 0xfd, 0x81, 0x00, 0x61, 0xfd, 0x51, 0x00, 0x4e, 0xfd, 0x15, 0x00, 0x33, 0xfd, 0xd3, 0xff, 0x11, 0xfd, 0x8f, 0xff, 0xec, 0xfc, 0x52, 0xff, 0xcc, 0xfc, 0x23, 0xff, 0xc0, 0xfc, 0xfe, 0xfe, 0xc1, 0xfc, 0xda, 0xfe, 0xc5, 0xfc, 0xac, 0xfe, 0xc3, 0xfc, 0x71, 0xfe, 0xbb, 0xfc, 0x31, 0xfe, 0xb5, 0xfc, 0xf6, 0xfd, 0xb9, 0xfc, 0xc7, 0xfd, 0xcd, 0xfc, 0xa9, 0xfd, 0xf4, 0xfc, 0x9b, 0xfd, 0x28, 0xfd, 0x93, 0xfd, 0x61, 0xfd, 0x88, 0xfd, 0x96, 0xfd, 0x7b, 0xfd, 0xc8, 0xfd, 0x71, 0xfd, 0xfb, 0xfd, 0x6e, 0xfd, 0x2f, 0xfe, 0x76, 0xfd, 0x67, 0xfe, 0x8c, 0xfd, 0xa9, 0xfe, 0xae, 0xfd, 0xf4, 0xfe, 0xd2, 0xfd, 0x41, 0xff, 0xf8, 0xfd, 0x8d, 0xff, 0x20, 0xfe, 0xd1, 0xff, 0x4b, 0xfe, 0x0d, 0x00, 0x79, 0xfe, 0x42, 0x00, 0xaa, 0xfe, 0x75, 0x00, 0xdd, 0xfe, 0xae, 0x00, 0x18, 0xff, 0xf1, 0x00, 0x59, 0xff, 0x3c, 0x01, 0x9a, 0xff, 0x83, 0x01, 0xd3, 0xff, 0xbd, 0x01, 0x09, 0x00, 0xeb, 0x01, 0x3e, 0x00, 0x0f, 0x02, 0x73, 0x00, 0x30, 0x02, 0xa9, 0x00, 0x53, 0x02, 0xdf, 0x00, 0x7a, 0x02, 0x17, 0x01, 0xa3, 0x02, 0x4b, 0x01, 0xc7, 0x02, 0x7a, 0x01, 0xe2, 0x02, 0xa3, 0x01, 0xf6, 0x02, 0xc3, 0x01, 0x01, 0x03, 0xde, 0x01, 0x07, 0x03, 0xf9, 0x01, 0x0b, 0x03, 0x17, 0x02, 0x0b, 0x03, 0x34, 0x02, 0x01, 0x03, 0x4d, 0x02, 0xe9, 0x02, 0x62, 0x02, 0xc5, 0x02, 0x75, 0x02, 0x9c, 0x02, 0x7f, 0x02, 0x6e, 0x02, 0x81, 0x02, 0x3d, 0x02, 0x7f, 0x02, 0x0e, 0x02, 0x7e, 0x02, 0xe0, 0x01, 0x81, 0x02, 0xb1, 0x01, 0x8d, 0x02, 0x82, 0x01, 0x9f, 0x02, 0x53, 0x01, 0xad, 0x02, 0x20, 0x01, 0xb4, 0x02, 0xed, 0x00, 0xb5, 0x02, 0xbd, 0x00, 0xae, 0x02, 0x91, 0x00, 0xa4, 0x02, 0x67, 0x00, 0x9e, 0x02, 0x44, 0x00, 0x9b, 0x02, 0x23, 0x00, 0x91, 0x02, 0xfe, 0xff, 0x7d, 0x02, 0xd6, 0xff, 0x5d, 0x02, 0xaf, 0xff, 0x31, 0x02, 0x8b, 0xff, 0xfd, 0x01, 0x68, 0xff, 0xc5, 0x01, 0x45, 0xff, 0x87, 0x01, 0x1c, 0xff, 0x45, 0x01, 0xf0, 0xfe, 0x00, 0x01, 0xc8, 0xfe, 0xbb, 0x00, 0xa9, 0xfe, 0x77, 0x00, 0x96, 0xfe, 0x2f, 0x00, 0x86, 0xfe, 0xe1, 0xff, 0x71, 0xfe, 0x8f, 0xff, 0x56, 0xfe, 0x41, 0xff, 0x3b, 0xfe, 0xfe, 0xfe, 0x23, 0xfe, 0xc6, 0xfe, 0x11, 0xfe, 0x94, 0xfe, 0x03, 0xfe, 0x63, 0xfe, 0xfb, 0xfd, 0x33, 0xfe, 0xf7, 0xfd, 0x05, 0xfe, 0xf6, 0xfd, 0xdd, 0xfd, 0xf6, 0xfd, 0xb9, 0xfd, 0xf2, 0xfd, 0x9c, 0xfd, 0xeb, 0xfd, 0x83, 0xfd, 0xe4, 0xfd, 0x6b, 0xfd, 0xe1, 0xfd, 0x56, 0xfd, 0xe5, 0xfd, 0x4a, 0xfd, 0xf8, 0xfd, 0x4a, 0xfd, 0x1a, 0xfe, 0x55, 0xfd, 0x48, 0xfe, 0x62, 0xfd, 0x75, 0xfe, 0x65, 0xfd, 0x99, 0xfe, 0x60, 0xfd, 0xb5, 0xfe, 0x5b, 0xfd, 0xd3, 0xfe, 0x5f, 0xfd, 0xfb, 0xfe, 0x72, 0xfd, 0x30, 0xff, 0x8e, 0xfd, 0x70, 0xff, 0xaa, 0xfd, 0xb2, 0xff, 0xc0, 0xfd, 0xef, 0xff, 0xd0, 0xfd, 0x23, 0x00, 0xdf, 0xfd, 0x54, 0x00, 0xf3, 0xfd, 0x85, 0x00, 0x09, 0xfe, 0xb7, 0x00, 0x26, 0xfe, 0xea, 0x00, 0x4a, 0xfe, 0x1e, 0x01, 0x75, 0xfe, 0x4d, 0x01, 0xa0, 0xfe, 0x73, 0x01, 0xce, 0xfe, 0x91, 0x01, 0xf9, 0xfe, 0xa4, 0x01, 0x23, 0xff, 0xaf, 0x01, 0x4f, 0xff, 0xb8, 0x01, 0x7d, 0xff, 0xc0, 0x01, 0xae, 0xff, 0xc9, 0x01, 0xe0, 0xff, 0xcd, 0x01, 0x14, 0x00, 0xc8, 0x01, 0x4a, 0x00, 0xbb, 0x01, 0x80, 0x00, 0xa4, 0x01, 0xb5, 0x00, 0x89, 0x01, 0xe7, 0x00, 0x6c, 0x01, 0x14, 0x01, 0x4e, 0x01, 0x3b, 0x01, 0x2d, 0x01, 0x5b, 0x01, 0x0a, 0x01, 0x75, 0x01, 0xe5, 0x00, 0x87, 0x01, 0xbc, 0x00, 0x94, 0x01, 0x90, 0x00, 0x9c, 0x01, 0x61, 0x00, 0xa2, 0x01, 0x2e, 0x00, 0xa3, 0x01, 0xf8, 0xff, 0xa1, 0x01, 0xc6, 0xff, 0x96, 0x01, 0x94, 0xff, 0x80, 0x01, 0x64, 0xff, 0x60, 0x01, 0x34, 0xff, 0x3d, 0x01, 0x07, 0xff, 0x1b, 0x01, 0xdb, 0xfe, 0xfc, 0x00, 0xac, 0xfe, 0xe1, 0x00, 0x7a, 0xfe, 0xc9, 0x00, 0x46, 0xfe, 0xad, 0x00, 0x12, 0xfe, 0x8b, 0x00, 0xde, 0xfd, 0x65, 0x00, 0xae, 0xfd, 0x3b, 0x00, 0x83, 0xfd, 0x11, 0x00, 0x60, 0xfd, 0xe9, 0xff, 0x44, 0xfd, 0xc1, 0xff, 0x2c, 0xfd, 0x94, 0xff, 0x13, 0xfd, 0x66, 0xff, 0xf9, 0xfc, 0x3d, 0xff, 0xe0, 0xfc, 0x15, 0xff, 0xc6, 0xfc, 0xef, 0xfe, 0xb3, 0xfc, 0xcd, 0xfe, 0xaa, 0xfc, 0xac, 0xfe, 0xb2, 0xfc, 0x8b, 0xfe, 0xc8, 0xfc, 0x6a, 0xfe, 0xe9, 0xfc, 0x4b, 0xfe, 0x0e, 0xfd, 0x26, 0xfe, 0x2e, 0xfd, 0xfe, 0xfd, 0x49, 0xfd, 0xda, 0xfd, 0x65, 0xfd, 0xc1, 0xfd, 0x89, 0xfd, 0xb2, 0xfd, 0xb3, 0xfd, 0xa7, 0xfd, 0xe1, 0xfd, 0x9a, 0xfd, 0x10, 0xfe, 0x88, 0xfd, 0x41, 0xfe, 0x76, 0xfd, 0x78, 0xfe, 0x6f, 0xfd, 0xb6, 0xfe, 0x78, 0xfd, 0xf8, 0xfe, 0x8f, 0xfd, 0x38, 0xff, 0xae, 0xfd, 0x72, 0xff, 0xca, 0xfd, 0xa1, 0xff, 0xde, 0xfd, 0xc7, 0xff, 0xf0, 0xfd, 0xed, 0xff, 0x07, 0xfe, 0x1b, 0x00, 0x2b, 0xfe, 0x54, 0x00, 0x60, 0xfe, 0x99, 0x00, 0xa3, 0xfe, 0xe0, 0x00, 0xe9, 0xfe, 0x1f, 0x01, 0x2c, 0xff, 0x53, 0x01, 0x65, 0xff, 0x7d, 0x01, 0x98, 0xff, 0xa4, 0x01, 0xc8, 0xff, 0xca, 0x01, 0xfe, 0xff, 0xf2, 0x01, 0x3e, 0x00, 0x1d, 0x02, 0x81, 0x00, 0x46, 0x02, 0xc5, 0x00, 0x6e, 0x02, 0x06, 0x01, 0x96, 0x02, 0x3e, 0x01, 0xb9, 0x02, 0x6c, 0x01, 0xd5, 0x02, 0x92, 0x01, 0xea, 0x02, 0xb3, 0x01, 0xf8, 0x02, 0xd4, 0x01, 0x03, 0x03, 0xf4, 0x01, 0x0c, 0x03, 0x12, 0x02, 0x12, 0x03, 0x2c, 0x02, 0x11, 0x03, 0x3f, 0x02, 0x09, 0x03, 0x4a, 0x02, 0xfa, 0x02, 0x51, 0x02, 0xe8, 0x02, 0x59, 0x02, 0xd3, 0x02, 0x65, 0x02, 0xbb, 0x02, 0x72, 0x02, 0x9d, 0x02, 0x7f, 0x02, 0x7a, 0x02, 0x88, 0x02, 0x55, 0x02, 0x8c, 0x02, 0x2f, 0x02, 0x8d, 0x02, 0x09, 0x02, 0x8b, 0x02, 0xde, 0x01, 0x89, 0x02, 0xad, 0x01, 0x84, 0x02, 0x78, 0x01, 0x81, 0x02, 0x44, 0x01, 0x7a, 0x02, 0x13, 0x01, 0x6f, 0x02, 0xe3, 0x00, 0x61, 0x02, 0xb7, 0x00, 0x52, 0x02, 0x8b, 0x00, 0x40, 0x02, 0x5b, 0x00, 0x2b, 0x02, 0x28, 0x00, 0x15, 0x02, 0xf3, 0xff, 0xf8, 0x01, 0xbd, 0xff, 0xd7, 0x01, 0x8c, 0xff, 0xb4, 0x01, 0x63, 0xff, 0x8f, 0x01, 0x42, 0xff, 0x6a, 0x01, 0x29, 0xff, 0x47, 0x01, 0x18, 0xff, 0x25, 0x01, 0x09, 0xff, 0x01, 0x01, 0xf5, 0xfe, 0xda, 0x00, 0xdf, 0xfe, 0xac, 0x00, 0xc8, 0xfe, 0x7d, 0x00, 0xb9, 0xfe, 0x4d, 0x00, 0xb5, 0xfe, 0x23, 0x00, 0xc0, 0xfe, 0xfd, 0xff, 0xcf, 0xfe, 0xd8, 0xff, 0xd9, 0xfe, 0xb4, 0xff, 0xdf, 0xfe, 0x8f, 0xff, 0xe6, 0xfe, 0x69, 0xff, 0xf0, 0xfe, 0x42, 0xff, 0x01, 0xff, 0x1b, 0xff, 0x17, 0xff, 0xf7, 0xfe, 0x2e, 0xff, 0xdf, 0xfe, 0x4a, 0xff, 0xd1, 0xfe, 0x67, 0xff, 0xc5, 0xfe, 0x7f, 0xff, 0xb5, 0xfe, 0x90, 0xff, 0x9f, 0xfe, 0x9b, 0xff, 0x87, 0xfe, 0xa5, 0xff, 0x74, 0xfe, 0xb3, 0xff, 0x6d, 0xfe, 0xc6, 0xff, 0x6f, 0xfe, 0xd9, 0xff, 0x76, 0xfe, 0xea, 0xff, 0x80, 0xfe, 0xf7, 0xff, 0x8c, 0xfe, 0x05, 0x00, 0x97, 0xfe, 0x17, 0x00, 0xa5, 0xfe, 0x31, 0x00, 0xb6, 0xfe, 0x51, 0x00, 0xcc, 0xfe, 0x73, 0x00, 0xe5, 0xfe, 0x91, 0x00, 0x02, 0xff, 0xa7, 0x00, 0x23, 0xff, 0xb6, 0x00, 0x49, 0xff, 0xc9, 0x00, 0x70, 0xff, 0xe4, 0x00, 0x93, 0xff, 0x03, 0x01, 0xb0, 0xff, 0x23, 0x01, 0xce, 0xff, 0x41, 0x01, 0xf6, 0xff, 0x60, 0x01, 0x2b, 0x00, 0x7e, 0x01, 0x65, 0x00, 0x99, 0x01, 0x96, 0x00, 0xaa, 0x01, 0xb8, 0x00, 0xb3, 0x01, 0xd2, 0x00, 0xbc, 0x01, 0xeb, 0x00, 0xc8, 0x01, 0x0b, 0x01, 0xd8, 0x01, 0x2e, 0x01, 0xe4, 0x01, 0x4e, 0x01, 0xe5, 0x01, 0x64, 0x01, 0xd6, 0x01, 0x6d, 0x01, 0xb8, 0x01, 0x6c, 0x01, 0x94, 0x01, 0x67, 0x01, 0x71, 0x01, 0x62, 0x01, 0x51, 0x01, 0x62, 0x01, 0x33, 0x01, 0x63, 0x01, 0x0f, 0x01, 0x64, 0x01, 0xe3, 0x00, 0x5a, 0x01, 0xae, 0x00, 0x47, 0x01, 0x76, 0x00, 0x2d, 0x01, 0x3f, 0x00, 0x10, 0x01, 0x0e, 0x00, 0xf9, 0x00, 0xe6, 0xff, 0xe8, 0x00, 0xc5, 0xff, 0xdd, 0x00, 0xa9, 0xff, 0xd5, 0x00, 0x8b, 0xff, 0xcb, 0x00, 0x69, 0xff, 0xbc, 0x00, 0x45, 0xff, 0xa5, 0x00, 0x21, 0xff, 0x89, 0x00, 0x03, 0xff, 0x6b, 0x00, 0xea, 0xfe, 0x50, 0x00, 0xd9, 0xfe, 0x3a, 0x00, 0xcd, 0xfe, 0x23, 0x00, 0xbf, 0xfe, 0x08, 0x00, 0xb1, 0xfe, 0xe6, 0xff, 0xa1, 0xfe, 0xbf, 0xff, 0x8f, 0xfe, 0x97, 0xff, 0x7b, 0xfe, 0x77, 0xff, 0x6b, 0xfe, 0x5f, 0xff, 0x5f, 0xfe, 0x48, 0xff, 0x53, 0xfe, 0x2d, 0xff, 0x46, 0xfe, 0x0d, 0xff, 0x39, 0xfe, 0xe5, 0xfe, 0x2a, 0xfe, 0xba, 0xfe, 0x19, 0xfe, 0x97, 0xfe, 0x0f, 0xfe, 0x83, 0xfe, 0x0e, 0xfe, 0x79, 0xfe, 0x0f, 0xfe, 0x73, 0xfe, 0x11, 0xfe, 0x6e, 0xfe, 0x13, 0xfe, 0x63, 0xfe, 0x16, 0xfe, 0x51, 0xfe, 0x1b, 0xfe, 0x3e, 0xfe, 0x27, 0xfe, 0x2b, 0xfe, 0x36, 0xfe, 0x20, 0xfe, 0x47, 0xfe, 0x20, 0xfe, 0x5a, 0xfe, 0x2c, 0xfe, 0x72, 0xfe, 0x3f, 0xfe, 0x8f, 0xfe, 0x55, 0xfe, 0xb0, 0xfe, 0x6a, 0xfe, 0xd3, 0xfe, 0x7b, 0xfe, 0xf9, 0xfe, 0x8a, 0xfe, 0x1e, 0xff, 0x99, 0xfe, 0x43, 0xff, 0xb0, 0xfe, 0x6a, 0xff, 0xd2, 0xfe, 0x93, 0xff, 0xfa, 0xfe, 0xbc, 0xff, 0x1e, 0xff, 0xe2, 0xff, 0x3d, 0xff, 0x08, 0x00, 0x54, 0xff, 0x2a, 0x00, 0x66, 0xff, 0x48, 0x00, 0x7d, 0xff, 0x65, 0x00, 0x9a, 0xff, 0x82, 0x00, 0xbb, 0xff, 0xa1, 0x00, 0xda, 0xff, 0xbc, 0x00, 0xf6, 0xff, 0xd6, 0x00, 0x0d, 0x00, 0xea, 0x00, 0x21, 0x00, 0xfa, 0x00, 0x38, 0x00, 0x0b, 0x01, 0x54, 0x00, 0x21, 0x01, 0x76, 0x00, 0x39, 0x01, 0x9d, 0x00, 0x55, 0x01, 0xc7, 0x00, 0x70, 0x01, 0xec, 0x00, 0x85, 0x01, 0x07, 0x01, 0x92, 0x01, 0x15, 0x01, 0x98, 0x01, 0x1d, 0x01, 0x99, 0x01, 0x25, 0x01, 0x99, 0x01, 0x35, 0x01, 0x9c, 0x01, 0x52, 0x01, 0xa4, 0x01, 0x77, 0x01, 0xae, 0x01, 0x97, 0x01, 0xb4, 0x01, 0xa8, 0x01, 0xb0, 0x01, 0xa6, 0x01, 0xa0, 0x01, 0x97, 0x01, 0x85, 0x01, 0x82, 0x01, 0x64, 0x01, 0x6f, 0x01, 0x40, 0x01, 0x61, 0x01, 0x20, 0x01, 0x5a, 0x01, 0x06, 0x01, 0x51, 0x01, 0xee, 0x00, 0x44, 0x01, 0xd5, 0x00, 0x32, 0x01, 0xbb, 0x00, 0x17, 0x01, 0x9e, 0x00, 0xf9, 0x00, 0x7f, 0x00, 0xdb, 0x00, 0x61, 0x00, 0xc0, 0x00, 0x43, 0x00, 0xaa, 0x00, 0x29, 0x00, 0x98, 0x00, 0x14, 0x00, 0x8c, 0x00, 0x05, 0x00, 0x7b, 0x00, 0xf4, 0xff, 0x5e, 0x00, 0xdc, 0xff, 0x3b, 0x00, 0xc1, 0xff, 0x1a, 0x00, 0xa9, 0xff, 0xfe, 0xff, 0x95, 0xff, 0xea, 0xff, 0x87, 0xff, 0xdc, 0xff, 0x7d, 0xff, 0xca, 0xff, 0x70, 0xff, 0xb2, 0xff, 0x62, 0xff, 0x97, 0xff, 0x54, 0xff, 0x7e, 0xff, 0x47, 0xff, 0x69, 0xff, 0x3a, 0xff, 0x56, 0xff, 0x2d, 0xff, 0x46, 0xff, 0x21, 0xff, 0x3a, 0xff, 0x19, 0xff, 0x30, 0xff, 0x15, 0xff, 0x28, 0xff, 0x12, 0xff, 0x22, 0xff, 0x0e, 0xff, 0x1f, 0xff, 0x0b, 0xff, 0x1d, 0xff, 0x09, 0xff, 0x17, 0xff, 0x04, 0xff, 0x0a, 0xff, 0xfc, 0xfe, 0xf9, 0xfe, 0xf2, 0xfe, 0xeb, 0xfe, 0xed, 0xfe, 0xe5, 0xfe, 0xef, 0xfe, 0xe8, 0xfe, 0xf9, 0xfe, 0xee, 0xfe, 0x06, 0xff, 0xf0, 0xfe, 0x11, 0xff, 0xeb, 0xfe, 0x19, 0xff, 0xde, 0xfe, 0x1b, 0xff, 0xcf, 0xfe, 0x1c, 0xff, 0xc3, 0xfe, 0x23, 0xff, 0xc2, 0xfe, 0x34, 0xff, 0xce, 0xfe, 0x52, 0xff, 0xe7, 0xfe, 0x7d, 0xff, 0x0a, 0xff, 0xb0, 0xff, 0x2f, 0xff, 0xe4, 0xff, 0x51, 0xff, 0x15, 0x00, 0x70, 0xff, 0x43, 0x00, 0x8a, 0xff, 0x6c, 0x00, 0xa4, 0xff, 0x94, 0x00, 0xc3, 0xff, 0xc2, 0x00, 0xed, 0xff, 0xfa, 0x00, 0x1f, 0x00, 0x37, 0x01, 0x53, 0x00, 0x73, 0x01, 0x82, 0x00, 0xa9, 0x01, 0xa4, 0x00, 0xd3, 0x01, 0xb7, 0x00, 0xed, 0x01, 0xc0, 0x00, 0xfb, 0x01, 0xca, 0x00, 0x03, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xed, 0x00, 0x0f, 0x02, 0x07, 0x01, 0x19, 0x02, 0x1c, 0x01, 0x21, 0x02, 0x25, 0x01, 0x20, 0x02, 0x22, 0x01, 0x15, 0x02, 0x15, 0x01, 0x01, 0x02, 0x03, 0x01, 0xe5, 0x01, 0xf3, 0x00, 0xc3, 0x01, 0xe9, 0x00, 0x9c, 0x01, 0xe7, 0x00, 0x75, 0x01, 0xe6, 0x00, 0x4e, 0x01, 0xe2, 0x00, 0x27, 0x01, 0xd9, 0x00, 0x05, 0x01, 0xcc, 0x00, 0xe6, 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0x81, 0x00, 0xa7, 0x00, 0x62, 0x00, 0xaa, 0x00, 0x4c, 0x00, 0xaa, 0x00, 0x3b, 0x00, 0x9d, 0x00, 0x28, 0x00, 0x84, 0x00, 0x0f, 0x00, 0x6a, 0x00, 0xf6, 0xff, 0x59, 0x00, 0xe1, 0xff, 0x54, 0x00, 0xd5, 0xff, 0x56, 0x00, 0xcf, 0xff, 0x51, 0x00, 0xc6, 0xff, 0x44, 0x00, 0xb7, 0xff, 0x2e, 0x00, 0xa2, 0xff, 0x15, 0x00, 0x8a, 0xff, 0xfb, 0xff, 0x6e, 0xff, 0xe3, 0xff, 0x51, 0xff, 0xcc, 0xff, 0x34, 0xff, 0xb4, 0xff, 0x14, 0xff, 0x99, 0xff, 0xf4, 0xfe, 0x7c, 0xff, 0xd4, 0xfe, 0x60, 0xff, 0xb7, 0xfe, 0x44, 0xff, 0x9e, 0xfe, 0x2d, 0xff, 0x87, 0xfe, 0x1c, 0xff, 0x73, 0xfe, 0x0c, 0xff, 0x5b, 0xfe, 0xfb, 0xfe, 0x3c, 0xfe, 0xe6, 0xfe, 0x1a, 0xfe, 0xcc, 0xfe, 0xf7, 0xfd, 0xb0, 0xfe, 0xd8, 0xfd, 0x9b, 0xfe, 0xc7, 0xfd, 0x94, 0xfe, 0xc4, 0xfd, 0x9a, 0xfe, 0xcc, 0xfd, 0xab, 0xfe, 0xdb, 0xfd, 0xc1, 0xfe, 0xec, 0xfd, 0xd1, 0xfe, 0xf9, 0xfd, 0xd3, 0xfe, 0xf9, 0xfd, 0xcb, 0xfe, 0xf4, 0xfd, 0xc5, 0xfe, 0xf6, 0xfd, 0xca, 0xfe, 0x07, 0xfe, 0xe0, 0xfe, 0x2d, 0xfe, 0x06, 0xff, 0x61, 0xfe, 0x32, 0xff, 0x97, 0xfe, 0x58, 0xff, 0xc4, 0xfe, 0x72, 0xff, 0xe4, 0xfe, 0x85, 0xff, 0xfd, 0xfe, 0x97, 0xff, 0x17, 0xff, 0xb1, 0xff, 0x39, 0xff, 0xd4, 0xff, 0x65, 0xff, 0xf9, 0xff, 0x97, 0xff, 0x19, 0x00, 0xc7, 0xff, 0x32, 0x00, 0xf3, 0xff, 0x47, 0x00, 0x18, 0x00, 0x5c, 0x00, 0x3c, 0x00, 0x76, 0x00, 0x61, 0x00, 0x95, 0x00, 0x87, 0x00, 0xb6, 0x00, 0xae, 0x00, 0xd5, 0x00, 0xcf, 0x00, 0xe6, 0x00, 0xe3, 0x00, 0xe7, 0x00, 0xe6, 0x00, 0xe2, 0x00, 0xe5, 0x00, 0xdd, 0x00, 0xe6, 0x00, 0xe0, 0x00, 0xed, 0x00, 0xf2, 0x00, 0x00, 0x01, 0x0f, 0x01, 0x1b, 0x01, 0x29, 0x01, 0x32, 0x01, 0x36, 0x01, 0x3a, 0x01, 0x32, 0x01, 0x34, 0x01, 0x24, 0x01, 0x25, 0x01, 0x12, 0x01, 0x12, 0x01, 0x04, 0x01, 0x01, 0x01, 0x05, 0x01, 0xfa, 0x00, 0x0f, 0x01, 0xfa, 0x00, 0x1c, 0x01, 0xfa, 0x00, 0x22, 0x01, 0xf4, 0x00, 0x1f, 0x01, 0xe7, 0x00, 0x14, 0x01, 0xd3, 0x00, 0x08, 0x01, 0xbb, 0x00, 0x02, 0x01, 0xa6, 0x00, 0x02, 0x01, 0x95, 0x00, 0x02, 0x01, 0x85, 0x00, 0xfa, 0x00, 0x73, 0x00, 0xeb, 0x00, 0x5f, 0x00, 0xd3, 0x00, 0x49, 0x00, 0xb9, 0x00, 0x35, 0x00, 0xa4, 0x00, 0x28, 0x00, 0x96, 0x00, 0x20, 0x00, 0x87, 0x00, 0x16, 0x00, 0x73, 0x00, 0x04, 0x00, 0x56, 0x00, 0xeb, 0xff, 0x32, 0x00, 0xce, 0xff, 0x06, 0x00, 0xb0, 0xff, 0xd6, 0xff, 0x93, 0xff, 0xaf, 0xff, 0x82, 0xff, 0x93, 0xff, 0x79, 0xff, 0x7f, 0xff, 0x73, 0xff, 0x6b, 0xff, 0x68, 0xff, 0x51, 0xff, 0x56, 0xff, 0x2e, 0xff, 0x3c, 0xff, 0x03, 0xff, 0x1c, 0xff, 0xda, 0xfe, 0xfd, 0xfe, 0xb7, 0xfe, 0xe4, 0xfe, 0x9f, 0xfe, 0xd3, 0xfe, 0x93, 0xfe, 0xcc, 0xfe, 0x90, 0xfe, 0xce, 0xfe, 0x8d, 0xfe, 0xce, 0xfe, 0x86, 0xfe, 0xcc, 0xfe, 0x7f, 0xfe, 0xca, 0xfe, 0x79, 0xfe, 0xca, 0xfe, 0x73, 0xfe, 0xcc, 0xfe, 0x71, 0xfe, 0xd3, 0xfe, 0x78, 0xfe, 0xe4, 0xfe, 0x84, 0xfe, 0xfa, 0xfe, 0x8f, 0xfe, 0x12, 0xff, 0x98, 0xfe, 0x29, 0xff, 0xa3, 0xfe, 0x41, 0xff, 0xb0, 0xfe, 0x5a, 0xff, 0xbe, 0xfe, 0x73, 0xff, 0xcf, 0xfe, 0x8d, 0xff, 0xe1, 0xfe, 0xa7, 0xff, 0xf3, 0xfe, 0xc0, 0xff, 0x05, 0xff, 0xdb, 0xff, 0x16, 0xff, 0xf6, 0xff, 0x26, 0xff, 0x10, 0x00, 0x37, 0xff, 0x2c, 0x00, 0x4c, 0xff, 0x4a, 0x00, 0x65, 0xff, 0x68, 0x00, 0x7c, 0xff, 0x83, 0x00, 0x91, 0xff, 0x9e, 0x00, 0xa1, 0xff, 0xb5, 0x00, 0xa7, 0xff, 0xc6, 0x00, 0xa8, 0xff, 0xcf, 0x00, 0xa7, 0xff, 0xd2, 0x00, 0xa9, 0xff, 0xd4, 0x00, 0xb2, 0xff, 0xdb, 0x00, 0xc5, 0xff, 0xea, 0x00, 0xdd, 0xff, 0xfc, 0x00, 0xf2, 0xff, 0x0a, 0x01, 0x04, 0x00, 0x12, 0x01, 0x10, 0x00, 0x11, 0x01, 0x19, 0x00, 0x0b, 0x01, 0x22, 0x00, 0x02, 0x01, 0x28, 0x00, 0xf5, 0x00, 0x2f, 0x00, 0xe8, 0x00, 0x37, 0x00, 0xdd, 0x00, 0x3e, 0x00, 0xd4, 0x00, 0x47, 0x00, 0xcd, 0x00, 0x54, 0x00, 0xc6, 0x00, 0x63, 0x00, 0xbd, 0x00, 0x73, 0x00, 0xb1, 0x00, 0x7e, 0x00, 0xa1, 0x00, 0x80, 0x00, 0x8c, 0x00, 0x76, 0x00, 0x71, 0x00, 0x66, 0x00, 0x55, 0x00, 0x58, 0x00, 0x3e, 0x00, 0x4f, 0x00, 0x2d, 0x00, 0x4d, 0x00, 0x24, 0x00, 0x4e, 0x00, 0x1d, 0x00, 0x4c, 0x00, 0x13, 0x00, 0x41, 0x00, 0x01, 0x00, 0x2d, 0x00, 0xe6, 0xff, 0x17, 0x00, 0xcb, 0xff, 0xff, 0xff, 0xb1, 0xff, 0xe5, 0xff, 0x95, 0xff, 0xcd, 0xff, 0x79, 0xff, 0xb6, 0xff, 0x5f, 0xff, 0xa3, 0xff, 0x49, 0xff, 0x93, 0xff, 0x36, 0xff, 0x89, 0xff, 0x28, 0xff, 0x82, 0xff, 0x1d, 0xff, 0x7e, 0xff, 0x10, 0xff, 0x7b, 0xff, 0x04, 0xff, 0x79, 0xff, 0xf9, 0xfe, 0x79, 0xff, 0xf2, 0xfe, 0x77, 0xff, 0xeb, 0xfe, 0x73, 0xff, 0xe2, 0xfe, 0x6f, 0xff, 0xda, 0xfe, 0x6c, 0xff, 0xd6, 0xfe, 0x6f, 0xff, 0xd7, 0xfe, 0x77, 0xff, 0xde, 0xfe, 0x82, 0xff, 0xe7, 0xfe, 0x8a, 0xff, 0xee, 0xfe, 0x8d, 0xff, 0xee, 0xfe, 0x8c, 0xff, 0xec, 0xfe, 0x8b, 0xff, 0xee, 0xfe, 0x92, 0xff, 0xfa, 0xfe, 0xa2, 0xff, 0x12, 0xff, 0xb9, 0xff, 0x2f, 0xff, 0xd3, 0xff, 0x4f, 0xff, 0xeb, 0xff, 0x6c, 0xff, 0x03, 0x00, 0x8a, 0xff, 0x1a, 0x00, 0xa6, 0xff, 0x2f, 0x00, 0xc2, 0xff, 0x43, 0x00, 0xde, 0xff, 0x56, 0x00, 0xfa, 0xff, 0x6a, 0x00, 0x17, 0x00, 0x80, 0x00, 0x35, 0x00, 0x9a, 0x00, 0x56, 0x00, 0xb6, 0x00, 0x7a, 0x00, 0xd2, 0x00, 0xa0, 0x00, 0xec, 0x00, 0xc6, 0x00, 0x04, 0x01, 0xea, 0x00, 0x18, 0x01, 0x08, 0x01, 0x28, 0x01, 0x1e, 0x01, 0x31, 0x01, 0x2c, 0x01, 0x31, 0x01, 0x33, 0x01, 0x30, 0x01, 0x3b, 0x01, 0x32, 0x01, 0x4a, 0x01, 0x39, 0x01, 0x5e, 0x01, 0x44, 0x01, 0x74, 0x01, 0x53, 0x01, 0x88, 0x01, 0x60, 0x01, 0x93, 0x01, 0x63, 0x01, 0x91, 0x01, 0x5c, 0x01, 0x85, 0x01, 0x51, 0x01, 0x76, 0x01, 0x44, 0x01, 0x6a, 0x01, 0x38, 0x01, 0x62, 0x01, 0x33, 0x01, 0x61, 0x01, 0x32, 0x01, 0x63, 0x01, 0x32, 0x01, 0x60, 0x01, 0x31, 0x01, 0x54, 0x01, 0x2e, 0x01, 0x43, 0x01, 0x29, 0x01, 0x30, 0x01, 0x20, 0x01, 0x1a, 0x01, 0x15, 0x01, 0x04, 0x01, 0x08, 0x01, 0xee, 0x00, 0xff, 0x00, 0xd9, 0x00, 0xf9, 0x00, 0xc4, 0x00, 0xf3, 0x00, 0xac, 0x00, 0xeb, 0x00, 0x91, 0x00, 0xe2, 0x00, 0x76, 0x00, 0xdb, 0x00, 0x5d, 0x00, 0xcf, 0x00, 0x42, 0x00, 0xc2, 0x00, 0x28, 0x00, 0xb7, 0x00, 0x14, 0x00, 0xae, 0x00, 0x04, 0x00, 0xa5, 0x00, 0xf7, 0xff, 0x9f, 0x00, 0xee, 0xff, 0x99, 0x00, 0xe9, 0xff, 0x91, 0x00, 0xe4, 0xff, 0x85, 0x00, 0xe0, 0xff, 0x76, 0x00, 0xdc, 0xff, 0x66, 0x00, 0xd6, 0xff, 0x55, 0x00, 0xd0, 0xff, 0x46, 0x00, 0xcd, 0xff, 0x38, 0x00, 0xcc, 0xff, 0x28, 0x00, 0xcf, 0xff, 0x14, 0x00, 0xcf, 0xff, 0xfd, 0xff, 0xcb, 0xff, 0xe7, 0xff, 0xc6, 0xff, 0xd2, 0xff, 0xbe, 0xff, 0xc1, 0xff, 0xb5, 0xff, 0xb4, 0xff, 0xae, 0xff, 0xac, 0xff, 0xa8, 0xff, 0xa9, 0xff, 0xa5, 0xff, 0xa8, 0xff, 0xa5, 0xff, 0xa9, 0xff, 0xa8, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0x9a, 0xff, 0x9b, 0xff, 0x90, 0xff, 0x92, 0xff, 0x8a, 0xff, 0x8b, 0xff, 0x8a, 0xff, 0x8a, 0xff, 0x92, 0xff, 0x91, 0xff, 0x9d, 0xff, 0x9d, 0xff, 0xa6, 0xff, 0xa7, 0xff, 0xae, 0xff, 0xb1, 0xff, 0xba, 0xff, 0xbb, 0xff, 0xc6, 0xff, 0xc8, 0xff, 0xce, 0xff, 0xd4, 0xff, 0xd3, 0xff, 0xe1, 0xff, 0xd7, 0xff, 0xf1, 0xff, 0xd9, 0xff, 0x00, 0x00, 0xda, 0xff, 0x0f, 0x00, 0xdf, 0xff, 0x1e, 0x00, 0xeb, 0xff, 0x31, 0x00, 0xf8, 0xff, 0x42, 0x00, 0x02, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x59, 0x00, 0x08, 0x00, 0x65, 0x00, 0x09, 0x00, 0x77, 0x00, 0x08, 0x00, 0x89, 0x00, 0x08, 0x00, 0x99, 0x00, 0x06, 0x00, 0xa3, 0x00, 0x03, 0x00, 0xa7, 0x00, 0x01, 0x00, 0xac, 0x00, 0xfd, 0xff, 0xae, 0x00, 0xf5, 0xff, 0xaf, 0x00, 0xec, 0xff, 0xb1, 0x00, 0xe4, 0xff, 0xb5, 0x00, 0xe1, 0xff, 0xbd, 0x00, 0xde, 0xff, 0xc0, 0x00, 0xd8, 0xff, 0xbc, 0x00, 0xcc, 0xff, 0xad, 0x00, 0xbb, 0xff, 0x98, 0x00, 0xa9, 0xff, 0x81, 0x00, 0x9a, 0xff, 0x6c, 0x00, 0x90, 0xff, 0x5b, 0x00, 0x88, 0xff, 0x49, 0x00, 0x7f, 0xff, 0x34, 0x00, 0x70, 0xff, 0x1b, 0x00, 0x5e, 0xff, 0xfd, 0xff, 0x4a, 0xff, 0xdf, 0xff, 0x39, 0xff, 0xc3, 0xff, 0x32, 0xff, 0xae, 0xff, 0x37, 0xff, 0xa0, 0xff, 0x44, 0xff, 0x98, 0xff, 0x52, 0xff, 0x90, 0xff, 0x5c, 0xff, 0x86, 0xff, 0x62, 0xff, 0x7b, 0xff, 0x62, 0xff, 0x6f, 0xff, 0x5f, 0xff, 0x65, 0xff, 0x5d, 0xff, 0x60, 0xff, 0x5e, 0xff, 0x5f, 0xff, 0x66, 0xff, 0x62, 0xff, 0x76, 0xff, 0x69, 0xff, 0x86, 0xff, 0x6d, 0xff, 0x91, 0xff, 0x6a, 0xff, 0x97, 0xff, 0x67, 0xff, 0x9d, 0xff, 0x67, 0xff, 0xa2, 0xff, 0x6b, 0xff, 0xa8, 0xff, 0x70, 0xff, 0xac, 0xff, 0x74, 0xff, 0xad, 0xff, 0x73, 0xff, 0xa8, 0xff, 0x68, 0xff, 0x9d, 0xff, 0x54, 0xff, 0x91, 0xff, 0x3c, 0xff, 0x85, 0xff, 0x26, 0xff, 0x7a, 0xff, 0x15, 0xff, 0x77, 0xff, 0x0e, 0xff, 0x7b, 0xff, 0x11, 0xff, 0x81, 0xff, 0x15, 0xff, 0x81, 0xff, 0x12, 0xff, 0x79, 0xff, 0x05, 0xff, 0x6d, 0xff, 0xf5, 0xfe, 0x66, 0xff, 0xe8, 0xfe, 0x68, 0xff, 0xe4, 0xfe, 0x74, 0xff, 0xea, 0xfe, 0x86, 0xff, 0xf7, 0xfe, 0x96, 0xff, 0x00, 0xff, 0xa3, 0xff, 0x09, 0xff, 0xb0, 0xff, 0x16, 0xff, 0xbe, 0xff, 0x25, 0xff, 0xcd, 0xff, 0x3a, 0xff, 0xdf, 0xff, 0x53, 0xff, 0xf4, 0xff, 0x72, 0xff, 0x06, 0x00, 0x8e, 0xff, 0x16, 0x00, 0xa7, 0xff, 0x25, 0x00, 0xbe, 0xff, 0x35, 0x00, 0xd5, 0xff, 0x48, 0x00, 0xee, 0xff, 0x5b, 0x00, 0x09, 0x00, 0x6e, 0x00, 0x29, 0x00, 0x7b, 0x00, 0x46, 0x00, 0x7d, 0x00, 0x57, 0x00, 0x74, 0x00, 0x5e, 0x00, 0x67, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x5b, 0x00, 0x62, 0x00, 0x60, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x7b, 0x00, 0x6e, 0x00, 0x85, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x5c, 0x00, 0x80, 0x00, 0x47, 0x00, 0x71, 0x00, 0x33, 0x00, 0x61, 0x00, 0x29, 0x00, 0x58, 0x00, 0x2b, 0x00, 0x58, 0x00, 0x36, 0x00, 0x5f, 0x00, 0x43, 0x00, 0x67, 0x00, 0x4a, 0x00, 0x68, 0x00, 0x49, 0x00, 0x61, 0x00, 0x44, 0x00, 0x56, 0x00, 0x40, 0x00, 0x4d, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x44, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x64, 0x00, 0x50, 0x00, 0x60, 0x00, 0x43, 0x00, 0x5c, 0x00, 0x38, 0x00, 0x5e, 0x00, 0x34, 0x00, 0x64, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3a, 0x00, 0x6e, 0x00, 0x3c, 0x00, 0x6f, 0x00, 0x3a, 0x00, 0x6d, 0x00, 0x34, 0x00, 0x69, 0x00, 0x2b, 0x00, 0x65, 0x00, 0x1f, 0x00, 0x63, 0x00, 0x15, 0x00, 0x60, 0x00, 0x0d, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x5a, 0x00, 0x02, 0x00, 0x54, 0x00, 0xf8, 0xff, 0x4b, 0x00, 0xeb, 0xff, 0x3f, 0x00, 0xd9, 0xff, 0x31, 0x00, 0xc5, 0xff, 0x25, 0x00, 0xb4, 0xff, 0x1e, 0x00, 0xa8, 0xff, 0x17, 0x00, 0x9d, 0xff, 0x0d, 0x00, 0x90, 0xff, 0x01, 0x00, 0x82, 0xff, 0xf3, 0xff, 0x73, 0xff, 0xe2, 0xff, 0x63, 0xff, 0xd5, 0xff, 0x58, 0xff, 0xcb, 0xff, 0x53, 0xff, 0xc3, 0xff, 0x54, 0xff, 0xbc, 0xff, 0x57, 0xff, 0xb5, 0xff, 0x59, 0xff, 0xae, 0xff, 0x5a, 0xff, 0xa6, 0xff, 0x58, 0xff, 0xa1, 0xff, 0x59, 0xff, 0xa3, 0xff, 0x61, 0xff, 0xa8, 0xff, 0x6e, 0xff, 0xae, 0xff, 0x7f, 0xff, 0xb3, 0xff, 0x91, 0xff, 0xb2, 0xff, 0x9e, 0xff, 0xab, 0xff, 0xa5, 0xff, 0xa2, 0xff, 0xab, 0xff, 0x9e, 0xff, 0xb4, 0xff, 0xa4, 0xff, 0xc7, 0xff, 0xb4, 0xff, 0xe2, 0xff, 0xc8, 0xff, 0x02, 0x00, 0xdb, 0xff, 0x22, 0x00, 0xe8, 0xff, 0x3c, 0x00, 0xf0, 0xff, 0x53, 0x00, 0xf5, 0xff, 0x66, 0x00, 0xf9, 0xff, 0x77, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x0c, 0x00, 0xa1, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0x32, 0x00, 0xdd, 0x00, 0x44, 0x00, 0xf8, 0x00, 0x50, 0x00, 0x0c, 0x01, 0x54, 0x00, 0x16, 0x01, 0x57, 0x00, 0x1d, 0x01, 0x59, 0x00, 0x25, 0x01, 0x5b, 0x00, 0x2b, 0x01, 0x5e, 0x00, 0x31, 0x01, 0x5e, 0x00, 0x33, 0x01, 0x58, 0x00, 0x2c, 0x01, 0x4e, 0x00, 0x1d, 0x01, 0x45, 0x00, 0x0a, 0x01, 0x41, 0x00, 0xf7, 0x00, 0x3f, 0x00, 0xe3, 0x00, 0x3d, 0x00, 0xd1, 0x00, 0x3e, 0x00, 0xc6, 0x00, 0x3e, 0x00, 0xbb, 0x00, 0x38, 0x00, 0xad, 0x00, 0x2e, 0x00, 0x9b, 0x00, 0x24, 0x00, 0x84, 0x00, 0x19, 0x00, 0x6a, 0x00, 0x12, 0x00, 0x4e, 0x00, 0x0c, 0x00, 0x32, 0x00, 0x07, 0x00, 0x17, 0x00, 0x01, 0x00, 0xfd, 0xff, 0xf7, 0xff, 0xe1, 0xff, 0xe4, 0xff, 0xc1, 0xff, 0xcf, 0xff, 0xa3, 0xff, 0xc1, 0xff, 0x8f, 0xff, 0xbc, 0xff, 0x85, 0xff, 0xbe, 0xff, 0x81, 0xff, 0xc4, 0xff, 0x81, 0xff, 0xca, 0xff, 0x7e, 0xff, 0xca, 0xff, 0x78, 0xff, 0xc3, 0xff, 0x6d, 0xff, 0xb8, 0xff, 0x63, 0xff, 0xac, 0xff, 0x5b, 0xff, 0xa6, 0xff, 0x5d, 0xff, 0xa6, 0xff, 0x68, 0xff, 0xa7, 0xff, 0x75, 0xff, 0xa6, 0xff, 0x7c, 0xff, 0xa0, 0xff, 0x7c, 0xff, 0x99, 0xff, 0x76, 0xff, 0x92, 0xff, 0x6e, 0xff, 0x91, 0xff, 0x6c, 0xff, 0x97, 0xff, 0x74, 0xff, 0xa2, 0xff, 0x82, 0xff, 0xb0, 0xff, 0x92, 0xff, 0xba, 0xff, 0x9f, 0xff, 0xbd, 0xff, 0xa4, 0xff, 0xbb, 0xff, 0xa0, 0xff, 0xb4, 0xff, 0x94, 0xff, 0xb2, 0xff, 0x8a, 0xff, 0xb6, 0xff, 0x83, 0xff, 0xbe, 0xff, 0x82, 0xff, 0xc5, 0xff, 0x85, 0xff, 0xc7, 0xff, 0x87, 0xff, 0xc3, 0xff, 0x87, 0xff, 0xbc, 0xff, 0x83, 0xff, 0xb7, 0xff, 0x82, 0xff, 0xb8, 0xff, 0x87, 0xff, 0xc0, 0xff, 0x94, 0xff, 0xcc, 0xff, 0xa5, 0xff, 0xd9, 0xff, 0xbb, 0xff, 0xe3, 0xff, 0xd1, 0xff, 0xe7, 0xff, 0xe2, 0xff, 0xe7, 0xff, 0xf3, 0xff, 0xe9, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x21, 0x00, 0x03, 0x00, 0x3f, 0x00, 0x14, 0x00, 0x5c, 0x00, 0x22, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x87, 0x00, 0x3c, 0x00, 0x9c, 0x00, 0x4d, 0x00, 0xb2, 0x00, 0x62, 0x00, 0xc7, 0x00, 0x74, 0x00, 0xd8, 0x00, 0x81, 0x00, 0xe4, 0x00, 0x8a, 0x00, 0xec, 0x00, 0x90, 0x00, 0xf1, 0x00, 0x93, 0x00, 0xf4, 0x00, 0x91, 0x00, 0xf3, 0x00, 0x8d, 0x00, 0xed, 0x00, 0x8e, 0x00, 0xe9, 0x00, 0x97, 0x00, 0xeb, 0x00, 0xa5, 0x00, 0xef, 0x00, 0xae, 0x00, 0xee, 0x00, 0xac, 0x00, 0xe5, 0x00, 0xa4, 0x00, 0xd9, 0x00, 0x96, 0x00, 0xca, 0x00, 0x84, 0x00, 0xb9, 0x00, 0x6f, 0x00, 0xa3, 0x00, 0x5b, 0x00, 0x8d, 0x00, 0x4f, 0x00, 0x7d, 0x00, 0x47, 0x00, 0x70, 0x00, 0x3b, 0x00, 0x5e, 0x00, 0x25, 0x00, 0x46, 0x00, 0x0a, 0x00, 0x29, 0x00, 0xef, 0xff, 0x10, 0x00, 0xd9, 0xff, 0xfc, 0xff, 0xc8, 0xff, 0xec, 0xff, 0xba, 0xff, 0xdd, 0xff, 0xac, 0xff, 0xcb, 0xff, 0xa0, 0xff, 0xb9, 0xff, 0x98, 0xff, 0xa9, 0xff, 0x96, 0xff, 0x9e, 0xff, 0x98, 0xff, 0x98, 0xff, 0x9a, 0xff, 0x92, 0xff, 0x9d, 0xff, 0x8d, 0xff, 0xa4, 0xff, 0x8d, 0xff, 0xaf, 0xff, 0x90, 0xff, 0xb9, 0xff, 0x92, 0xff, 0xc0, 0xff, 0x8f, 0xff, 0xc2, 0xff, 0x88, 0xff, 0xc3, 0xff, 0x7f, 0xff, 0xc6, 0xff, 0x76, 0xff, 0xd0, 0xff, 0x73, 0xff, 0xe3, 0xff, 0x78, 0xff, 0xf5, 0xff, 0x80, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x80, 0xff, 0xf4, 0xff, 0x77, 0xff, 0xe7, 0xff, 0x6e, 0xff, 0xe0, 0xff, 0x6b, 0xff, 0xe2, 0xff, 0x70, 0xff, 0xe6, 0xff, 0x79, 0xff, 0xec, 0xff, 0x84, 0xff, 0xef, 0xff, 0x8e, 0xff, 0xe8, 0xff, 0x90, 0xff, 0xd6, 0xff, 0x89, 0xff, 0xc6, 0xff, 0x83, 0xff, 0xbe, 0xff, 0x87, 0xff, 0xbe, 0xff, 0x92, 0xff, 0xc1, 0xff, 0xa0, 0xff, 0xc3, 0xff, 0xaf, 0xff, 0xc1, 0xff, 0xba, 0xff, 0xb8, 0xff, 0xbd, 0xff, 0xaf, 0xff, 0xbe, 0xff, 0xac, 0xff, 0xc1, 0xff, 0xb1, 0xff, 0xc8, 0xff, 0xbc, 0xff, 0xd5, 0xff, 0xcd, 0xff, 0xe7, 0xff, 0xdd, 0xff, 0xf9, 0xff, 0xe4, 0xff, 0x03, 0x00, 0xe2, 0xff, 0x07, 0x00, 0xde, 0xff, 0x09, 0x00, 0xde, 0xff, 0x0e, 0x00, 0xe7, 0xff, 0x19, 0x00, 0xfc, 0xff, 0x2c, 0x00, 0x15, 0x00, 0x41, 0x00, 0x29, 0x00, 0x52, 0x00, 0x30, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x57, 0x00, 0x21, 0x00, 0x54, 0x00, 0x1c, 0x00, 0x55, 0x00, 0x21, 0x00, 0x5e, 0x00, 0x2d, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x7a, 0x00, 0x48, 0x00, 0x85, 0x00, 0x4c, 0x00, 0x88, 0x00, 0x49, 0x00, 0x87, 0x00, 0x3f, 0x00, 0x82, 0x00, 0x33, 0x00, 0x7d, 0x00, 0x2b, 0x00, 0x7d, 0x00, 0x28, 0x00, 0x81, 0x00, 0x29, 0x00, 0x86, 0x00, 0x29, 0x00, 0x88, 0x00, 0x26, 0x00, 0x87, 0x00, 0x1c, 0x00, 0x7f, 0x00, 0x0c, 0x00, 0x70, 0x00, 0xfc, 0xff, 0x61, 0x00, 0xf3, 0xff, 0x58, 0x00, 0xee, 0xff, 0x52, 0x00, 0xe6, 0xff, 0x4a, 0x00, 0xdb, 0xff, 0x3f, 0x00, 0xca, 0xff, 0x2d, 0x00, 0xb9, 0xff, 0x16, 0x00, 0xab, 0xff, 0x00, 0x00, 0xa2, 0xff, 0xeb, 0xff, 0x9d, 0xff, 0xdb, 0xff, 0x99, 0xff, 0xcb, 0xff, 0x93, 0xff, 0xb8, 0xff, 0x86, 0xff, 0x9f, 0xff, 0x74, 0xff, 0x80, 0xff, 0x62, 0xff, 0x64, 0xff, 0x5b, 0xff, 0x50, 0xff, 0x5f, 0xff, 0x45, 0xff, 0x68, 0xff, 0x3f, 0xff, 0x71, 0xff, 0x36, 0xff, 0x76, 0xff, 0x2b, 0xff, 0x79, 0xff, 0x20, 0xff, 0x7f, 0xff, 0x1a, 0xff, 0x8b, 0xff, 0x1b, 0xff, 0x9a, 0xff, 0x1f, 0xff, 0xac, 0xff, 0x26, 0xff, 0xc2, 0xff, 0x33, 0xff, 0xda, 0xff, 0x43, 0xff, 0xeb, 0xff, 0x51, 0xff, 0xf2, 0xff, 0x57, 0xff, 0xf1, 0xff, 0x58, 0xff, 0xf0, 0xff, 0x59, 0xff, 0xf6, 0xff, 0x63, 0xff, 0x02, 0x00, 0x72, 0xff, 0x0c, 0x00, 0x81, 0xff, 0x0e, 0x00, 0x8c, 0xff, 0x0b, 0x00, 0x93, 0xff, 0x04, 0x00, 0x99, 0xff, 0xfb, 0xff, 0x9f, 0xff, 0xf3, 0xff, 0xa5, 0xff, 0xf1, 0xff, 0xb1, 0xff, 0xfb, 0xff, 0xc5, 0xff, 0x0c, 0x00, 0xdd, 0xff, 0x1e, 0x00, 0xf6, 0xff, 0x2e, 0x00, 0x0c, 0x00, 0x37, 0x00, 0x1c, 0x00, 0x39, 0x00, 0x26, 0x00, 0x3d, 0x00, 0x31, 0x00, 0x48, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x59, 0x00, 0x74, 0x00, 0x74, 0x00, 0x96, 0x00, 0x95, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xcc, 0x00, 0xc5, 0x00, 0xdc, 0x00, 0xd2, 0x00, 0xe9, 0x00, 0xdd, 0x00, 0xf2, 0x00, 0xe3, 0x00, 0xf8, 0x00, 0xe6, 0x00, 0xf9, 0x00, 0xe5, 0x00, 0xfb, 0x00, 0xe6, 0x00, 0xfe, 0x00, 0xea, 0x00, 0x06, 0x01, 0xf1, 0x00, 0x0d, 0x01, 0xf5, 0x00, 0x0c, 0x01, 0xf0, 0x00, 0x05, 0x01, 0xe6, 0x00, 0xfb, 0x00, 0xd9, 0x00, 0xf1, 0x00, 0xce, 0x00, 0xea, 0x00, 0xc9, 0x00, 0xeb, 0x00, 0xcb, 0x00, 0xed, 0x00, 0xce, 0x00, 0xe5, 0x00, 0xc7, 0x00, 0xd5, 0x00, 0xb9, 0x00, 0xbf, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x65, 0x00, 0x6a, 0x00, 0x52, 0x00, 0x57, 0x00, 0x3f, 0x00, 0x47, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x22, 0x00, 0x30, 0x00, 0x16, 0x00, 0x22, 0x00, 0x07, 0x00, 0x0f, 0x00, 0xf4, 0xff, 0xfb, 0xff, 0xe1, 0xff, 0xec, 0xff, 0xd1, 0xff, 0xe6, 0xff, 0xc9, 0xff, 0xe5, 0xff, 0xc5, 0xff, 0xe4, 0xff, 0xc1, 0xff, 0xdf, 0xff, 0xba, 0xff, 0xd5, 0xff, 0xb1, 0xff, 0xc6, 0xff, 0xa5, 0xff, 0xb5, 0xff, 0x98, 0xff, 0xa8, 0xff, 0x8e, 0xff, 0x9e, 0xff, 0x86, 0xff, 0x97, 0xff, 0x7e, 0xff, 0x90, 0xff, 0x77, 0xff, 0x89, 0xff, 0x71, 0xff, 0x83, 0xff, 0x6f, 0xff, 0x7d, 0xff, 0x70, 0xff, 0x74, 0xff, 0x71, 0xff, 0x68, 0xff, 0x70, 0xff, 0x5d, 0xff, 0x6c, 0xff, 0x57, 0xff, 0x6a, 0xff, 0x56, 0xff, 0x69, 0xff, 0x5a, 0xff, 0x6d, 0xff, 0x61, 0xff, 0x75, 0xff, 0x67, 0xff, 0x7f, 0xff, 0x6b, 0xff, 0x87, 0xff, 0x6d, 0xff, 0x8d, 0xff, 0x70, 0xff, 0x91, 0xff, 0x75, 0xff, 0x97, 0xff, 0x78, 0xff, 0x9a, 0xff, 0x7b, 0xff, 0x9e, 0xff, 0x7c, 0xff, 0xa3, 0xff, 0x81, 0xff, 0xac, 0xff, 0x8a, 0xff, 0xba, 0xff, 0x96, 0xff, 0xc9, 0xff, 0xa4, 0xff, 0xd9, 0xff, 0xb4, 0xff, 0xe7, 0xff, 0xc1, 0xff, 0xf4, 0xff, 0xcd, 0xff, 0x00, 0x00, 0xd8, 0xff, 0x0e, 0x00, 0xe5, 0xff, 0x23, 0x00, 0xf9, 0xff, 0x3f, 0x00, 0x11, 0x00, 0x5f, 0x00, 0x2d, 0x00, 0x7f, 0x00, 0x47, 0x00, 0x9a, 0x00, 0x56, 0x00, 0xab, 0x00, 0x5e, 0x00, 0xb6, 0x00, 0x5f, 0x00, 0xbe, 0x00, 0x5d, 0x00, 0xc5, 0x00, 0x5a, 0x00, 0xce, 0x00, 0x57, 0x00, 0xd6, 0x00, 0x53, 0x00, 0xdc, 0x00, 0x4c, 0x00, 0xdd, 0x00, 0x42, 0x00, 0xd9, 0x00, 0x32, 0x00, 0xcc, 0x00, 0x1c, 0x00, 0xba, 0x00, 0x08, 0x00, 0xa8, 0x00, 0xf7, 0xff, 0x99, 0x00, 0xe9, 0xff, 0x8c, 0x00, 0xdb, 0xff, 0x7e, 0x00, 0xcd, 0xff, 0x70, 0x00, 0xbf, 0xff, 0x5f, 0x00, 0xac, 0xff, 0x49, 0x00, 0x9a, 0xff, 0x31, 0x00, 0x8d, 0xff, 0x1d, 0x00, 0x87, 0xff, 0x0d, 0x00, 0x86, 0xff, 0xff, 0xff, 0x83, 0xff, 0xed, 0xff, 0x7c, 0xff, 0xd8, 0xff, 0x73, 0xff, 0xc0, 0xff, 0x64, 0xff, 0xa8, 0xff, 0x55, 0xff, 0x90, 0xff, 0x47, 0xff, 0x7a, 0xff, 0x41, 0xff, 0x69, 0xff, 0x43, 0xff, 0x5e, 0xff, 0x4a, 0xff, 0x55, 0xff, 0x53, 0xff, 0x4d, 0xff, 0x58, 0xff, 0x44, 0xff, 0x5c, 0xff, 0x3b, 0xff, 0x5e, 0xff, 0x35, 0xff, 0x5f, 0xff, 0x2e, 0xff, 0x5c, 0xff, 0x25, 0xff, 0x56, 0xff, 0x1b, 0xff, 0x59, 0xff, 0x19, 0xff, 0x6d, 0xff, 0x26, 0xff, 0x8b, 0xff, 0x3e, 0xff, 0x9e, 0xff, 0x4b, 0xff, 0x9c, 0xff, 0x45, 0xff, 0x92, 0xff, 0x37, 0xff, 0x90, 0xff, 0x34, 0xff, 0x9a, 0xff, 0x3c, 0xff, 0xa0, 0xff, 0x43, 0xff, 0x9d, 0xff, 0x42, 0xff, 0x9e, 0xff, 0x45, 0xff, 0xb0, 0xff, 0x5a, 0xff, 0xcd, 0xff, 0x7a, 0xff, 0xe4, 0xff, 0x94, 0xff, 0xeb, 0xff, 0x9f, 0xff, 0xe5, 0xff, 0x9b, 0xff, 0xd9, 0xff, 0x90, 0xff, 0xcc, 0xff, 0x85, 0xff, 0xca, 0xff, 0x85, 0xff, 0xd5, 0xff, 0x95, 0xff, 0xeb, 0xff, 0xae, 0xff, 0xfb, 0xff, 0xc0, 0xff, 0xfd, 0xff, 0xc0, 0xff, 0xf4, 0xff, 0xb2, 0xff, 0xed, 0xff, 0xa7, 0xff, 0xf4, 0xff, 0xac, 0xff, 0x05, 0x00, 0xbd, 0xff, 0x19, 0x00, 0xd3, 0xff, 0x2b, 0x00, 0xe6, 0xff, 0x37, 0x00, 0xf1, 0xff, 0x3e, 0x00, 0xf5, 0xff, 0x44, 0x00, 0xf6, 0xff, 0x49, 0x00, 0xf3, 0xff, 0x4e, 0x00, 0xf1, 0xff, 0x57, 0x00, 0xf6, 0xff, 0x6e, 0x00, 0x0c, 0x00, 0x97, 0x00, 0x36, 0x00, 0xc2, 0x00, 0x62, 0x00, 0xda, 0x00, 0x79, 0x00, 0xda, 0x00, 0x77, 0x00, 0xd3, 0x00, 0x6c, 0x00, 0xd5, 0x00, 0x6e, 0x00, 0xe5, 0x00, 0x82, 0x00, 0xfd, 0x00, 0xa2, 0x00, 0x16, 0x01, 0xc2, 0x00, 0x30, 0x01, 0xe2, 0x00, 0x44, 0x01, 0xfa, 0x00, 0x4b, 0x01, 0x03, 0x01, 0x46, 0x01, 0xfe, 0x00, 0x38, 0x01, 0xef, 0x00, 0x27, 0x01, 0xdf, 0x00, 0x1a, 0x01, 0xd7, 0x00, 0x18, 0x01, 0xdb, 0x00, 0x1d, 0x01, 0xe7, 0x00, 0x22, 0x01, 0xf0, 0x00, 0x18, 0x01, 0xe6, 0x00, 0xf7, 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x8b, 0x00, 0x93, 0x00, 0x58, 0x00, 0x77, 0x00, 0x3b, 0x00, 0x72, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x3e, 0x00, 0x78, 0x00, 0x38, 0x00, 0x5f, 0x00, 0x1c, 0x00, 0x35, 0x00, 0xee, 0xff, 0x0a, 0x00, 0xc3, 0xff, 0xf0, 0xff, 0xa8, 0xff, 0xe6, 0xff, 0xa0, 0xff, 0xde, 0xff, 0x9b, 0xff, 0xcc, 0xff, 0x8b, 0xff, 0xb2, 0xff, 0x72, 0xff, 0x97, 0xff, 0x5a, 0xff, 0x84, 0xff, 0x4c, 0xff, 0x79, 0xff, 0x48, 0xff, 0x6e, 0xff, 0x45, 0xff, 0x66, 0xff, 0x45, 0xff, 0x61, 0xff, 0x48, 0xff, 0x65, 0xff, 0x4f, 0xff, 0x70, 0xff, 0x5b, 0xff, 0x84, 0xff, 0x6f, 0xff, 0x9e, 0xff, 0x89, 0xff, 0xb5, 0xff, 0xa2, 0xff, 0xc3, 0xff, 0xb6, 0xff, 0xcc, 0xff, 0xc5, 0xff, 0xd8, 0xff, 0xd6, 0xff, 0xea, 0xff, 0xee, 0xff, 0x03, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x3c, 0x00, 0x3e, 0x00, 0x46, 0x00, 0x4b, 0x00, 0x4d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x6a, 0x00, 0x5a, 0x00, 0x7b, 0x00, 0x60, 0x00, 0x89, 0x00, 0x61, 0x00, 0x8f, 0x00, 0x5e, 0x00, 0x90, 0x00, 0x60, 0x00, 0x95, 0x00, 0x67, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0xae, 0x00, 0x75, 0x00, 0xbb, 0x00, 0x74, 0x00, 0xc1, 0x00, 0x6b, 0x00, 0xbe, 0x00, 0x5f, 0x00, 0xb6, 0x00, 0x54, 0x00, 0xb0, 0x00, 0x51, 0x00, 0xb2, 0x00, 0x56, 0x00, 0xbd, 0x00, 0x5c, 0x00, 0xc9, 0x00, 0x58, 0x00, 0xca, 0x00, 0x45, 0x00, 0xb8, 0x00, 0x26, 0x00, 0x97, 0x00, 0x0c, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x01, 0x00, 0x68, 0x00, 0x08, 0x00, 0x6d, 0x00, 0x0c, 0x00, 0x70, 0x00, 0x04, 0x00, 0x67, 0x00, 0xf3, 0xff, 0x52, 0x00, 0xdd, 0xff, 0x33, 0x00, 0xc6, 0xff, 0x13, 0x00, 0xb1, 0xff, 0xf3, 0xff, 0x9c, 0xff, 0xd8, 0xff, 0x8e, 0xff, 0xc5, 0xff, 0x84, 0xff, 0xb9, 0xff, 0x7f, 0xff, 0xaf, 0xff, 0x79, 0xff, 0xa1, 0xff, 0x6b, 0xff, 0x89, 0xff, 0x55, 0xff, 0x69, 0xff, 0x3d, 0xff, 0x48, 0xff, 0x2e, 0xff, 0x32, 0xff, 0x2b, 0xff, 0x2a, 0xff, 0x2f, 0xff, 0x2d, 0xff, 0x36, 0xff, 0x35, 0xff, 0x38, 0xff, 0x3a, 0xff, 0x33, 0xff, 0x38, 0xff, 0x2e, 0xff, 0x36, 0xff, 0x2f, 0xff, 0x3a, 0xff, 0x39, 0xff, 0x49, 0xff, 0x44, 0xff, 0x5c, 0xff, 0x4d, 0xff, 0x6c, 0xff, 0x54, 0xff, 0x77, 0xff, 0x59, 0xff, 0x7e, 0xff, 0x65, 0xff, 0x89, 0xff, 0x77, 0xff, 0x9b, 0xff, 0x87, 0xff, 0xac, 0xff, 0x91, 0xff, 0xb8, 0xff, 0x96, 0xff, 0xc0, 0xff, 0x98, 0xff, 0xc7, 0xff, 0x9c, 0xff, 0xcd, 0xff, 0xa2, 0xff, 0xd4, 0xff, 0xac, 0xff, 0xdb, 0xff, 0xb9, 0xff, 0xe3, 0xff, 0xc9, 0xff, 0xeb, 0xff, 0xdb, 0xff, 0xf8, 0xff, 0xec, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00, 0x07, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x19, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x15, 0x00, 0xf8, 0xff, 0x16, 0x00, 0xf8, 0xff, 0x20, 0x00, 0x01, 0x00, 0x2e, 0x00, 0x0d, 0x00, 0x3d, 0x00, 0x18, 0x00, 0x4a, 0x00, 0x21, 0x00, 0x52, 0x00, 0x22, 0x00, 0x56, 0x00, 0x20, 0x00, 0x5a, 0x00, 0x1f, 0x00, 0x5f, 0x00, 0x22, 0x00, 0x67, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x38, 0x00, 0x85, 0x00, 0x48, 0x00, 0x95, 0x00, 0x53, 0x00, 0x9d, 0x00, 0x57, 0x00, 0x9f, 0x00, 0x54, 0x00, 0xa0, 0x00, 0x52, 0x00, 0xa6, 0x00, 0x56, 0x00, 0xb3, 0x00, 0x64, 0x00, 0xc2, 0x00, 0x76, 0x00, 0xcf, 0x00, 0x87, 0x00, 0xd3, 0x00, 0x91, 0x00, 0xca, 0x00, 0x8e, 0x00, 0xb8, 0x00, 0x82, 0x00, 0xa6, 0x00, 0x76, 0x00, 0x98, 0x00, 0x70, 0x00, 0x8c, 0x00, 0x6e, 0x00, 0x81, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6a, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x46, 0x00, 0x54, 0x00, 0x30, 0x00, 0x47, 0x00, 0x1c, 0x00, 0x3e, 0x00, 0x08, 0x00, 0x37, 0x00, 0xf3, 0xff, 0x2f, 0x00, 0xdc, 0xff, 0x24, 0x00, 0xc0, 0xff, 0x12, 0x00, 0xa3, 0xff, 0xfc, 0xff, 0x88, 0xff, 0xe4, 0xff, 0x73, 0xff, 0xcf, 0xff, 0x64, 0xff, 0xc1, 0xff, 0x57, 0xff, 0xb9, 0xff, 0x45, 0xff, 0xb1, 0xff, 0x2d, 0xff, 0xa5, 0xff, 0x13, 0xff, 0x96, 0xff, 0xfc, 0xfe, 0x88, 0xff, 0xec, 0xfe, 0x7d, 0xff, 0xe3, 0xfe, 0x79, 0xff, 0xe4, 0xfe, 0x7e, 0xff, 0xec, 0xfe, 0x8a, 0xff, 0xf6, 0xfe, 0x98, 0xff, 0xfe, 0xfe, 0xa7, 0xff, 0x03, 0xff, 0xb4, 0xff, 0x08, 0xff, 0xc1, 0xff, 0x0d, 0xff, 0xcc, 0xff, 0x15, 0xff, 0xd9, 0xff, 0x22, 0xff, 0xe8, 0xff, 0x34, 0xff, 0xfa, 0xff, 0x46, 0xff, 0x0b, 0x00, 0x55, 0xff, 0x17, 0x00, 0x61, 0xff, 0x1f, 0x00, 0x69, 0xff, 0x21, 0x00, 0x74, 0xff, 0x25, 0x00, 0x88, 0xff, 0x31, 0x00, 0xa6, 0xff, 0x45, 0x00, 0xc9, 0xff, 0x5e, 0x00, 0xea, 0xff, 0x71, 0x00, 0x04, 0x00, 0x7c, 0x00, 0x1a, 0x00, 0x82, 0x00, 0x33, 0x00, 0x8a, 0x00, 0x51, 0x00, 0x97, 0x00, 0x75, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xc4, 0x00, 0xab, 0x00, 0xc5, 0x00, 0x9d, 0x00, 0xce, 0x00, 0x95, 0x00, 0xdf, 0x00, 0x94, 0x00, 0xef, 0x00, 0x93, 0x00, 0xf8, 0x00, 0x8d, 0x00, 0xf8, 0x00, 0x82, 0x00, 0xf4, 0x00, 0x78, 0x00, 0xee, 0x00, 0x6f, 0x00, 0xe6, 0x00, 0x66, 0x00, 0xe3, 0x00, 0x60, 0x00, 0xe2, 0x00, 0x5a, 0x00, 0xe1, 0x00, 0x52, 0x00, 0xda, 0x00, 0x45, 0x00, 0xcf, 0x00, 0x35, 0x00, 0xc0, 0x00, 0x25, 0x00, 0xb1, 0x00, 0x17, 0x00, 0xa8, 0x00, 0x10, 0x00, 0xa5, 0x00, 0x0f, 0x00, 0xa4, 0x00, 0x11, 0x00, 0xa2, 0x00, 0x0f, 0x00, 0x98, 0x00, 0x07, 0x00, 0x85, 0x00, 0xf6, 0xff, 0x6f, 0x00, 0xe2, 0xff, 0x5b, 0x00, 0xd1, 0xff, 0x4d, 0x00, 0xc8, 0xff, 0x45, 0x00, 0xc6, 0xff, 0x3b, 0x00, 0xc3, 0xff, 0x2f, 0x00, 0xc0, 0xff, 0x1b, 0x00, 0xb9, 0xff, 0xfe, 0xff, 0xaa, 0xff, 0xda, 0xff, 0x96, 0xff, 0xb4, 0xff, 0x7e, 0xff, 0x94, 0xff, 0x69, 0xff, 0x7f, 0xff, 0x5e, 0xff, 0x72, 0xff, 0x5b, 0xff, 0x69, 0xff, 0x5f, 0xff, 0x5e, 0xff, 0x65, 0xff, 0x4e, 0xff, 0x6a, 0xff, 0x37, 0xff, 0x66, 0xff, 0x1b, 0xff, 0x5a, 0xff, 0x01, 0xff, 0x4c, 0xff, 0xea, 0xfe, 0x3d, 0xff, 0xd7, 0xfe, 0x30, 0xff, 0xc7, 0xfe, 0x26, 0xff, 0xba, 0xfe, 0x1f, 0xff, 0xad, 0xfe, 0x17, 0xff, 0xa0, 0xfe, 0x0f, 0xff, 0x96, 0xfe, 0x08, 0xff, 0x92, 0xfe, 0x04, 0xff, 0x95, 0xfe, 0x06, 0xff, 0x9c, 0xfe, 0x0a, 0xff, 0xa5, 0xfe, 0x10, 0xff, 0xac, 0xfe, 0x14, 0xff, 0xb4, 0xfe, 0x19, 0xff, 0xc2, 0xfe, 0x20, 0xff, 0xd5, 0xfe, 0x2a, 0xff, 0xf1, 0xfe, 0x37, 0xff, 0x13, 0xff, 0x4a, 0xff, 0x3a, 0xff, 0x61, 0xff, 0x5d, 0xff, 0x79, 0xff, 0x7a, 0xff, 0x8e, 0xff, 0x92, 0xff, 0xa0, 0xff, 0xa8, 0xff, 0xae, 0xff, 0xc1, 0xff, 0xbc, 0xff, 0xe1, 0xff, 0xcc, 0xff, 0x05, 0x00, 0xe0, 0xff, 0x2d, 0x00, 0xf7, 0xff, 0x57, 0x00, 0x11, 0x00, 0x7f, 0x00, 0x2b, 0x00, 0xa2, 0x00, 0x44, 0x00, 0xbb, 0x00, 0x55, 0x00, 0xcc, 0x00, 0x5f, 0x00, 0xde, 0x00, 0x69, 0x00, 0xf1, 0x00, 0x74, 0x00, 0x04, 0x01, 0x7f, 0x00, 0x17, 0x01, 0x89, 0x00, 0x2c, 0x01, 0x94, 0x00, 0x40, 0x01, 0x9d, 0x00, 0x52, 0x01, 0xa4, 0x00, 0x60, 0x01, 0xa6, 0x00, 0x68, 0x01, 0xa6, 0x00, 0x67, 0x01, 0xa1, 0x00, 0x5e, 0x01, 0x97, 0x00, 0x4e, 0x01, 0x8a, 0x00, 0x3c, 0x01, 0x79, 0x00, 0x2a, 0x01, 0x66, 0x00, 0x1a, 0x01, 0x4f, 0x00, 0x09, 0x01, 0x37, 0x00, 0xf9, 0x00, 0x23, 0x00, 0xeb, 0x00, 0x15, 0x00, 0xdd, 0x00, 0x0e, 0x00, 0xce, 0x00, 0x09, 0x00, 0xbc, 0x00, 0x02, 0x00, 0xaa, 0x00, 0xf8, 0xff, 0x98, 0x00, 0xeb, 0xff, 0x89, 0x00, 0xdd, 0xff, 0x7f, 0x00, 0xd2, 0xff, 0x77, 0x00, 0xca, 0xff, 0x6e, 0x00, 0xc6, 0xff, 0x62, 0x00, 0xc4, 0xff, 0x55, 0x00, 0xc5, 0xff, 0x48, 0x00, 0xc7, 0xff, 0x38, 0x00, 0xc5, 0xff, 0x24, 0x00, 0xbd, 0xff, 0x0d, 0x00, 0xb2, 0xff, 0xf4, 0xff, 0xa7, 0xff, 0xdc, 0xff, 0x9e, 0xff, 0xc9, 0xff, 0x9d, 0xff, 0xb6, 0xff, 0x9f, 0xff, 0xa3, 0xff, 0xa1, 0xff, 0x91, 0xff, 0xa4, 0xff, 0x81, 0xff, 0xaa, 0xff, 0x73, 0xff, 0xb1, 0xff, 0x63, 0xff, 0xb6, 0xff, 0x4f, 0xff, 0xb7, 0xff, 0x38, 0xff, 0xb2, 0xff, 0x21, 0xff, 0xab, 0xff, 0x10, 0xff, 0xa6, 0xff, 0x06, 0xff, 0xa6, 0xff, 0xff, 0xfe, 0xa8, 0xff, 0xf9, 0xfe, 0xaa, 0xff, 0xf2, 0xfe, 0xac, 0xff, 0xee, 0xfe, 0xaf, 0xff, 0xef, 0xfe, 0xb6, 0xff, 0xef, 0xfe, 0xb9, 0xff, 0xf0, 0xfe, 0xba, 0xff, 0xf0, 0xfe, 0xb9, 0xff, 0xf6, 0xfe, 0xb9, 0xff, 0x00, 0xff, 0xbe, 0xff, 0x0f, 0xff, 0xca, 0xff, 0x24, 0xff, 0xde, 0xff, 0x3d, 0xff, 0xf7, 0xff, 0x57, 0xff, 0x0f, 0x00, 0x6e, 0xff, 0x21, 0x00, 0x82, 0xff, 0x2d, 0x00, 0x93, 0xff, 0x35, 0x00, 0xa3, 0xff, 0x3f, 0x00, 0xb7, 0xff, 0x4f, 0x00, 0xd1, 0xff, 0x65, 0x00, 0xed, 0xff, 0x7c, 0x00, 0x0b, 0x00, 0x93, 0x00, 0x28, 0x00, 0xa6, 0x00, 0x41, 0x00, 0xb7, 0x00, 0x54, 0x00, 0xc5, 0x00, 0x64, 0x00, 0xd2, 0x00, 0x74, 0x00, 0xe0, 0x00, 0x85, 0x00, 0xed, 0x00, 0x95, 0x00, 0xf8, 0x00, 0xa3, 0x00, 0xfd, 0x00, 0xab, 0x00, 0xfd, 0x00, 0xac, 0x00, 0xf6, 0x00, 0xab, 0x00, 0xee, 0x00, 0xa9, 0x00, 0xe7, 0x00, 0xa5, 0x00, 0xde, 0x00, 0x9f, 0x00, 0xd3, 0x00, 0x98, 0x00, 0xc4, 0x00, 0x95, 0x00, 0xb7, 0x00, 0x96, 0x00, 0xa8, 0x00, 0x96, 0x00, 0x95, 0x00, 0x93, 0x00, 0x7f, 0x00, 0x91, 0x00, 0x6a, 0x00, 0x90, 0x00, 0x5a, 0x00, 0x93, 0x00, 0x50, 0x00, 0x99, 0x00, 0x48, 0x00, 0x9c, 0x00, 0x3e, 0x00, 0x99, 0x00, 0x2b, 0x00, 0x8e, 0x00, 0x10, 0x00, 0x7e, 0x00, 0xf4, 0xff, 0x72, 0x00, 0xe0, 0xff, 0x69, 0x00, 0xd3, 0xff, 0x63, 0x00, 0xcb, 0xff, 0x63, 0x00, 0xc8, 0xff, 0x64, 0x00, 0xc4, 0xff, 0x63, 0x00, 0xbf, 0xff, 0x60, 0x00, 0xba, 0xff, 0x5b, 0x00, 0xb9, 0xff, 0x54, 0x00, 0xba, 0xff, 0x4a, 0x00, 0xbb, 0xff, 0x3f, 0x00, 0xba, 0xff, 0x34, 0x00, 0xb9, 0xff, 0x2a, 0x00, 0xb5, 0xff, 0x1e, 0x00, 0xae, 0xff, 0x12, 0x00, 0xa9, 0xff, 0x06, 0x00, 0xa5, 0xff, 0xf7, 0xff, 0xa3, 0xff, 0xe9, 0xff, 0xa4, 0xff, 0xdd, 0xff, 0xa4, 0xff, 0xcf, 0xff, 0xa1, 0xff, 0xc0, 0xff, 0x96, 0xff, 0xb0, 0xff, 0x87, 0xff, 0xa0, 0xff, 0x77, 0xff, 0x8d, 0xff, 0x65, 0xff, 0x7b, 0xff, 0x58, 0xff, 0x71, 0xff, 0x54, 0xff, 0x6c, 0xff, 0x55, 0xff, 0x68, 0xff, 0x54, 0xff, 0x66, 0xff, 0x51, 0xff, 0x62, 0xff, 0x4b, 0xff, 0x5f, 0xff, 0x43, 0xff, 0x60, 0xff, 0x40, 0xff, 0x66, 0xff, 0x43, 0xff, 0x6d, 0xff, 0x4a, 0xff, 0x78, 0xff, 0x55, 0xff, 0x87, 0xff, 0x64, 0xff, 0x99, 0xff, 0x75, 0xff, 0xa9, 0xff, 0x83, 0xff, 0xb7, 0xff, 0x91, 0xff, 0xc6, 0xff, 0xa3, 0xff, 0xd6, 0xff, 0xb7, 0xff, 0xe6, 0xff, 0xcb, 0xff, 0xf6, 0xff, 0xdf, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x15, 0x00, 0x04, 0x00, 0x22, 0x00, 0x17, 0x00, 0x2c, 0x00, 0x28, 0x00, 0x32, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3f, 0x00, 0x43, 0x00, 0x4b, 0x00, 0x4d, 0x00, 0x55, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x62, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8f, 0x00, 0x93, 0x00, 0x94, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x9d, 0x00, 0x90, 0x00, 0x9a, 0x00, 0x8e, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x9e, 0x00, 0x93, 0x00, 0xaa, 0x00, 0x9b, 0x00, 0xb6, 0x00, 0xa0, 0x00, 0xbf, 0x00, 0xa3, 0x00, 0xc4, 0x00, 0xa5, 0x00, 0xc6, 0x00, 0xa6, 0x00, 0xc1, 0x00, 0xa3, 0x00, 0xbb, 0x00, 0x9d, 0x00, 0xb9, 0x00, 0x98, 0x00, 0xba, 0x00, 0x94, 0x00, 0xbb, 0x00, 0x8e, 0x00, 0xb5, 0x00, 0x85, 0x00, 0xa8, 0x00, 0x76, 0x00, 0x98, 0x00, 0x69, 0x00, 0x8c, 0x00, 0x62, 0x00, 0x85, 0x00, 0x61, 0x00, 0x7e, 0x00, 0x60, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x63, 0x00, 0x51, 0x00, 0x4b, 0x00, 0x3e, 0x00, 0x2d, 0x00, 0x26, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xd8, 0xff, 0xf5, 0xff, 0xbf, 0xff, 0xef, 0xff, 0xa9, 0xff, 0xea, 0xff, 0x92, 0xff, 0xe1, 0xff, 0x79, 0xff, 0xd2, 0xff, 0x5f, 0xff, 0xc3, 0xff, 0x49, 0xff, 0xbc, 0xff, 0x35, 0xff, 0xba, 0xff, 0x24, 0xff, 0xbc, 0xff, 0x18, 0xff, 0xbd, 0xff, 0x11, 0xff, 0xbb, 0xff, 0x0d, 0xff, 0xb8, 0xff, 0x10, 0xff, 0xb9, 0xff, 0x15, 0xff, 0xbd, 0xff, 0x1b, 0xff, 0xc2, 0xff, 0x23, 0xff, 0xc9, 0xff, 0x2d, 0xff, 0xd4, 0xff, 0x3a, 0xff, 0xdf, 0xff, 0x47, 0xff, 0xe5, 0xff, 0x4f, 0xff, 0xe5, 0xff, 0x59, 0xff, 0xe2, 0xff, 0x63, 0xff, 0xe0, 0xff, 0x6c, 0xff, 0xe2, 0xff, 0x77, 0xff, 0xe8, 0xff, 0x80, 0xff, 0xef, 0xff, 0x89, 0xff, 0xf5, 0xff, 0x94, 0xff, 0xfa, 0xff, 0xa0, 0xff, 0xfb, 0xff, 0xaa, 0xff, 0xfa, 0xff, 0xb5, 0xff, 0xfa, 0xff, 0xc1, 0xff, 0xfc, 0xff, 0xcf, 0xff, 0x05, 0x00, 0xe1, 0xff, 0x11, 0x00, 0xf1, 0xff, 0x1b, 0x00, 0xfc, 0xff, 0x1e, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x09, 0x00, 0x16, 0x00, 0x14, 0x00, 0x14, 0x00, 0x21, 0x00, 0x16, 0x00, 0x2f, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x4e, 0x00, 0x23, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x65, 0x00, 0x1f, 0x00, 0x70, 0x00, 0x1c, 0x00, 0x7f, 0x00, 0x20, 0x00, 0x91, 0x00, 0x29, 0x00, 0xa3, 0x00, 0x34, 0x00, 0xaf, 0x00, 0x3a, 0x00, 0xb8, 0x00, 0x3c, 0x00, 0xbc, 0x00, 0x38, 0x00, 0xbc, 0x00, 0x2f, 0x00, 0xbc, 0x00, 0x25, 0x00, 0xbe, 0x00, 0x20, 0x00, 0xc2, 0x00, 0x21, 0x00, 0xc2, 0x00, 0x22, 0x00, 0xbf, 0x00, 0x23, 0x00, 0xba, 0x00, 0x22, 0x00, 0xb1, 0x00, 0x1c, 0x00, 0xa2, 0x00, 0x0f, 0x00, 0x92, 0x00, 0x00, 0x00, 0x84, 0x00, 0xf6, 0xff, 0x78, 0x00, 0xf1, 0xff, 0x6b, 0x00, 0xf1, 0xff, 0x5f, 0x00, 0xf6, 0xff, 0x51, 0x00, 0xf9, 0xff, 0x3c, 0x00, 0xf4, 0xff, 0x21, 0x00, 0xe5, 0xff, 0x00, 0x00, 0xd1, 0xff, 0xe0, 0xff, 0xbe, 0xff, 0xc4, 0xff, 0xb3, 0xff, 0xae, 0xff, 0xad, 0xff, 0x9c, 0xff, 0xaa, 0xff, 0x89, 0xff, 0xa5, 0xff, 0x70, 0xff, 0x99, 0xff, 0x4f, 0xff, 0x84, 0xff, 0x2d, 0xff, 0x6d, 0xff, 0x14, 0xff, 0x5f, 0xff, 0x0c, 0xff, 0x64, 0xff, 0x07, 0xff, 0x6a, 0xff, 0xf5, 0xfe, 0x63, 0xff, 0xda, 0xfe, 0x50, 0xff, 0xc8, 0xfe, 0x44, 0xff, 0xc5, 0xfe, 0x46, 0xff, 0xc6, 0xfe, 0x4c, 0xff, 0xc0, 0xfe, 0x4f, 0xff, 0xb2, 0xfe, 0x4b, 0xff, 0xa8, 0xfe, 0x4b, 0xff, 0xae, 0xfe, 0x59, 0xff, 0xc1, 0xfe, 0x71, 0xff, 0xd1, 0xfe, 0x81, 0xff, 0xd5, 0xfe, 0x82, 0xff, 0xd7, 0xfe, 0x81, 0xff, 0xe0, 0xfe, 0x89, 0xff, 0xf3, 0xfe, 0x9c, 0xff, 0x0e, 0xff, 0xb7, 0xff, 0x29, 0xff, 0xce, 0xff, 0x38, 0xff, 0xd4, 0xff, 0x40, 0xff, 0xce, 0xff, 0x4f, 0xff, 0xcd, 0xff, 0x67, 0xff, 0xd8, 0xff, 0x81, 0xff, 0xe6, 0xff, 0x96, 0xff, 0xf1, 0xff, 0xa8, 0xff, 0xf8, 0xff, 0xba, 0xff, 0xf9, 0xff, 0xce, 0xff, 0xf5, 0xff, 0xe4, 0xff, 0xef, 0xff, 0xfa, 0xff, 0xec, 0xff, 0x10, 0x00, 0xec, 0xff, 0x25, 0x00, 0xf0, 0xff, 0x38, 0x00, 0xf4, 0xff, 0x45, 0x00, 0xf0, 0xff, 0x50, 0x00, 0xeb, 0xff, 0x60, 0x00, 0xeb, 0xff, 0x76, 0x00, 0xf5, 0xff, 0x8e, 0x00, 0x02, 0x00, 0xa2, 0x00, 0x10, 0x00, 0xb0, 0x00, 0x1d, 0x00, 0xb8, 0x00, 0x27, 0x00, 0xbd, 0x00, 0x30, 0x00, 0xc4, 0x00, 0x3b, 0x00, 0xd0, 0x00, 0x48, 0x00, 0xdd, 0x00, 0x54, 0x00, 0xe0, 0x00, 0x59, 0x00, 0xdd, 0x00, 0x5a, 0x00, 0xd8, 0x00, 0x5d, 0x00, 0xd7, 0x00, 0x65, 0x00, 0xd6, 0x00, 0x6f, 0x00, 0xd2, 0x00, 0x74, 0x00, 0xce, 0x00, 0x77, 0x00, 0xcd, 0x00, 0x7d, 0x00, 0xce, 0x00, 0x85, 0x00, 0xcd, 0x00, 0x8e, 0x00, 0xcc, 0x00, 0x96, 0x00, 0xcb, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0xa6, 0x00, 0xcc, 0x00, 0xab, 0x00, 0xcc, 0x00, 0xaf, 0x00, 0xc9, 0x00, 0xb0, 0x00, 0xc2, 0x00, 0xaf, 0x00, 0xb8, 0x00, 0xaf, 0x00, 0xab, 0x00, 0xad, 0x00, 0x9c, 0x00, 0xab, 0x00, 0x8e, 0x00, 0xa6, 0x00, 0x7e, 0x00, 0x9c, 0x00, 0x6a, 0x00, 0x8d, 0x00, 0x56, 0x00, 0x81, 0x00, 0x44, 0x00, 0x7b, 0x00, 0x31, 0x00, 0x75, 0x00, 0x1c, 0x00, 0x6a, 0x00, 0x05, 0x00, 0x59, 0x00, 0xf1, 0xff, 0x48, 0x00, 0xdc, 0xff, 0x36, 0x00, 0xc4, 0xff, 0x22, 0x00, 0xa8, 0xff, 0x0a, 0x00, 0x89, 0xff, 0xef, 0xff, 0x6c, 0xff, 0xd5, 0xff, 0x52, 0xff, 0xbf, 0xff, 0x3c, 0xff, 0xae, 0xff, 0x27, 0xff, 0x9e, 0xff, 0x16, 0xff, 0x91, 0xff, 0x0b, 0xff, 0x85, 0xff, 0x03, 0xff, 0x7b, 0xff, 0xfd, 0xfe, 0x73, 0xff, 0xf8, 0xfe, 0x6f, 0xff, 0xf8, 0xfe, 0x6f, 0xff, 0xfb, 0xfe, 0x70, 0xff, 0x03, 0xff, 0x70, 0xff, 0x0c, 0xff, 0x6d, 0xff, 0x16, 0xff, 0x6a, 0xff, 0x26, 0xff, 0x6d, 0xff, 0x38, 0xff, 0x74, 0xff, 0x49, 0xff, 0x7a, 0xff, 0x57, 0xff, 0x7a, 0xff, 0x67, 0xff, 0x77, 0xff, 0x7a, 0xff, 0x75, 0xff, 0x91, 0xff, 0x77, 0xff, 0xac, 0xff, 0x7f, 0xff, 0xc4, 0xff, 0x89, 0xff, 0xd9, 0xff, 0x93, 0xff, 0xed, 0xff, 0x9f, 0xff, 0x07, 0x00, 0xb0, 0xff, 0x22, 0x00, 0xc1, 0xff, 0x3a, 0x00, 0xce, 0xff, 0x4f, 0x00, 0xd9, 0xff, 0x5c, 0x00, 0xe1, 0xff, 0x66, 0x00, 0xea, 0xff, 0x70, 0x00, 0xf7, 0xff, 0x7d, 0x00, 0x06, 0x00, 0x89, 0x00, 0x15, 0x00, 0x92, 0x00, 0x1e, 0x00, 0x99, 0x00, 0x24, 0x00, 0xa3, 0x00, 0x2c, 0x00, 0xad, 0x00, 0x33, 0x00, 0xb4, 0x00, 0x38, 0x00, 0xb7, 0x00, 0x3b, 0x00, 0xb8, 0x00, 0x3e, 0x00, 0xbc, 0x00, 0x41, 0x00, 0xbf, 0x00, 0x42, 0x00, 0xc5, 0x00, 0x42, 0x00, 0xca, 0x00, 0x40, 0x00, 0xd1, 0x00, 0x41, 0x00, 0xd9, 0x00, 0x46, 0x00, 0xe0, 0x00, 0x4a, 0x00, 0xe5, 0x00, 0x4d, 0x00, 0xec, 0x00, 0x52, 0x00, 0xf4, 0x00, 0x57, 0x00, 0xfa, 0x00, 0x59, 0x00, 0xff, 0x00, 0x5b, 0x00, 0x02, 0x01, 0x5e, 0x00, 0x02, 0x01, 0x61, 0x00, 0xfe, 0x00, 0x63, 0x00, 0xf4, 0x00, 0x63, 0x00, 0xe7, 0x00, 0x62, 0x00, 0xd5, 0x00, 0x5b, 0x00, 0xc5, 0x00, 0x54, 0x00, 0xc0, 0x00, 0x56, 0x00, 0xbc, 0x00, 0x5a, 0x00, 0xae, 0x00, 0x56, 0x00, 0x98, 0x00, 0x4e, 0x00, 0x83, 0x00, 0x4a, 0x00, 0x74, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x25, 0x00, 0x44, 0x00, 0xf7, 0xff, 0x29, 0x00, 0xdd, 0xff, 0x1e, 0x00, 0xd9, 0xff, 0x28, 0x00, 0xd2, 0xff, 0x2d, 0x00, 0xb2, 0xff, 0x19, 0x00, 0x80, 0xff, 0xf3, 0xff, 0x51, 0xff, 0xd1, 0xff, 0x32, 0xff, 0xbf, 0xff, 0x1e, 0xff, 0xb6, 0xff, 0x07, 0xff, 0xa7, 0xff, 0xe8, 0xfe, 0x8a, 0xff, 0xca, 0xfe, 0x68, 0xff, 0xbd, 0xfe, 0x53, 0xff, 0xbb, 0xfe, 0x48, 0xff, 0xb8, 0xfe, 0x41, 0xff, 0xb2, 0xfe, 0x39, 0xff, 0xaf, 0xfe, 0x36, 0xff, 0xb2, 0xfe, 0x38, 0xff, 0xbb, 0xfe, 0x3d, 0xff, 0xc8, 0xfe, 0x41, 0xff, 0xd9, 0xfe, 0x46, 0xff, 0xed, 0xfe, 0x4e, 0xff, 0xfc, 0xfe, 0x55, 0xff, 0x05, 0xff, 0x59, 0xff, 0x09, 0xff, 0x5f, 0xff, 0x11, 0xff, 0x68, 0xff, 0x1f, 0xff, 0x76, 0xff, 0x32, 0xff, 0x84, 0xff, 0x43, 0xff, 0x90, 0xff, 0x4f, 0xff, 0x97, 0xff, 0x56, 0xff, 0x9a, 0xff, 0x58, 0xff, 0x9d, 0xff, 0x5b, 0xff, 0xa2, 0xff, 0x62, 0xff, 0xab, 0xff, 0x6e, 0xff, 0xb9, 0xff, 0x7e, 0xff, 0xc9, 0xff, 0x8f, 0xff, 0xd9, 0xff, 0xa2, 0xff, 0xea, 0xff, 0xb4, 0xff, 0xfa, 0xff, 0xc6, 0xff, 0x0c, 0x00, 0xd9, 0xff, 0x22, 0x00, 0xee, 0xff, 0x39, 0x00, 0x03, 0x00, 0x4f, 0x00, 0x18, 0x00, 0x62, 0x00, 0x2c, 0x00, 0x74, 0x00, 0x42, 0x00, 0x87, 0x00, 0x54, 0x00, 0x9b, 0x00, 0x64, 0x00, 0xaf, 0x00, 0x72, 0x00, 0xc0, 0x00, 0x7e, 0x00, 0xcf, 0x00, 0x8b, 0x00, 0xdc, 0x00, 0x96, 0x00, 0xe6, 0x00, 0x9e, 0x00, 0xef, 0x00, 0xa5, 0x00, 0xf8, 0x00, 0xb1, 0x00, 0x07, 0x01, 0xbc, 0x00, 0x16, 0x01, 0xc0, 0x00, 0x1f, 0x01, 0xbe, 0x00, 0x23, 0x01, 0xb7, 0x00, 0x20, 0x01, 0xb1, 0x00, 0x1c, 0x01, 0xae, 0x00, 0x17, 0x01, 0xaf, 0x00, 0x10, 0x01, 0xae, 0x00, 0x06, 0x01, 0xa4, 0x00, 0xf4, 0x00, 0x95, 0x00, 0xde, 0x00, 0x88, 0x00, 0xc9, 0x00, 0x80, 0x00, 0xb9, 0x00, 0x7e, 0x00, 0xac, 0x00, 0x7b, 0x00, 0x9d, 0x00, 0x73, 0x00, 0x8a, 0x00, 0x69, 0x00, 0x78, 0x00, 0x62, 0x00, 0x69, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x54, 0x00, 0x45, 0x00, 0x49, 0x00, 0x2b, 0x00, 0x3d, 0x00, 0x11, 0x00, 0x33, 0x00, 0xfd, 0xff, 0x2b, 0x00, 0xf2, 0xff, 0x21, 0x00, 0xe9, 0xff, 0x13, 0x00, 0xdd, 0xff, 0x01, 0x00, 0xcb, 0xff, 0xf0, 0xff, 0xb4, 0xff, 0xde, 0xff, 0x9b, 0xff, 0xcb, 0xff, 0x81, 0xff, 0xb5, 0xff, 0x66, 0xff, 0x9b, 0xff, 0x4a, 0xff, 0x7e, 0xff, 0x2d, 0xff, 0x63, 0xff, 0x14, 0xff, 0x51, 0xff, 0x04, 0xff, 0x47, 0xff, 0xfa, 0xfe, 0x3e, 0xff, 0xef, 0xfe, 0x31, 0xff, 0xdf, 0xfe, 0x25, 0xff, 0xcd, 0xfe, 0x1f, 0xff, 0xc1, 0xfe, 0x25, 0xff, 0xc3, 0xfe, 0x34, 0xff, 0xd2, 0xfe, 0x43, 0xff, 0xe6, 0xfe, 0x4e, 0xff, 0xf6, 0xfe, 0x54, 0xff, 0x01, 0xff, 0x5f, 0xff, 0x0f, 0xff, 0x6f, 0xff, 0x20, 0xff, 0x82, 0xff, 0x37, 0xff, 0x97, 0xff, 0x50, 0xff, 0xae, 0xff, 0x69, 0xff, 0xc6, 0xff, 0x81, 0xff, 0xe2, 0xff, 0x99, 0xff, 0x01, 0x00, 0xb0, 0xff, 0x1d, 0x00, 0xc5, 0xff, 0x32, 0x00, 0xd7, 0xff, 0x43, 0x00, 0xe7, 0xff, 0x53, 0x00, 0xf8, 0xff, 0x69, 0x00, 0x0f, 0x00, 0x84, 0x00, 0x2b, 0x00, 0x9e, 0x00, 0x45, 0x00, 0xb2, 0x00, 0x57, 0x00, 0xba, 0x00, 0x5d, 0x00, 0xbd, 0x00, 0x5d, 0x00, 0xc1, 0x00, 0x60, 0x00, 0xc6, 0x00, 0x6a, 0x00, 0xcd, 0x00, 0x7b, 0x00, 0xd1, 0x00, 0x8a, 0x00, 0xcf, 0x00, 0x90, 0x00, 0xca, 0x00, 0x90, 0x00, 0xc8, 0x00, 0x8e, 0x00, 0xc9, 0x00, 0x8f, 0x00, 0xc7, 0x00, 0x91, 0x00, 0xc0, 0x00, 0x92, 0x00, 0xb7, 0x00, 0x94, 0x00, 0xb0, 0x00, 0x97, 0x00, 0xa8, 0x00, 0x99, 0x00, 0xa3, 0x00, 0x99, 0x00, 0xa2, 0x00, 0x9b, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa5, 0x00, 0xa2, 0x00, 0xa9, 0x00, 0x9e, 0x00, 0xac, 0x00, 0x97, 0x00, 0xac, 0x00, 0x90, 0x00, 0xab, 0x00, 0x8c, 0x00, 0xaa, 0x00, 0x89, 0x00, 0xaa, 0x00, 0x83, 0x00, 0xaa, 0x00, 0x78, 0x00, 0xa6, 0x00, 0x68, 0x00, 0xa0, 0x00, 0x57, 0x00, 0x97, 0x00, 0x42, 0x00, 0x8a, 0x00, 0x28, 0x00, 0x75, 0x00, 0x0b, 0x00, 0x5b, 0x00, 0xee, 0xff, 0x41, 0x00, 0xd3, 0xff, 0x27, 0x00, 0xbb, 0xff, 0x0d, 0x00, 0xa2, 0xff, 0xf3, 0xff, 0x83, 0xff, 0xd5, 0xff, 0x60, 0xff, 0xb6, 0xff, 0x40, 0xff, 0x9a, 0xff, 0x24, 0xff, 0x82, 0xff, 0x0e, 0xff, 0x6e, 0xff, 0xfd, 0xfe, 0x5b, 0xff, 0xf3, 0xfe, 0x4f, 0xff, 0xec, 0xfe, 0x45, 0xff, 0xe5, 0xfe, 0x39, 0xff, 0xdc, 0xfe, 0x2a, 0xff, 0xd6, 0xfe, 0x1a, 0xff, 0xd7, 0xfe, 0x12, 0xff, 0xde, 0xfe, 0x10, 0xff, 0xec, 0xfe, 0x17, 0xff, 0xfe, 0xfe, 0x24, 0xff, 0x10, 0xff, 0x33, 0xff, 0x20, 0xff, 0x3d, 0xff, 0x2c, 0xff, 0x41, 0xff, 0x39, 0xff, 0x44, 0xff, 0x49, 0xff, 0x49, 0xff, 0x61, 0xff, 0x56, 0xff, 0x7e, 0xff, 0x6c, 0xff, 0x9e, 0xff, 0x86, 0xff, 0xbc, 0xff, 0xa0, 0xff, 0xd2, 0xff, 0xb3, 0xff, 0xe0, 0xff, 0xbb, 0xff, 0xe8, 0xff, 0xbc, 0xff, 0xf1, 0xff, 0xbe, 0xff, 0xfa, 0xff, 0xc3, 0xff, 0x03, 0x00, 0xcc, 0xff, 0x0c, 0x00, 0xd7, 0xff, 0x11, 0x00, 0xdf, 0xff, 0x16, 0x00, 0xe3, 0xff, 0x19, 0x00, 0xe5, 0xff, 0x1d, 0x00, 0xe5, 0xff, 0x20, 0x00, 0xe6, 0xff, 0x25, 0x00, 0xe9, 0xff, 0x2b, 0x00, 0xed, 0xff, 0x33, 0x00, 0xf4, 0xff, 0x40, 0x00, 0x02, 0x00, 0x51, 0x00, 0x14, 0x00, 0x65, 0x00, 0x26, 0x00, 0x78, 0x00, 0x33, 0x00, 0x8a, 0x00, 0x3f, 0x00, 0x9e, 0x00, 0x4f, 0x00, 0xad, 0x00, 0x5f, 0x00, 0xb9, 0x00, 0x6f, 0x00, 0xc5, 0x00, 0x7f, 0x00, 0xd5, 0x00, 0x8f, 0x00, 0xe5, 0x00, 0x9c, 0x00, 0xf2, 0x00, 0xa7, 0x00, 0xfc, 0x00, 0xb1, 0x00, 0xff, 0x00, 0xb8, 0x00, 0xfd, 0x00, 0xbf, 0x00, 0xf7, 0x00, 0xc4, 0x00, 0xec, 0x00, 0xc5, 0x00, 0xdd, 0x00, 0xc0, 0x00, 0xca, 0x00, 0xb6, 0x00, 0xb5, 0x00, 0xa9, 0x00, 0xa0, 0x00, 0x9c, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x8d, 0x00, 0x67, 0x00, 0x85, 0x00, 0x4e, 0x00, 0x79, 0x00, 0x32, 0x00, 0x67, 0x00, 0x18, 0x00, 0x53, 0x00, 0x02, 0x00, 0x40, 0x00, 0xf1, 0xff, 0x33, 0x00, 0xe3, 0xff, 0x2c, 0x00, 0xd5, 0xff, 0x28, 0x00, 0xc3, 0xff, 0x20, 0x00, 0xae, 0xff, 0x10, 0x00, 0x99, 0xff, 0xfa, 0xff, 0x84, 0xff, 0xe0, 0xff, 0x78, 0xff, 0xcc, 0xff, 0x76, 0xff, 0xc2, 0xff, 0x7a, 0xff, 0xc1, 0xff, 0x7d, 0xff, 0xc0, 0xff, 0x7b, 0xff, 0xbd, 0xff, 0x77, 0xff, 0xb7, 0xff, 0x70, 0xff, 0xaf, 0xff, 0x69, 0xff, 0xa4, 0xff, 0x63, 0xff, 0x9c, 0xff, 0x5d, 0xff, 0x96, 0xff, 0x59, 0xff, 0x94, 0xff, 0x59, 0xff, 0x93, 0xff, 0x5d, 0xff, 0x96, 0xff, 0x5e, 0xff, 0x95, 0xff, 0x58, 0xff, 0x8d, 0xff, 0x4d, 0xff, 0x81, 0xff, 0x3f, 0xff, 0x75, 0xff, 0x33, 0xff, 0x6d, 0xff, 0x2e, 0xff, 0x6d, 0xff, 0x30, 0xff, 0x75, 0xff, 0x34, 0xff, 0x7c, 0xff, 0x37, 0xff, 0x7e, 0xff, 0x3d, 0xff, 0x7f, 0xff, 0x45, 0xff, 0x7d, 0xff, 0x4d, 0xff, 0x7c, 0xff, 0x59, 0xff, 0x80, 0xff, 0x6b, 0xff, 0x8c, 0xff, 0x80, 0xff, 0x9e, 0xff, 0x9a, 0xff, 0xb2, 0xff, 0xb7, 0xff, 0xc5, 0xff, 0xd6, 0xff, 0xd3, 0xff, 0xf2, 0xff, 0xda, 0xff, 0x0b, 0x00, 0xde, 0xff, 0x21, 0x00, 0xe5, 0xff, 0x34, 0x00, 0xee, 0xff, 0x44, 0x00, 0xfa, 0xff, 0x54, 0x00, 0x09, 0x00, 0x66, 0x00, 0x19, 0x00, 0x79, 0x00, 0x28, 0x00, 0x8e, 0x00, 0x37, 0x00, 0xa0, 0x00, 0x43, 0x00, 0xab, 0x00, 0x4c, 0x00, 0xb3, 0x00, 0x57, 0x00, 0xbb, 0x00, 0x64, 0x00, 0xc0, 0x00, 0x70, 0x00, 0xc2, 0x00, 0x7a, 0x00, 0xc2, 0x00, 0x84, 0x00, 0xbd, 0x00, 0x8c, 0x00, 0xb8, 0x00, 0x94, 0x00, 0xb7, 0x00, 0xa1, 0x00, 0xbc, 0x00, 0xb2, 0x00, 0xc3, 0x00, 0xc3, 0x00, 0xc8, 0x00, 0xd1, 0x00, 0xc7, 0x00, 0xd8, 0x00, 0xbf, 0x00, 0xd9, 0x00, 0xb5, 0x00, 0xd7, 0x00, 0xac, 0x00, 0xd4, 0x00, 0xa2, 0x00, 0xce, 0x00, 0x99, 0x00, 0xc5, 0x00, 0x8d, 0x00, 0xb7, 0x00, 0x7e, 0x00, 0xa1, 0x00, 0x6d, 0x00, 0x89, 0x00, 0x5c, 0x00, 0x71, 0x00, 0x4a, 0x00, 0x59, 0x00, 0x38, 0x00, 0x41, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x08, 0x00, 0x03, 0x00, 0xf3, 0xff, 0xf3, 0xff, 0xdf, 0xff, 0xe5, 0xff, 0xd0, 0xff, 0xda, 0xff, 0xc7, 0xff, 0xd2, 0xff, 0xc4, 0xff, 0xd1, 0xff, 0xc7, 0xff, 0xd2, 0xff, 0xc9, 0xff, 0xd4, 0xff, 0xcc, 0xff, 0xd7, 0xff, 0xd0, 0xff, 0xd9, 0xff, 0xd7, 0xff, 0xd7, 0xff, 0xdd, 0xff, 0xd0, 0xff, 0xe2, 0xff, 0xc9, 0xff, 0xe8, 0xff, 0xc5, 0xff, 0xf1, 0xff, 0xc4, 0xff, 0xf9, 0xff, 0xc7, 0xff, 0x00, 0x00, 0xca, 0xff, 0x01, 0x00, 0xcb, 0xff, 0xfd, 0xff, 0xcb, 0xff, 0xf6, 0xff, 0xca, 0xff, 0xf0, 0xff, 0xcd, 0xff, 0xf0, 0xff, 0xd4, 0xff, 0xf6, 0xff, 0xdc, 0xff, 0xfd, 0xff, 0xe3, 0xff, 0x00, 0x00, 0xe5, 0xff, 0xfd, 0xff, 0xe5, 0xff, 0xf2, 0xff, 0xe4, 0xff, 0xe1, 0xff, 0xe7, 0xff, 0xd2, 0xff, 0xf0, 0xff, 0xc9, 0xff, 0xf8, 0xff, 0xc1, 0xff, 0xfb, 0xff, 0xb7, 0xff, 0xfb, 0xff, 0xac, 0xff, 0xf8, 0xff, 0xa0, 0xff, 0xf8, 0xff, 0x97, 0xff, 0xfc, 0xff, 0x93, 0xff, 0x05, 0x00, 0x93, 0xff, 0x10, 0x00, 0x94, 0xff, 0x1d, 0x00, 0x93, 0xff, 0x2d, 0x00, 0x94, 0xff, 0x3b, 0x00, 0x94, 0xff, 0x44, 0x00, 0x95, 0xff, 0x42, 0x00, 0x8f, 0xff, 0x3c, 0x00, 0x8a, 0xff, 0x3e, 0x00, 0x90, 0xff, 0x4d, 0x00, 0xa3, 0xff, 0x64, 0x00, 0xbc, 0xff, 0x7b, 0x00, 0xd2, 0xff, 0x8d, 0x00, 0xe2, 0xff, 0x97, 0x00, 0xe9, 0xff, 0x9a, 0x00, 0xec, 0xff, 0x96, 0x00, 0xef, 0xff, 0x8b, 0x00, 0xf4, 0xff, 0x78, 0x00, 0xf8, 0xff, 0x63, 0x00, 0xfa, 0xff, 0x52, 0x00, 0xfc, 0xff, 0x46, 0x00, 0xfd, 0xff, 0x3e, 0x00, 0xfd, 0xff, 0x34, 0x00, 0xfa, 0xff, 0x26, 0x00, 0xf6, 0xff, 0x14, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf2, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf3, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xe8, 0xff, 0x0a, 0x00, 0xde, 0xff, 0x06, 0x00, 0xd8, 0xff, 0x05, 0x00, 0xd8, 0xff, 0x0a, 0x00, 0xe1, 0xff, 0x16, 0x00, 0xec, 0xff, 0x23, 0x00, 0xf7, 0xff, 0x2b, 0x00, 0xfa, 0xff, 0x28, 0x00, 0xf1, 0xff, 0x19, 0x00, 0xe4, 0xff, 0x08, 0x00, 0xdb, 0xff, 0xfd, 0xff, 0xd7, 0xff, 0xfa, 0xff, 0xd3, 0xff, 0xf6, 0xff, 0xcc, 0xff, 0xee, 0xff, 0xc0, 0xff, 0xe2, 0xff, 0xb0, 0xff, 0xd1, 0xff, 0xa2, 0xff, 0xc3, 0xff, 0x96, 0xff, 0xb9, 0xff, 0x8a, 0xff, 0xb1, 0xff, 0x7e, 0xff, 0xaa, 0xff, 0x71, 0xff, 0xa2, 0xff, 0x61, 0xff, 0x97, 0xff, 0x51, 0xff, 0x8a, 0xff, 0x47, 0xff, 0x84, 0xff, 0x41, 0xff, 0x85, 0xff, 0x3b, 0xff, 0x89, 0xff, 0x38, 0xff, 0x90, 0xff, 0x3b, 0xff, 0x9a, 0xff, 0x40, 0xff, 0xa4, 0xff, 0x42, 0xff, 0xaa, 0xff, 0x3f, 0xff, 0xa8, 0xff, 0x33, 0xff, 0x9f, 0xff, 0x25, 0xff, 0x96, 0xff, 0x1e, 0xff, 0x95, 0xff, 0x23, 0xff, 0x9e, 0xff, 0x30, 0xff, 0xaa, 0xff, 0x41, 0xff, 0xb4, 0xff, 0x5a, 0xff, 0xbf, 0xff, 0x75, 0xff, 0xc8, 0xff, 0x8c, 0xff, 0xcc, 0xff, 0x9a, 0xff, 0xc9, 0xff, 0xa2, 0xff, 0xc5, 0xff, 0xa9, 0xff, 0xc5, 0xff, 0xb7, 0xff, 0xce, 0xff, 0xcc, 0xff, 0xdc, 0xff, 0xe2, 0xff, 0xe7, 0xff, 0xf6, 0xff, 0xeb, 0xff, 0x06, 0x00, 0xea, 0xff, 0x13, 0x00, 0xea, 0xff, 0x1d, 0x00, 0xee, 0xff, 0x21, 0x00, 0xf0, 0xff, 0x22, 0x00, 0xf0, 0xff, 0x22, 0x00, 0xf1, 0xff, 0x1f, 0x00, 0xf1, 0xff, 0x16, 0x00, 0xee, 0xff, 0x05, 0x00, 0xe4, 0xff, 0xf4, 0xff, 0xdb, 0xff, 0xeb, 0xff, 0xd8, 0xff, 0xef, 0xff, 0xe0, 0xff, 0xf9, 0xff, 0xee, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xe6, 0xff, 0xfa, 0xff, 0xdd, 0xff, 0xfa, 0xff, 0xd9, 0xff, 0xff, 0xff, 0xde, 0xff, 0x0b, 0x00, 0xeb, 0xff, 0x1f, 0x00, 0xfa, 0xff, 0x33, 0x00, 0x09, 0x00, 0x45, 0x00, 0x17, 0x00, 0x53, 0x00, 0x24, 0x00, 0x5f, 0x00, 0x34, 0x00, 0x70, 0x00, 0x48, 0x00, 0x86, 0x00, 0x5c, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x79, 0x00, 0xbf, 0x00, 0x84, 0x00, 0xc8, 0x00, 0x8a, 0x00, 0xc9, 0x00, 0x8c, 0x00, 0xc5, 0x00, 0x8d, 0x00, 0xbf, 0x00, 0x8b, 0x00, 0xb9, 0x00, 0x84, 0x00, 0xad, 0x00, 0x74, 0x00, 0x98, 0x00, 0x64, 0x00, 0x82, 0x00, 0x52, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x52, 0x00, 0x25, 0x00, 0x3b, 0x00, 0x12, 0x00, 0x2a, 0x00, 0x04, 0x00, 0x1c, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xf2, 0xff, 0xff, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xd3, 0xff, 0xd8, 0xff, 0xb9, 0xff, 0xc0, 0xff, 0xa1, 0xff, 0xb0, 0xff, 0x90, 0xff, 0xaa, 0xff, 0x83, 0xff, 0xa9, 0xff, 0x79, 0xff, 0xa8, 0xff, 0x78, 0xff, 0xab, 0xff, 0x7f, 0xff, 0xb3, 0xff, 0x88, 0xff, 0xba, 0xff, 0x91, 0xff, 0xc0, 0xff, 0x9b, 0xff, 0xc8, 0xff, 0xa6, 0xff, 0xd3, 0xff, 0xb5, 0xff, 0xe3, 0xff, 0xc7, 0xff, 0xf7, 0xff, 0xd5, 0xff, 0x07, 0x00, 0xda, 0xff, 0x0d, 0x00, 0xdc, 0xff, 0x0d, 0x00, 0xe3, 0xff, 0x0d, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xef, 0xff, 0x09, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf6, 0xff, 0xff, 0xff, 0x02, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf6, 0xff, 0x14, 0x00, 0xff, 0xff, 0x1d, 0x00, 0x07, 0x00, 0x24, 0x00, 0x08, 0x00, 0x26, 0x00, 0x06, 0x00, 0x2b, 0x00, 0x02, 0x00, 0x36, 0x00, 0xfd, 0xff, 0x46, 0x00, 0xf7, 0xff, 0x56, 0x00, 0xf0, 0xff, 0x62, 0x00, 0xee, 0xff, 0x6c, 0x00, 0xf6, 0xff, 0x7b, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x1b, 0x00, 0xa3, 0x00, 0x29, 0x00, 0xb1, 0x00, 0x33, 0x00, 0xbe, 0x00, 0x3b, 0x00, 0xca, 0x00, 0x3d, 0x00, 0xd1, 0x00, 0x3b, 0x00, 0xd0, 0x00, 0x3f, 0x00, 0xcc, 0x00, 0x4a, 0x00, 0xc9, 0x00, 0x56, 0x00, 0xc5, 0x00, 0x5f, 0x00, 0xbe, 0x00, 0x66, 0x00, 0xb6, 0x00, 0x6f, 0x00, 0xad, 0x00, 0x78, 0x00, 0xa0, 0x00, 0x7f, 0x00, 0x8e, 0x00, 0x87, 0x00, 0x7e, 0x00, 0x8b, 0x00, 0x6c, 0x00, 0x88, 0x00, 0x58, 0x00, 0x83, 0x00, 0x47, 0x00, 0x84, 0x00, 0x40, 0x00, 0x87, 0x00, 0x3d, 0x00, 0x89, 0x00, 0x36, 0x00, 0x8d, 0x00, 0x2e, 0x00, 0x92, 0x00, 0x26, 0x00, 0x95, 0x00, 0x1f, 0x00, 0x96, 0x00, 0x19, 0x00, 0x96, 0x00, 0x16, 0x00, 0x95, 0x00, 0x15, 0x00, 0x92, 0x00, 0x15, 0x00, 0x92, 0x00, 0x17, 0x00, 0x92, 0x00, 0x18, 0x00, 0x8d, 0x00, 0x11, 0x00, 0x84, 0x00, 0x04, 0x00, 0x7b, 0x00, 0xf7, 0xff, 0x74, 0x00, 0xee, 0xff, 0x6e, 0x00, 0xe6, 0xff, 0x67, 0x00, 0xe0, 0xff, 0x60, 0x00, 0xd9, 0xff, 0x52, 0x00, 0xcc, 0xff, 0x3f, 0x00, 0xbc, 0xff, 0x29, 0x00, 0xaa, 0xff, 0x15, 0x00, 0x99, 0xff, 0x02, 0x00, 0x86, 0xff, 0xf3, 0xff, 0x75, 0xff, 0xeb, 0xff, 0x6a, 0xff, 0xe8, 0xff, 0x64, 0xff, 0xe5, 0xff, 0x63, 0xff, 0xe2, 0xff, 0x66, 0xff, 0xdd, 0xff, 0x6a, 0xff, 0xd8, 0xff, 0x6f, 0xff, 0xd2, 0xff, 0x70, 0xff, 0xcf, 0xff, 0x6f, 0xff, 0xd3, 0xff, 0x72, 0xff, 0xda, 0xff, 0x76, 0xff, 0xe0, 0xff, 0x7b, 0xff, 0xe1, 0xff, 0x83, 0xff, 0xdc, 0xff, 0x8a, 0xff, 0xd5, 0xff, 0x92, 0xff, 0xd3, 0xff, 0x9d, 0xff, 0xd4, 0xff, 0xa7, 0xff, 0xd3, 0xff, 0xad, 0xff, 0xd3, 0xff, 0xb1, 0xff, 0xd3, 0xff, 0xb7, 0xff, 0xd2, 0xff, 0xbc, 0xff, 0xce, 0xff, 0xbf, 0xff, 0xcc, 0xff, 0xc5, 0xff, 0xce, 0xff, 0xcd, 0xff, 0xd1, 0xff, 0xd5, 0xff, 0xd7, 0xff, 0xdf, 0xff, 0xe1, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0x02, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x15, 0x00, 0x21, 0x00, 0x21, 0x00, 0x30, 0x00, 0x2b, 0x00, 0x40, 0x00, 0x32, 0x00, 0x4e, 0x00, 0x37, 0x00, 0x58, 0x00, 0x3a, 0x00, 0x5e, 0x00, 0x3d, 0x00, 0x63, 0x00, 0x40, 0x00, 0x67, 0x00, 0x44, 0x00, 0x68, 0x00, 0x42, 0x00, 0x63, 0x00, 0x3a, 0x00, 0x5d, 0x00, 0x31, 0x00, 0x57, 0x00, 0x27, 0x00, 0x54, 0x00, 0x20, 0x00, 0x51, 0x00, 0x19, 0x00, 0x4d, 0x00, 0x13, 0x00, 0x45, 0x00, 0x0b, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x31, 0x00, 0xf7, 0xff, 0x2a, 0x00, 0xec, 0xff, 0x24, 0x00, 0xe1, 0xff, 0x1c, 0x00, 0xd4, 0xff, 0x18, 0x00, 0xc9, 0xff, 0x17, 0x00, 0xbf, 0xff, 0x19, 0x00, 0xb5, 0xff, 0x1c, 0x00, 0xa9, 0xff, 0x1e, 0x00, 0x9e, 0xff, 0x20, 0x00, 0x92, 0xff, 0x1e, 0x00, 0x85, 0xff, 0x1d, 0x00, 0x7d, 0xff, 0x21, 0x00, 0x7b, 0xff, 0x28, 0x00, 0x7c, 0xff, 0x31, 0x00, 0x7c, 0xff, 0x39, 0x00, 0x78, 0xff, 0x40, 0x00, 0x72, 0xff, 0x46, 0x00, 0x70, 0xff, 0x4d, 0x00, 0x74, 0xff, 0x54, 0x00, 0x7d, 0xff, 0x5b, 0x00, 0x86, 0xff, 0x5c, 0x00, 0x8c, 0xff, 0x5a, 0x00, 0x90, 0xff, 0x53, 0x00, 0x92, 0xff, 0x48, 0x00, 0x95, 0xff, 0x3b, 0x00, 0x97, 0xff, 0x2e, 0x00, 0x9d, 0xff, 0x21, 0x00, 0xa7, 0xff, 0x14, 0x00, 0xb6, 0xff, 0x04, 0x00, 0xc6, 0xff, 0xf2, 0xff, 0xd4, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xd2, 0xff, 0xec, 0xff, 0xc2, 0xff, 0xf5, 0xff, 0xb3, 0xff, 0xff, 0xff, 0xa4, 0xff, 0x0c, 0x00, 0x8f, 0xff, 0x16, 0x00, 0x76, 0xff, 0x1a, 0x00, 0x5b, 0xff, 0x18, 0x00, 0x40, 0xff, 0x14, 0x00, 0x29, 0xff, 0x11, 0x00, 0x18, 0xff, 0x17, 0x00, 0x0d, 0xff, 0x22, 0x00, 0x03, 0xff, 0x2e, 0x00, 0xfa, 0xfe, 0x35, 0x00, 0xf1, 0xfe, 0x39, 0x00, 0xea, 0xfe, 0x3c, 0x00, 0xe0, 0xfe, 0x3c, 0x00, 0xda, 0xfe, 0x3c, 0x00, 0xdc, 0xfe, 0x40, 0x00, 0xe7, 0xfe, 0x4a, 0x00, 0xf6, 0xfe, 0x59, 0x00, 0x04, 0xff, 0x67, 0x00, 0x0e, 0xff, 0x72, 0x00, 0x13, 0xff, 0x76, 0x00, 0x1a, 0xff, 0x79, 0x00, 0x25, 0xff, 0x80, 0x00, 0x34, 0xff, 0x8a, 0x00, 0x44, 0xff, 0x91, 0x00, 0x56, 0xff, 0x97, 0x00, 0x6b, 0xff, 0x9c, 0x00, 0x7f, 0xff, 0x9f, 0x00, 0x8f, 0xff, 0xa2, 0x00, 0x9a, 0xff, 0xa4, 0x00, 0xa5, 0xff, 0xa7, 0x00, 0xaf, 0xff, 0xa6, 0x00, 0xba, 0xff, 0xa3, 0x00, 0xc8, 0xff, 0xa0, 0x00, 0xd8, 0xff, 0x9a, 0x00, 0xe5, 0xff, 0x90, 0x00, 0xf5, 0xff, 0x89, 0x00, 0x09, 0x00, 0x88, 0x00, 0x1f, 0x00, 0x8d, 0x00, 0x2f, 0x00, 0x8f, 0x00, 0x38, 0x00, 0x88, 0x00, 0x40, 0x00, 0x7c, 0x00, 0x46, 0x00, 0x69, 0x00, 0x4a, 0x00, 0x50, 0x00, 0x50, 0x00, 0x37, 0x00, 0x5c, 0x00, 0x23, 0x00, 0x6b, 0x00, 0x16, 0x00, 0x7a, 0x00, 0x0d, 0x00, 0x86, 0x00, 0x04, 0x00, 0x8f, 0x00, 0xf9, 0xff, 0x97, 0x00, 0xee, 0xff, 0x9f, 0x00, 0xe1, 0xff, 0xa5, 0x00, 0xd1, 0xff, 0xa4, 0x00, 0xb9, 0xff, 0xa0, 0x00, 0x9d, 0xff, 0x9e, 0x00, 0x84, 0xff, 0x9f, 0x00, 0x73, 0xff, 0xa2, 0x00, 0x69, 0xff, 0x9e, 0x00, 0x5e, 0xff, 0x92, 0x00, 0x4f, 0xff, 0x81, 0x00, 0x3e, 0xff, 0x75, 0x00, 0x30, 0xff, 0x73, 0x00, 0x2a, 0xff, 0x7b, 0x00, 0x2c, 0xff, 0x82, 0x00, 0x2d, 0xff, 0x82, 0x00, 0x2a, 0xff, 0x80, 0x00, 0x29, 0xff, 0x81, 0x00, 0x32, 0xff, 0x83, 0x00, 0x41, 0xff, 0x81, 0x00, 0x4e, 0xff, 0x7c, 0x00, 0x59, 0xff, 0x79, 0x00, 0x62, 0xff, 0x78, 0x00, 0x6c, 0xff, 0x76, 0x00, 0x76, 0xff, 0x72, 0x00, 0x7f, 0xff, 0x6b, 0x00, 0x88, 0xff, 0x5f, 0x00, 0x92, 0xff, 0x4f, 0x00, 0x9a, 0xff, 0x3a, 0x00, 0x9d, 0xff, 0x1f, 0x00, 0x9a, 0xff, 0xfe, 0xff, 0x8f, 0xff, 0xd8, 0xff, 0x80, 0xff, 0xb2, 0xff, 0x71, 0xff, 0x90, 0xff, 0x68, 0xff, 0x78, 0xff, 0x6b, 0xff, 0x69, 0xff, 0x78, 0xff, 0x61, 0xff, 0x8c, 0xff, 0x67, 0xff, 0xab, 0xff, 0x79, 0xff, 0xd5, 0xff, 0x8a, 0xff, 0xfb, 0xff, 0x8d, 0xff, 0x13, 0x00, 0x86, 0xff, 0x20, 0x00, 0x83, 0xff, 0x30, 0x00, 0x88, 0xff, 0x46, 0x00, 0x93, 0xff, 0x60, 0x00, 0x9f, 0xff, 0x79, 0x00, 0xa8, 0xff, 0x8c, 0x00, 0xb0, 0xff, 0x9b, 0x00, 0xb8, 0xff, 0xa7, 0x00, 0xbe, 0xff, 0xb1, 0x00, 0xb9, 0xff, 0xad, 0x00, 0xaa, 0xff, 0xa0, 0x00, 0x9d, 0xff, 0x92, 0x00, 0x98, 0xff, 0x88, 0x00, 0x97, 0xff, 0x7d, 0x00, 0x91, 0xff, 0x69, 0x00, 0x86, 0xff, 0x4e, 0x00, 0x7f, 0xff, 0x37, 0x00, 0x80, 0xff, 0x29, 0x00, 0x8b, 0xff, 0x25, 0x00, 0x9d, 0xff, 0x27, 0x00, 0xb3, 0xff, 0x2d, 0x00, 0xca, 0xff, 0x34, 0x00, 0xe7, 0xff, 0x43, 0x00, 0x0b, 0x00, 0x59, 0x00, 0x2f, 0x00, 0x70, 0x00, 0x4d, 0x00, 0x81, 0x00, 0x68, 0x00, 0x90, 0x00, 0x80, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x9e, 0x00, 0x95, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x8c, 0x00, 0x7e, 0x00, 0x81, 0x00, 0x71, 0x00, 0x72, 0x00, 0x61, 0x00, 0x61, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x20, 0x00, 0xea, 0xff, 0x10, 0x00, 0xd0, 0xff, 0x05, 0x00, 0xbf, 0xff, 0x03, 0x00, 0xb8, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x13, 0x00, 0xbe, 0xff, 0x22, 0x00, 0xc7, 0xff, 0x37, 0x00, 0xd4, 0xff, 0x4d, 0x00, 0xe4, 0xff, 0x5e, 0x00, 0xf0, 0xff, 0x6a, 0x00, 0xfb, 0xff, 0x6e, 0x00, 0x01, 0x00, 0x71, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, 0x00, 0x69, 0x00, 0x01, 0x00, 0x59, 0x00, 0xf1, 0xff, 0x42, 0x00, 0xdc, 0xff, 0x25, 0x00, 0xc5, 0xff, 0x01, 0x00, 0xad, 0xff, 0xda, 0xff, 0x97, 0xff, 0xb3, 0xff, 0x86, 0xff, 0x90, 0xff, 0x7a, 0xff, 0x71, 0xff, 0x72, 0xff, 0x55, 0xff, 0x6b, 0xff, 0x3e, 0xff, 0x67, 0xff, 0x2b, 0xff, 0x6a, 0xff, 0x20, 0xff, 0x77, 0xff, 0x1c, 0xff, 0x8f, 0xff, 0x1d, 0xff, 0xae, 0xff, 0x22, 0xff, 0xd0, 0xff, 0x29, 0xff, 0xf0, 0xff, 0x32, 0xff, 0x0f, 0x00, 0x3d, 0xff, 0x2f, 0x00, 0x4b, 0xff, 0x50, 0x00, 0x57, 0xff, 0x6c, 0x00, 0x5f, 0xff, 0x81, 0x00, 0x65, 0xff, 0x91, 0x00, 0x68, 0xff, 0x9f, 0x00, 0x66, 0xff, 0xa6, 0x00, 0x61, 0xff, 0xa9, 0x00, 0x5a, 0xff, 0xa5, 0x00, 0x51, 0xff, 0x9a, 0x00, 0x47, 0xff, 0x8b, 0x00, 0x41, 0xff, 0x7f, 0x00, 0x42, 0xff, 0x79, 0x00, 0x4a, 0xff, 0x77, 0x00, 0x57, 0xff, 0x77, 0x00, 0x6c, 0xff, 0x7e, 0x00, 0x8a, 0xff, 0x90, 0x00, 0xaa, 0xff, 0xa7, 0x00, 0xca, 0xff, 0xc0, 0x00, 0xe8, 0xff, 0xd4, 0x00, 0x01, 0x00, 0xe0, 0x00, 0x19, 0x00, 0xe7, 0x00, 0x3d, 0x00, 0xfb, 0x00, 0x73, 0x00, 0x1f, 0x01, 0xac, 0x00, 0x47, 0x01, 0xda, 0x00, 0x64, 0x01, 0xf5, 0x00, 0x6d, 0x01, 0xfb, 0x00, 0x5f, 0x01, 0xee, 0x00, 0x38, 0x01, 0xdd, 0x00, 0x09, 0x01, 0xd1, 0x00, 0xdb, 0x00, 0xc6, 0x00, 0xac, 0x00, 0xb7, 0x00, 0x7c, 0x00, 0xac, 0x00, 0x52, 0x00, 0xab, 0x00, 0x31, 0x00, 0xb4, 0x00, 0x1b, 0x00, 0xc3, 0x00, 0x07, 0x00, 0xca, 0x00, 0xe9, 0xff, 0xbe, 0x00, 0xb8, 0xff, 0xac, 0x00, 0x81, 0xff, 0xaf, 0x00, 0x64, 0xff, 0xd4, 0x00, 0x6c, 0xff, 0x07, 0x01, 0x87, 0xff, 0x2e, 0x01, 0x99, 0xff, 0x3d, 0x01, 0x93, 0xff, 0x3c, 0x01, 0x7f, 0xff, 0x3b, 0x01, 0x70, 0xff, 0x44, 0x01, 0x70, 0xff, 0x51, 0x01, 0x7b, 0xff, 0x54, 0x01, 0x83, 0xff, 0x45, 0x01, 0x7d, 0xff, 0x27, 0x01, 0x6a, 0xff, 0x01, 0x01, 0x4f, 0xff, 0xdb, 0x00, 0x34, 0xff, 0xb4, 0x00, 0x1c, 0xff, 0x8c, 0x00, 0x08, 0xff, 0x65, 0x00, 0xfb, 0xfe, 0x39, 0x00, 0xed, 0xfe, 0x0b, 0x00, 0xdd, 0xfe, 0xe5, 0xff, 0xd2, 0xfe, 0xcf, 0xff, 0xd1, 0xfe, 0xc9, 0xff, 0xda, 0xfe, 0xc7, 0xff, 0xe6, 0xfe, 0xc5, 0xff, 0xf3, 0xfe, 0xc6, 0xff, 0x07, 0xff, 0xcb, 0xff, 0x26, 0xff, 0xd7, 0xff, 0x51, 0xff, 0xe6, 0xff, 0x7c, 0xff, 0xf1, 0xff, 0xa0, 0xff, 0xf9, 0xff, 0xba, 0xff, 0xf8, 0xff, 0xca, 0xff, 0xf1, 0xff, 0xd2, 0xff, 0xe7, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xe9, 0xff, 0xc9, 0xff, 0xf2, 0xff, 0xad, 0xff, 0xf0, 0xff, 0x84, 0xff, 0xe0, 0xff, 0x57, 0xff, 0xc8, 0xff, 0x2b, 0xff, 0xae, 0xff, 0x06, 0xff, 0x9a, 0xff, 0xef, 0xfe, 0x94, 0xff, 0xde, 0xfe, 0x97, 0xff, 0xd4, 0xfe, 0xa2, 0xff, 0xd3, 0xfe, 0xb7, 0xff, 0xdd, 0xfe, 0xd5, 0xff, 0xef, 0xfe, 0xf8, 0xff, 0x09, 0xff, 0x1e, 0x00, 0x2e, 0xff, 0x4b, 0x00, 0x59, 0xff, 0x7e, 0x00, 0x82, 0xff, 0xae, 0x00, 0xa3, 0xff, 0xd4, 0x00, 0xbb, 0xff, 0xee, 0x00, 0xcc, 0xff, 0xfd, 0x00, 0xd7, 0xff, 0x03, 0x01, 0xdc, 0xff, 0x01, 0x01, 0xda, 0xff, 0xf7, 0x00, 0xd4, 0xff, 0xe9, 0x00, 0xca, 0xff, 0xd4, 0x00, 0xbc, 0xff, 0xb8, 0x00, 0xae, 0xff, 0x97, 0x00, 0xa0, 0xff, 0x71, 0x00, 0x97, 0xff, 0x4b, 0x00, 0x95, 0xff, 0x2a, 0x00, 0xa2, 0xff, 0x18, 0x00, 0xbc, 0xff, 0x16, 0x00, 0xd9, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x42, 0x00, 0x20, 0x00, 0x6b, 0x00, 0x24, 0x00, 0x97, 0x00, 0x2b, 0x00, 0xc0, 0x00, 0x35, 0x00, 0xdd, 0x00, 0x3a, 0x00, 0xec, 0x00, 0x34, 0x00, 0xf4, 0x00, 0x2c, 0x00, 0xf6, 0x00, 0x1f, 0x00, 0xec, 0x00, 0x07, 0x00, 0xdc, 0x00, 0xec, 0xff, 0xc9, 0x00, 0xcf, 0xff, 0xaf, 0x00, 0xb0, 0xff, 0x8f, 0x00, 0x8f, 0xff, 0x71, 0x00, 0x74, 0xff, 0x55, 0x00, 0x5d, 0xff, 0x37, 0x00, 0x46, 0xff, 0x20, 0x00, 0x32, 0xff, 0x17, 0x00, 0x2b, 0xff, 0x13, 0x00, 0x2a, 0xff, 0x0e, 0x00, 0x2c, 0xff, 0x0e, 0x00, 0x3a, 0xff, 0x10, 0x00, 0x4d, 0xff, 0x0e, 0x00, 0x5c, 0xff, 0x0d, 0x00, 0x68, 0xff, 0x16, 0x00, 0x7b, 0xff, 0x1c, 0x00, 0x8b, 0xff, 0x18, 0x00, 0x92, 0xff, 0x16, 0x00, 0x9c, 0xff, 0x11, 0x00, 0xa4, 0xff, 0xfd, 0xff, 0x9a, 0xff, 0xdf, 0xff, 0x86, 0xff, 0xce, 0xff, 0x7c, 0xff, 0xc5, 0xff, 0x7c, 0xff, 0xb6, 0xff, 0x75, 0xff, 0xa1, 0xff, 0x69, 0xff, 0x8e, 0xff, 0x5f, 0xff, 0x80, 0xff, 0x5b, 0xff, 0x7d, 0xff, 0x65, 0xff, 0x89, 0xff, 0x80, 0xff, 0x92, 0xff, 0x99, 0xff, 0x90, 0xff, 0xa5, 0xff, 0x96, 0xff, 0xb8, 0xff, 0xac, 0xff, 0xdc, 0xff, 0xbe, 0xff, 0xfc, 0xff, 0xc7, 0xff, 0x15, 0x00, 0xce, 0xff, 0x2b, 0x00, 0xcb, 0xff, 0x36, 0x00, 0xbd, 0xff, 0x33, 0x00, 0xaf, 0xff, 0x31, 0x00, 0xa4, 0xff, 0x33, 0x00, 0x92, 0xff, 0x31, 0x00, 0x89, 0xff, 0x3a, 0x00, 0x97, 0xff, 0x5a, 0x00, 0x98, 0xff, 0x6b, 0x00, 0x7e, 0xff, 0x59, 0x00, 0x77, 0xff, 0x55, 0x00, 0xa0, 0xff, 0x7a, 0x00, 0xc8, 0xff, 0x9c, 0x00, 0xca, 0xff, 0x96, 0x00, 0xc4, 0xff, 0x88, 0x00, 0xcb, 0xff, 0x87, 0x00, 0xdf, 0xff, 0x8e, 0x00, 0x03, 0x00, 0xa1, 0x00, 0x2b, 0x00, 0xb3, 0x00, 0x35, 0x00, 0xa2, 0x00, 0x23, 0x00, 0x78, 0x00, 0x28, 0x00, 0x64, 0x00, 0x45, 0x00, 0x6b, 0x00, 0x4d, 0x00, 0x60, 0x00, 0x44, 0x00, 0x45, 0x00, 0x48, 0x00, 0x36, 0x00, 0x52, 0x00, 0x2d, 0x00, 0x55, 0x00, 0x1d, 0x00, 0x61, 0x00, 0x19, 0x00, 0x72, 0x00, 0x21, 0x00, 0x73, 0x00, 0x1e, 0x00, 0x72, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x2e, 0x00, 0x9a, 0x00, 0x40, 0x00, 0xa4, 0x00, 0x42, 0x00, 0xb2, 0x00, 0x46, 0x00, 0xc5, 0x00, 0x53, 0x00, 0xcb, 0x00, 0x56, 0x00, 0xc3, 0x00, 0x4f, 0x00, 0xbc, 0x00, 0x4a, 0x00, 0xad, 0x00, 0x3a, 0x00, 0x93, 0x00, 0x1b, 0x00, 0x7f, 0x00, 0xfc, 0xff, 0x6d, 0x00, 0xdd, 0xff, 0x4b, 0x00, 0xae, 0xff, 0x2a, 0x00, 0x83, 0xff, 0x1c, 0x00, 0x6f, 0xff, 0x0f, 0x00, 0x5c, 0xff, 0xf4, 0xff, 0x3d, 0xff, 0xe4, 0xff, 0x2a, 0xff, 0xe9, 0xff, 0x2f, 0xff, 0xec, 0xff, 0x35, 0xff, 0xe5, 0xff, 0x32, 0xff, 0xe1, 0xff, 0x35, 0xff, 0xe1, 0xff, 0x3e, 0xff, 0xde, 0xff, 0x47, 0xff, 0xdd, 0xff, 0x53, 0xff, 0xdf, 0xff, 0x63, 0xff, 0xd8, 0xff, 0x6b, 0xff, 0xcc, 0xff, 0x70, 0xff, 0xc3, 0xff, 0x78, 0xff, 0xb5, 0xff, 0x7d, 0xff, 0x9d, 0xff, 0x7b, 0xff, 0x8a, 0xff, 0x7d, 0xff, 0x7b, 0xff, 0x81, 0xff, 0x6c, 0xff, 0x81, 0xff, 0x63, 0xff, 0x86, 0xff, 0x61, 0xff, 0x93, 0xff, 0x5c, 0xff, 0xa1, 0xff, 0x54, 0xff, 0xaf, 0xff, 0x5b, 0xff, 0xce, 0xff, 0x6e, 0xff, 0xf9, 0xff, 0x7f, 0xff, 0x1e, 0x00, 0x90, 0xff, 0x40, 0x00, 0xa8, 0xff, 0x65, 0x00, 0xba, 0xff, 0x83, 0x00, 0xc4, 0xff, 0x99, 0x00, 0xd4, 0xff, 0xb5, 0x00, 0xe6, 0xff, 0xd3, 0x00, 0xe5, 0xff, 0xe0, 0x00, 0xd5, 0xff, 0xde, 0x00, 0xce, 0xff, 0xe1, 0x00, 0xcf, 0xff, 0xe9, 0x00, 0xc9, 0xff, 0xe9, 0x00, 0xb8, 0xff, 0xdb, 0x00, 0xa1, 0xff, 0xc5, 0x00, 0x8f, 0xff, 0xb6, 0x00, 0x8e, 0xff, 0xba, 0x00, 0x9c, 0xff, 0xcd, 0x00, 0xa8, 0xff, 0xde, 0x00, 0xab, 0xff, 0xe2, 0x00, 0xae, 0xff, 0xe5, 0x00, 0xbb, 0xff, 0xef, 0x00, 0xcf, 0xff, 0xff, 0x00, 0xe8, 0xff, 0x12, 0x01, 0x02, 0x00, 0x23, 0x01, 0x16, 0x00, 0x2a, 0x01, 0x25, 0x00, 0x2c, 0x01, 0x37, 0x00, 0x30, 0x01, 0x47, 0x00, 0x34, 0x01, 0x4f, 0x00, 0x2d, 0x01, 0x54, 0x00, 0x22, 0x01, 0x62, 0x00, 0x1c, 0x01, 0x74, 0x00, 0x19, 0x01, 0x80, 0x00, 0x0e, 0x01, 0x82, 0x00, 0xfa, 0x00, 0x7f, 0x00, 0xde, 0x00, 0x77, 0x00, 0xbb, 0x00, 0x75, 0x00, 0x9b, 0x00, 0x7a, 0x00, 0x84, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x49, 0x00, 0x76, 0x00, 0x3c, 0x00, 0x73, 0x00, 0x2c, 0x00, 0x6b, 0x00, 0x17, 0x00, 0x64, 0x00, 0x02, 0x00, 0x60, 0x00, 0xf2, 0xff, 0x58, 0x00, 0xdf, 0xff, 0x4d, 0x00, 0xc6, 0xff, 0x42, 0x00, 0xae, 0xff, 0x37, 0x00, 0x96, 0xff, 0x29, 0x00, 0x7a, 0xff, 0x14, 0x00, 0x5a, 0xff, 0xff, 0xff, 0x3a, 0xff, 0xef, 0xff, 0x1e, 0xff, 0xe6, 0xff, 0x07, 0xff, 0xe6, 0xff, 0xfa, 0xfe, 0xec, 0xff, 0xf4, 0xfe, 0xf0, 0xff, 0xf3, 0xfe, 0xef, 0xff, 0xef, 0xfe, 0xe8, 0xff, 0xea, 0xfe, 0xe1, 0xff, 0xe7, 0xfe, 0xdb, 0xff, 0xe9, 0xfe, 0xdb, 0xff, 0xf0, 0xfe, 0xde, 0xff, 0xfa, 0xfe, 0xe2, 0xff, 0x05, 0xff, 0xe5, 0xff, 0x0e, 0xff, 0xe5, 0xff, 0x16, 0xff, 0xe0, 0xff, 0x1c, 0xff, 0xda, 0xff, 0x21, 0xff, 0xd6, 0xff, 0x2a, 0xff, 0xd1, 0xff, 0x33, 0xff, 0xcf, 0xff, 0x40, 0xff, 0xd2, 0xff, 0x54, 0xff, 0xd6, 0xff, 0x6e, 0xff, 0xd7, 0xff, 0x82, 0xff, 0xd0, 0xff, 0x8c, 0xff, 0xca, 0xff, 0x91, 0xff, 0xc8, 0xff, 0x98, 0xff, 0xc7, 0xff, 0xa2, 0xff, 0xc2, 0xff, 0xae, 0xff, 0xb9, 0xff, 0xba, 0xff, 0xaa, 0xff, 0xc3, 0xff, 0x9c, 0xff, 0xca, 0xff, 0x96, 0xff, 0xd5, 0xff, 0x95, 0xff, 0xe1, 0xff, 0x94, 0xff, 0xe9, 0xff, 0x94, 0xff, 0xef, 0xff, 0x98, 0xff, 0xfc, 0xff, 0x9e, 0xff, 0x0e, 0x00, 0xa6, 0xff, 0x25, 0x00, 0xad, 0xff, 0x38, 0x00, 0xb5, 0xff, 0x47, 0x00, 0xc0, 0xff, 0x54, 0x00, 0xd4, 0xff, 0x66, 0x00, 0xf0, 0xff, 0x82, 0x00, 0x08, 0x00, 0x98, 0x00, 0x16, 0x00, 0xa5, 0x00, 0x26, 0x00, 0xb0, 0x00, 0x3b, 0x00, 0xbc, 0x00, 0x4c, 0x00, 0xc4, 0x00, 0x5c, 0x00, 0xca, 0x00, 0x6a, 0x00, 0xce, 0x00, 0x74, 0x00, 0xce, 0x00, 0x7b, 0x00, 0xcb, 0x00, 0x80, 0x00, 0xc6, 0x00, 0x83, 0x00, 0xbc, 0x00, 0x77, 0x00, 0xa1, 0x00, 0x60, 0x00, 0x78, 0x00, 0x4b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x6c, 0x00, 0x50, 0x00, 0x82, 0x00, 0x61, 0x00, 0x8c, 0x00, 0x62, 0x00, 0x8a, 0x00, 0x53, 0x00, 0x7d, 0x00, 0x36, 0x00, 0x65, 0x00, 0x10, 0x00, 0x4a, 0x00, 0xe9, 0xff, 0x30, 0x00, 0xcb, 0xff, 0x16, 0x00, 0xb1, 0xff, 0x03, 0x00, 0xa0, 0xff, 0x04, 0x00, 0xa4, 0xff, 0x13, 0x00, 0xb4, 0xff, 0x1a, 0x00, 0xbb, 0xff, 0x0d, 0x00, 0xaf, 0xff, 0xf0, 0xff, 0x98, 0xff, 0xcf, 0xff, 0x80, 0xff, 0xb6, 0xff, 0x72, 0xff, 0xb2, 0xff, 0x78, 0xff, 0xbd, 0xff, 0x88, 0xff, 0xc3, 0xff, 0x8e, 0xff, 0xc1, 0xff, 0x87, 0xff, 0xc0, 0xff, 0x7f, 0xff, 0xc0, 0xff, 0x7b, 0xff, 0xbd, 0xff, 0x76, 0xff, 0xbb, 0xff, 0x75, 0xff, 0xbf, 0xff, 0x7a, 0xff, 0xc1, 0xff, 0x79, 0xff, 0xbb, 0xff, 0x6d, 0xff, 0xb9, 0xff, 0x62, 0xff, 0xbe, 0xff, 0x5e, 0xff, 0xc5, 0xff, 0x61, 0xff, 0xca, 0xff, 0x66, 0xff, 0xcb, 0xff, 0x69, 0xff, 0xc3, 0xff, 0x65, 0xff, 0xb3, 0xff, 0x58, 0xff, 0xa6, 0xff, 0x4c, 0xff, 0x9f, 0xff, 0x48, 0xff, 0xa0, 0xff, 0x4e, 0xff, 0xa8, 0xff, 0x60, 0xff, 0xb3, 0xff, 0x79, 0xff, 0xbf, 0xff, 0x9a, 0xff, 0xd0, 0xff, 0xc1, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xfd, 0xff, 0x15, 0x00, 0x09, 0x00, 0x34, 0x00, 0x0d, 0x00, 0x4c, 0x00, 0x15, 0x00, 0x69, 0x00, 0x1f, 0x00, 0x89, 0x00, 0x24, 0x00, 0xa2, 0x00, 0x22, 0x00, 0xad, 0x00, 0x20, 0x00, 0xb2, 0x00, 0x23, 0x00, 0xb9, 0x00, 0x26, 0x00, 0xbf, 0x00, 0x24, 0x00, 0xc3, 0x00, 0x1e, 0x00, 0xc6, 0x00, 0x14, 0x00, 0xc7, 0x00, 0x0a, 0x00, 0xc7, 0x00, 0x08, 0x00, 0xcb, 0x00, 0x10, 0x00, 0xd3, 0x00, 0x17, 0x00, 0xd6, 0x00, 0x1c, 0x00, 0xd4, 0x00, 0x23, 0x00, 0xd6, 0x00, 0x29, 0x00, 0xda, 0x00, 0x29, 0x00, 0xda, 0x00, 0x29, 0x00, 0xda, 0x00, 0x2d, 0x00, 0xdd, 0x00, 0x2f, 0x00, 0xdb, 0x00, 0x2b, 0x00, 0xcd, 0x00, 0x27, 0x00, 0xbe, 0x00, 0x23, 0x00, 0xae, 0x00, 0x17, 0x00, 0x98, 0x00, 0x08, 0x00, 0x7f, 0x00, 0xfc, 0xff, 0x6b, 0x00, 0xf5, 0xff, 0x57, 0x00, 0xeb, 0xff, 0x3e, 0x00, 0xe4, 0xff, 0x23, 0x00, 0xe1, 0xff, 0x0e, 0x00, 0xe3, 0xff, 0x03, 0x00, 0xe6, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfe, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xea, 0xff, 0xec, 0xff, 0xe4, 0xff, 0xe3, 0xff, 0xdb, 0xff, 0xd6, 0xff, 0xd1, 0xff, 0xc9, 0xff, 0xc9, 0xff, 0xbe, 0xff, 0xc1, 0xff, 0xb2, 0xff, 0xb7, 0xff, 0xa4, 0xff, 0xb0, 0xff, 0x98, 0xff, 0xb0, 0xff, 0x91, 0xff, 0xae, 0xff, 0x89, 0xff, 0xa5, 0xff, 0x7b, 0xff, 0x97, 0xff, 0x67, 0xff, 0x8a, 0xff, 0x53, 0xff, 0x80, 0xff, 0x3d, 0xff, 0x78, 0xff, 0x26, 0xff, 0x73, 0xff, 0x10, 0xff, 0x74, 0xff, 0xfd, 0xfe, 0x7c, 0xff, 0xf1, 0xfe, 0x84, 0xff, 0xe8, 0xfe, 0x8a, 0xff, 0xe2, 0xfe, 0x8e, 0xff, 0xe1, 0xfe, 0x95, 0xff, 0xe8, 0xfe, 0xa5, 0xff, 0xf8, 0xfe, 0xba, 0xff, 0x0d, 0xff, 0xd2, 0xff, 0x23, 0xff, 0xe8, 0xff, 0x37, 0xff, 0xf9, 0xff, 0x4b, 0xff, 0x06, 0x00, 0x5d, 0xff, 0x0d, 0x00, 0x6e, 0xff, 0x12, 0x00, 0x7e, 0xff, 0x15, 0x00, 0x8c, 0xff, 0x12, 0x00, 0x92, 0xff, 0x0a, 0x00, 0x92, 0xff, 0x02, 0x00, 0x94, 0xff, 0xff, 0xff, 0x9a, 0xff, 0xfc, 0xff, 0xa2, 0xff, 0xfd, 0xff, 0xae, 0xff, 0x02, 0x00, 0xbc, 0xff, 0x0a, 0x00, 0xcd, 0xff, 0x17, 0x00, 0xe1, 0xff, 0x24, 0x00, 0xf6, 0xff, 0x31, 0x00, 0x0b, 0x00, 0x3f, 0x00, 0x22, 0x00, 0x51, 0x00, 0x3a, 0x00, 0x66, 0x00, 0x53, 0x00, 0x80, 0x00, 0x69, 0x00, 0x9c, 0x00, 0x7d, 0x00, 0xba, 0x00, 0x91, 0x00, 0xd3, 0x00, 0xa1, 0x00, 0xe3, 0x00, 0xab, 0x00, 0xeb, 0x00, 0xb3, 0x00, 0xf2, 0x00, 0xb9, 0x00, 0xf9, 0x00, 0xc0, 0x00, 0x05, 0x01, 0xca, 0x00, 0x13, 0x01, 0xd1, 0x00, 0x1f, 0x01, 0xd2, 0x00, 0x2c, 0x01, 0xd1, 0x00, 0x38, 0x01, 0xcf, 0x00, 0x3f, 0x01, 0xcd, 0x00, 0x3c, 0x01, 0xc3, 0x00, 0x30, 0x01, 0xb2, 0x00, 0x25, 0x01, 0xa0, 0x00, 0x1c, 0x01, 0x91, 0x00, 0x13, 0x01, 0x84, 0x00, 0x0a, 0x01, 0x77, 0x00, 0xfc, 0x00, 0x68, 0x00, 0xeb, 0x00, 0x55, 0x00, 0xd6, 0x00, 0x3f, 0x00, 0xbf, 0x00, 0x2a, 0x00, 0xa8, 0x00, 0x18, 0x00, 0x8f, 0x00, 0x09, 0x00, 0x72, 0x00, 0xfb, 0xff, 0x53, 0x00, 0xec, 0xff, 0x35, 0x00, 0xdc, 0xff, 0x19, 0x00, 0xca, 0xff, 0x00, 0x00, 0xb6, 0xff, 0xe8, 0xff, 0xa0, 0xff, 0xcd, 0xff, 0x8a, 0xff, 0xb1, 0xff, 0x78, 0xff, 0x96, 0xff, 0x6d, 0xff, 0x7d, 0xff, 0x66, 0xff, 0x67, 0xff, 0x63, 0xff, 0x58, 0xff, 0x61, 0xff, 0x53, 0xff, 0x64, 0xff, 0x57, 0xff, 0x67, 0xff, 0x5d, 0xff, 0x6b, 0xff, 0x63, 0xff, 0x6f, 0xff, 0x65, 0xff, 0x75, 0xff, 0x62, 0xff, 0x7d, 0xff, 0x5f, 0xff, 0x87, 0xff, 0x5c, 0xff, 0x8e, 0xff, 0x5b, 0xff, 0x90, 0xff, 0x59, 0xff, 0x8b, 0xff, 0x56, 0xff, 0x85, 0xff, 0x53, 0xff, 0x7f, 0xff, 0x4e, 0xff, 0x7d, 0xff, 0x47, 0xff, 0x7f, 0xff, 0x40, 0xff, 0x81, 0xff, 0x39, 0xff, 0x82, 0xff, 0x33, 0xff, 0x81, 0xff, 0x2f, 0xff, 0x7f, 0xff, 0x31, 0xff, 0x7f, 0xff, 0x3b, 0xff, 0x86, 0xff, 0x4b, 0xff, 0x93, 0xff, 0x5b, 0xff, 0xa0, 0xff, 0x6d, 0xff, 0xb0, 0xff, 0x81, 0xff, 0xc2, 0xff, 0x96, 0xff, 0xd8, 0xff, 0xac, 0xff, 0xf0, 0xff, 0xbf, 0xff, 0x05, 0x00, 0xcf, 0xff, 0x15, 0x00, 0xdf, 0xff, 0x20, 0x00, 0xef, 0xff, 0x2a, 0x00, 0xfd, 0xff, 0x31, 0x00, 0x09, 0x00, 0x38, 0x00, 0x13, 0x00, 0x3d, 0x00, 0x1c, 0x00, 0x44, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x2a, 0x00, 0x59, 0x00, 0x31, 0x00, 0x67, 0x00, 0x36, 0x00, 0x71, 0x00, 0x3e, 0x00, 0x77, 0x00, 0x4b, 0x00, 0x7a, 0x00, 0x5c, 0x00, 0x7f, 0x00, 0x6f, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x92, 0x00, 0x85, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0xa2, 0x00, 0x8d, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x94, 0x00, 0x99, 0x00, 0x8c, 0x00, 0xa0, 0x00, 0x87, 0x00, 0xa6, 0x00, 0x84, 0x00, 0xa4, 0x00, 0x7d, 0x00, 0x9d, 0x00, 0x74, 0x00, 0x96, 0x00, 0x6c, 0x00, 0x8f, 0x00, 0x61, 0x00, 0x8a, 0x00, 0x55, 0x00, 0x83, 0x00, 0x47, 0x00, 0x7c, 0x00, 0x3a, 0x00, 0x71, 0x00, 0x2d, 0x00, 0x63, 0x00, 0x22, 0x00, 0x54, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x15, 0x00, 0x38, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x12, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xf9, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xe6, 0xff, 0xfc, 0xff, 0xd8, 0xff, 0xfd, 0xff, 0xcb, 0xff, 0xf9, 0xff, 0xbd, 0xff, 0xf2, 0xff, 0xab, 0xff, 0xe6, 0xff, 0x96, 0xff, 0xdb, 0xff, 0x7e, 0xff, 0xd3, 0xff, 0x64, 0xff, 0xce, 0xff, 0x4a, 0xff, 0xc9, 0xff, 0x35, 0xff, 0xc2, 0xff, 0x25, 0xff, 0xba, 0xff, 0x19, 0xff, 0xb3, 0xff, 0x0e, 0xff, 0xae, 0xff, 0x04, 0xff, 0xab, 0xff, 0xfa, 0xfe, 0xac, 0xff, 0xf2, 0xfe, 0xae, 0xff, 0xf0, 0xfe, 0xb4, 0xff, 0xf4, 0xfe, 0xbc, 0xff, 0xfc, 0xfe, 0xc4, 0xff, 0x06, 0xff, 0xca, 0xff, 0x0e, 0xff, 0xcf, 0xff, 0x14, 0xff, 0xd8, 0xff, 0x18, 0xff, 0xe3, 0xff, 0x1c, 0xff, 0xf0, 0xff, 0x23, 0xff, 0xfc, 0xff, 0x30, 0xff, 0x08, 0x00, 0x43, 0xff, 0x13, 0x00, 0x56, 0xff, 0x1a, 0x00, 0x69, 0xff, 0x23, 0x00, 0x7c, 0xff, 0x2d, 0x00, 0x8e, 0xff, 0x3c, 0x00, 0xa2, 0xff, 0x4c, 0x00, 0xb6, 0xff, 0x5b, 0x00, 0xcd, 0xff, 0x69, 0x00, 0xe4, 0xff, 0x75, 0x00, 0xfc, 0xff, 0x7d, 0x00, 0x11, 0x00, 0x85, 0x00, 0x22, 0x00, 0x8f, 0x00, 0x2e, 0x00, 0x98, 0x00, 0x35, 0x00, 0xa0, 0x00, 0x3a, 0x00, 0xa5, 0x00, 0x40, 0x00, 0xa6, 0x00, 0x4a, 0x00, 0xa6, 0x00, 0x57, 0x00, 0xa4, 0x00, 0x63, 0x00, 0xa0, 0x00, 0x6d, 0x00, 0x9e, 0x00, 0x75, 0x00, 0x9e, 0x00, 0x7c, 0x00, 0xa0, 0x00, 0x82, 0x00, 0xa1, 0x00, 0x89, 0x00, 0x9f, 0x00, 0x90, 0x00, 0x9a, 0x00, 0x97, 0x00, 0x93, 0x00, 0x9e, 0x00, 0x8c, 0x00, 0xa5, 0x00, 0x87, 0x00, 0xac, 0x00, 0x83, 0x00, 0xb1, 0x00, 0x7e, 0x00, 0xb4, 0x00, 0x79, 0x00, 0xb5, 0x00, 0x71, 0x00, 0xb5, 0x00, 0x68, 0x00, 0xb4, 0x00, 0x5e, 0x00, 0xaf, 0x00, 0x54, 0x00, 0xa7, 0x00, 0x4c, 0x00, 0x9a, 0x00, 0x46, 0x00, 0x8f, 0x00, 0x41, 0x00, 0x82, 0x00, 0x3b, 0x00, 0x73, 0x00, 0x2f, 0x00, 0x63, 0x00, 0x22, 0x00, 0x53, 0x00, 0x15, 0x00, 0x43, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x05, 0x00, 0x1f, 0x00, 0xfa, 0xff, 0x0d, 0x00, 0xf1, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xf5, 0xff, 0xe1, 0xff, 0xf2, 0xff, 0xdf, 0xff, 0xf1, 0xff, 0xdd, 0xff, 0xec, 0xff, 0xd8, 0xff, 0xe5, 0xff, 0xd0, 0xff, 0xdc, 0xff, 0xc6, 0xff, 0xd1, 0xff, 0xb9, 0xff, 0xc5, 0xff, 0xa9, 0xff, 0xb9, 0xff, 0x9a, 0xff, 0xac, 0xff, 0x8c, 0xff, 0x9f, 0xff, 0x82, 0xff, 0x94, 0xff, 0x7c, 0xff, 0x8a, 0xff, 0x78, 0xff, 0x83, 0xff, 0x74, 0xff, 0x7d, 0xff, 0x6c, 0xff, 0x79, 0xff, 0x61, 0xff, 0x74, 0xff, 0x55, 0xff, 0x6f, 0xff, 0x49, 0xff, 0x6e, 0xff, 0x44, 0xff, 0x70, 0xff, 0x45, 0xff, 0x70, 0xff, 0x45, 0xff, 0x72, 0xff, 0x43, 0xff, 0x77, 0xff, 0x3f, 0xff, 0x80, 0xff, 0x3a, 0xff, 0x89, 0xff, 0x31, 0xff, 0x90, 0xff, 0x27, 0xff, 0x98, 0xff, 0x22, 0xff, 0xa0, 0xff, 0x22, 0xff, 0xa9, 0xff, 0x24, 0xff, 0xb3, 0xff, 0x26, 0xff, 0xbc, 0xff, 0x25, 0xff, 0xc8, 0xff, 0x25, 0xff, 0xd6, 0xff, 0x27, 0xff, 0xe7, 0xff, 0x2f, 0xff, 0xfb, 0xff, 0x3e, 0xff, 0x12, 0x00, 0x52, 0xff, 0x2a, 0x00, 0x6b, 0xff, 0x41, 0x00, 0x85, 0xff, 0x56, 0x00, 0x9c, 0xff, 0x6b, 0x00, 0xb2, 0xff, 0x7d, 0x00, 0xc5, 0xff, 0x8c, 0x00, 0xd5, 0xff, 0x95, 0x00, 0xe5, 0xff, 0x97, 0x00, 0xf5, 0xff, 0x96, 0x00, 0x04, 0x00, 0x94, 0x00, 0x10, 0x00, 0x93, 0x00, 0x18, 0x00, 0x95, 0x00, 0x1d, 0x00, 0x95, 0x00, 0x21, 0x00, 0x95, 0x00, 0x25, 0x00, 0x95, 0x00, 0x2b, 0x00, 0x98, 0x00, 0x36, 0x00, 0x9a, 0x00, 0x43, 0x00, 0x9c, 0x00, 0x51, 0x00, 0x9c, 0x00, 0x5c, 0x00, 0x9a, 0x00, 0x63, 0x00, 0x98, 0x00, 0x65, 0x00, 0x97, 0x00, 0x63, 0x00, 0x92, 0x00, 0x5b, 0x00, 0x86, 0x00, 0x4f, 0x00, 0x78, 0x00, 0x44, 0x00, 0x69, 0x00, 0x3b, 0x00, 0x59, 0x00, 0x32, 0x00, 0x47, 0x00, 0x27, 0x00, 0x36, 0x00, 0x1a, 0x00, 0x27, 0x00, 0x0c, 0x00, 0x19, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xe9, 0xff, 0xfd, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xcc, 0xff, 0xf3, 0xff, 0xcd, 0xff, 0xf8, 0xff, 0xd7, 0xff, 0xfe, 0xff, 0xe3, 0xff, 0x01, 0x00, 0xea, 0xff, 0x05, 0x00, 0xf1, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0xee, 0xff, 0x00, 0x00, 0xdd, 0xff, 0xfb, 0xff, 0xce, 0xff, 0xf7, 0xff, 0xc3, 0xff, 0xf6, 0xff, 0xbb, 0xff, 0xf8, 0xff, 0xaf, 0xff, 0xf9, 0xff, 0x9d, 0xff, 0xf6, 0xff, 0x88, 0xff, 0xf0, 0xff, 0x71, 0xff, 0xe4, 0xff, 0x5a, 0xff, 0xd2, 0xff, 0x46, 0xff, 0xbe, 0xff, 0x37, 0xff, 0xa9, 0xff, 0x2b, 0xff, 0x95, 0xff, 0x22, 0xff, 0x84, 0xff, 0x1e, 0xff, 0x78, 0xff, 0x1d, 0xff, 0x70, 0xff, 0x20, 0xff, 0x6c, 0xff, 0x2a, 0xff, 0x6c, 0xff, 0x3c, 0xff, 0x6e, 0xff, 0x4f, 0xff, 0x6f, 0xff, 0x5d, 0xff, 0x6a, 0xff, 0x67, 0xff, 0x66, 0xff, 0x71, 0xff, 0x69, 0xff, 0x7a, 0xff, 0x71, 0xff, 0x85, 0xff, 0x7e, 0xff, 0x92, 0xff, 0x90, 0xff, 0xa3, 0xff, 0xa5, 0xff, 0xb6, 0xff, 0xbd, 0xff, 0xc8, 0xff, 0xd4, 0xff, 0xd6, 0xff, 0xeb, 0xff, 0xde, 0xff, 0xfc, 0xff, 0xe1, 0xff, 0x09, 0x00, 0xe5, 0xff, 0x13, 0x00, 0xea, 0xff, 0x1c, 0x00, 0xf5, 0xff, 0x28, 0x00, 0x0a, 0x00, 0x3d, 0x00, 0x27, 0x00, 0x59, 0x00, 0x41, 0x00, 0x70, 0x00, 0x52, 0x00, 0x7e, 0x00, 0x60, 0x00, 0x89, 0x00, 0x67, 0x00, 0x8d, 0x00, 0x6d, 0x00, 0x8e, 0x00, 0x72, 0x00, 0x8d, 0x00, 0x79, 0x00, 0x8a, 0x00, 0x7c, 0x00, 0x87, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x79, 0x00, 0x8a, 0x00, 0x70, 0x00, 0x8d, 0x00, 0x64, 0x00, 0x8e, 0x00, 0x5c, 0x00, 0x91, 0x00, 0x52, 0x00, 0x92, 0x00, 0x46, 0x00, 0x90, 0x00, 0x3e, 0x00, 0x92, 0x00, 0x3e, 0x00, 0x9f, 0x00, 0x46, 0x00, 0xb5, 0x00, 0x51, 0x00, 0xce, 0x00, 0x55, 0x00, 0xdd, 0x00, 0x50, 0x00, 0xe1, 0x00, 0x43, 0x00, 0xda, 0x00, 0x32, 0x00, 0xce, 0x00, 0x24, 0x00, 0xc5, 0x00, 0x1a, 0x00, 0xbf, 0x00, 0x14, 0x00, 0xbc, 0x00, 0x15, 0x00, 0xbf, 0x00, 0x22, 0x00, 0xcd, 0x00, 0x30, 0x00, 0xdc, 0x00, 0x37, 0x00, 0xe3, 0x00, 0x2e, 0x00, 0xdc, 0x00, 0x12, 0x00, 0xc6, 0x00, 0xed, 0xff, 0xa9, 0x00, 0xcd, 0xff, 0x94, 0x00, 0xbb, 0xff, 0x89, 0x00, 0xb7, 0xff, 0x86, 0x00, 0xbe, 0xff, 0x88, 0x00, 0xca, 0xff, 0x8a, 0x00, 0xd3, 0xff, 0x88, 0x00, 0xd7, 0xff, 0x81, 0x00, 0xd4, 0xff, 0x76, 0x00, 0xc9, 0xff, 0x61, 0x00, 0xb6, 0xff, 0x40, 0x00, 0xa2, 0xff, 0x18, 0x00, 0x96, 0xff, 0xf2, 0xff, 0x95, 0xff, 0xd5, 0xff, 0x9f, 0xff, 0xc6, 0xff, 0xb1, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xc4, 0xff, 0xd5, 0xff, 0xc5, 0xff, 0xe0, 0xff, 0xc3, 0xff, 0xe8, 0xff, 0xc1, 0xff, 0xeb, 0xff, 0xbe, 0xff, 0xe9, 0xff, 0xb7, 0xff, 0xe4, 0xff, 0xaf, 0xff, 0xdf, 0xff, 0xa7, 0xff, 0xe1, 0xff, 0xa6, 0xff, 0xee, 0xff, 0xaf, 0xff, 0x06, 0x00, 0xc0, 0xff, 0x20, 0x00, 0xd1, 0xff, 0x37, 0x00, 0xdf, 0xff, 0x46, 0x00, 0xe9, 0xff, 0x4f, 0x00, 0xef, 0xff, 0x55, 0x00, 0xf4, 0xff, 0x5c, 0x00, 0xf7, 0xff, 0x65, 0x00, 0xf9, 0xff, 0x6f, 0x00, 0xf7, 0xff, 0x7f, 0x00, 0xf8, 0xff, 0x94, 0x00, 0xfd, 0xff, 0xa6, 0x00, 0x06, 0x00, 0xb1, 0x00, 0x0f, 0x00, 0xae, 0x00, 0x12, 0x00, 0xa0, 0x00, 0x0c, 0x00, 0x8a, 0x00, 0xfb, 0xff, 0x75, 0x00, 0xe6, 0xff, 0x66, 0x00, 0xd6, 0xff, 0x64, 0x00, 0xd4, 0xff, 0x6e, 0x00, 0xe3, 0xff, 0x7c, 0x00, 0xfd, 0xff, 0x8a, 0x00, 0x1a, 0x00, 0x97, 0x00, 0x33, 0x00, 0x9f, 0x00, 0x44, 0x00, 0xa0, 0x00, 0x4b, 0x00, 0x9e, 0x00, 0x48, 0x00, 0x95, 0x00, 0x3c, 0x00, 0x8c, 0x00, 0x31, 0x00, 0x85, 0x00, 0x2c, 0x00, 0x85, 0x00, 0x2e, 0x00, 0x90, 0x00, 0x3c, 0x00, 0xa5, 0x00, 0x50, 0x00, 0xb8, 0x00, 0x60, 0x00, 0xc7, 0x00, 0x6c, 0x00, 0xcf, 0x00, 0x74, 0x00, 0xc8, 0x00, 0x71, 0x00, 0xb4, 0x00, 0x68, 0x00, 0x9b, 0x00, 0x5e, 0x00, 0x80, 0x00, 0x54, 0x00, 0x65, 0x00, 0x48, 0x00, 0x52, 0x00, 0x40, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x43, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x2f, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xe4, 0xff, 0x02, 0x00, 0xcd, 0xff, 0xe9, 0xff, 0xc2, 0xff, 0xd6, 0xff, 0xbe, 0xff, 0xc9, 0xff, 0xba, 0xff, 0xba, 0xff, 0xb8, 0xff, 0xaf, 0xff, 0xba, 0xff, 0xaa, 0xff, 0xb0, 0xff, 0x99, 0xff, 0x98, 0xff, 0x78, 0xff, 0x84, 0xff, 0x58, 0xff, 0x72, 0xff, 0x3b, 0xff, 0x5e, 0xff, 0x1b, 0xff, 0x5e, 0xff, 0x12, 0xff, 0x7b, 0xff, 0x29, 0xff, 0x94, 0xff, 0x3d, 0xff, 0x9f, 0xff, 0x46, 0xff, 0xa6, 0xff, 0x4a, 0xff, 0xa2, 0xff, 0x41, 0xff, 0x90, 0xff, 0x29, 0xff, 0x81, 0xff, 0x14, 0xff, 0x7a, 0xff, 0x07, 0xff, 0x78, 0xff, 0x00, 0xff, 0x83, 0xff, 0x07, 0xff, 0x9a, 0xff, 0x1a, 0xff, 0xb0, 0xff, 0x2c, 0xff, 0xc0, 0xff, 0x38, 0xff, 0xc7, 0xff, 0x3d, 0xff, 0xba, 0xff, 0x2f, 0xff, 0xa1, 0xff, 0x17, 0xff, 0x97, 0xff, 0x12, 0xff, 0x9a, 0xff, 0x1b, 0xff, 0xa7, 0xff, 0x2c, 0xff, 0xd2, 0xff, 0x58, 0xff, 0x11, 0x00, 0x99, 0xff, 0x34, 0x00, 0xc3, 0xff, 0x27, 0x00, 0xc2, 0xff, 0xf2, 0xff, 0x9e, 0xff, 0x9e, 0xff, 0x5a, 0xff, 0x53, 0xff, 0x1d, 0xff, 0x33, 0xff, 0x0a, 0xff, 0x39, 0xff, 0x1d, 0xff, 0x67, 0xff, 0x58, 0xff, 0xcb, 0xff, 0xc9, 0xff, 0x44, 0x00, 0x4b, 0x00, 0xa2, 0x00, 0xb2, 0x00, 0xc9, 0x00, 0xde, 0x00, 0x96, 0x00, 0xad, 0x00, 0x1a, 0x00, 0x30, 0x00, 0xa1, 0xff, 0xb3, 0xff, 0x58, 0xff, 0x66, 0xff, 0x55, 0xff, 0x63, 0xff, 0xae, 0xff, 0xc3, 0xff, 0x3b, 0x00, 0x5d, 0x00, 0xb5, 0x00, 0xe4, 0x00, 0xf6, 0x00, 0x2f, 0x01, 0xe5, 0x00, 0x24, 0x01, 0x8b, 0x00, 0xcd, 0x00, 0x29, 0x00, 0x6f, 0x00, 0xf1, 0xff, 0x42, 0x00, 0xf4, 0xff, 0x55, 0x00, 0x32, 0x00, 0xa7, 0x00, 0x71, 0x00, 0xfa, 0x00, 0x6c, 0x00, 0x05, 0x01, 0x0d, 0x00, 0xb0, 0x00, 0x60, 0xff, 0x09, 0x00, 0xae, 0xfe, 0x5b, 0xff, 0x66, 0xfe, 0x14, 0xff, 0xbf, 0xfe, 0x6d, 0xff, 0xb2, 0xff, 0x61, 0x00, 0xfb, 0x00, 0xaa, 0x01, 0x0e, 0x02, 0xbd, 0x02, 0x7e, 0x02, 0x2d, 0x03, 0x15, 0x02, 0xc0, 0x02, 0xb1, 0x00, 0x52, 0x01, 0xcc, 0xfe, 0x5e, 0xff, 0x6a, 0xfd, 0xea, 0xfd, 0x17, 0xfd, 0x86, 0xfd, 0xee, 0xfd, 0x4f, 0xfe, 0xd1, 0xff, 0x29, 0x00, 0xf6, 0x01, 0x46, 0x02, 0x61, 0x03, 0xa9, 0x03, 0xad, 0x03, 0xea, 0x03, 0xb2, 0x02, 0xe1, 0x02, 0xa7, 0x00, 0xca, 0x00, 0x8d, 0xfe, 0xa2, 0xfe, 0x50, 0xfd, 0x56, 0xfd, 0x3d, 0xfd, 0x33, 0xfd, 0x52, 0xfe, 0x39, 0xfe, 0x0b, 0x00, 0xe6, 0xff, 0x88, 0x01, 0x5b, 0x01, 0x42, 0x02, 0x10, 0x02, 0x02, 0x02, 0xcb, 0x01, 0xd8, 0x00, 0x9d, 0x00, 0x58, 0xff, 0x18, 0xff, 0x22, 0xfe, 0xe0, 0xfd, 0x98, 0xfd, 0x54, 0xfd, 0xee, 0xfd, 0xa9, 0xfd, 0xeb, 0xfe, 0xa7, 0xfe, 0xff, 0xff, 0xbd, 0xff, 0xc7, 0x00, 0x8c, 0x00, 0xfd, 0x00, 0xcc, 0x00, 0x7b, 0x00, 0x54, 0x00, 0x8a, 0xff, 0x68, 0xff, 0x84, 0xfe, 0x63, 0xfe, 0xbe, 0xfd, 0x9a, 0xfd, 0xa2, 0xfd, 0x7d, 0xfd, 0x33, 0xfe, 0x0e, 0xfe, 0x12, 0xff, 0xf2, 0xfe, 0x01, 0x00, 0xe9, 0xff, 0xb4, 0x00, 0xa7, 0x00, 0xe0, 0x00, 0xde, 0x00, 0x9a, 0x00, 0xa0, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x39, 0xff, 0x40, 0xff, 0x90, 0xfe, 0x95, 0xfe, 0x49, 0xfe, 0x4e, 0xfe, 0x69, 0xfe, 0x72, 0xfe, 0x02, 0xff, 0x13, 0xff, 0xe8, 0xff, 0x06, 0x00, 0xac, 0x00, 0xd8, 0x00, 0x19, 0x01, 0x51, 0x01, 0x12, 0x01, 0x51, 0x01, 0x84, 0x00, 0xc7, 0x00, 0xbb, 0xff, 0x00, 0x00, 0x0b, 0xff, 0x50, 0xff, 0x98, 0xfe, 0xde, 0xfe, 0xa4, 0xfe, 0xeb, 0xfe, 0x39, 0xff, 0x80, 0xff, 0xf2, 0xff, 0x39, 0x00, 0x85, 0x00, 0xcb, 0x00, 0xd3, 0x00, 0x17, 0x01, 0xb6, 0x00, 0xf8, 0x00, 0x4f, 0x00, 0x90, 0x00, 0xf2, 0xff, 0x32, 0x00, 0xbe, 0xff, 0xfc, 0xff, 0xba, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0x39, 0x00, 0x5f, 0x00, 0xa2, 0x00, 0xc3, 0x00, 0x0c, 0x01, 0xfb, 0x00, 0x4b, 0x01, 0xe0, 0x00, 0x35, 0x01, 0x75, 0x00, 0xcf, 0x00, 0xeb, 0xff, 0x49, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0x6d, 0xff, 0xcf, 0xff, 0xc9, 0xff, 0x29, 0x00, 0x63, 0x00, 0xc2, 0x00, 0xfd, 0x00, 0x5b, 0x01, 0x60, 0x01, 0xbe, 0x01, 0x58, 0x01, 0xb4, 0x01, 0xda, 0x00, 0x31, 0x01, 0x11, 0x00, 0x61, 0x00, 0x37, 0xff, 0x7e, 0xff, 0xa0, 0xfe, 0xdf, 0xfe, 0xad, 0xfe, 0xe4, 0xfe, 0x6b, 0xff, 0x9a, 0xff, 0x7b, 0x00, 0x9e, 0x00, 0x63, 0x01, 0x79, 0x01, 0xce, 0x01, 0xd5, 0x01, 0x95, 0x01, 0x8a, 0x01, 0xcb, 0x00, 0xac, 0x00, 0xc0, 0xff, 0x8c, 0xff, 0xe7, 0xfe, 0x9f, 0xfe, 0xa9, 0xfe, 0x4f, 0xfe, 0x36, 0xff, 0xce, 0xfe, 0x6e, 0x00, 0xfa, 0xff, 0xc9, 0x01, 0x48, 0x01, 0x7b, 0x02, 0xea, 0x01, 0x0f, 0x02, 0x6b, 0x01, 0xc1, 0x00, 0x08, 0x00, 0x17, 0xff, 0x4f, 0xfe, 0xba, 0xfd, 0xea, 0xfc, 0x6e, 0xfd, 0x9f, 0xfc, 0x70, 0xfe, 0xa7, 0xfd, 0x34, 0x00, 0x75, 0xff, 0xf4, 0x01, 0x40, 0x01, 0xe6, 0x02, 0x3e, 0x02, 0x6e, 0x02, 0xd2, 0x01, 0xbe, 0x00, 0x2f, 0x00, 0xb3, 0xfe, 0x32, 0xfe, 0x27, 0xfd, 0xb7, 0xfc, 0xa8, 0xfc, 0x50, 0xfc, 0x5c, 0xfd, 0x22, 0xfd, 0xf2, 0xfe, 0xd8, 0xfe, 0xb9, 0x00, 0xbc, 0x00, 0xdc, 0x01, 0xf8, 0x01, 0xdf, 0x01, 0x0e, 0x02, 0xe2, 0x00, 0x21, 0x01, 0x52, 0xff, 0x9e, 0xff, 0xc4, 0xfd, 0x1c, 0xfe, 0xfa, 0xfc, 0x59, 0xfd, 0x47, 0xfd, 0xaa, 0xfd, 0x5b, 0xfe, 0xc0, 0xfe, 0xc4, 0xff, 0x2c, 0x00, 0x0a, 0x01, 0x76, 0x01, 0xa5, 0x01, 0x14, 0x02, 0x63, 0x01, 0xd4, 0x01, 0x85, 0x00, 0xf6, 0x00, 0x76, 0xff, 0xe6, 0xff, 0x96, 0xfe, 0x03, 0xff, 0x10, 0xfe, 0x7e, 0xfe, 0x22, 0xfe, 0x93, 0xfe, 0xf7, 0xfe, 0x6e, 0xff, 0x22, 0x00, 0x9f, 0x00, 0x18, 0x01, 0x9b, 0x01, 0xbf, 0x01, 0x46, 0x02, 0xf5, 0x01, 0x7d, 0x02, 0x78, 0x01, 0xff, 0x01, 0x90, 0x00, 0x14, 0x01, 0xa5, 0xff, 0x22, 0x00, 0xd1, 0xfe, 0x48, 0xff, 0x71, 0xfe, 0xe5, 0xfe, 0xf0, 0xfe, 0x62, 0xff, 0x25, 0x00, 0x96, 0x00, 0x7d, 0x01, 0xeb, 0x01, 0x62, 0x02, 0xc7, 0x02, 0x76, 0x02, 0xd1, 0x02, 0xbb, 0x01, 0x09, 0x02, 0x80, 0x00, 0xc3, 0x00, 0x58, 0xff, 0x8f, 0xff, 0xdf, 0xfe, 0x0d, 0xff, 0x3e, 0xff, 0x65, 0xff, 0x2f, 0x00, 0x52, 0x00, 0x5b, 0x01, 0x7c, 0x01, 0x43, 0x02, 0x61, 0x02, 0x68, 0x02, 0x81, 0x02, 0xcb, 0x01, 0xde, 0x01, 0xd0, 0x00, 0xda, 0x00, 0xe4, 0xff, 0xe2, 0xff, 0x69, 0xff, 0x58, 0xff, 0x7f, 0xff, 0x5e, 0xff, 0x06, 0x00, 0xd6, 0xff, 0xc5, 0x00, 0x87, 0x00, 0x66, 0x01, 0x1c, 0x01, 0xa8, 0x01, 0x53, 0x01, 0x8a, 0x01, 0x2c, 0x01, 0x0b, 0x01, 0xa5, 0x00, 0x4f, 0x00, 0xe1, 0xff, 0xbd, 0xff, 0x41, 0xff, 0x80, 0xff, 0xf0, 0xfe, 0x86, 0xff, 0xe0, 0xfe, 0xd7, 0xff, 0x1f, 0xff, 0x4f, 0x00, 0x8d, 0xff, 0xa0, 0x00, 0xdc, 0xff, 0xb5, 0x00, 0xf4, 0xff, 0x93, 0x00, 0xd6, 0xff, 0x3c, 0x00, 0x82, 0xff, 0xd1, 0xff, 0x18, 0xff, 0x7d, 0xff, 0xc3, 0xfe, 0x56, 0xff, 0x9a, 0xfe, 0x67, 0xff, 0xa9, 0xfe, 0x9a, 0xff, 0xda, 0xfe, 0xd9, 0xff, 0x19, 0xff, 0x1d, 0x00, 0x61, 0xff, 0x3e, 0x00, 0x89, 0xff, 0x23, 0x00, 0x75, 0xff, 0xe8, 0xff, 0x43, 0xff, 0xaa, 0xff, 0x0d, 0xff, 0x77, 0xff, 0xe4, 0xfe, 0x70, 0xff, 0xe9, 0xfe, 0x9c, 0xff, 0x23, 0xff, 0xd9, 0xff, 0x72, 0xff, 0x0c, 0x00, 0xbc, 0xff, 0x13, 0x00, 0xde, 0xff, 0xe3, 0xff, 0xce, 0xff, 0x99, 0xff, 0xa4, 0xff, 0x49, 0xff, 0x74, 0xff, 0x14, 0xff, 0x58, 0xff, 0x1f, 0xff, 0x74, 0xff, 0x54, 0xff, 0xb5, 0xff, 0x84, 0xff, 0xef, 0xff, 0xab, 0xff, 0x1e, 0x00, 0xbe, 0xff, 0x38, 0x00, 0xa6, 0xff, 0x26, 0x00, 0x7d, 0xff, 0x04, 0x00, 0x60, 0xff, 0xee, 0xff, 0x4d, 0xff, 0xe1, 0xff, 0x49, 0xff, 0xe0, 0xff, 0x52, 0xff, 0xe7, 0xff, 0x5e, 0xff, 0xec, 0xff, 0x73, 0xff, 0xf7, 0xff, 0x8b, 0xff, 0x06, 0x00, 0xa1, 0xff, 0x16, 0x00, 0xbc, 0xff, 0x2d, 0x00, 0xce, 0xff, 0x3d, 0x00, 0xcd, 0xff, 0x3c, 0x00, 0xcd, 0xff, 0x3a, 0x00, 0xd4, 0xff, 0x3b, 0x00, 0xd7, 0xff, 0x36, 0x00, 0xea, 0xff, 0x40, 0x00, 0x15, 0x00, 0x60, 0x00, 0x35, 0x00, 0x7a, 0x00, 0x3f, 0x00, 0x81, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x47, 0x00, 0xca, 0xff, 0x0e, 0x00, 0xb4, 0xff, 0xf0, 0xff, 0xe0, 0xff, 0x0d, 0x00, 0x44, 0x00, 0x5e, 0x00, 0xa0, 0x00, 0xa7, 0x00, 0xc6, 0x00, 0xc0, 0x00, 0xbf, 0x00, 0xb2, 0x00, 0x8f, 0x00, 0x82, 0x00, 0x3a, 0x00, 0x2b, 0x00, 0xdb, 0xff, 0xc6, 0xff, 0x91, 0xff, 0x6d, 0xff, 0x7f, 0xff, 0x46, 0xff, 0xcf, 0xff, 0x7b, 0xff, 0x62, 0x00, 0xf4, 0xff, 0xdb, 0x00, 0x58, 0x00, 0xf6, 0x00, 0x64, 0x00, 0xac, 0x00, 0x10, 0x00, 0x24, 0x00, 0x82, 0xff, 0xa7, 0xff, 0xfc, 0xfe, 0x67, 0xff, 0xad, 0xfe, 0x7e, 0xff, 0xae, 0xfe, 0xef, 0xff, 0x06, 0xff, 0x80, 0x00, 0x81, 0xff, 0xdc, 0x00, 0xcf, 0xff, 0xdc, 0x00, 0xcd, 0xff, 0x8c, 0x00, 0x83, 0xff, 0x15, 0x00, 0x18, 0xff, 0xbe, 0xff, 0xce, 0xfe, 0xa9, 0xff, 0xc6, 0xfe, 0xcb, 0xff, 0xf4, 0xfe, 0x0e, 0x00, 0x42, 0xff, 0x54, 0x00, 0x92, 0xff, 0x79, 0x00, 0xc5, 0xff, 0x74, 0x00, 0xd1, 0xff, 0x47, 0x00, 0xbb, 0xff, 0x03, 0x00, 0x93, 0xff, 0xcb, 0xff, 0x77, 0xff, 0xad, 0xff, 0x70, 0xff, 0xa9, 0xff, 0x7c, 0xff, 0xbe, 0xff, 0x9c, 0xff, 0xdd, 0xff, 0xc5, 0xff, 0xf0, 0xff, 0xe1, 0xff, 0xef, 0xff, 0xeb, 0xff, 0xd9, 0xff, 0xe2, 0xff, 0xb0, 0xff, 0xc8, 0xff, 0x88, 0xff, 0xb1, 0xff, 0x72, 0xff, 0xad, 0xff, 0x73, 0xff, 0xc0, 0xff, 0x85, 0xff, 0xe0, 0xff, 0x99, 0xff, 0x01, 0x00, 0xa0, 0xff, 0x13, 0x00, 0xa1, 0xff, 0x1f, 0x00, 0xa0, 0xff, 0x27, 0x00, 0x9a, 0xff, 0x2b, 0x00, 0x9d, 0xff, 0x39, 0x00, 0xa7, 0xff, 0x4e, 0x00, 0xae, 0xff, 0x61, 0x00, 0xae, 0xff, 0x6d, 0x00, 0xac, 0xff, 0x74, 0x00, 0xb2, 0xff, 0x80, 0x00, 0xcb, 0xff, 0x9a, 0x00, 0xee, 0xff, 0xb7, 0x00, 0x07, 0x00, 0xc8, 0x00, 0x11, 0x00, 0xc9, 0x00, 0x0f, 0x00, 0xc2, 0x00, 0x07, 0x00, 0xbe, 0x00, 0x03, 0x00, 0xc3, 0x00, 0x0a, 0x00, 0xd2, 0x00, 0x23, 0x00, 0xef, 0x00, 0x4b, 0x00, 0x12, 0x01, 0x6b, 0x00, 0x25, 0x01, 0x7e, 0x00, 0x27, 0x01, 0x84, 0x00, 0x1e, 0x01, 0x7a, 0x00, 0x0b, 0x01, 0x64, 0x00, 0xf5, 0x00, 0x52, 0x00, 0xe9, 0x00, 0x4c, 0x00, 0xec, 0x00, 0x4c, 0x00, 0xf3, 0x00, 0x54, 0x00, 0xf9, 0x00, 0x5e, 0x00, 0xf8, 0x00, 0x6a, 0x00, 0xf0, 0x00, 0x76, 0x00, 0xe2, 0x00, 0x7c, 0x00, 0xd0, 0x00, 0x7d, 0x00, 0xc2, 0x00, 0x72, 0x00, 0xb2, 0x00, 0x5b, 0x00, 0x9d, 0x00, 0x48, 0x00, 0x8c, 0x00, 0x40, 0x00, 0x7f, 0x00, 0x40, 0x00, 0x72, 0x00, 0x48, 0x00, 0x63, 0x00, 0x58, 0x00, 0x58, 0x00, 0x68, 0x00, 0x4e, 0x00, 0x71, 0x00, 0x45, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x58, 0x00, 0x2b, 0x00, 0x43, 0x00, 0x20, 0x00, 0x33, 0x00, 0x17, 0x00, 0x2d, 0x00, 0x0b, 0x00, 0x37, 0x00, 0x01, 0x00, 0x4e, 0x00, 0xfc, 0xff, 0x6a, 0x00, 0xfb, 0xff, 0x7e, 0x00, 0xfc, 0xff, 0x7c, 0x00, 0xf6, 0xff, 0x62, 0x00, 0xe5, 0xff, 0x3d, 0x00, 0xd2, 0xff, 0x1d, 0x00, 0xc2, 0xff, 0x08, 0x00, 0xb5, 0xff, 0x08, 0x00, 0xae, 0xff, 0x18, 0x00, 0xad, 0xff, 0x2c, 0x00, 0xaf, 0xff, 0x3a, 0x00, 0xaf, 0xff, 0x34, 0x00, 0xa8, 0xff, 0x18, 0x00, 0x99, 0xff, 0xf2, 0xff, 0x8b, 0xff, 0xd0, 0xff, 0x87, 0xff, 0xb8, 0xff, 0x8c, 0xff, 0xb0, 0xff, 0x9d, 0xff, 0xb4, 0xff, 0xb1, 0xff, 0xbb, 0xff, 0xc0, 0xff, 0xc7, 0xff, 0xcb, 0xff, 0xd0, 0xff, 0xd2, 0xff, 0xd0, 0xff, 0xd3, 0xff, 0xc8, 0xff, 0xd4, 0xff, 0xbb, 0xff, 0xd8, 0xff, 0xae, 0xff, 0xe2, 0xff, 0xa8, 0xff, 0xf1, 0xff, 0xac, 0xff, 0x05, 0x00, 0xb6, 0xff, 0x18, 0x00, 0xc3, 0xff, 0x24, 0x00, 0xcf, 0xff, 0x27, 0x00, 0xd5, 0xff, 0x22, 0x00, 0xd6, 0xff, 0x1a, 0x00, 0xd1, 0xff, 0x11, 0x00, 0xc7, 0xff, 0x09, 0x00, 0xbf, 0xff, 0x06, 0x00, 0xbe, 0xff, 0x08, 0x00, 0xc6, 0xff, 0x0d, 0x00, 0xd8, 0xff, 0x14, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0x12, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2a, 0x00, 0x23, 0x00, 0x21, 0x00, 0x0f, 0x00, 0x15, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xf1, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0x0e, 0x00, 0xf1, 0xff, 0x25, 0x00, 0xf1, 0xff, 0x30, 0x00, 0xeb, 0xff, 0x30, 0x00, 0xe4, 0xff, 0x25, 0x00, 0xde, 0xff, 0x14, 0x00, 0xd8, 0xff, 0x05, 0x00, 0xd6, 0xff, 0xfc, 0xff, 0xd4, 0xff, 0xf7, 0xff, 0xce, 0xff, 0xf4, 0xff, 0xc3, 0xff, 0xf2, 0xff, 0xb6, 0xff, 0xf1, 0xff, 0xab, 0xff, 0xeb, 0xff, 0xa0, 0xff, 0xe1, 0xff, 0x97, 0xff, 0xd6, 0xff, 0x91, 0xff, 0xd0, 0xff, 0x91, 0xff, 0xcd, 0xff, 0x93, 0xff, 0xcd, 0xff, 0x93, 0xff, 0xd0, 0xff, 0x90, 0xff, 0xd1, 0xff, 0x85, 0xff, 0xcf, 0xff, 0x72, 0xff, 0xcc, 0xff, 0x5c, 0xff, 0xc7, 0xff, 0x47, 0xff, 0xbe, 0xff, 0x32, 0xff, 0xb2, 0xff, 0x1f, 0xff, 0xa9, 0xff, 0x11, 0xff, 0xa3, 0xff, 0x06, 0xff, 0xa1, 0xff, 0xf9, 0xfe, 0xa4, 0xff, 0xeb, 0xfe, 0xae, 0xff, 0xe1, 0xfe, 0xbc, 0xff, 0xdc, 0xfe, 0xc8, 0xff, 0xda, 0xfe, 0xcd, 0xff, 0xdc, 0xfe, 0xc9, 0xff, 0xe1, 0xfe, 0xbe, 0xff, 0xe5, 0xfe, 0xb1, 0xff, 0xe8, 0xfe, 0xa6, 0xff, 0xe8, 0xfe, 0x9f, 0xff, 0xe3, 0xfe, 0xa3, 0xff, 0xe1, 0xfe, 0xae, 0xff, 0xe3, 0xfe, 0xba, 0xff, 0xec, 0xfe, 0xbd, 0xff, 0xf3, 0xfe, 0xb4, 0xff, 0xfa, 0xfe, 0xa5, 0xff, 0x06, 0xff, 0x93, 0xff, 0x12, 0xff, 0x85, 0xff, 0x21, 0xff, 0x81, 0xff, 0x30, 0xff, 0x89, 0xff, 0x40, 0xff, 0x9a, 0xff, 0x4e, 0xff, 0xad, 0xff, 0x5a, 0xff, 0xbe, 0xff, 0x67, 0xff, 0xc5, 0xff, 0x77, 0xff, 0xc5, 0xff, 0x8a, 0xff, 0xc3, 0xff, 0xa3, 0xff, 0xc5, 0xff, 0xc0, 0xff, 0xcd, 0xff, 0xdd, 0xff, 0xdb, 0xff, 0xf8, 0xff, 0xed, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0e, 0x00, 0x31, 0x00, 0x15, 0x00, 0x38, 0x00, 0x13, 0x00, 0x3a, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0xff, 0xff, 0x44, 0x00, 0xf8, 0xff, 0x57, 0x00, 0xf7, 0xff, 0x6f, 0x00, 0xfc, 0xff, 0x85, 0x00, 0x07, 0x00, 0x97, 0x00, 0x17, 0x00, 0xa6, 0x00, 0x23, 0x00, 0xae, 0x00, 0x28, 0x00, 0xb1, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x2f, 0x00, 0xce, 0x00, 0x35, 0x00, 0xed, 0x00, 0x3d, 0x00, 0x11, 0x01, 0x46, 0x00, 0x33, 0x01, 0x4f, 0x00, 0x48, 0x01, 0x52, 0x00, 0x4a, 0x01, 0x4f, 0x00, 0x3d, 0x01, 0x4e, 0x00, 0x31, 0x01, 0x4e, 0x00, 0x2b, 0x01, 0x4b, 0x00, 0x2a, 0x01, 0x49, 0x00, 0x2e, 0x01, 0x47, 0x00, 0x33, 0x01, 0x47, 0x00, 0x33, 0x01, 0x49, 0x00, 0x2c, 0x01, 0x49, 0x00, 0x1a, 0x01, 0x48, 0x00, 0x03, 0x01, 0x43, 0x00, 0xeb, 0x00, 0x3b, 0x00, 0xd5, 0x00, 0x36, 0x00, 0xc7, 0x00, 0x33, 0x00, 0xbc, 0x00, 0x35, 0x00, 0xb3, 0x00, 0x3b, 0x00, 0xa9, 0x00, 0x44, 0x00, 0x9b, 0x00, 0x4d, 0x00, 0x89, 0x00, 0x53, 0x00, 0x78, 0x00, 0x55, 0x00, 0x68, 0x00, 0x51, 0x00, 0x5c, 0x00, 0x49, 0x00, 0x55, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x26, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x18, 0x00, 0xfa, 0xff, 0x1d, 0x00, 0xea, 0xff, 0x1d, 0x00, 0xdb, 0xff, 0x19, 0x00, 0xd2, 0xff, 0x14, 0x00, 0xcd, 0xff, 0x0b, 0x00, 0xc5, 0xff, 0xfd, 0xff, 0xb5, 0xff, 0xf4, 0xff, 0xa5, 0xff, 0xf6, 0xff, 0x9b, 0xff, 0x00, 0x00, 0x95, 0xff, 0x12, 0x00, 0x98, 0xff, 0x28, 0x00, 0xa3, 0xff, 0x3d, 0x00, 0xb6, 0xff, 0x46, 0x00, 0xc7, 0xff, 0x3f, 0x00, 0xce, 0xff, 0x30, 0x00, 0xcb, 0xff, 0x20, 0x00, 0xc1, 0xff, 0x15, 0x00, 0xb4, 0xff, 0x14, 0x00, 0xac, 0xff, 0x1b, 0x00, 0xa9, 0xff, 0x26, 0x00, 0xab, 0xff, 0x30, 0x00, 0xb3, 0xff, 0x37, 0x00, 0xc4, 0xff, 0x3a, 0x00, 0xd9, 0xff, 0x36, 0x00, 0xeb, 0xff, 0x2b, 0x00, 0xf4, 0xff, 0x20, 0x00, 0xf4, 0xff, 0x18, 0x00, 0xf0, 0xff, 0x17, 0x00, 0xf0, 0xff, 0x1e, 0x00, 0xf9, 0xff, 0x2a, 0x00, 0x0a, 0x00, 0x37, 0x00, 0x21, 0x00, 0x41, 0x00, 0x3a, 0x00, 0x46, 0x00, 0x52, 0x00, 0x42, 0x00, 0x66, 0x00, 0x39, 0x00, 0x72, 0x00, 0x31, 0x00, 0x7b, 0x00, 0x2c, 0x00, 0x82, 0x00, 0x28, 0x00, 0x87, 0x00, 0x21, 0x00, 0x89, 0x00, 0x19, 0x00, 0x8e, 0x00, 0x0e, 0x00, 0x93, 0x00, 0x05, 0x00, 0x98, 0x00, 0x00, 0x00, 0x9c, 0x00, 0xfc, 0xff, 0x9c, 0x00, 0xf8, 0xff, 0x98, 0x00, 0xf0, 0xff, 0x8f, 0x00, 0xe7, 0xff, 0x85, 0x00, 0xdc, 0xff, 0x7e, 0x00, 0xd0, 0xff, 0x78, 0x00, 0xc7, 0xff, 0x79, 0x00, 0xc4, 0xff, 0x80, 0x00, 0xc7, 0xff, 0x87, 0x00, 0xce, 0xff, 0x8a, 0x00, 0xdb, 0xff, 0x89, 0x00, 0xe8, 0xff, 0x86, 0x00, 0xf2, 0xff, 0x82, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0xfd, 0xff, 0x7e, 0x00, 0x04, 0x00, 0x7d, 0x00, 0x0e, 0x00, 0x79, 0x00, 0x19, 0x00, 0x73, 0x00, 0x24, 0x00, 0x68, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x2f, 0x00, 0x41, 0x00, 0x2c, 0x00, 0x28, 0x00, 0x25, 0x00, 0x11, 0x00, 0x1d, 0x00, 0xfb, 0xff, 0x18, 0x00, 0xe7, 0xff, 0x1c, 0x00, 0xd6, 0xff, 0x26, 0x00, 0xc8, 0xff, 0x2e, 0x00, 0xb7, 0xff, 0x30, 0x00, 0xa3, 0xff, 0x27, 0x00, 0x8c, 0xff, 0x15, 0x00, 0x76, 0xff, 0xfe, 0xff, 0x65, 0xff, 0xe6, 0xff, 0x5a, 0xff, 0xd4, 0xff, 0x56, 0xff, 0xc9, 0xff, 0x54, 0xff, 0xc7, 0xff, 0x50, 0xff, 0xca, 0xff, 0x4a, 0xff, 0xcb, 0xff, 0x40, 0xff, 0xc6, 0xff, 0x34, 0xff, 0xbc, 0xff, 0x2b, 0xff, 0xac, 0xff, 0x25, 0xff, 0x9c, 0xff, 0x22, 0xff, 0x94, 0xff, 0x27, 0xff, 0x97, 0xff, 0x32, 0xff, 0x9d, 0xff, 0x3b, 0xff, 0x9f, 0xff, 0x3d, 0xff, 0x9d, 0xff, 0x3c, 0xff, 0x98, 0xff, 0x37, 0xff, 0x91, 0xff, 0x30, 0xff, 0x8d, 0xff, 0x2f, 0xff, 0x94, 0xff, 0x36, 0xff, 0x9f, 0xff, 0x43, 0xff, 0xa9, 0xff, 0x50, 0xff, 0xae, 0xff, 0x5a, 0xff, 0xaf, 0xff, 0x66, 0xff, 0xaf, 0xff, 0x75, 0xff, 0xad, 0xff, 0x87, 0xff, 0xad, 0xff, 0x9b, 0xff, 0xb2, 0xff, 0xb0, 0xff, 0xbf, 0xff, 0xc5, 0xff, 0xd1, 0xff, 0xd7, 0xff, 0xe5, 0xff, 0xe8, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x23, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0xfd, 0xff, 0x5b, 0x00, 0x02, 0x00, 0x74, 0x00, 0x0d, 0x00, 0x86, 0x00, 0x1b, 0x00, 0x8f, 0x00, 0x27, 0x00, 0x92, 0x00, 0x2c, 0x00, 0x92, 0x00, 0x2a, 0x00, 0x96, 0x00, 0x20, 0x00, 0xa1, 0x00, 0x14, 0x00, 0xb5, 0x00, 0x0b, 0x00, 0xcf, 0x00, 0x07, 0x00, 0xe4, 0x00, 0x07, 0x00, 0xec, 0x00, 0x0c, 0x00, 0xe4, 0x00, 0x13, 0x00, 0xd3, 0x00, 0x19, 0x00, 0xbe, 0x00, 0x19, 0x00, 0xab, 0x00, 0x16, 0x00, 0xa1, 0x00, 0x0e, 0x00, 0x9f, 0x00, 0x04, 0x00, 0xa3, 0x00, 0xfd, 0xff, 0xaa, 0x00, 0xfc, 0xff, 0xaf, 0x00, 0x00, 0x00, 0xad, 0x00, 0x04, 0x00, 0x9f, 0x00, 0x06, 0x00, 0x88, 0x00, 0x07, 0x00, 0x71, 0x00, 0x05, 0x00, 0x5e, 0x00, 0x01, 0x00, 0x51, 0x00, 0xff, 0xff, 0x4c, 0x00, 0x02, 0x00, 0x4f, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x15, 0x00, 0x5b, 0x00, 0x20, 0x00, 0x5d, 0x00, 0x26, 0x00, 0x56, 0x00, 0x24, 0x00, 0x46, 0x00, 0x1e, 0x00, 0x2e, 0x00, 0x19, 0x00, 0x17, 0x00, 0x19, 0x00, 0x04, 0x00, 0x1f, 0x00, 0xf5, 0xff, 0x2c, 0x00, 0xee, 0xff, 0x3a, 0x00, 0xeb, 0xff, 0x46, 0x00, 0xe7, 0xff, 0x4e, 0x00, 0xe1, 0xff, 0x50, 0x00, 0xd7, 0xff, 0x4d, 0x00, 0xc7, 0xff, 0x46, 0x00, 0xaf, 0xff, 0x41, 0x00, 0x98, 0xff, 0x44, 0x00, 0x89, 0xff, 0x4c, 0x00, 0x83, 0xff, 0x53, 0x00, 0x81, 0xff, 0x57, 0x00, 0x84, 0xff, 0x57, 0x00, 0x87, 0xff, 0x50, 0x00, 0x81, 0xff, 0x46, 0x00, 0x75, 0xff, 0x3d, 0x00, 0x64, 0xff, 0x38, 0x00, 0x55, 0xff, 0x34, 0x00, 0x4c, 0xff, 0x31, 0x00, 0x4a, 0xff, 0x2e, 0x00, 0x50, 0xff, 0x29, 0x00, 0x58, 0xff, 0x25, 0x00, 0x60, 0xff, 0x21, 0x00, 0x67, 0xff, 0x1f, 0x00, 0x6c, 0xff, 0x1b, 0x00, 0x6d, 0xff, 0x1a, 0x00, 0x6f, 0xff, 0x1c, 0x00, 0x75, 0xff, 0x1f, 0x00, 0x7e, 0xff, 0x1f, 0x00, 0x88, 0xff, 0x1b, 0x00, 0x92, 0xff, 0x16, 0x00, 0x9c, 0xff, 0x11, 0x00, 0xa4, 0xff, 0x0c, 0x00, 0xa8, 0xff, 0x07, 0x00, 0xa9, 0xff, 0x03, 0x00, 0xaa, 0xff, 0xfb, 0xff, 0xaa, 0xff, 0xf0, 0xff, 0xab, 0xff, 0xe6, 0xff, 0xae, 0xff, 0xdc, 0xff, 0xb1, 0xff, 0xd5, 0xff, 0xb7, 0xff, 0xd5, 0xff, 0xc4, 0xff, 0xdc, 0xff, 0xd6, 0xff, 0xe3, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xf0, 0xff, 0xe3, 0xff, 0xf6, 0xff, 0xdb, 0xff, 0xfb, 0xff, 0xd0, 0xff, 0x01, 0x00, 0xc5, 0xff, 0x0c, 0x00, 0xbb, 0xff, 0x19, 0x00, 0xb3, 0xff, 0x25, 0x00, 0xaf, 0xff, 0x2f, 0x00, 0xad, 0xff, 0x33, 0x00, 0xad, 0xff, 0x32, 0x00, 0xab, 0xff, 0x29, 0x00, 0xa8, 0xff, 0x23, 0x00, 0xa9, 0xff, 0x28, 0x00, 0xad, 0xff, 0x37, 0x00, 0xae, 0xff, 0x4a, 0x00, 0xad, 0xff, 0x5b, 0x00, 0xae, 0xff, 0x67, 0x00, 0xac, 0xff, 0x65, 0x00, 0xaa, 0xff, 0x58, 0x00, 0xa7, 0xff, 0x44, 0x00, 0xa3, 0xff, 0x30, 0x00, 0xa1, 0xff, 0x25, 0x00, 0xa2, 0xff, 0x25, 0x00, 0xa5, 0xff, 0x2d, 0x00, 0xaa, 0xff, 0x38, 0x00, 0xaf, 0xff, 0x3d, 0x00, 0xb1, 0xff, 0x37, 0x00, 0xb0, 0xff, 0x28, 0x00, 0xac, 0xff, 0x0f, 0x00, 0xa8, 0xff, 0xf8, 0xff, 0xa9, 0xff, 0xea, 0xff, 0xae, 0xff, 0xe2, 0xff, 0xb4, 0xff, 0xdf, 0xff, 0xbd, 0xff, 0xde, 0xff, 0xc8, 0xff, 0xde, 0xff, 0xd1, 0xff, 0xdb, 0xff, 0xd7, 0xff, 0xd6, 0xff, 0xda, 0xff, 0xcf, 0xff, 0xdc, 0xff, 0xc7, 0xff, 0xdd, 0xff, 0xbe, 0xff, 0xde, 0xff, 0xb3, 0xff, 0xe2, 0xff, 0xaa, 0xff, 0xe8, 0xff, 0xa5, 0xff, 0xf0, 0xff, 0xa2, 0xff, 0xf9, 0xff, 0xa6, 0xff, 0x05, 0x00, 0xb0, 0xff, 0x14, 0x00, 0xbb, 0xff, 0x23, 0x00, 0xc2, 0xff, 0x2f, 0x00, 0xc1, 0xff, 0x37, 0x00, 0xb9, 0xff, 0x37, 0x00, 0xab, 0xff, 0x34, 0x00, 0x9e, 0xff, 0x33, 0x00, 0x99, 0xff, 0x34, 0x00, 0x9c, 0xff, 0x3b, 0x00, 0xa6, 0xff, 0x45, 0x00, 0xb4, 0xff, 0x51, 0x00, 0xc0, 0xff, 0x58, 0x00, 0xc3, 0xff, 0x59, 0x00, 0xbf, 0xff, 0x53, 0x00, 0xba, 0xff, 0x40, 0x00, 0xb4, 0xff, 0x29, 0x00, 0xb3, 0xff, 0x18, 0x00, 0xbd, 0xff, 0x15, 0x00, 0xd4, 0xff, 0x23, 0x00, 0xf1, 0xff, 0x37, 0x00, 0x08, 0x00, 0x45, 0x00, 0x12, 0x00, 0x44, 0x00, 0x11, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0a, 0x00, 0xf6, 0xff, 0x11, 0x00, 0xf2, 0xff, 0x1d, 0x00, 0xfd, 0xff, 0x2b, 0x00, 0x12, 0x00, 0x3a, 0x00, 0x28, 0x00, 0x46, 0x00, 0x35, 0x00, 0x4e, 0x00, 0x34, 0x00, 0x51, 0x00, 0x25, 0x00, 0x51, 0x00, 0x11, 0x00, 0x52, 0x00, 0x01, 0x00, 0x56, 0x00, 0xf7, 0xff, 0x5c, 0x00, 0xf6, 0xff, 0x64, 0x00, 0xfd, 0xff, 0x6d, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x18, 0x00, 0x84, 0x00, 0x22, 0x00, 0x8b, 0x00, 0x21, 0x00, 0x8a, 0x00, 0x13, 0x00, 0x81, 0x00, 0xfe, 0xff, 0x76, 0x00, 0xeb, 0xff, 0x72, 0x00, 0xe0, 0xff, 0x75, 0x00, 0xdb, 0xff, 0x79, 0x00, 0xde, 0xff, 0x7d, 0x00, 0xe6, 0xff, 0x7c, 0x00, 0xef, 0xff, 0x76, 0x00, 0xf7, 0xff, 0x68, 0x00, 0xfe, 0xff, 0x56, 0x00, 0x04, 0x00, 0x47, 0x00, 0x06, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x3d, 0x00, 0xfc, 0xff, 0x3e, 0x00, 0xf4, 0xff, 0x3d, 0x00, 0xeb, 0xff, 0x31, 0x00, 0xe7, 0xff, 0x1e, 0x00, 0xe7, 0xff, 0x06, 0x00, 0xea, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xe4, 0xff, 0xff, 0xff, 0xe6, 0xff, 0x09, 0x00, 0xf2, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x09, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf5, 0xff, 0x21, 0x00, 0xff, 0xff, 0x29, 0x00, 0x11, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x01, 0x00, 0x21, 0x00, 0xf3, 0xff, 0x13, 0x00, 0xeb, 0xff, 0x06, 0x00, 0xeb, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x00, 0x00, 0xde, 0xff, 0xfd, 0xff, 0xca, 0xff, 0xf7, 0xff, 0xbb, 0xff, 0xee, 0xff, 0xb5, 0xff, 0xe3, 0xff, 0xb7, 0xff, 0xd4, 0xff, 0xbf, 0xff, 0xc5, 0xff, 0xce, 0xff, 0xbd, 0xff, 0xdc, 0xff, 0xc1, 0xff, 0xe2, 0xff, 0xd0, 0xff, 0xe2, 0xff, 0xe6, 0xff, 0xdf, 0xff, 0xfd, 0xff, 0xda, 0xff, 0x09, 0x00, 0xd7, 0xff, 0x07, 0x00, 0xd8, 0xff, 0xf8, 0xff, 0xdf, 0xff, 0xea, 0xff, 0xec, 0xff, 0xe5, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0x0c, 0x00, 0x11, 0x00, 0x17, 0x00, 0x36, 0x00, 0x1b, 0x00, 0x55, 0x00, 0x1c, 0x00, 0x65, 0x00, 0x1a, 0x00, 0x61, 0x00, 0x15, 0x00, 0x4d, 0x00, 0x11, 0x00, 0x35, 0x00, 0x10, 0x00, 0x27, 0x00, 0x10, 0x00, 0x25, 0x00, 0x0f, 0x00, 0x2e, 0x00, 0x0c, 0x00, 0x3e, 0x00, 0x0c, 0x00, 0x4b, 0x00, 0x0f, 0x00, 0x4f, 0x00, 0x14, 0x00, 0x47, 0x00, 0x1d, 0x00, 0x38, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x19, 0x00, 0x22, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x34, 0x00, 0x06, 0x00, 0x3d, 0x00, 0x03, 0x00, 0x42, 0x00, 0x01, 0x00, 0x3f, 0x00, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x05, 0x00, 0x3d, 0x00, 0x0a, 0x00, 0x42, 0x00, 0x0e, 0x00, 0x4e, 0x00, 0x14, 0x00, 0x5b, 0x00, 0x19, 0x00, 0x65, 0x00, 0x19, 0x00, 0x6a, 0x00, 0x15, 0x00, 0x67, 0x00, 0x0c, 0x00, 0x5f, 0x00, 0x02, 0x00, 0x51, 0x00, 0xf6, 0xff, 0x43, 0x00, 0xec, 0xff, 0x3b, 0x00, 0xe4, 0xff, 0x39, 0x00, 0xd9, 0xff, 0x3c, 0x00, 0xc9, 0xff, 0x44, 0x00, 0xb4, 0xff, 0x4b, 0x00, 0x9c, 0xff, 0x4d, 0x00, 0x85, 0xff, 0x4d, 0x00, 0x75, 0xff, 0x4b, 0x00, 0x6f, 0xff, 0x46, 0x00, 0x6e, 0xff, 0x3e, 0x00, 0x6f, 0xff, 0x35, 0x00, 0x6e, 0xff, 0x2f, 0x00, 0x6a, 0xff, 0x2e, 0x00, 0x61, 0xff, 0x35, 0x00, 0x59, 0xff, 0x44, 0x00, 0x57, 0xff, 0x56, 0x00, 0x5d, 0xff, 0x60, 0x00, 0x69, 0xff, 0x5e, 0x00, 0x78, 0xff, 0x4f, 0x00, 0x87, 0xff, 0x37, 0x00, 0x8e, 0xff, 0x1e, 0x00, 0x8d, 0xff, 0x09, 0x00, 0x88, 0xff, 0x01, 0x00, 0x85, 0xff, 0x00, 0x00, 0x85, 0xff, 0x04, 0x00, 0x8e, 0xff, 0x0c, 0x00, 0xa2, 0xff, 0x10, 0x00, 0xba, 0xff, 0x0b, 0x00, 0xd0, 0xff, 0xfe, 0xff, 0xde, 0xff, 0xec, 0xff, 0xe2, 0xff, 0xda, 0xff, 0xdd, 0xff, 0xcd, 0xff, 0xd3, 0xff, 0xc9, 0xff, 0xc8, 0xff, 0xce, 0xff, 0xc1, 0xff, 0xd8, 0xff, 0xc5, 0xff, 0xe3, 0xff, 0xd3, 0xff, 0xeb, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xdd, 0xff, 0x02, 0x00, 0xcf, 0xff, 0x04, 0x00, 0xc4, 0xff, 0x00, 0x00, 0xbf, 0xff, 0xf9, 0xff, 0xc0, 0xff, 0xf1, 0xff, 0xc7, 0xff, 0xef, 0xff, 0xd1, 0xff, 0xf6, 0xff, 0xd9, 0xff, 0x05, 0x00, 0xdd, 0xff, 0x1c, 0x00, 0xe0, 0xff, 0x37, 0x00, 0xdd, 0xff, 0x4f, 0x00, 0xd7, 0xff, 0x5e, 0x00, 0xd1, 0xff, 0x65, 0x00, 0xcf, 0xff, 0x67, 0x00, 0xcf, 0xff, 0x66, 0x00, 0xd2, 0xff, 0x66, 0x00, 0xda, 0xff, 0x6d, 0x00, 0xe5, 0xff, 0x7e, 0x00, 0xee, 0xff, 0x95, 0x00, 0xf3, 0xff, 0xac, 0x00, 0xf2, 0xff, 0xc0, 0x00, 0xeb, 0xff, 0xc8, 0x00, 0xe2, 0xff, 0xc6, 0x00, 0xdc, 0xff, 0xbd, 0x00, 0xdb, 0xff, 0xae, 0x00, 0xdd, 0xff, 0xa1, 0x00, 0xe4, 0xff, 0x9b, 0x00, 0xef, 0xff, 0xa2, 0x00, 0xfc, 0xff, 0xb1, 0x00, 0x04, 0x00, 0xbf, 0x00, 0x06, 0x00, 0xc3, 0x00, 0x04, 0x00, 0xba, 0x00, 0xfb, 0xff, 0xa0, 0x00, 0xf0, 0xff, 0x7c, 0x00, 0xed, 0xff, 0x5d, 0x00, 0xf2, 0xff, 0x4b, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x14, 0x00, 0x5b, 0x00, 0x25, 0x00, 0x6f, 0x00, 0x2d, 0x00, 0x7c, 0x00, 0x2b, 0x00, 0x7b, 0x00, 0x25, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x55, 0x00, 0x1f, 0x00, 0x39, 0x00, 0x25, 0x00, 0x25, 0x00, 0x31, 0x00, 0x1d, 0x00, 0x3d, 0x00, 0x22, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x45, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x38, 0x00, 0x32, 0x00, 0x33, 0x00, 0x26, 0x00, 0x28, 0x00, 0x20, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0xf4, 0xff, 0x21, 0x00, 0xe8, 0xff, 0x13, 0x00, 0xdb, 0xff, 0x00, 0x00, 0xce, 0xff, 0xed, 0xff, 0xc4, 0xff, 0xe0, 0xff, 0xbd, 0xff, 0xda, 0xff, 0xba, 0xff, 0xda, 0xff, 0xba, 0xff, 0xdd, 0xff, 0xbb, 0xff, 0xe1, 0xff, 0xbf, 0xff, 0xe1, 0xff, 0xc4, 0xff, 0xda, 0xff, 0xc6, 0xff, 0xce, 0xff, 0xc5, 0xff, 0xbe, 0xff, 0xc3, 0xff, 0xb1, 0xff, 0xc3, 0xff, 0xaa, 0xff, 0xc5, 0xff, 0xac, 0xff, 0xc9, 0xff, 0xb3, 0xff, 0xcf, 0xff, 0xbb, 0xff, 0xd5, 0xff, 0xbf, 0xff, 0xdb, 0xff, 0xbd, 0xff, 0xe0, 0xff, 0xb5, 0xff, 0xe1, 0xff, 0xad, 0xff, 0xe1, 0xff, 0xa9, 0xff, 0xe2, 0xff, 0xac, 0xff, 0xe2, 0xff, 0xb5, 0xff, 0xe6, 0xff, 0xc3, 0xff, 0xed, 0xff, 0xd2, 0xff, 0xf8, 0xff, 0xdc, 0xff, 0x07, 0x00, 0xe3, 0xff, 0x17, 0x00, 0xe5, 0xff, 0x26, 0x00, 0xe0, 0xff, 0x2c, 0x00, 0xd7, 0xff, 0x28, 0x00, 0xcd, 0xff, 0x1f, 0x00, 0xc8, 0xff, 0x19, 0x00, 0xca, 0xff, 0x1b, 0x00, 0xd0, 0xff, 0x24, 0x00, 0xd5, 0xff, 0x31, 0x00, 0xd5, 0xff, 0x3b, 0x00, 0xd0, 0xff, 0x40, 0x00, 0xc7, 0xff, 0x3f, 0x00, 0xbd, 0xff, 0x39, 0x00, 0xb4, 0xff, 0x2f, 0x00, 0xb0, 0xff, 0x28, 0x00, 0xb6, 0xff, 0x29, 0x00, 0xc3, 0xff, 0x2f, 0x00, 0xd0, 0xff, 0x37, 0x00, 0xdc, 0xff, 0x3d, 0x00, 0xe5, 0xff, 0x3e, 0x00, 0xea, 0xff, 0x38, 0x00, 0xe7, 0xff, 0x2b, 0x00, 0xe0, 0xff, 0x18, 0x00, 0xd9, 0xff, 0x05, 0x00, 0xd6, 0xff, 0xf5, 0xff, 0xd7, 0xff, 0xe9, 0xff, 0xde, 0xff, 0xdf, 0xff, 0xe9, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xce, 0xff, 0xff, 0xff, 0xc6, 0xff, 0x05, 0x00, 0xbe, 0xff, 0x05, 0x00, 0xb6, 0xff, 0xfe, 0xff, 0xaa, 0xff, 0xf2, 0xff, 0x99, 0xff, 0xe6, 0xff, 0x83, 0xff, 0xe0, 0xff, 0x6f, 0xff, 0xe1, 0xff, 0x5e, 0xff, 0xec, 0xff, 0x55, 0xff, 0xfd, 0xff, 0x55, 0xff, 0x0f, 0x00, 0x5c, 0xff, 0x19, 0x00, 0x63, 0xff, 0x18, 0x00, 0x66, 0xff, 0x0f, 0x00, 0x66, 0xff, 0xff, 0xff, 0x61, 0xff, 0xed, 0xff, 0x5b, 0xff, 0xe0, 0xff, 0x56, 0xff, 0xde, 0xff, 0x59, 0xff, 0xe9, 0xff, 0x65, 0xff, 0xfa, 0xff, 0x72, 0xff, 0x07, 0x00, 0x7b, 0xff, 0x0a, 0x00, 0x7f, 0xff, 0x01, 0x00, 0x7b, 0xff, 0xf0, 0xff, 0x76, 0xff, 0xe0, 0xff, 0x75, 0xff, 0xd4, 0xff, 0x78, 0xff, 0xcf, 0xff, 0x7c, 0xff, 0xd2, 0xff, 0x81, 0xff, 0xdd, 0xff, 0x85, 0xff, 0xee, 0xff, 0x89, 0xff, 0xfd, 0xff, 0x8c, 0xff, 0x06, 0x00, 0x8f, 0xff, 0x05, 0x00, 0x8e, 0xff, 0xfe, 0xff, 0x8a, 0xff, 0xf1, 0xff, 0x82, 0xff, 0xe3, 0xff, 0x79, 0xff, 0xdb, 0xff, 0x75, 0xff, 0xd9, 0xff, 0x78, 0xff, 0xdf, 0xff, 0x85, 0xff, 0xeb, 0xff, 0x9c, 0xff, 0xf8, 0xff, 0xb6, 0xff, 0x00, 0x00, 0xca, 0xff, 0xfd, 0xff, 0xd3, 0xff, 0xf1, 0xff, 0xd2, 0xff, 0xe1, 0xff, 0xcc, 0xff, 0xd3, 0xff, 0xca, 0xff, 0xca, 0xff, 0xcf, 0xff, 0xcd, 0xff, 0xe2, 0xff, 0xdb, 0xff, 0x01, 0x00, 0xef, 0xff, 0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x0c, 0x00, 0x51, 0x00, 0x12, 0x00, 0x56, 0x00, 0x12, 0x00, 0x51, 0x00, 0x10, 0x00, 0x4a, 0x00, 0x12, 0x00, 0x47, 0x00, 0x19, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x5c, 0x00, 0x36, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x82, 0x00, 0x5c, 0x00, 0x8f, 0x00, 0x6b, 0x00, 0x94, 0x00, 0x73, 0x00, 0x92, 0x00, 0x77, 0x00, 0x8d, 0x00, 0x79, 0x00, 0x89, 0x00, 0x7c, 0x00, 0x87, 0x00, 0x81, 0x00, 0x88, 0x00, 0x85, 0x00, 0x89, 0x00, 0x88, 0x00, 0x87, 0x00, 0x88, 0x00, 0x81, 0x00, 0x85, 0x00, 0x77, 0x00, 0x7f, 0x00, 0x6a, 0x00, 0x78, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x43, 0x00, 0x58, 0x00, 0x39, 0x00, 0x4e, 0x00, 0x33, 0x00, 0x43, 0x00, 0x2e, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x2b, 0x00, 0x21, 0x00, 0x23, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x19, 0x00, 0x08, 0x00, 0x18, 0x00, 0xfd, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x17, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfa, 0xff, 0xef, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xdf, 0xff, 0xd6, 0xff, 0xcc, 0xff, 0xd2, 0xff, 0xbc, 0xff, 0xd5, 0xff, 0xb2, 0xff, 0xdd, 0xff, 0xb2, 0xff, 0xe7, 0xff, 0xb9, 0xff, 0xea, 0xff, 0xbd, 0xff, 0xe5, 0xff, 0xba, 0xff, 0xd8, 0xff, 0xaf, 0xff, 0xcb, 0xff, 0xa1, 0xff, 0xbf, 0xff, 0x93, 0xff, 0xb6, 0xff, 0x8b, 0xff, 0xb1, 0xff, 0x8c, 0xff, 0xb2, 0xff, 0x94, 0xff, 0xb5, 0xff, 0xa1, 0xff, 0xba, 0xff, 0xad, 0xff, 0xbd, 0xff, 0xb5, 0xff, 0xbe, 0xff, 0xb8, 0xff, 0xbc, 0xff, 0xb6, 0xff, 0xba, 0xff, 0xb2, 0xff, 0xb9, 0xff, 0xb2, 0xff, 0xb9, 0xff, 0xb4, 0xff, 0xbb, 0xff, 0xba, 0xff, 0xbd, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xc8, 0xff, 0xc7, 0xff, 0xd0, 0xff, 0xce, 0xff, 0xda, 0xff, 0xd4, 0xff, 0xe3, 0xff, 0xda, 0xff, 0xec, 0xff, 0xdd, 0xff, 0xf0, 0xff, 0xde, 0xff, 0xf1, 0xff, 0xde, 0xff, 0xee, 0xff, 0xdf, 0xff, 0xeb, 0xff, 0xe2, 0xff, 0xed, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0x12, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x1e, 0x00, 0x45, 0x00, 0x28, 0x00, 0x52, 0x00, 0x31, 0x00, 0x56, 0x00, 0x38, 0x00, 0x51, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x55, 0x00, 0x57, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x7f, 0x00, 0x81, 0x00, 0x90, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7e, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x64, 0x00, 0x72, 0x00, 0x61, 0x00, 0x71, 0x00, 0x67, 0x00, 0x74, 0x00, 0x70, 0x00, 0x7a, 0x00, 0x78, 0x00, 0x81, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x74, 0x00, 0x83, 0x00, 0x65, 0x00, 0x78, 0x00, 0x52, 0x00, 0x67, 0x00, 0x40, 0x00, 0x56, 0x00, 0x34, 0x00, 0x48, 0x00, 0x32, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x37, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x3a, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x14, 0x00, 0x08, 0x00, 0x0c, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfb, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xde, 0xff, 0x0a, 0x00, 0xc9, 0xff, 0x09, 0x00, 0xb3, 0xff, 0x02, 0x00, 0xa1, 0xff, 0xf6, 0xff, 0x95, 0xff, 0xe7, 0xff, 0x8e, 0xff, 0xd8, 0xff, 0x8e, 0xff, 0xd2, 0xff, 0x90, 0xff, 0xd5, 0xff, 0x92, 0xff, 0xe2, 0xff, 0x8e, 0xff, 0xf0, 0xff, 0x84, 0xff, 0xf8, 0xff, 0x75, 0xff, 0xf5, 0xff, 0x68, 0xff, 0xe9, 0xff, 0x63, 0xff, 0xd9, 0xff, 0x68, 0xff, 0xcd, 0xff, 0x73, 0xff, 0xca, 0xff, 0x7f, 0xff, 0xce, 0xff, 0x87, 0xff, 0xd7, 0xff, 0x8a, 0xff, 0xe2, 0xff, 0x8a, 0xff, 0xec, 0xff, 0x88, 0xff, 0xef, 0xff, 0x87, 0xff, 0xe8, 0xff, 0x8b, 0xff, 0xd9, 0xff, 0x95, 0xff, 0xc9, 0xff, 0xa4, 0xff, 0xbd, 0xff, 0xb2, 0xff, 0xb9, 0xff, 0xbd, 0xff, 0xbe, 0xff, 0xc1, 0xff, 0xc9, 0xff, 0xc1, 0xff, 0xd3, 0xff, 0xc0, 0xff, 0xda, 0xff, 0xc5, 0xff, 0xdd, 0xff, 0xcf, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xd7, 0xff, 0xed, 0xff, 0xd0, 0xff, 0xfc, 0xff, 0xc9, 0xff, 0x0b, 0x00, 0xc8, 0xff, 0x18, 0x00, 0xce, 0xff, 0x23, 0x00, 0xdc, 0xff, 0x2e, 0x00, 0xef, 0xff, 0x34, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x0c, 0x00, 0x40, 0x00, 0x10, 0x00, 0x48, 0x00, 0x0f, 0x00, 0x56, 0x00, 0x0f, 0x00, 0x67, 0x00, 0x13, 0x00, 0x7b, 0x00, 0x1e, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x9c, 0x00, 0x42, 0x00, 0xa3, 0x00, 0x53, 0x00, 0xa5, 0x00, 0x5e, 0x00, 0xa2, 0x00, 0x62, 0x00, 0x9e, 0x00, 0x5f, 0x00, 0x9b, 0x00, 0x5b, 0x00, 0x9d, 0x00, 0x5a, 0x00, 0xa2, 0x00, 0x5d, 0x00, 0xa6, 0x00, 0x63, 0x00, 0xa8, 0x00, 0x6b, 0x00, 0xa2, 0x00, 0x70, 0x00, 0x94, 0x00, 0x6e, 0x00, 0x7e, 0x00, 0x65, 0x00, 0x68, 0x00, 0x58, 0x00, 0x58, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x47, 0x00, 0x50, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x42, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x24, 0x00, 0x31, 0x00, 0x09, 0x00, 0x23, 0x00, 0xf2, 0xff, 0x16, 0x00, 0xe2, 0xff, 0x0c, 0x00, 0xda, 0xff, 0x07, 0x00, 0xd9, 0xff, 0x06, 0x00, 0xdb, 0xff, 0x07, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xd6, 0xff, 0x0e, 0x00, 0xcf, 0xff, 0x12, 0x00, 0xc6, 0xff, 0x14, 0x00, 0xbc, 0xff, 0x11, 0x00, 0xb1, 0xff, 0x08, 0x00, 0xa6, 0xff, 0xfb, 0xff, 0x9f, 0xff, 0xee, 0xff, 0x9c, 0xff, 0xe8, 0xff, 0x9a, 0xff, 0xe8, 0xff, 0x9c, 0xff, 0xef, 0xff, 0xa0, 0xff, 0xfc, 0xff, 0xa4, 0xff, 0x09, 0x00, 0xa5, 0xff, 0x10, 0x00, 0xa1, 0xff, 0x0e, 0x00, 0x9a, 0xff, 0x03, 0x00, 0x90, 0xff, 0xf1, 0xff, 0x88, 0xff, 0xe2, 0xff, 0x84, 0xff, 0xd8, 0xff, 0x87, 0xff, 0xd6, 0xff, 0x8d, 0xff, 0xdb, 0xff, 0x95, 0xff, 0xe1, 0xff, 0x9b, 0xff, 0xe6, 0xff, 0x9d, 0xff, 0xe8, 0xff, 0x9e, 0xff, 0xe7, 0xff, 0x9e, 0xff, 0xe6, 0xff, 0xa1, 0xff, 0xe6, 0xff, 0xab, 0xff, 0xe8, 0xff, 0xbc, 0xff, 0xed, 0xff, 0xd2, 0xff, 0xf5, 0xff, 0xe7, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x14, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xfd, 0xff, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x08, 0x00, 0x22, 0x00, 0x16, 0x00, 0x22, 0x00, 0x28, 0x00, 0x25, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x45, 0x00, 0x38, 0x00, 0x49, 0x00, 0x42, 0x00, 0x47, 0x00, 0x49, 0x00, 0x43, 0x00, 0x4a, 0x00, 0x42, 0x00, 0x45, 0x00, 0x44, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x53, 0x00, 0x35, 0x00, 0x5b, 0x00, 0x3b, 0x00, 0x5f, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x55, 0x00, 0x52, 0x00, 0x50, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x50, 0x00, 0x3b, 0x00, 0x54, 0x00, 0x38, 0x00, 0x56, 0x00, 0x39, 0x00, 0x56, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x44, 0x00, 0x45, 0x00, 0x44, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x24, 0x00, 0x33, 0x00, 0x16, 0x00, 0x24, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xda, 0xff, 0xfd, 0xff, 0xc1, 0xff, 0xef, 0xff, 0xac, 0xff, 0xdc, 0xff, 0x9e, 0xff, 0xc9, 0xff, 0x9a, 0xff, 0xbb, 0xff, 0x9b, 0xff, 0xb2, 0xff, 0x9c, 0xff, 0xaf, 0xff, 0x96, 0xff, 0xb0, 0xff, 0x86, 0xff, 0xb2, 0xff, 0x70, 0xff, 0xb3, 0xff, 0x57, 0xff, 0xad, 0xff, 0x45, 0xff, 0xa3, 0xff, 0x3e, 0xff, 0x96, 0xff, 0x41, 0xff, 0x87, 0xff, 0x4a, 0xff, 0x78, 0xff, 0x51, 0xff, 0x6d, 0xff, 0x52, 0xff, 0x69, 0xff, 0x4e, 0xff, 0x6d, 0xff, 0x47, 0xff, 0x76, 0xff, 0x43, 0xff, 0x7e, 0xff, 0x48, 0xff, 0x82, 0xff, 0x57, 0xff, 0x7f, 0xff, 0x6f, 0xff, 0x78, 0xff, 0x89, 0xff, 0x6f, 0xff, 0xa1, 0xff, 0x68, 0xff, 0xb1, 0xff, 0x64, 0xff, 0xbc, 0xff, 0x65, 0xff, 0xc3, 0xff, 0x69, 0xff, 0xca, 0xff, 0x6e, 0xff, 0xd7, 0xff, 0x74, 0xff, 0xec, 0xff, 0x79, 0xff, 0x07, 0x00, 0x7d, 0xff, 0x20, 0x00, 0x7c, 0xff, 0x34, 0x00, 0x76, 0xff, 0x42, 0x00, 0x71, 0xff, 0x4e, 0x00, 0x71, 0xff, 0x59, 0x00, 0x78, 0xff, 0x63, 0x00, 0x83, 0xff, 0x6d, 0x00, 0x91, 0xff, 0x77, 0x00, 0x9c, 0xff, 0x81, 0x00, 0xa4, 0xff, 0x8c, 0x00, 0xa8, 0xff, 0x96, 0x00, 0xaa, 0xff, 0x9f, 0x00, 0xac, 0xff, 0xa8, 0x00, 0xb2, 0xff, 0xb2, 0x00, 0xbe, 0xff, 0xbc, 0x00, 0xd3, 0xff, 0xc5, 0x00, 0xed, 0xff, 0xca, 0x00, 0x08, 0x00, 0xcc, 0x00, 0x1e, 0x00, 0xcd, 0x00, 0x2b, 0x00, 0xcd, 0x00, 0x2f, 0x00, 0xcd, 0x00, 0x2d, 0x00, 0xcf, 0x00, 0x2c, 0x00, 0xd2, 0x00, 0x2f, 0x00, 0xd5, 0x00, 0x3a, 0x00, 0xd7, 0x00, 0x4c, 0x00, 0xd6, 0x00, 0x5f, 0x00, 0xd0, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x78, 0x00, 0xbe, 0x00, 0x79, 0x00, 0xb1, 0x00, 0x72, 0x00, 0xa1, 0x00, 0x65, 0x00, 0x91, 0x00, 0x58, 0x00, 0x84, 0x00, 0x50, 0x00, 0x79, 0x00, 0x4b, 0x00, 0x6f, 0x00, 0x4c, 0x00, 0x64, 0x00, 0x4f, 0x00, 0x55, 0x00, 0x51, 0x00, 0x43, 0x00, 0x50, 0x00, 0x30, 0x00, 0x4c, 0x00, 0x1d, 0x00, 0x44, 0x00, 0x0b, 0x00, 0x3a, 0x00, 0xfe, 0xff, 0x31, 0x00, 0xf3, 0xff, 0x2c, 0x00, 0xe8, 0xff, 0x2a, 0x00, 0xda, 0xff, 0x2b, 0x00, 0xc8, 0xff, 0x2d, 0x00, 0xb5, 0xff, 0x30, 0x00, 0xa3, 0xff, 0x2e, 0x00, 0x93, 0xff, 0x27, 0x00, 0x89, 0xff, 0x1d, 0x00, 0x84, 0xff, 0x10, 0x00, 0x82, 0xff, 0x05, 0x00, 0x81, 0xff, 0xff, 0xff, 0x7c, 0xff, 0xfe, 0xff, 0x72, 0xff, 0x01, 0x00, 0x65, 0xff, 0x02, 0x00, 0x59, 0xff, 0x01, 0x00, 0x54, 0xff, 0xfb, 0xff, 0x56, 0xff, 0xf2, 0xff, 0x5e, 0xff, 0xe8, 0xff, 0x68, 0xff, 0xe2, 0xff, 0x71, 0xff, 0xde, 0xff, 0x72, 0xff, 0xd9, 0xff, 0x6f, 0xff, 0xd5, 0xff, 0x6b, 0xff, 0xd0, 0xff, 0x68, 0xff, 0xcb, 0xff, 0x6c, 0xff, 0xc8, 0xff, 0x76, 0xff, 0xc6, 0xff, 0x81, 0xff, 0xc6, 0xff, 0x8a, 0xff, 0xc6, 0xff, 0x8f, 0xff, 0xc8, 0xff, 0x91, 0xff, 0xca, 0xff, 0x92, 0xff, 0xc9, 0xff, 0x96, 0xff, 0xc9, 0xff, 0xa1, 0xff, 0xcb, 0xff, 0xb4, 0xff, 0xd2, 0xff, 0xcb, 0xff, 0xdc, 0xff, 0xe0, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x09, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x14, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x26, 0x00, 0x43, 0x00, 0x30, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x6c, 0x00, 0x40, 0x00, 0x78, 0x00, 0x41, 0x00, 0x7c, 0x00, 0x3f, 0x00, 0x7d, 0x00, 0x3f, 0x00, 0x7c, 0x00, 0x42, 0x00, 0x7c, 0x00, 0x4a, 0x00, 0x7e, 0x00, 0x51, 0x00, 0x81, 0x00, 0x54, 0x00, 0x85, 0x00, 0x55, 0x00, 0x88, 0x00, 0x51, 0x00, 0x89, 0x00, 0x4b, 0x00, 0x85, 0x00, 0x47, 0x00, 0x7d, 0x00, 0x47, 0x00, 0x71, 0x00, 0x4b, 0x00, 0x66, 0x00, 0x55, 0x00, 0x5d, 0x00, 0x60, 0x00, 0x56, 0x00, 0x65, 0x00, 0x51, 0x00, 0x65, 0x00, 0x4b, 0x00, 0x5e, 0x00, 0x3f, 0x00, 0x54, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x18, 0x00, 0x48, 0x00, 0x01, 0x00, 0x46, 0x00, 0xed, 0xff, 0x45, 0x00, 0xe2, 0xff, 0x44, 0x00, 0xe0, 0xff, 0x41, 0x00, 0xe0, 0xff, 0x3b, 0x00, 0xdd, 0xff, 0x2f, 0x00, 0xd2, 0xff, 0x21, 0x00, 0xbf, 0xff, 0x13, 0x00, 0xa7, 0xff, 0x06, 0x00, 0x8f, 0xff, 0xfd, 0xff, 0x7e, 0xff, 0xfa, 0xff, 0x77, 0xff, 0xfb, 0xff, 0x78, 0xff, 0xff, 0xff, 0x80, 0xff, 0x05, 0x00, 0x89, 0xff, 0x08, 0x00, 0x8d, 0xff, 0x06, 0x00, 0x8c, 0xff, 0xfe, 0xff, 0x86, 0xff, 0xef, 0xff, 0x7e, 0xff, 0xdf, 0xff, 0x79, 0xff, 0xd3, 0xff, 0x79, 0xff, 0xcf, 0xff, 0x7e, 0xff, 0xd1, 0xff, 0x86, 0xff, 0xd7, 0xff, 0x90, 0xff, 0xdd, 0xff, 0x9a, 0xff, 0xdc, 0xff, 0x9e, 0xff, 0xd0, 0xff, 0x9f, 0xff, 0xbe, 0xff, 0xa1, 0xff, 0xaa, 0xff, 0xa3, 0xff, 0x9a, 0xff, 0xa6, 0xff, 0x91, 0xff, 0xaa, 0xff, 0x90, 0xff, 0xb3, 0xff, 0x95, 0xff, 0xbf, 0xff, 0x9a, 0xff, 0xcc, 0xff, 0x9a, 0xff, 0xd8, 0xff, 0x92, 0xff, 0xe0, 0xff, 0x87, 0xff, 0xe4, 0xff, 0x7b, 0xff, 0xe3, 0xff, 0x72, 0xff, 0xe1, 0xff, 0x70, 0xff, 0xe1, 0xff, 0x75, 0xff, 0xe5, 0xff, 0x7f, 0xff, 0xef, 0xff, 0x8b, 0xff, 0xfc, 0xff, 0x93, 0xff, 0x0b, 0x00, 0x98, 0xff, 0x18, 0x00, 0x9a, 0xff, 0x21, 0x00, 0x9c, 0xff, 0x24, 0x00, 0xa1, 0xff, 0x26, 0x00, 0xac, 0xff, 0x2a, 0x00, 0xbc, 0xff, 0x32, 0x00, 0xcf, 0xff, 0x3e, 0x00, 0xe2, 0xff, 0x4c, 0x00, 0xf4, 0xff, 0x5a, 0x00, 0x04, 0x00, 0x66, 0x00, 0x13, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x6e, 0x00, 0x2f, 0x00, 0x6f, 0x00, 0x3c, 0x00, 0x72, 0x00, 0x49, 0x00, 0x77, 0x00, 0x53, 0x00, 0x7f, 0x00, 0x5a, 0x00, 0x88, 0x00, 0x5f, 0x00, 0x92, 0x00, 0x63, 0x00, 0x99, 0x00, 0x66, 0x00, 0x9c, 0x00, 0x69, 0x00, 0x9c, 0x00, 0x6a, 0x00, 0x98, 0x00, 0x69, 0x00, 0x90, 0x00, 0x65, 0x00, 0x85, 0x00, 0x5e, 0x00, 0x79, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x69, 0x00, 0x42, 0x00, 0x66, 0x00, 0x3a, 0x00, 0x62, 0x00, 0x33, 0x00, 0x5a, 0x00, 0x2e, 0x00, 0x4d, 0x00, 0x2c, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x07, 0x00, 0x30, 0x00, 0xf0, 0xff, 0x31, 0x00, 0xe0, 0xff, 0x32, 0x00, 0xda, 0xff, 0x32, 0x00, 0xdc, 0xff, 0x31, 0x00, 0xe0, 0xff, 0x30, 0x00, 0xe0, 0xff, 0x2e, 0x00, 0xd7, 0xff, 0x2e, 0x00, 0xc4, 0xff, 0x2f, 0x00, 0xac, 0xff, 0x2f, 0x00, 0x97, 0xff, 0x30, 0x00, 0x8d, 0xff, 0x32, 0x00, 0x8c, 0xff, 0x31, 0x00, 0x91, 0xff, 0x2a, 0x00, 0x99, 0xff, 0x1e, 0x00, 0x9d, 0xff, 0x0f, 0x00, 0x97, 0xff, 0xff, 0xff, 0x88, 0xff, 0xf1, 0xff, 0x76, 0xff, 0xe9, 0xff, 0x68, 0xff, 0xe7, 0xff, 0x61, 0xff, 0xeb, 0xff, 0x65, 0xff, 0xf1, 0xff, 0x71, 0xff, 0xf7, 0xff, 0x80, 0xff, 0xf9, 0xff, 0x8c, 0xff, 0xf5, 0xff, 0x92, 0xff, 0xee, 0xff, 0x91, 0xff, 0xe8, 0xff, 0x8d, 0xff, 0xe7, 0xff, 0x8a, 0xff, 0xec, 0xff, 0x8b, 0xff, 0xf6, 0xff, 0x93, 0xff, 0x01, 0x00, 0xa0, 0xff, 0x09, 0x00, 0xaf, 0xff, 0x0c, 0x00, 0xbe, 0xff, 0x09, 0x00, 0xcb, 0xff, 0x03, 0x00, 0xd4, 0xff, 0xfc, 0xff, 0xdb, 0xff, 0xf9, 0xff, 0xe1, 0xff, 0xfc, 0xff, 0xe6, 0xff, 0x03, 0x00, 0xea, 0xff, 0x0a, 0x00, 0xef, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x12, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x08, 0x00, 0x2e, 0x00, 0xff, 0xff, 0x39, 0x00, 0xf6, 0xff, 0x3e, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0xee, 0xff, 0x40, 0x00, 0xf2, 0xff, 0x45, 0x00, 0xf8, 0xff, 0x4d, 0x00, 0xfd, 0xff, 0x58, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x72, 0x00, 0xfd, 0xff, 0x78, 0x00, 0xf7, 0xff, 0x77, 0x00, 0xf1, 0xff, 0x71, 0x00, 0xee, 0xff, 0x6c, 0x00, 0xf2, 0xff, 0x6a, 0x00, 0xfc, 0xff, 0x6c, 0x00, 0x08, 0x00, 0x70, 0x00, 0x11, 0x00, 0x74, 0x00, 0x16, 0x00, 0x76, 0x00, 0x16, 0x00, 0x74, 0x00, 0x13, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x61, 0x00, 0x0e, 0x00, 0x55, 0x00, 0x11, 0x00, 0x4a, 0x00, 0x15, 0x00, 0x40, 0x00, 0x19, 0x00, 0x37, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x19, 0x00, 0x27, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x10, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xe6, 0xff, 0xf9, 0xff, 0xe1, 0xff, 0xf0, 0xff, 0xe3, 0xff, 0xe9, 0xff, 0xea, 0xff, 0xe2, 0xff, 0xf1, 0xff, 0xd9, 0xff, 0xf3, 0xff, 0xd2, 0xff, 0xef, 0xff, 0xcc, 0xff, 0xe7, 0xff, 0xc9, 0xff, 0xde, 0xff, 0xc7, 0xff, 0xd7, 0xff, 0xc4, 0xff, 0xd1, 0xff, 0xc0, 0xff, 0xcf, 0xff, 0xbb, 0xff, 0xd1, 0xff, 0xb8, 0xff, 0xd6, 0xff, 0xb5, 0xff, 0xda, 0xff, 0xb5, 0xff, 0xdd, 0xff, 0xb7, 0xff, 0xde, 0xff, 0xbc, 0xff, 0xdc, 0xff, 0xc3, 0xff, 0xd7, 0xff, 0xc7, 0xff, 0xcf, 0xff, 0xc7, 0xff, 0xc7, 0xff, 0xc5, 0xff, 0xc1, 0xff, 0xc1, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xc9, 0xff, 0xce, 0xff, 0xd0, 0xff, 0xdc, 0xff, 0xd4, 0xff, 0xe7, 0xff, 0xd3, 0xff, 0xeb, 0xff, 0xce, 0xff, 0xea, 0xff, 0xc9, 0xff, 0xe9, 0xff, 0xca, 0xff, 0xec, 0xff, 0xd0, 0xff, 0xf3, 0xff, 0xd8, 0xff, 0xfd, 0xff, 0xde, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x10, 0x00, 0xdf, 0xff, 0x16, 0x00, 0xdb, 0xff, 0x1a, 0x00, 0xd8, 0xff, 0x1c, 0x00, 0xd9, 0xff, 0x1c, 0x00, 0xdf, 0xff, 0x1d, 0x00, 0xe7, 0xff, 0x24, 0x00, 0xf1, 0xff, 0x31, 0x00, 0xfb, 0xff, 0x41, 0x00, 0xff, 0xff, 0x50, 0x00, 0xfe, 0xff, 0x5b, 0x00, 0xfc, 0xff, 0x62, 0x00, 0xfc, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6b, 0x00, 0x07, 0x00, 0x70, 0x00, 0x11, 0x00, 0x76, 0x00, 0x1a, 0x00, 0x7d, 0x00, 0x21, 0x00, 0x83, 0x00, 0x22, 0x00, 0x87, 0x00, 0x1e, 0x00, 0x88, 0x00, 0x18, 0x00, 0x84, 0x00, 0x12, 0x00, 0x7d, 0x00, 0x10, 0x00, 0x76, 0x00, 0x13, 0x00, 0x6e, 0x00, 0x18, 0x00, 0x68, 0x00, 0x1e, 0x00, 0x62, 0x00, 0x23, 0x00, 0x5e, 0x00, 0x27, 0x00, 0x5a, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x4d, 0x00, 0x28, 0x00, 0x40, 0x00, 0x25, 0x00, 0x32, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x16, 0x00, 0x34, 0x00, 0x13, 0x00, 0x3c, 0x00, 0x0f, 0x00, 0x42, 0x00, 0x0b, 0x00, 0x46, 0x00, 0x05, 0x00, 0x47, 0x00, 0xfb, 0xff, 0x44, 0x00, 0xed, 0xff, 0x3f, 0x00, 0xde, 0xff, 0x3b, 0x00, 0xcf, 0xff, 0x38, 0x00, 0xc2, 0xff, 0x39, 0x00, 0xba, 0xff, 0x3c, 0x00, 0xb5, 0xff, 0x3e, 0x00, 0xb1, 0xff, 0x3d, 0x00, 0xab, 0xff, 0x36, 0x00, 0xa2, 0xff, 0x2b, 0x00, 0x97, 0xff, 0x1e, 0x00, 0x8a, 0xff, 0x14, 0x00, 0x81, 0xff, 0x10, 0x00, 0x7b, 0xff, 0x11, 0x00, 0x78, 0xff, 0x17, 0x00, 0x78, 0xff, 0x1d, 0x00, 0x7a, 0xff, 0x21, 0x00, 0x7c, 0xff, 0x1f, 0x00, 0x7d, 0xff, 0x18, 0x00, 0x7e, 0xff, 0x10, 0x00, 0x7f, 0xff, 0x0a, 0x00, 0x80, 0xff, 0x04, 0x00, 0x82, 0xff, 0x02, 0x00, 0x86, 0xff, 0x04, 0x00, 0x8c, 0xff, 0x08, 0x00, 0x92, 0xff, 0x0b, 0x00, 0x9a, 0xff, 0x0b, 0x00, 0xa5, 0xff, 0x09, 0x00, 0xb1, 0xff, 0x03, 0x00, 0xbe, 0xff, 0xfb, 0xff, 0xcd, 0xff, 0xf5, 0xff, 0xde, 0xff, 0xf2, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x0e, 0x00, 0xff, 0xff, 0x1c, 0x00, 0x05, 0x00, 0x2a, 0x00, 0x09, 0x00, 0x3a, 0x00, 0x08, 0x00, 0x47, 0x00, 0x02, 0x00, 0x4e, 0x00, 0xf7, 0xff, 0x4f, 0x00, 0xec, 0xff, 0x4b, 0x00, 0xe3, 0xff, 0x44, 0x00, 0xde, 0xff, 0x3f, 0x00, 0xdc, 0xff, 0x3f, 0x00, 0xde, 0xff, 0x46, 0x00, 0xe5, 0xff, 0x51, 0x00, 0xed, 0xff, 0x59, 0x00, 0xf0, 0xff, 0x5d, 0x00, 0xef, 0xff, 0x5b, 0x00, 0xea, 0xff, 0x51, 0x00, 0xe2, 0xff, 0x44, 0x00, 0xde, 0xff, 0x3a, 0x00, 0xdf, 0xff, 0x37, 0x00, 0xe6, 0xff, 0x3c, 0x00, 0xef, 0xff, 0x46, 0x00, 0xf9, 0xff, 0x52, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x55, 0x00, 0x04, 0x00, 0x4a, 0x00, 0xff, 0xff, 0x40, 0x00, 0xfc, 0xff, 0x3b, 0x00, 0xfe, 0xff, 0x3d, 0x00, 0x04, 0x00, 0x45, 0x00, 0x0e, 0x00, 0x4c, 0x00, 0x17, 0x00, 0x4e, 0x00, 0x1b, 0x00, 0x48, 0x00, 0x1a, 0x00, 0x3a, 0x00, 0x16, 0x00, 0x2a, 0x00, 0x11, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x05, 0x00, 0x13, 0x00, 0xfc, 0xff, 0x13, 0x00, 0xed, 0xff, 0x11, 0x00, 0xda, 0xff, 0x0e, 0x00, 0xc7, 0xff, 0x0a, 0x00, 0xb7, 0xff, 0x05, 0x00, 0xac, 0xff, 0x00, 0x00, 0xa4, 0xff, 0xf8, 0xff, 0x9c, 0xff, 0xf0, 0xff, 0x92, 0xff, 0xe9, 0xff, 0x88, 0xff, 0xe6, 0xff, 0x7d, 0xff, 0xe6, 0xff, 0x71, 0xff, 0xe6, 0xff, 0x67, 0xff, 0xe5, 0xff, 0x61, 0xff, 0xe1, 0xff, 0x60, 0xff, 0xdd, 0xff, 0x64, 0xff, 0xda, 0xff, 0x6a, 0xff, 0xd8, 0xff, 0x71, 0xff, 0xd9, 0xff, 0x77, 0xff, 0xdb, 0xff, 0x79, 0xff, 0xdb, 0xff, 0x79, 0xff, 0xda, 0xff, 0x7a, 0xff, 0xda, 0xff, 0x7e, 0xff, 0xd9, 0xff, 0x86, 0xff, 0xd9, 0xff, 0x93, 0xff, 0xd9, 0xff, 0xa4, 0xff, 0xd9, 0xff, 0xb4, 0xff, 0xd8, 0xff, 0xc2, 0xff, 0xd5, 0xff, 0xcd, 0xff, 0xd2, 0xff, 0xd3, 0xff, 0xce, 0xff, 0xd6, 0xff, 0xca, 0xff, 0xd9, 0xff, 0xc8, 0xff, 0xdf, 0xff, 0xc9, 0xff, 0xe8, 0xff, 0xcb, 0xff, 0xf4, 0xff, 0xcd, 0xff, 0x02, 0x00, 0xcc, 0xff, 0x10, 0x00, 0xc8, 0xff, 0x1b, 0x00, 0xc2, 0xff, 0x22, 0x00, 0xbc, 0xff, 0x28, 0x00, 0xb8, 0xff, 0x2c, 0x00, 0xba, 0xff, 0x2f, 0x00, 0xbe, 0xff, 0x32, 0x00, 0xc5, 0xff, 0x38, 0x00, 0xca, 0xff, 0x3f, 0x00, 0xcf, 0xff, 0x49, 0x00, 0xd2, 0xff, 0x52, 0x00, 0xd2, 0xff, 0x5a, 0x00, 0xd1, 0xff, 0x62, 0x00, 0xd2, 0xff, 0x69, 0x00, 0xd5, 0xff, 0x6e, 0x00, 0xda, 0xff, 0x6f, 0x00, 0xe0, 0xff, 0x71, 0x00, 0xe6, 0xff, 0x73, 0x00, 0xec, 0xff, 0x78, 0x00, 0xf2, 0xff, 0x7f, 0x00, 0xf7, 0xff, 0x86, 0x00, 0xfc, 0xff, 0x8b, 0x00, 0x01, 0x00, 0x8d, 0x00, 0x05, 0x00, 0x89, 0x00, 0x09, 0x00, 0x7f, 0x00, 0x0b, 0x00, 0x74, 0x00, 0x0e, 0x00, 0x6a, 0x00, 0x13, 0x00, 0x64, 0x00, 0x1a, 0x00, 0x61, 0x00, 0x25, 0x00, 0x5f, 0x00, 0x30, 0x00, 0x5a, 0x00, 0x39, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x3b, 0x00, 0x19, 0x00, 0x3c, 0x00, 0x0a, 0x00, 0x41, 0x00, 0xfe, 0xff, 0x48, 0x00, 0xf8, 0xff, 0x52, 0x00, 0xf8, 0xff, 0x5d, 0x00, 0xfa, 0xff, 0x66, 0x00, 0xfa, 0xff, 0x6a, 0x00, 0xf2, 0xff, 0x67, 0x00, 0xe4, 0xff, 0x5e, 0x00, 0xd3, 0xff, 0x53, 0x00, 0xc4, 0xff, 0x4c, 0x00, 0xbb, 0xff, 0x49, 0x00, 0xba, 0xff, 0x4b, 0x00, 0xbe, 0xff, 0x4f, 0x00, 0xc3, 0xff, 0x50, 0x00, 0xc6, 0xff, 0x4e, 0x00, 0xc5, 0xff, 0x49, 0x00, 0xbe, 0xff, 0x42, 0x00, 0xb2, 0xff, 0x39, 0x00, 0xa5, 0xff, 0x30, 0x00, 0x99, 0xff, 0x26, 0x00, 0x94, 0xff, 0x1f, 0x00, 0x95, 0xff, 0x1b, 0x00, 0x9b, 0xff, 0x1c, 0x00, 0xa2, 0xff, 0x1f, 0x00, 0xa4, 0xff, 0x22, 0x00, 0xa0, 0xff, 0x23, 0x00, 0x99, 0xff, 0x21, 0x00, 0x91, 0xff, 0x1c, 0x00, 0x8d, 0xff, 0x12, 0x00, 0x8e, 0xff, 0x07, 0x00, 0x94, 0xff, 0xfe, 0xff, 0x9e, 0xff, 0xfb, 0xff, 0xa9, 0xff, 0xfd, 0xff, 0xb3, 0xff, 0x05, 0x00, 0xbc, 0xff, 0x0d, 0x00, 0xc4, 0xff, 0x13, 0x00, 0xcc, 0xff, 0x14, 0x00, 0xd5, 0xff, 0x0e, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xeb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x1a, 0x00, 0xf8, 0xff, 0x26, 0x00, 0xfc, 0xff, 0x30, 0x00, 0xfd, 0xff, 0x39, 0x00, 0xfb, 0xff, 0x41, 0x00, 0xf7, 0xff, 0x4a, 0x00, 0xf2, 0xff, 0x53, 0x00, 0xee, 0xff, 0x5b, 0x00, 0xea, 0xff, 0x61, 0x00, 0xe6, 0xff, 0x64, 0x00, 0xe3, 0xff, 0x66, 0x00, 0xe1, 0xff, 0x65, 0x00, 0xe0, 0xff, 0x64, 0x00, 0xde, 0xff, 0x65, 0x00, 0xdc, 0xff, 0x66, 0x00, 0xdb, 0xff, 0x67, 0x00, 0xdb, 0xff, 0x6a, 0x00, 0xdc, 0xff, 0x6c, 0x00, 0xde, 0xff, 0x6c, 0x00, 0xe0, 0xff, 0x68, 0x00, 0xe0, 0xff, 0x61, 0x00, 0xde, 0xff, 0x58, 0x00, 0xda, 0xff, 0x50, 0x00, 0xd8, 0xff, 0x4a, 0x00, 0xd9, 0xff, 0x47, 0x00, 0xdd, 0xff, 0x45, 0x00, 0xe4, 0xff, 0x43, 0x00, 0xea, 0xff, 0x41, 0x00, 0xee, 0xff, 0x3e, 0x00, 0xf0, 0xff, 0x3a, 0x00, 0xf0, 0xff, 0x33, 0x00, 0xef, 0xff, 0x2c, 0x00, 0xee, 0xff, 0x24, 0x00, 0xed, 0xff, 0x1e, 0x00, 0xf0, 0xff, 0x1b, 0x00, 0xf4, 0xff, 0x1c, 0x00, 0xfa, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x04, 0x00, 0x23, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x16, 0x00, 0x04, 0x00, 0x0a, 0x00, 0xfe, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xe7, 0xff, 0xed, 0xff, 0xe6, 0xff, 0xee, 0xff, 0xe5, 0xff, 0xed, 0xff, 0xe1, 0xff, 0xea, 0xff, 0xd8, 0xff, 0xe4, 0xff, 0xcd, 0xff, 0xdc, 0xff, 0xbf, 0xff, 0xd6, 0xff, 0xb1, 0xff, 0xcf, 0xff, 0xa6, 0xff, 0xcc, 0xff, 0xa0, 0xff, 0xcb, 0xff, 0x9e, 0xff, 0xcc, 0xff, 0xa0, 0xff, 0xcd, 0xff, 0xa4, 0xff, 0xcd, 0xff, 0xa7, 0xff, 0xcd, 0xff, 0xa8, 0xff, 0xcd, 0xff, 0xa8, 0xff, 0xcd, 0xff, 0xa8, 0xff, 0xd1, 0xff, 0xa9, 0xff, 0xd7, 0xff, 0xac, 0xff, 0xde, 0xff, 0xb3, 0xff, 0xe5, 0xff, 0xbe, 0xff, 0xe9, 0xff, 0xc8, 0xff, 0xeb, 0xff, 0xd0, 0xff, 0xeb, 0xff, 0xd6, 0xff, 0xed, 0xff, 0xda, 0xff, 0xf1, 0xff, 0xdc, 0xff, 0xf5, 0xff, 0xde, 0xff, 0xfa, 0xff, 0xe0, 0xff, 0xfd, 0xff, 0xe5, 0xff, 0xff, 0xff, 0xed, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x15, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x0b, 0x00, 0x1e, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x0f, 0x00, 0x25, 0x00, 0x12, 0x00, 0x29, 0x00, 0x16, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x2b, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x26, 0x00, 0x29, 0x00, 0x27, 0x00, 0x29, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x30, 0x00, 0x24, 0x00, 0x35, 0x00, 0x1f, 0x00, 0x39, 0x00, 0x19, 0x00, 0x3b, 0x00, 0x15, 0x00, 0x3b, 0x00, 0x15, 0x00, 0x39, 0x00, 0x16, 0x00, 0x37, 0x00, 0x17, 0x00, 0x34, 0x00, 0x15, 0x00, 0x33, 0x00, 0x11, 0x00, 0x34, 0x00, 0x0a, 0x00, 0x36, 0x00, 0x02, 0x00, 0x37, 0x00, 0xfb, 0xff, 0x35, 0x00, 0xf5, 0xff, 0x32, 0x00, 0xf1, 0xff, 0x2d, 0x00, 0xef, 0xff, 0x28, 0x00, 0xed, 0xff, 0x25, 0x00, 0xea, 0xff, 0x24, 0x00, 0xe7, 0xff, 0x25, 0x00, 0xe3, 0xff, 0x25, 0x00, 0xde, 0xff, 0x25, 0x00, 0xd7, 0xff, 0x22, 0x00, 0xcf, 0xff, 0x1d, 0x00, 0xc6, 0xff, 0x16, 0x00, 0xbd, 0xff, 0x10, 0x00, 0xb6, 0xff, 0x0b, 0x00, 0xb0, 0xff, 0x08, 0x00, 0xac, 0xff, 0x05, 0x00, 0xab, 0xff, 0x03, 0x00, 0xac, 0xff, 0x02, 0x00, 0xad, 0xff, 0x01, 0x00, 0xab, 0xff, 0xfd, 0xff, 0xa6, 0xff, 0xf6, 0xff, 0x9f, 0xff, 0xed, 0xff, 0x9a, 0xff, 0xe4, 0xff, 0x9a, 0xff, 0xdd, 0xff, 0x9e, 0xff, 0xd9, 0xff, 0xa7, 0xff, 0xd9, 0xff, 0xb2, 0xff, 0xdd, 0xff, 0xb9, 0xff, 0xe0, 0xff, 0xbd, 0xff, 0xe1, 0xff, 0xbf, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xdd, 0xff, 0xc4, 0xff, 0xd8, 0xff, 0xc9, 0xff, 0xd3, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xdd, 0xff, 0xd4, 0xff, 0xe8, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xde, 0xff, 0xf8, 0xff, 0xe1, 0xff, 0xfe, 0xff, 0xe1, 0xff, 0x02, 0x00, 0xde, 0xff, 0x07, 0x00, 0xdb, 0xff, 0x0c, 0x00, 0xd8, 0xff, 0x13, 0x00, 0xd8, 0xff, 0x1c, 0x00, 0xd9, 0xff, 0x24, 0x00, 0xdb, 0xff, 0x2c, 0x00, 0xdc, 0xff, 0x33, 0x00, 0xda, 0xff, 0x38, 0x00, 0xd6, 0xff, 0x3e, 0x00, 0xd1, 0xff, 0x43, 0x00, 0xcb, 0xff, 0x46, 0x00, 0xc6, 0xff, 0x46, 0x00, 0xc2, 0xff, 0x43, 0x00, 0xc1, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0x3d, 0x00, 0xc2, 0xff, 0x3f, 0x00, 0xc5, 0xff, 0x44, 0x00, 0xca, 0xff, 0x49, 0x00, 0xce, 0xff, 0x4c, 0x00, 0xd1, 0xff, 0x4d, 0x00, 0xd5, 0xff, 0x4c, 0x00, 0xda, 0xff, 0x4a, 0x00, 0xe1, 0xff, 0x47, 0x00, 0xe9, 0xff, 0x45, 0x00, 0xf1, 0xff, 0x46, 0x00, 0xfb, 0xff, 0x48, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x0c, 0x00, 0x4a, 0x00, 0x14, 0x00, 0x48, 0x00, 0x1a, 0x00, 0x43, 0x00, 0x1e, 0x00, 0x3d, 0x00, 0x21, 0x00, 0x36, 0x00, 0x25, 0x00, 0x30, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x29, 0x00, 0x38, 0x00, 0x26, 0x00, 0x3b, 0x00, 0x21, 0x00, 0x3a, 0x00, 0x1c, 0x00, 0x36, 0x00, 0x16, 0x00, 0x33, 0x00, 0x10, 0x00, 0x32, 0x00, 0x0b, 0x00, 0x34, 0x00, 0x05, 0x00, 0x37, 0x00, 0xff, 0xff, 0x3a, 0x00, 0xf9, 0xff, 0x3a, 0x00, 0xf4, 0xff, 0x37, 0x00, 0xef, 0xff, 0x30, 0x00, 0xec, 0xff, 0x29, 0x00, 0xe9, 0xff, 0x23, 0x00, 0xe6, 0xff, 0x1d, 0x00, 0xe0, 0xff, 0x19, 0x00, 0xd9, 0xff, 0x16, 0x00, 0xd3, 0xff, 0x14, 0x00, 0xcc, 0xff, 0x11, 0x00, 0xc7, 0xff, 0x0c, 0x00, 0xc5, 0xff, 0x08, 0x00, 0xc5, 0xff, 0x06, 0x00, 0xc5, 0xff, 0x04, 0x00, 0xc5, 0xff, 0x03, 0x00, 0xc5, 0xff, 0x02, 0x00, 0xc3, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xfa, 0xff, 0xbe, 0xff, 0xf5, 0xff, 0xbd, 0xff, 0xf1, 0xff, 0xbe, 0xff, 0xed, 0xff, 0xc0, 0xff, 0xeb, 0xff, 0xc3, 0xff, 0xe9, 0xff, 0xc8, 0xff, 0xe8, 0xff, 0xcc, 0xff, 0xe6, 0xff, 0xcf, 0xff, 0xe3, 0xff, 0xd3, 0xff, 0xdf, 0xff, 0xd9, 0xff, 0xdd, 0xff, 0xe2, 0xff, 0xde, 0xff, 0xec, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xe5, 0xff, 0xfe, 0xff, 0xe6, 0xff, 0x03, 0x00, 0xe7, 0xff, 0x07, 0x00, 0xe8, 0xff, 0x09, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xe9, 0xff, 0x0e, 0x00, 0xee, 0xff, 0x12, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0x06, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x13, 0x00, 0x19, 0x00, 0x12, 0x00, 0x14, 0x00, 0x11, 0x00, 0x10, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x18, 0x00, 0xfe, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x09, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x09, 0x00, 0x18, 0x00, 0x08, 0x00, 0x1a, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x34, 0x00, 0x1e, 0x00, 0x3c, 0x00, 0x26, 0x00, 0x42, 0x00, 0x2c, 0x00, 0x46, 0x00, 0x30, 0x00, 0x45, 0x00, 0x32, 0x00, 0x41, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x38, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x46, 0x00, 0x2f, 0x00, 0x4b, 0x00, 0x2d, 0x00, 0x4e, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x26, 0x00, 0x4b, 0x00, 0x1f, 0x00, 0x47, 0x00, 0x16, 0x00, 0x43, 0x00, 0x0d, 0x00, 0x40, 0x00, 0x04, 0x00, 0x3c, 0x00, 0xfd, 0xff, 0x38, 0x00, 0xf9, 0xff, 0x32, 0x00, 0xf7, 0xff, 0x27, 0x00, 0xf4, 0xff, 0x19, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xf2, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xed, 0xff, 0xec, 0xff, 0xea, 0xff, 0xeb, 0xff, 0xe6, 0xff, 0xeb, 0xff, 0xe1, 0xff, 0xeb, 0xff, 0xda, 0xff, 0xed, 0xff, 0xd5, 0xff, 0xf0, 0xff, 0xd3, 0xff, 0xf5, 0xff, 0xd3, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xfd, 0xff, 0xd6, 0xff, 0xff, 0xff, 0xd8, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0xfa, 0xff, 0xe1, 0xff, 0xf9, 0xff, 0xe2, 0xff, 0xf8, 0xff, 0xe1, 0xff, 0xf8, 0xff, 0xde, 0xff, 0xf9, 0xff, 0xdb, 0xff, 0xf8, 0xff, 0xd7, 0xff, 0xf5, 0xff, 0xd3, 0xff, 0xf2, 0xff, 0xd0, 0xff, 0xf1, 0xff, 0xcf, 0xff, 0xf0, 0xff, 0xcd, 0xff, 0xf1, 0xff, 0xca, 0xff, 0xf4, 0xff, 0xc6, 0xff, 0xfa, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xbc, 0xff, 0x04, 0x00, 0xb7, 0xff, 0x08, 0x00, 0xb6, 0xff, 0x0c, 0x00, 0xb7, 0xff, 0x10, 0x00, 0xba, 0xff, 0x16, 0x00, 0xbe, 0xff, 0x1c, 0x00, 0xc1, 0xff, 0x1f, 0x00, 0xc2, 0xff, 0x21, 0x00, 0xc1, 0xff, 0x22, 0x00, 0xc0, 0xff, 0x22, 0x00, 0xbf, 0xff, 0x23, 0x00, 0xc0, 0xff, 0x24, 0x00, 0xc2, 0xff, 0x26, 0x00, 0xc8, 0xff, 0x28, 0x00, 0xcf, 0xff, 0x2a, 0x00, 0xd6, 0xff, 0x2b, 0x00, 0xdd, 0xff, 0x2a, 0x00, 0xe2, 0xff, 0x26, 0x00, 0xe5, 0xff, 0x21, 0x00, 0xe6, 0xff, 0x1c, 0x00, 0xe7, 0xff, 0x19, 0x00, 0xe9, 0xff, 0x16, 0x00, 0xea, 0xff, 0x12, 0x00, 0xec, 0xff, 0x0f, 0x00, 0xf1, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0x05, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x15, 0x00, 0x13, 0x00, 0x19, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x13, 0x00, 0x10, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x06, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xf6, 0xff, 0x0b, 0x00, 0xef, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x05, 0x00, 0xe3, 0xff, 0x03, 0x00, 0xde, 0xff, 0x00, 0x00, 0xd9, 0xff, 0x00, 0x00, 0xd6, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff, 0xd1, 0xff, 0xfe, 0xff, 0xd1, 0xff, 0xfc, 0xff, 0xd3, 0xff, 0xfa, 0xff, 0xd6, 0xff, 0xf7, 0xff, 0xda, 0xff, 0xf4, 0xff, 0xde, 0xff, 0xf0, 0xff, 0xe1, 0xff, 0xec, 0xff, 0xe3, 0xff, 0xe6, 0xff, 0xe5, 0xff, 0xe3, 0xff, 0xe8, 0xff, 0xe3, 0xff, 0xeb, 0xff, 0xe4, 0xff, 0xed, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xe4, 0xff, 0xe9, 0xff, 0xde, 0xff, 0xe4, 0xff, 0xd8, 0xff, 0xe0, 0xff, 0xd5, 0xff, 0xdf, 0xff, 0xd4, 0xff, 0xdf, 0xff, 0xd4, 0xff, 0xde, 0xff, 0xd3, 0xff, 0xda, 0xff, 0xd3, 0xff, 0xd5, 0xff, 0xd3, 0xff, 0xce, 0xff, 0xd2, 0xff, 0xc8, 0xff, 0xd2, 0xff, 0xc2, 0xff, 0xd3, 0xff, 0xbe, 0xff, 0xd5, 0xff, 0xbb, 0xff, 0xd8, 0xff, 0xbb, 0xff, 0xde, 0xff, 0xbd, 0xff, 0xe6, 0xff, 0xc1, 0xff, 0xef, 0xff, 0xc6, 0xff, 0xf7, 0xff, 0xca, 0xff, 0xff, 0xff, 0xcd, 0xff, 0x05, 0x00, 0xd0, 0xff, 0x0d, 0x00, 0xd5, 0xff, 0x17, 0x00, 0xdd, 0xff, 0x24, 0x00, 0xe5, 0xff, 0x33, 0x00, 0xeb, 0xff, 0x41, 0x00, 0xee, 0xff, 0x4c, 0x00, 0xf1, 0xff, 0x56, 0x00, 0xf8, 0xff, 0x5e, 0x00, 0x02, 0x00, 0x66, 0x00, 0x0d, 0x00, 0x6e, 0x00, 0x14, 0x00, 0x74, 0x00, 0x15, 0x00, 0x7a, 0x00, 0x12, 0x00, 0x7f, 0x00, 0x0f, 0x00, 0x85, 0x00, 0x0e, 0x00, 0x8c, 0x00, 0x0e, 0x00, 0x91, 0x00, 0x0f, 0x00, 0x92, 0x00, 0x10, 0x00, 0x8d, 0x00, 0x0f, 0x00, 0x86, 0x00, 0x0f, 0x00, 0x7e, 0x00, 0x0d, 0x00, 0x79, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x05, 0x00, 0x76, 0x00, 0x00, 0x00, 0x76, 0x00, 0xfb, 0xff, 0x75, 0x00, 0xf7, 0xff, 0x71, 0x00, 0xf3, 0xff, 0x6a, 0x00, 0xef, 0xff, 0x5d, 0x00, 0xea, 0xff, 0x4f, 0x00, 0xe7, 0xff, 0x41, 0x00, 0xe7, 0xff, 0x37, 0x00, 0xe8, 0xff, 0x33, 0x00, 0xeb, 0xff, 0x31, 0x00, 0xec, 0xff, 0x2f, 0x00, 0xec, 0xff, 0x2b, 0x00, 0xeb, 0xff, 0x22, 0x00, 0xec, 0xff, 0x16, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xef, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xed, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xe4, 0xff, 0xea, 0xff, 0xe2, 0xff, 0xe4, 0xff, 0xe5, 0xff, 0xdf, 0xff, 0xe9, 0xff, 0xdb, 0xff, 0xee, 0xff, 0xd8, 0xff, 0xf1, 0xff, 0xd6, 0xff, 0xf2, 0xff, 0xd4, 0xff, 0xef, 0xff, 0xd2, 0xff, 0xe7, 0xff, 0xcf, 0xff, 0xdd, 0xff, 0xcc, 0xff, 0xd3, 0xff, 0xca, 0xff, 0xcc, 0xff, 0xca, 0xff, 0xc9, 0xff, 0xcc, 0xff, 0xca, 0xff, 0xd3, 0xff, 0xce, 0xff, 0xda, 0xff, 0xd1, 0xff, 0xe2, 0xff, 0xd0, 0xff, 0xe9, 0xff, 0xcc, 0xff, 0xed, 0xff, 0xc6, 0xff, 0xf2, 0xff, 0xc1, 0xff, 0xf7, 0xff, 0xc0, 0xff, 0xfe, 0xff, 0xc2, 0xff, 0x07, 0x00, 0xc8, 0xff, 0x11, 0x00, 0xd1, 0xff, 0x1a, 0x00, 0xdb, 0xff, 0x22, 0x00, 0xe4, 0xff, 0x28, 0x00, 0xea, 0xff, 0x2d, 0x00, 0xed, 0xff, 0x30, 0x00, 0xee, 0xff, 0x32, 0x00, 0xee, 0xff, 0x35, 0x00, 0xef, 0xff, 0x39, 0x00, 0xf3, 0xff, 0x3e, 0x00, 0xfb, 0xff, 0x41, 0x00, 0x04, 0x00, 0x42, 0x00, 0x0e, 0x00, 0x3f, 0x00, 0x17, 0x00, 0x3a, 0x00, 0x1e, 0x00, 0x35, 0x00, 0x21, 0x00, 0x30, 0x00, 0x22, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x27, 0x00, 0x24, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x31, 0x00, 0x1a, 0x00, 0x31, 0x00, 0x15, 0x00, 0x2d, 0x00, 0x0e, 0x00, 0x24, 0x00, 0x06, 0x00, 0x19, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf1, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xf2, 0xff, 0xef, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xd9, 0xff, 0xe8, 0xff, 0xce, 0xff, 0xe5, 0xff, 0xc8, 0xff, 0xe2, 0xff, 0xc7, 0xff, 0xe0, 0xff, 0xc7, 0xff, 0xe1, 0xff, 0xc8, 0xff, 0xe4, 0xff, 0xc6, 0xff, 0xe6, 0xff, 0xc1, 0xff, 0xe8, 0xff, 0xba, 0xff, 0xe8, 0xff, 0xb4, 0xff, 0xe6, 0xff, 0xb0, 0xff, 0xe2, 0xff, 0xaf, 0xff, 0xdc, 0xff, 0xae, 0xff, 0xd5, 0xff, 0xae, 0xff, 0xd1, 0xff, 0xad, 0xff, 0xcf, 0xff, 0xac, 0xff, 0xd0, 0xff, 0xaa, 0xff, 0xd2, 0xff, 0xa7, 0xff, 0xd6, 0xff, 0xa4, 0xff, 0xd9, 0xff, 0xa2, 0xff, 0xdc, 0xff, 0xa1, 0xff, 0xde, 0xff, 0xa4, 0xff, 0xe1, 0xff, 0xa9, 0xff, 0xe4, 0xff, 0xae, 0xff, 0xe8, 0xff, 0xb4, 0xff, 0xee, 0xff, 0xb9, 0xff, 0xf6, 0xff, 0xbd, 0xff, 0x00, 0x00, 0xc1, 0xff, 0x0c, 0x00, 0xc5, 0xff, 0x18, 0x00, 0xcb, 0xff, 0x21, 0x00, 0xd2, 0xff, 0x28, 0x00, 0xd9, 0xff, 0x2c, 0x00, 0xe1, 0xff, 0x2f, 0x00, 0xeb, 0xff, 0x33, 0x00, 0xf5, 0xff, 0x39, 0x00, 0xfd, 0xff, 0x41, 0x00, 0x04, 0x00, 0x49, 0x00, 0x08, 0x00, 0x50, 0x00, 0x0b, 0x00, 0x55, 0x00, 0x0f, 0x00, 0x58, 0x00, 0x16, 0x00, 0x5a, 0x00, 0x20, 0x00, 0x5d, 0x00, 0x2c, 0x00, 0x5f, 0x00, 0x35, 0x00, 0x62, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x6a, 0x00, 0x41, 0x00, 0x6d, 0x00, 0x41, 0x00, 0x6d, 0x00, 0x40, 0x00, 0x6b, 0x00, 0x40, 0x00, 0x6a, 0x00, 0x40, 0x00, 0x6a, 0x00, 0x40, 0x00, 0x6c, 0x00, 0x40, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x6e, 0x00, 0x3e, 0x00, 0x6d, 0x00, 0x3c, 0x00, 0x69, 0x00, 0x39, 0x00, 0x65, 0x00, 0x35, 0x00, 0x62, 0x00, 0x30, 0x00, 0x5e, 0x00, 0x2b, 0x00, 0x5c, 0x00, 0x26, 0x00, 0x5b, 0x00, 0x22, 0x00, 0x5c, 0x00, 0x20, 0x00, 0x5d, 0x00, 0x21, 0x00, 0x5e, 0x00, 0x24, 0x00, 0x5f, 0x00, 0x29, 0x00, 0x5e, 0x00, 0x2e, 0x00, 0x5d, 0x00, 0x31, 0x00, 0x5b, 0x00, 0x32, 0x00, 0x58, 0x00, 0x32, 0x00, 0x53, 0x00, 0x30, 0x00, 0x4b, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x22, 0x00, 0x2d, 0x00, 0x17, 0x00, 0x2a, 0x00, 0x0a, 0x00, 0x25, 0x00, 0xfd, 0xff, 0x1f, 0x00, 0xef, 0xff, 0x16, 0x00, 0xe3, 0xff, 0x0f, 0x00, 0xd8, 0xff, 0x09, 0x00, 0xce, 0xff, 0x05, 0x00, 0xc5, 0xff, 0x02, 0x00, 0xbb, 0xff, 0xff, 0xff, 0xb1, 0xff, 0xfb, 0xff, 0xa8, 0xff, 0xf4, 0xff, 0x9f, 0xff, 0xec, 0xff, 0x99, 0xff, 0xe5, 0xff, 0x97, 0xff, 0xe0, 0xff, 0x96, 0xff, 0xde, 0xff, 0x96, 0xff, 0xdd, 0xff, 0x97, 0xff, 0xdd, 0xff, 0x97, 0xff, 0xdd, 0xff, 0x98, 0xff, 0xdb, 0xff, 0x99, 0xff, 0xd9, 0xff, 0x9c, 0xff, 0xd5, 0xff, 0xa0, 0xff, 0xd0, 0xff, 0xa4, 0xff, 0xcd, 0xff, 0xa9, 0xff, 0xcd, 0xff, 0xb0, 0xff, 0xcd, 0xff, 0xb7, 0xff, 0xcf, 0xff, 0xbf, 0xff, 0xd2, 0xff, 0xc8, 0xff, 0xd6, 0xff, 0xd1, 0xff, 0xda, 0xff, 0xda, 0xff, 0xdf, 0xff, 0xe1, 0xff, 0xe3, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xe8, 0xff, 0xea, 0xff, 0xe9, 0xff, 0xed, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x08, 0x00, 0xf5, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x16, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xfb, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xff, 0xff, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x1e, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xf6, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xea, 0xff, 0xf0, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xe4, 0xff, 0xe9, 0xff, 0xdf, 0xff, 0xe3, 0xff, 0xd9, 0xff, 0xdc, 0xff, 0xd2, 0xff, 0xd4, 0xff, 0xce, 0xff, 0xd0, 0xff, 0xcd, 0xff, 0xcd, 0xff, 0xcf, 0xff, 0xcd, 0xff, 0xd4, 0xff, 0xce, 0xff, 0xd7, 0xff, 0xcf, 0xff, 0xd8, 0xff, 0xcf, 0xff, 0xd6, 0xff, 0xcc, 0xff, 0xd1, 0xff, 0xc7, 0xff, 0xcc, 0xff, 0xc2, 0xff, 0xcb, 0xff, 0xbf, 0xff, 0xcd, 0xff, 0xc0, 0xff, 0xd0, 0xff, 0xc6, 0xff, 0xd3, 0xff, 0xcf, 0xff, 0xd4, 0xff, 0xda, 0xff, 0xd3, 0xff, 0xe2, 0xff, 0xd3, 0xff, 0xe7, 0xff, 0xd2, 0xff, 0xe8, 0xff, 0xd3, 0xff, 0xe8, 0xff, 0xd5, 0xff, 0xe7, 0xff, 0xd6, 0xff, 0xe8, 0xff, 0xd8, 0xff, 0xed, 0xff, 0xd9, 0xff, 0xf3, 0xff, 0xda, 0xff, 0xfa, 0xff, 0xdb, 0xff, 0xfe, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xfe, 0xff, 0xe5, 0xff, 0xfc, 0xff, 0xea, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xff, 0xff, 0xee, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x12, 0x00, 0x04, 0x00, 0x17, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x0b, 0x00, 0x23, 0x00, 0x0c, 0x00, 0x29, 0x00, 0x0c, 0x00, 0x2c, 0x00, 0x0e, 0x00, 0x2e, 0x00, 0x13, 0x00, 0x2e, 0x00, 0x1a, 0x00, 0x2e, 0x00, 0x23, 0x00, 0x2f, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x2f, 0x00, 0x36, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x38, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x42, 0x00, 0x2d, 0x00, 0x49, 0x00, 0x29, 0x00, 0x4f, 0x00, 0x26, 0x00, 0x54, 0x00, 0x24, 0x00, 0x57, 0x00, 0x22, 0x00, 0x5a, 0x00, 0x20, 0x00, 0x5b, 0x00, 0x1d, 0x00, 0x5c, 0x00, 0x1b, 0x00, 0x5d, 0x00, 0x19, 0x00, 0x5d, 0x00, 0x15, 0x00, 0x5c, 0x00, 0x11, 0x00, 0x58, 0x00, 0x0d, 0x00, 0x54, 0x00, 0x08, 0x00, 0x50, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0xfd, 0xff, 0x4a, 0x00, 0xfa, 0xff, 0x46, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0xf5, 0xff, 0x36, 0x00, 0xf1, 0xff, 0x2d, 0x00, 0xeb, 0xff, 0x25, 0x00, 0xe5, 0xff, 0x1e, 0x00, 0xdf, 0xff, 0x18, 0x00, 0xdb, 0xff, 0x12, 0x00, 0xd8, 0xff, 0x0a, 0x00, 0xd7, 0xff, 0x01, 0x00, 0xd6, 0xff, 0xf7, 0xff, 0xd5, 0xff, 0xef, 0xff, 0xd2, 0xff, 0xe9, 0xff, 0xce, 0xff, 0xe5, 0xff, 0xcb, 0xff, 0xe4, 0xff, 0xc9, 0xff, 0xe1, 0xff, 0xc9, 0xff, 0xdb, 0xff, 0xca, 0xff, 0xd1, 0xff, 0xcc, 0xff, 0xc6, 0xff, 0xcd, 0xff, 0xbd, 0xff, 0xce, 0xff, 0xb7, 0xff, 0xce, 0xff, 0xb4, 0xff, 0xcd, 0xff, 0xb5, 0xff, 0xce, 0xff, 0xb7, 0xff, 0xd1, 0xff, 0xb8, 0xff, 0xd6, 0xff, 0xb7, 0xff, 0xdb, 0xff, 0xb4, 0xff, 0xe1, 0xff, 0xb0, 0xff, 0xe5, 0xff, 0xaf, 0xff, 0xe8, 0xff, 0xb2, 0xff, 0xeb, 0xff, 0xb9, 0xff, 0xef, 0xff, 0xc1, 0xff, 0xf4, 0xff, 0xc7, 0xff, 0xfc, 0xff, 0xcb, 0xff, 0x05, 0x00, 0xce, 0xff, 0x0e, 0x00, 0xd1, 0xff, 0x15, 0x00, 0xd4, 0xff, 0x18, 0x00, 0xda, 0xff, 0x18, 0x00, 0xe1, 0xff, 0x19, 0x00, 0xe9, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x1c, 0x00, 0xfc, 0xff, 0x1d, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x0c, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x21, 0x00, 0x15, 0x00, 0x25, 0x00, 0x13, 0x00, 0x28, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x0e, 0x00, 0x30, 0x00, 0x0b, 0x00, 0x33, 0x00, 0x09, 0x00, 0x36, 0x00, 0x07, 0x00, 0x36, 0x00, 0x07, 0x00, 0x33, 0x00, 0x0a, 0x00, 0x2d, 0x00, 0x0d, 0x00, 0x27, 0x00, 0x11, 0x00, 0x21, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x18, 0x00, 0x18, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x21, 0x00, 0x0f, 0x00, 0x28, 0x00, 0x07, 0x00, 0x30, 0x00, 0xfe, 0xff, 0x37, 0x00, 0xf6, 0xff, 0x3c, 0x00, 0xf1, 0xff, 0x3d, 0x00, 0xee, 0xff, 0x3b, 0x00, 0xed, 0xff, 0x38, 0x00, 0xec, 0xff, 0x36, 0x00, 0xec, 0xff, 0x37, 0x00, 0xe9, 0xff, 0x3b, 0x00, 0xe5, 0xff, 0x41, 0x00, 0xdf, 0xff, 0x45, 0x00, 0xda, 0xff, 0x47, 0x00, 0xd5, 0xff, 0x45, 0x00, 0xd3, 0xff, 0x40, 0x00, 0xd3, 0xff, 0x3a, 0x00, 0xd3, 0xff, 0x35, 0x00, 0xd2, 0xff, 0x32, 0x00, 0xd0, 0xff, 0x30, 0x00, 0xcc, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x32, 0x00, 0xc1, 0xff, 0x31, 0x00, 0xbd, 0xff, 0x2d, 0x00, 0xbc, 0xff, 0x27, 0x00, 0xbc, 0xff, 0x20, 0x00, 0xbf, 0xff, 0x18, 0x00, 0xc2, 0xff, 0x12, 0x00, 0xc5, 0xff, 0x0d, 0x00, 0xc6, 0xff, 0x09, 0x00, 0xc5, 0xff, 0x08, 0x00, 0xc3, 0xff, 0x07, 0x00, 0xc2, 0xff, 0x06, 0x00, 0xc2, 0xff, 0x04, 0x00, 0xc4, 0xff, 0x01, 0x00, 0xc9, 0xff, 0xfd, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xf6, 0xff, 0xd9, 0xff, 0xf7, 0xff, 0xdb, 0xff, 0xfb, 0xff, 0xdc, 0xff, 0x01, 0x00, 0xdd, 0xff, 0x08, 0x00, 0xe0, 0xff, 0x0d, 0x00, 0xe4, 0xff, 0x0e, 0x00, 0xeb, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x19, 0x00, 0x06, 0x00, 0x1f, 0x00, 0x02, 0x00, 0x25, 0x00, 0xff, 0xff, 0x29, 0x00, 0xfc, 0xff, 0x2c, 0x00, 0xf8, 0xff, 0x2e, 0x00, 0xf5, 0xff, 0x30, 0x00, 0xf2, 0xff, 0x33, 0x00, 0xee, 0xff, 0x37, 0x00, 0xeb, 0xff, 0x3c, 0x00, 0xe9, 0xff, 0x41, 0x00, 0xe9, 0xff, 0x44, 0x00, 0xea, 0xff, 0x46, 0x00, 0xe9, 0xff, 0x46, 0x00, 0xe6, 0xff, 0x45, 0x00, 0xe1, 0xff, 0x45, 0x00, 0xdb, 0xff, 0x44, 0x00, 0xd7, 0xff, 0x43, 0x00, 0xd5, 0xff, 0x44, 0x00, 0xd6, 0xff, 0x46, 0x00, 0xd8, 0xff, 0x48, 0x00, 0xdb, 0xff, 0x4a, 0x00, 0xdc, 0xff, 0x49, 0x00, 0xdb, 0xff, 0x46, 0x00, 0xd9, 0xff, 0x41, 0x00, 0xd7, 0xff, 0x3c, 0x00, 0xd6, 0xff, 0x37, 0x00, 0xd7, 0xff, 0x34, 0x00, 0xda, 0xff, 0x31, 0x00, 0xdc, 0xff, 0x30, 0x00, 0xde, 0xff, 0x2e, 0x00, 0xdf, 0xff, 0x2c, 0x00, 0xde, 0xff, 0x2a, 0x00, 0xdd, 0xff, 0x27, 0x00, 0xdc, 0xff, 0x23, 0x00, 0xdc, 0xff, 0x1e, 0x00, 0xdc, 0xff, 0x18, 0x00, 0xdc, 0xff, 0x13, 0x00, 0xdc, 0xff, 0x0e, 0x00, 0xdb, 0xff, 0x09, 0x00, 0xda, 0xff, 0x04, 0x00, 0xdb, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xfa, 0xff, 0xdc, 0xff, 0xf7, 0xff, 0xdb, 0xff, 0xf4, 0xff, 0xd9, 0xff, 0xf2, 0xff, 0xd8, 0xff, 0xf0, 0xff, 0xd7, 0xff, 0xef, 0xff, 0xd7, 0xff, 0xef, 0xff, 0xda, 0xff, 0xef, 0xff, 0xde, 0xff, 0xef, 0xff, 0xe3, 0xff, 0xee, 0xff, 0xe7, 0xff, 0xec, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xed, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0x02, 0x00, 0xff, 0xff, 0x08, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x12, 0x00, 0x05, 0x00, 0x15, 0x00, 0x04, 0x00, 0x19, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x1e, 0x00, 0x09, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x22, 0x00, 0xff, 0xff, 0x26, 0x00, 0xf9, 0xff, 0x2a, 0x00, 0xf5, 0xff, 0x2e, 0x00, 0xf3, 0xff, 0x31, 0x00, 0xf2, 0xff, 0x33, 0x00, 0xf2, 0xff, 0x33, 0x00, 0xf2, 0xff, 0x31, 0x00, 0xf2, 0xff, 0x2f, 0x00, 0xf2, 0xff, 0x2f, 0x00, 0xf3, 0xff, 0x30, 0x00, 0xf4, 0xff, 0x32, 0x00, 0xf5, 0xff, 0x33, 0x00, 0xf5, 0xff, 0x33, 0x00, 0xf5, 0xff, 0x2f, 0x00, 0xf4, 0xff, 0x29, 0x00, 0xf4, 0xff, 0x1f, 0x00, 0xf5, 0xff, 0x14, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x03, 0x00, 0xd0, 0xff, 0x08, 0x00, 0xc8, 0xff, 0x0e, 0x00, 0xc1, 0xff, 0x13, 0x00, 0xbc, 0xff, 0x16, 0x00, 0xb9, 0xff, 0x17, 0x00, 0xb7, 0xff, 0x16, 0x00, 0xb3, 0xff, 0x15, 0x00, 0xaf, 0xff, 0x16, 0x00, 0xaa, 0xff, 0x17, 0x00, 0xa8, 0xff, 0x1a, 0x00, 0xa8, 0xff, 0x1d, 0x00, 0xab, 0xff, 0x1d, 0x00, 0xb0, 0xff, 0x1c, 0x00, 0xb3, 0xff, 0x1a, 0x00, 0xb3, 0xff, 0x18, 0x00, 0xb1, 0xff, 0x17, 0x00, 0xb0, 0xff, 0x17, 0x00, 0xb0, 0xff, 0x17, 0x00, 0xb3, 0xff, 0x18, 0x00, 0xb5, 0xff, 0x1a, 0x00, 0xb7, 0xff, 0x1c, 0x00, 0xb6, 0xff, 0x20, 0x00, 0xb5, 0xff, 0x23, 0x00, 0xb3, 0xff, 0x27, 0x00, 0xb1, 0xff, 0x29, 0x00, 0xb0, 0xff, 0x2b, 0x00, 0xb1, 0xff, 0x2c, 0x00, 0xb5, 0xff, 0x2e, 0x00, 0xb9, 0xff, 0x2f, 0x00, 0xbe, 0xff, 0x32, 0x00, 0xc0, 0xff, 0x35, 0x00, 0xc2, 0xff, 0x3a, 0x00, 0xc3, 0xff, 0x3f, 0x00, 0xc5, 0xff, 0x43, 0x00, 0xca, 0xff, 0x43, 0x00, 0xd2, 0xff, 0x3e, 0x00, 0xdb, 0xff, 0x37, 0x00, 0xe6, 0xff, 0x30, 0x00, 0xf1, 0xff, 0x2a, 0x00, 0xfc, 0xff, 0x26, 0x00, 0x06, 0x00, 0x23, 0x00, 0x10, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x25, 0x00, 0x17, 0x00, 0x31, 0x00, 0x10, 0x00, 0x3d, 0x00, 0x08, 0x00, 0x49, 0x00, 0xff, 0xff, 0x53, 0x00, 0xf8, 0xff, 0x5c, 0x00, 0xf1, 0xff, 0x64, 0x00, 0xed, 0xff, 0x6b, 0x00, 0xea, 0xff, 0x71, 0x00, 0xe6, 0xff, 0x74, 0x00, 0xe1, 0xff, 0x75, 0x00, 0xdb, 0xff, 0x75, 0x00, 0xd6, 0xff, 0x75, 0x00, 0xd2, 0xff, 0x77, 0x00, 0xce, 0xff, 0x79, 0x00, 0xcb, 0xff, 0x7a, 0x00, 0xc9, 0xff, 0x77, 0x00, 0xc8, 0xff, 0x72, 0x00, 0xc9, 0xff, 0x6b, 0x00, 0xcc, 0xff, 0x63, 0x00, 0xd0, 0xff, 0x5b, 0x00, 0xd3, 0xff, 0x54, 0x00, 0xd5, 0xff, 0x4e, 0x00, 0xd6, 0xff, 0x49, 0x00, 0xd5, 0xff, 0x45, 0x00, 0xd3, 0xff, 0x3f, 0x00, 0xd3, 0xff, 0x35, 0x00, 0xd5, 0xff, 0x2a, 0x00, 0xd8, 0xff, 0x1f, 0x00, 0xdc, 0xff, 0x17, 0x00, 0xe0, 0xff, 0x13, 0x00, 0xe2, 0xff, 0x11, 0x00, 0xe1, 0xff, 0x0e, 0x00, 0xe0, 0xff, 0x08, 0x00, 0xde, 0xff, 0x00, 0x00, 0xde, 0xff, 0xf6, 0xff, 0xe0, 0xff, 0xed, 0xff, 0xe3, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xe5, 0xff, 0xeb, 0xff, 0xe4, 0xff, 0xef, 0xff, 0xe4, 0xff, 0xf3, 0xff, 0xe2, 0xff, 0xf5, 0xff, 0xdc, 0xff, 0xf7, 0xff, 0xd3, 0xff, 0xf9, 0xff, 0xc9, 0xff, 0xfc, 0xff, 0xbf, 0xff, 0x01, 0x00, 0xb8, 0xff, 0x06, 0x00, 0xb5, 0xff, 0x0a, 0x00, 0xb4, 0xff, 0x0d, 0x00, 0xb5, 0xff, 0x10, 0x00, 0xb6, 0xff, 0x12, 0x00, 0xb5, 0xff, 0x13, 0x00, 0xb3, 0xff, 0x14, 0x00, 0xaf, 0xff, 0x14, 0x00, 0xaa, 0xff, 0x15, 0x00, 0xa5, 0xff, 0x14, 0x00, 0xa2, 0xff, 0x14, 0x00, 0xa2, 0xff, 0x12, 0x00, 0xa4, 0xff, 0x11, 0x00, 0xa8, 0xff, 0x10, 0x00, 0xad, 0xff, 0x0e, 0x00, 0xb4, 0xff, 0x0b, 0x00, 0xba, 0xff, 0x08, 0x00, 0xbe, 0xff, 0x03, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xbe, 0xff, 0xfc, 0xff, 0xbe, 0xff, 0xfb, 0xff, 0xc0, 0xff, 0xfa, 0xff, 0xc7, 0xff, 0xf8, 0xff, 0xd2, 0xff, 0xf4, 0xff, 0xdf, 0xff, 0xef, 0xff, 0xe9, 0xff, 0xea, 0xff, 0xf0, 0xff, 0xe5, 0xff, 0xf1, 0xff, 0xe2, 0xff, 0xf1, 0xff, 0xe2, 0xff, 0xf2, 0xff, 0xe3, 0xff, 0xf7, 0xff, 0xe5, 0xff, 0x01, 0x00, 0xe6, 0xff, 0x0f, 0x00, 0xe5, 0xff, 0x1d, 0x00, 0xe2, 0xff, 0x28, 0x00, 0xdf, 0xff, 0x2f, 0x00, 0xdd, 0xff, 0x32, 0x00, 0xdd, 0xff, 0x31, 0x00, 0xde, 0xff, 0x31, 0x00, 0xe0, 0xff, 0x33, 0x00, 0xe0, 0xff, 0x39, 0x00, 0xde, 0xff, 0x42, 0x00, 0xda, 0xff, 0x4a, 0x00, 0xd5, 0xff, 0x4f, 0x00, 0xd2, 0xff, 0x4f, 0x00, 0xd0, 0xff, 0x4b, 0x00, 0xd0, 0xff, 0x46, 0x00, 0xd2, 0xff, 0x42, 0x00, 0xd3, 0xff, 0x41, 0x00, 0xd4, 0xff, 0x41, 0x00, 0xd4, 0xff, 0x41, 0x00, 0xd4, 0xff, 0x41, 0x00, 0xd5, 0xff, 0x3f, 0x00, 0xd8, 0xff, 0x3c, 0x00, 0xdc, 0xff, 0x37, 0x00, 0xe1, 0xff, 0x32, 0x00, 0xe6, 0xff, 0x2d, 0x00, 0xeb, 0xff, 0x27, 0x00, 0xf1, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x07, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x09, 0x00, 0x14, 0x00, 0x02, 0x00, 0x16, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xee, 0xff, 0x19, 0x00, 0xe2, 0xff, 0x1d, 0x00, 0xd7, 0xff, 0x24, 0x00, 0xce, 0xff, 0x2b, 0x00, 0xc7, 0xff, 0x2f, 0x00, 0xc4, 0xff, 0x30, 0x00, 0xc3, 0xff, 0x2f, 0x00, 0xc1, 0xff, 0x2d, 0x00, 0xbd, 0xff, 0x2b, 0x00, 0xb7, 0xff, 0x2a, 0x00, 0xae, 0xff, 0x2b, 0x00, 0xa7, 0xff, 0x2d, 0x00, 0xa4, 0xff, 0x2f, 0x00, 0xa6, 0xff, 0x31, 0x00, 0xac, 0xff, 0x31, 0x00, 0xb4, 0xff, 0x30, 0x00, 0xb9, 0xff, 0x2f, 0x00, 0xbb, 0xff, 0x2c, 0x00, 0xba, 0xff, 0x29, 0x00, 0xb9, 0xff, 0x24, 0x00, 0xb9, 0xff, 0x1e, 0x00, 0xbb, 0xff, 0x18, 0x00, 0xc1, 0xff, 0x12, 0x00, 0xc8, 0xff, 0x0d, 0x00, 0xd1, 0xff, 0x0a, 0x00, 0xd8, 0xff, 0x08, 0x00, 0xdd, 0xff, 0x05, 0x00, 0xdf, 0xff, 0x01, 0x00, 0xe0, 0xff, 0xfb, 0xff, 0xe1, 0xff, 0xf5, 0xff, 0xe5, 0xff, 0xf0, 0xff, 0xed, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xed, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x14, 0x00, 0xf6, 0xff, 0x1a, 0x00, 0xf7, 0xff, 0x1e, 0x00, 0xf5, 0xff, 0x22, 0x00, 0xf1, 0xff, 0x28, 0x00, 0xed, 0xff, 0x2f, 0x00, 0xeb, 0xff, 0x38, 0x00, 0xec, 0xff, 0x41, 0x00, 0xf1, 0xff, 0x4a, 0x00, 0xf8, 0xff, 0x52, 0x00, 0xfe, 0xff, 0x58, 0x00, 0x02, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x5e, 0x00, 0x03, 0x00, 0x5f, 0x00, 0x01, 0x00, 0x61, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xff, 0x69, 0x00, 0x01, 0x00, 0x70, 0x00, 0x06, 0x00, 0x76, 0x00, 0x0d, 0x00, 0x7a, 0x00, 0x14, 0x00, 0x7a, 0x00, 0x1b, 0x00, 0x75, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x23, 0x00, 0x65, 0x00, 0x25, 0x00, 0x5f, 0x00, 0x26, 0x00, 0x5c, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x2b, 0x00, 0x5a, 0x00, 0x2e, 0x00, 0x57, 0x00, 0x31, 0x00, 0x52, 0x00, 0x33, 0x00, 0x48, 0x00, 0x32, 0x00, 0x3b, 0x00, 0x2f, 0x00, 0x2d, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x24, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, 0x00, 0x17, 0x00, 0x01, 0x00, 0x17, 0x00, 0xf7, 0xff, 0x17, 0x00, 0xeb, 0xff, 0x16, 0x00, 0xdf, 0xff, 0x13, 0x00, 0xd2, 0xff, 0x11, 0x00, 0xc8, 0xff, 0x11, 0x00, 0xbf, 0xff, 0x15, 0x00, 0xb7, 0xff, 0x1b, 0x00, 0xb1, 0xff, 0x20, 0x00, 0xac, 0xff, 0x24, 0x00, 0xa8, 0xff, 0x25, 0x00, 0xa4, 0xff, 0x24, 0x00, 0x9e, 0xff, 0x22, 0x00, 0x98, 0xff, 0x1f, 0x00, 0x90, 0xff, 0x1c, 0x00, 0x89, 0xff, 0x19, 0x00, 0x84, 0xff, 0x16, 0x00, 0x82, 0xff, 0x13, 0x00, 0x84, 0xff, 0x0f, 0x00, 0x88, 0xff, 0x0a, 0x00, 0x8d, 0xff, 0x04, 0x00, 0x90, 0xff, 0xfe, 0xff, 0x92, 0xff, 0xf7, 0xff, 0x92, 0xff, 0xf0, 0xff, 0x92, 0xff, 0xe9, 0xff, 0x94, 0xff, 0xe3, 0xff, 0x98, 0xff, 0xdf, 0xff, 0xa1, 0xff, 0xdb, 0xff, 0xab, 0xff, 0xd7, 0xff, 0xb7, 0xff, 0xd1, 0xff, 0xc1, 0xff, 0xcb, 0xff, 0xc7, 0xff, 0xc5, 0xff, 0xcc, 0xff, 0xbf, 0xff, 0xd0, 0xff, 0xba, 0xff, 0xd5, 0xff, 0xb8, 0xff, 0xdd, 0xff, 0xb8, 0xff, 0xe6, 0xff, 0xbb, 0xff, 0xf0, 0xff, 0xbd, 0xff, 0xfb, 0xff, 0xbd, 0xff, 0x04, 0x00, 0xbd, 0xff, 0x0d, 0x00, 0xbb, 0xff, 0x16, 0x00, 0xbb, 0xff, 0x1e, 0x00, 0xbd, 0xff, 0x27, 0x00, 0xc1, 0xff, 0x31, 0x00, 0xc7, 0xff, 0x3b, 0x00, 0xcf, 0xff, 0x43, 0x00, 0xd6, 0xff, 0x4b, 0x00, 0xdc, 0xff, 0x52, 0x00, 0xe1, 0xff, 0x5a, 0x00, 0xe4, 0xff, 0x63, 0x00, 0xe7, 0xff, 0x6b, 0x00, 0xea, 0xff, 0x70, 0x00, 0xed, 0xff, 0x72, 0x00, 0xef, 0xff, 0x71, 0x00, 0xee, 0xff, 0x6f, 0x00, 0xed, 0xff, 0x6d, 0x00, 0xec, 0xff, 0x6b, 0x00, 0xeb, 0xff, 0x68, 0x00, 0xea, 0xff, 0x64, 0x00, 0xea, 0xff, 0x60, 0x00, 0xea, 0xff, 0x5a, 0x00, 0xea, 0xff, 0x51, 0x00, 0xe9, 0xff, 0x46, 0x00, 0xe9, 0xff, 0x3b, 0x00, 0xe9, 0xff, 0x32, 0x00, 0xed, 0xff, 0x2a, 0x00, 0xf5, 0xff, 0x23, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x14, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x1c, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x32, 0x00, 0xff, 0xff, 0x38, 0x00, 0xfc, 0xff, 0x3b, 0x00, 0xfa, 0xff, 0x39, 0x00, 0xf7, 0xff, 0x36, 0x00, 0xf4, 0xff, 0x31, 0x00, 0xf2, 0xff, 0x2d, 0x00, 0xf1, 0xff, 0x29, 0x00, 0xef, 0xff, 0x26, 0x00, 0xed, 0xff, 0x25, 0x00, 0xea, 0xff, 0x24, 0x00, 0xe6, 0xff, 0x23, 0x00, 0xe3, 0xff, 0x21, 0x00, 0xdf, 0xff, 0x1f, 0x00, 0xda, 0xff, 0x1c, 0x00, 0xd6, 0xff, 0x18, 0x00, 0xd1, 0xff, 0x12, 0x00, 0xcc, 0xff, 0x0c, 0x00, 0xc8, 0xff, 0x05, 0x00, 0xc5, 0xff, 0x00, 0x00, 0xc2, 0xff, 0xfe, 0xff, 0xc0, 0xff, 0xfe, 0xff, 0xbe, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xfd, 0xff, 0xb7, 0xff, 0xf8, 0xff, 0xb4, 0xff, 0xf1, 0xff, 0xb2, 0xff, 0xe7, 0xff, 0xb4, 0xff, 0xde, 0xff, 0xb8, 0xff, 0xd8, 0xff, 0xbe, 0xff, 0xd6, 0xff, 0xc4, 0xff, 0xd9, 0xff, 0xc8, 0xff, 0xde, 0xff, 0xcb, 0xff, 0xe1, 0xff, 0xcc, 0xff, 0xe0, 0xff, 0xcd, 0xff, 0xdb, 0xff, 0xd0, 0xff, 0xd7, 0xff, 0xd5, 0xff, 0xd4, 0xff, 0xde, 0xff, 0xd4, 0xff, 0xe9, 0xff, 0xd8, 0xff, 0xf5, 0xff, 0xdd, 0xff, 0x00, 0x00, 0xe2, 0xff, 0x09, 0x00, 0xe5, 0xff, 0x0f, 0x00, 0xe6, 0xff, 0x15, 0x00, 0xe6, 0xff, 0x1a, 0x00, 0xe6, 0xff, 0x20, 0x00, 0xe5, 0xff, 0x27, 0x00, 0xe5, 0xff, 0x2f, 0x00, 0xe7, 0xff, 0x37, 0x00, 0xeb, 0xff, 0x3f, 0x00, 0xef, 0xff, 0x45, 0x00, 0xf2, 0xff, 0x49, 0x00, 0xf6, 0xff, 0x4b, 0x00, 0xf8, 0xff, 0x4c, 0x00, 0xfb, 0xff, 0x4d, 0x00, 0xfe, 0xff, 0x4e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x02, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x07, 0x00, 0x4b, 0x00, 0x0b, 0x00, 0x47, 0x00, 0x10, 0x00, 0x43, 0x00, 0x15, 0x00, 0x3d, 0x00, 0x18, 0x00, 0x36, 0x00, 0x19, 0x00, 0x2f, 0x00, 0x18, 0x00, 0x29, 0x00, 0x17, 0x00, 0x22, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x11, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x2d, 0x00, 0x07, 0x00, 0x34, 0x00, 0x01, 0x00, 0x39, 0x00, 0xfa, 0xff, 0x3c, 0x00, 0xf2, 0xff, 0x3e, 0x00, 0xec, 0xff, 0x40, 0x00, 0xe7, 0xff, 0x44, 0x00, 0xe3, 0xff, 0x49, 0x00, 0xe1, 0xff, 0x4f, 0x00, 0xe0, 0xff, 0x54, 0x00, 0xde, 0xff, 0x57, 0x00, 0xdd, 0xff, 0x56, 0x00, 0xda, 0xff, 0x54, 0x00, 0xd5, 0xff, 0x51, 0x00, 0xcf, 0xff, 0x4e, 0x00, 0xc9, 0xff, 0x4a, 0x00, 0xc4, 0xff, 0x45, 0x00, 0xc1, 0xff, 0x3e, 0x00, 0xc1, 0xff, 0x37, 0x00, 0xc4, 0xff, 0x2f, 0x00, 0xc7, 0xff, 0x26, 0x00, 0xc8, 0xff, 0x1c, 0x00, 0xc7, 0xff, 0x12, 0x00, 0xc4, 0xff, 0x06, 0x00, 0xc0, 0xff, 0xfa, 0xff, 0xbc, 0xff, 0xed, 0xff, 0xbb, 0xff, 0xe1, 0xff, 0xbd, 0xff, 0xd7, 0xff, 0xc1, 0xff, 0xcf, 0xff, 0xc6, 0xff, 0xcb, 0xff, 0xcb, 0xff, 0xc8, 0xff, 0xcd, 0xff, 0xc5, 0xff, 0xcc, 0xff, 0xc0, 0xff, 0xcb, 0xff, 0xba, 0xff, 0xcb, 0xff, 0xb3, 0xff, 0xd0, 0xff, 0xb0, 0xff, 0xd9, 0xff, 0xb0, 0xff, 0xe4, 0xff, 0xb5, 0xff, 0xf0, 0xff, 0xbc, 0xff, 0xfa, 0xff, 0xc3, 0xff, 0x00, 0x00, 0xc8, 0xff, 0x03, 0x00, 0xc9, 0xff, 0x04, 0x00, 0xca, 0xff, 0x07, 0x00, 0xca, 0xff, 0x0d, 0x00, 0xcd, 0xff, 0x16, 0x00, 0xd3, 0xff, 0x22, 0x00, 0xdd, 0xff, 0x2e, 0x00, 0xe8, 0xff, 0x39, 0x00, 0xf2, 0xff, 0x40, 0x00, 0xf9, 0xff, 0x43, 0x00, 0xfd, 0xff, 0x44, 0x00, 0xfe, 0xff, 0x43, 0x00, 0xfd, 0xff, 0x43, 0x00, 0xfe, 0xff, 0x45, 0x00, 0x01, 0x00, 0x48, 0x00, 0x06, 0x00, 0x4c, 0x00, 0x0b, 0x00, 0x4e, 0x00, 0x11, 0x00, 0x4f, 0x00, 0x14, 0x00, 0x4d, 0x00, 0x16, 0x00, 0x4a, 0x00, 0x16, 0x00, 0x47, 0x00, 0x15, 0x00, 0x45, 0x00, 0x13, 0x00, 0x44, 0x00, 0x13, 0x00, 0x45, 0x00, 0x14, 0x00, 0x46, 0x00, 0x18, 0x00, 0x47, 0x00, 0x1e, 0x00, 0x48, 0x00, 0x25, 0x00, 0x48, 0x00, 0x29, 0x00, 0x47, 0x00, 0x2b, 0x00, 0x46, 0x00, 0x2b, 0x00, 0x43, 0x00, 0x2a, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x2a, 0x00, 0x37, 0x00, 0x30, 0x00, 0x33, 0x00, 0x38, 0x00, 0x30, 0x00, 0x40, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x2a, 0x00, 0x48, 0x00, 0x26, 0x00, 0x46, 0x00, 0x20, 0x00, 0x43, 0x00, 0x18, 0x00, 0x40, 0x00, 0x0e, 0x00, 0x3f, 0x00, 0x04, 0x00, 0x40, 0x00, 0xfa, 0xff, 0x43, 0x00, 0xf1, 0xff, 0x44, 0x00, 0xea, 0xff, 0x42, 0x00, 0xe4, 0xff, 0x3c, 0x00, 0xde, 0xff, 0x32, 0x00, 0xd7, 0xff, 0x27, 0x00, 0xcf, 0xff, 0x1d, 0x00, 0xc6, 0xff, 0x17, 0x00, 0xbe, 0xff, 0x13, 0x00, 0xb5, 0xff, 0x10, 0x00, 0xad, 0xff, 0x0c, 0x00, 0xa6, 0xff, 0x07, 0x00, 0xa1, 0xff, 0xff, 0xff, 0x9d, 0xff, 0xf7, 0xff, 0x9b, 0xff, 0xf0, 0xff, 0x9a, 0xff, 0xea, 0xff, 0x99, 0xff, 0xe7, 0xff, 0x9a, 0xff, 0xe4, 0xff, 0x9b, 0xff, 0xe1, 0xff, 0x9f, 0xff, 0xdd, 0xff, 0xa4, 0xff, 0xd8, 0xff, 0xab, 0xff, 0xd3, 0xff, 0xb0, 0xff, 0xcf, 0xff, 0xb5, 0xff, 0xcb, 0xff, 0xb8, 0xff, 0xc8, 0xff, 0xba, 0xff, 0xc4, 0xff, 0xbb, 0xff, 0xc0, 0xff, 0xbd, 0xff, 0xbd, 0xff, 0xc0, 0xff, 0xbb, 0xff, 0xc4, 0xff, 0xba, 0xff, 0xcb, 0xff, 0xb9, 0xff, 0xd2, 0xff, 0xba, 0xff, 0xd6, 0xff, 0xba, 0xff, 0xd7, 0xff, 0xbb, 0xff, 0xd5, 0xff, 0xbb, 0xff, 0xd2, 0xff, 0xba, 0xff, 0xd1, 0xff, 0xbb, 0xff, 0xd2, 0xff, 0xbd, 0xff, 0xd6, 0xff, 0xc2, 0xff, 0xdd, 0xff, 0xc8, 0xff, 0xe4, 0xff, 0xce, 0xff, 0xeb, 0xff, 0xd3, 0xff, 0xf0, 0xff, 0xd6, 0xff, 0xf4, 0xff, 0xd8, 0xff, 0xf7, 0xff, 0xd9, 0xff, 0xf9, 0xff, 0xdb, 0xff, 0xfc, 0xff, 0xdf, 0xff, 0x00, 0x00, 0xe2, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x0b, 0x00, 0xe8, 0xff, 0x12, 0x00, 0xe9, 0xff, 0x17, 0x00, 0xe9, 0xff, 0x1b, 0x00, 0xe8, 0xff, 0x1d, 0x00, 0xe8, 0xff, 0x1e, 0x00, 0xe9, 0xff, 0x1e, 0x00, 0xea, 0xff, 0x20, 0x00, 0xec, 0xff, 0x23, 0x00, 0xef, 0xff, 0x28, 0x00, 0xf3, 0xff, 0x2e, 0x00, 0xf7, 0xff, 0x36, 0x00, 0xfd, 0xff, 0x3d, 0x00, 0x02, 0x00, 0x41, 0x00, 0x06, 0x00, 0x44, 0x00, 0x09, 0x00, 0x46, 0x00, 0x0b, 0x00, 0x48, 0x00, 0x0b, 0x00, 0x4a, 0x00, 0x0c, 0x00, 0x4d, 0x00, 0x0e, 0x00, 0x4f, 0x00, 0x12, 0x00, 0x50, 0x00, 0x18, 0x00, 0x4e, 0x00, 0x1d, 0x00, 0x4b, 0x00, 0x21, 0x00, 0x45, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x1b, 0x00, 0x2f, 0x00, 0x18, 0x00, 0x29, 0x00, 0x18, 0x00, 0x22, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x08, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x19, 0x00, 0xf4, 0xff, 0x14, 0x00, 0xeb, 0xff, 0x0e, 0x00, 0xe3, 0xff, 0x08, 0x00, 0xdb, 0xff, 0x03, 0x00, 0xd3, 0xff, 0xff, 0xff, 0xcc, 0xff, 0xfd, 0xff, 0xc6, 0xff, 0xfd, 0xff, 0xc1, 0xff, 0xfc, 0xff, 0xbc, 0xff, 0xf9, 0xff, 0xb6, 0xff, 0xf5, 0xff, 0xb1, 0xff, 0xf0, 0xff, 0xad, 0xff, 0xec, 0xff, 0xab, 0xff, 0xeb, 0xff, 0xaa, 0xff, 0xeb, 0xff, 0xad, 0xff, 0xee, 0xff, 0xb2, 0xff, 0xf2, 0xff, 0xba, 0xff, 0xf6, 0xff, 0xc2, 0xff, 0xfa, 0xff, 0xca, 0xff, 0xfc, 0xff, 0xcf, 0xff, 0xfd, 0xff, 0xd4, 0xff, 0xfe, 0xff, 0xd7, 0xff, 0x00, 0x00, 0xdd, 0xff, 0x03, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xee, 0xff, 0x0b, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0x06, 0x00, 0x11, 0x00, 0x10, 0x00, 0x12, 0x00, 0x17, 0x00, 0x11, 0x00, 0x19, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x08, 0x00, 0x21, 0x00, 0x09, 0x00, 0x26, 0x00, 0x08, 0x00, 0x2b, 0x00, 0x08, 0x00, 0x30, 0x00, 0x06, 0x00, 0x35, 0x00, 0x04, 0x00, 0x38, 0x00, 0x01, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x44, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x07, 0x00, 0x55, 0x00, 0x0a, 0x00, 0x5d, 0x00, 0x0b, 0x00, 0x63, 0x00, 0x09, 0x00, 0x69, 0x00, 0x07, 0x00, 0x6f, 0x00, 0x04, 0x00, 0x75, 0x00, 0x03, 0x00, 0x79, 0x00, 0x04, 0x00, 0x7c, 0x00, 0x06, 0x00, 0x7e, 0x00, 0x08, 0x00, 0x80, 0x00, 0x09, 0x00, 0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x05, 0x00, 0x7e, 0x00, 0x02, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x02, 0x00, 0x69, 0x00, 0x04, 0x00, 0x61, 0x00, 0x04, 0x00, 0x59, 0x00, 0x02, 0x00, 0x51, 0x00, 0xfe, 0xff, 0x49, 0x00, 0xf8, 0xff, 0x40, 0x00, 0xf4, 0xff, 0x37, 0x00, 0xf0, 0xff, 0x2c, 0x00, 0xef, 0xff, 0x20, 0x00, 0xee, 0xff, 0x15, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xe9, 0xff, 0x04, 0x00, 0xe5, 0xff, 0xfd, 0xff, 0xe0, 0xff, 0xf5, 0xff, 0xdc, 0xff, 0xeb, 0xff, 0xda, 0xff, 0xe0, 0xff, 0xdb, 0xff, 0xd5, 0xff, 0xdd, 0xff, 0xcb, 0xff, 0xe1, 0xff, 0xc2, 0xff, 0xe3, 0xff, 0xbc, 0xff, 0xe2, 0xff, 0xb7, 0xff, 0xe1, 0xff, 0xb2, 0xff, 0xe0, 0xff, 0xac, 0xff, 0xe1, 0xff, 0xa4, 0xff, 0xe6, 0xff, 0x9c, 0xff, 0xed, 0xff, 0x96, 0xff, 0xf5, 0xff, 0x91, 0xff, 0xfd, 0xff, 0x8e, 0xff, 0x02, 0x00, 0x8d, 0xff, 0x04, 0x00, 0x8c, 0xff, 0x06, 0x00, 0x8b, 0xff, 0x07, 0x00, 0x8a, 0xff, 0x0a, 0x00, 0x8a, 0xff, 0x0c, 0x00, 0x8c, 0xff, 0x0e, 0x00, 0x92, 0xff, 0x0f, 0x00, 0x9a, 0xff, 0x0e, 0x00, 0xa2, 0xff, 0x0c, 0x00, 0xaa, 0xff, 0x0a, 0x00, 0xb1, 0xff, 0x0a, 0x00, 0xb7, 0xff, 0x0c, 0x00, 0xbd, 0xff, 0x11, 0x00, 0xc4, 0xff, 0x15, 0x00, 0xcc, 0xff, 0x18, 0x00, 0xd5, 0xff, 0x19, 0x00, 0xdf, 0xff, 0x17, 0x00, 0xe8, 0xff, 0x14, 0x00, 0xf0, 0xff, 0x12, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x14, 0x00, 0x01, 0x00, 0x18, 0x00, 0x06, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x17, 0x00, 0x19, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x0b, 0x00, 0x28, 0x00, 0x0a, 0x00, 0x2c, 0x00, 0x0c, 0x00, 0x2d, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x12, 0x00, 0x28, 0x00, 0x12, 0x00, 0x25, 0x00, 0x0f, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x28, 0x00, 0x09, 0x00, 0x2e, 0x00, 0x08, 0x00, 0x33, 0x00, 0x0c, 0x00, 0x36, 0x00, 0x11, 0x00, 0x36, 0x00, 0x17, 0x00, 0x34, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x1a, 0x00, 0x2e, 0x00, 0x15, 0x00, 0x2e, 0x00, 0x0f, 0x00, 0x2f, 0x00, 0x09, 0x00, 0x30, 0x00, 0x07, 0x00, 0x30, 0x00, 0x09, 0x00, 0x2d, 0x00, 0x0d, 0x00, 0x27, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x0b, 0x00, 0xec, 0xff, 0x10, 0x00, 0xe4, 0xff, 0x16, 0x00, 0xdc, 0xff, 0x1c, 0x00, 0xd3, 0xff, 0x1f, 0x00, 0xca, 0xff, 0x20, 0x00, 0xc1, 0xff, 0x21, 0x00, 0xba, 0xff, 0x23, 0x00, 0xb5, 0xff, 0x26, 0x00, 0xb2, 0xff, 0x29, 0x00, 0xb1, 0xff, 0x28, 0x00, 0xb2, 0xff, 0x25, 0x00, 0xb5, 0xff, 0x1f, 0x00, 0xb9, 0xff, 0x18, 0x00, 0xbd, 0xff, 0x12, 0x00, 0xbf, 0xff, 0x10, 0x00, 0xbe, 0xff, 0x10, 0x00, 0xbd, 0xff, 0x12, 0x00, 0xbd, 0xff, 0x14, 0x00, 0xc0, 0xff, 0x13, 0x00, 0xc5, 0xff, 0x0e, 0x00, 0xcb, 0xff, 0x07, 0x00, 0xd0, 0xff, 0x01, 0x00, 0xd4, 0xff, 0xfd, 0xff, 0xd5, 0xff, 0xfd, 0xff, 0xd7, 0xff, 0xff, 0xff, 0xd9, 0xff, 0x02, 0x00, 0xdc, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x01, 0x00, 0xe4, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf2, 0xff, 0xec, 0xff, 0xef, 0xff, 0xed, 0xff, 0xed, 0xff, 0xef, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe1, 0xff, 0x04, 0x00, 0xdb, 0xff, 0x06, 0x00, 0xd4, 0xff, 0x05, 0x00, 0xce, 0xff, 0x04, 0x00, 0xc9, 0xff, 0x03, 0x00, 0xc5, 0xff, 0x05, 0x00, 0xc1, 0xff, 0x09, 0x00, 0xbe, 0xff, 0x0e, 0x00, 0xbd, 0xff, 0x14, 0x00, 0xbc, 0xff, 0x1a, 0x00, 0xbc, 0xff, 0x1e, 0x00, 0xbb, 0xff, 0x22, 0x00, 0xb8, 0xff, 0x24, 0x00, 0xb5, 0xff, 0x25, 0x00, 0xb2, 0xff, 0x25, 0x00, 0xaf, 0xff, 0x24, 0x00, 0xad, 0xff, 0x24, 0x00, 0xac, 0xff, 0x23, 0x00, 0xaa, 0xff, 0x22, 0x00, 0xa9, 0xff, 0x22, 0x00, 0xa7, 0xff, 0x23, 0x00, 0xa6, 0xff, 0x23, 0x00, 0xa7, 0xff, 0x23, 0x00, 0xab, 0xff, 0x21, 0x00, 0xb2, 0xff, 0x1d, 0x00, 0xbb, 0xff, 0x17, 0x00, 0xc4, 0xff, 0x11, 0x00, 0xcd, 0xff, 0x0e, 0x00, 0xd4, 0xff, 0x0e, 0x00, 0xdb, 0xff, 0x10, 0x00, 0xe2, 0xff, 0x14, 0x00, 0xec, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x14, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x15, 0x00, 0x07, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2a, 0x00, 0xfb, 0xff, 0x31, 0x00, 0xfb, 0xff, 0x35, 0x00, 0xff, 0xff, 0x3b, 0x00, 0x03, 0x00, 0x43, 0x00, 0x06, 0x00, 0x4e, 0x00, 0x06, 0x00, 0x5a, 0x00, 0x02, 0x00, 0x64, 0x00, 0xfc, 0xff, 0x6a, 0x00, 0xf5, 0xff, 0x6a, 0x00, 0xf0, 0xff, 0x66, 0x00, 0xed, 0xff, 0x62, 0x00, 0xee, 0xff, 0x5e, 0x00, 0xf2, 0xff, 0x5e, 0x00, 0xf6, 0xff, 0x61, 0x00, 0xf9, 0xff, 0x64, 0x00, 0xfa, 0xff, 0x66, 0x00, 0xfa, 0xff, 0x65, 0x00, 0xf7, 0xff, 0x61, 0x00, 0xf3, 0xff, 0x5a, 0x00, 0xef, 0xff, 0x51, 0x00, 0xed, 0xff, 0x48, 0x00, 0xed, 0xff, 0x41, 0x00, 0xf0, 0xff, 0x3a, 0x00, 0xf5, 0xff, 0x35, 0x00, 0xfb, 0xff, 0x31, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x03, 0x00, 0x27, 0x00, 0x03, 0x00, 0x20, 0x00, 0x03, 0x00, 0x19, 0x00, 0x03, 0x00, 0x12, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1d, 0x00, 0xfd, 0xff, 0x23, 0x00, 0xf9, 0xff, 0x27, 0x00, 0xf3, 0xff, 0x29, 0x00, 0xeb, 0xff, 0x2a, 0x00, 0xe2, 0xff, 0x2c, 0x00, 0xda, 0xff, 0x31, 0x00, 0xd4, 0xff, 0x36, 0x00, 0xd0, 0xff, 0x3b, 0x00, 0xcd, 0xff, 0x3e, 0x00, 0xca, 0xff, 0x3d, 0x00, 0xc5, 0xff, 0x3a, 0x00, 0xbe, 0xff, 0x36, 0x00, 0xb4, 0xff, 0x34, 0x00, 0xa8, 0xff, 0x34, 0x00, 0x9d, 0xff, 0x34, 0x00, 0x94, 0xff, 0x34, 0x00, 0x8e, 0xff, 0x32, 0x00, 0x8d, 0xff, 0x2d, 0x00, 0x8f, 0xff, 0x27, 0x00, 0x92, 0xff, 0x22, 0x00, 0x94, 0xff, 0x1d, 0x00, 0x95, 0xff, 0x1b, 0x00, 0x96, 0xff, 0x19, 0x00, 0x98, 0xff, 0x18, 0x00, 0x9c, 0xff, 0x16, 0x00, 0xa2, 0xff, 0x12, 0x00, 0xab, 0xff, 0x0d, 0x00, 0xb4, 0xff, 0x07, 0x00, 0xbd, 0xff, 0x00, 0x00, 0xc6, 0xff, 0xfb, 0xff, 0xce, 0xff, 0xf6, 0xff, 0xd5, 0xff, 0xf4, 0xff, 0xdc, 0xff, 0xf3, 0xff, 0xe4, 0xff, 0xf4, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xe2, 0xff, 0x05, 0x00, 0xd8, 0xff, 0x0b, 0x00, 0xd1, 0xff, 0x10, 0x00, 0xce, 0xff, 0x13, 0x00, 0xce, 0xff, 0x16, 0x00, 0xd1, 0xff, 0x19, 0x00, 0xd5, 0xff, 0x1e, 0x00, 0xd8, 0xff, 0x25, 0x00, 0xd8, 0xff, 0x2d, 0x00, 0xd5, 0xff, 0x36, 0x00, 0xd0, 0xff, 0x3e, 0x00, 0xca, 0xff, 0x46, 0x00, 0xc7, 0xff, 0x4d, 0x00, 0xc7, 0xff, 0x51, 0x00, 0xcd, 0xff, 0x53, 0x00, 0xd6, 0xff, 0x53, 0x00, 0xdf, 0xff, 0x55, 0x00, 0xe7, 0xff, 0x58, 0x00, 0xec, 0xff, 0x5e, 0x00, 0xed, 0xff, 0x65, 0x00, 0xec, 0xff, 0x6b, 0x00, 0xeb, 0xff, 0x6d, 0x00, 0xec, 0xff, 0x6d, 0x00, 0xf0, 0xff, 0x6a, 0x00, 0xf6, 0xff, 0x65, 0x00, 0xfe, 0xff, 0x61, 0x00, 0x05, 0x00, 0x5e, 0x00, 0x0a, 0x00, 0x5d, 0x00, 0x0b, 0x00, 0x5b, 0x00, 0x08, 0x00, 0x58, 0x00, 0x04, 0x00, 0x50, 0x00, 0xff, 0xff, 0x46, 0x00, 0xfe, 0xff, 0x39, 0x00, 0xff, 0xff, 0x2b, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x15, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xf2, 0xff, 0xd6, 0xff, 0xee, 0xff, 0xc6, 0xff, 0xee, 0xff, 0xba, 0xff, 0xf1, 0xff, 0xb2, 0xff, 0xf8, 0xff, 0xae, 0xff, 0xff, 0xff, 0xac, 0xff, 0x05, 0x00, 0xab, 0xff, 0x08, 0x00, 0xa9, 0xff, 0x09, 0x00, 0xa5, 0xff, 0x09, 0x00, 0xa1, 0xff, 0x0b, 0x00, 0x9c, 0xff, 0x0d, 0x00, 0x97, 0xff, 0x10, 0x00, 0x94, 0xff, 0x15, 0x00, 0x95, 0xff, 0x1b, 0x00, 0x99, 0xff, 0x21, 0x00, 0x9f, 0xff, 0x25, 0x00, 0xa4, 0xff, 0x26, 0x00, 0xa8, 0xff, 0x24, 0x00, 0xa8, 0xff, 0x1f, 0x00, 0xa6, 0xff, 0x1a, 0x00, 0xa3, 0xff, 0x15, 0x00, 0xa2, 0xff, 0x10, 0x00, 0xa3, 0xff, 0x0c, 0x00, 0xa8, 0xff, 0x08, 0x00, 0xaf, 0xff, 0x04, 0x00, 0xb6, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xf8, 0xff, 0xc0, 0xff, 0xf1, 0xff, 0xc4, 0xff, 0xea, 0xff, 0xc8, 0xff, 0xe4, 0xff, 0xcd, 0xff, 0xe1, 0xff, 0xd4, 0xff, 0xe0, 0xff, 0xde, 0xff, 0xdf, 0xff, 0xea, 0xff, 0xde, 0xff, 0xf8, 0xff, 0xdc, 0xff, 0x07, 0x00, 0xda, 0xff, 0x14, 0x00, 0xd8, 0xff, 0x20, 0x00, 0xd8, 0xff, 0x29, 0x00, 0xdb, 0xff, 0x30, 0x00, 0xdf, 0xff, 0x38, 0x00, 0xe3, 0xff, 0x41, 0x00, 0xe6, 0xff, 0x4b, 0x00, 0xe9, 0xff, 0x55, 0x00, 0xea, 0xff, 0x5e, 0x00, 0xeb, 0xff, 0x67, 0x00, 0xeb, 0xff, 0x6e, 0x00, 0xed, 0xff, 0x74, 0x00, 0xf2, 0xff, 0x76, 0x00, 0xf8, 0xff, 0x75, 0x00, 0xff, 0xff, 0x72, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, 0x00, 0x6f, 0x00, 0x08, 0x00, 0x71, 0x00, 0x08, 0x00, 0x73, 0x00, 0x08, 0x00, 0x73, 0x00, 0x08, 0x00, 0x72, 0x00, 0x0a, 0x00, 0x6e, 0x00, 0x0d, 0x00, 0x68, 0x00, 0x10, 0x00, 0x61, 0x00, 0x15, 0x00, 0x5b, 0x00, 0x18, 0x00, 0x55, 0x00, 0x19, 0x00, 0x50, 0x00, 0x18, 0x00, 0x4c, 0x00, 0x15, 0x00, 0x4a, 0x00, 0x12, 0x00, 0x45, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0x0f, 0x00, 0x35, 0x00, 0x13, 0x00, 0x2a, 0x00, 0x19, 0x00, 0x20, 0x00, 0x20, 0x00, 0x18, 0x00, 0x25, 0x00, 0x13, 0x00, 0x26, 0x00, 0x0e, 0x00, 0x24, 0x00, 0x0a, 0x00, 0x20, 0x00, 0x05, 0x00, 0x1b, 0x00, 0xfe, 0xff, 0x17, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xed, 0xff, 0x16, 0x00, 0xe5, 0xff, 0x18, 0x00, 0xde, 0xff, 0x19, 0x00, 0xd9, 0xff, 0x17, 0x00, 0xd5, 0xff, 0x12, 0x00, 0xcf, 0xff, 0x09, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xf8, 0xff, 0xb7, 0xff, 0xf3, 0xff, 0xb0, 0xff, 0xf2, 0xff, 0xa9, 0xff, 0xf2, 0xff, 0xa4, 0xff, 0xf2, 0xff, 0xa1, 0xff, 0xf2, 0xff, 0x9e, 0xff, 0xf0, 0xff, 0x9b, 0xff, 0xee, 0xff, 0x98, 0xff, 0xeb, 0xff, 0x97, 0xff, 0xe8, 0xff, 0x97, 0xff, 0xe6, 0xff, 0x99, 0xff, 0xe5, 0xff, 0x9c, 0xff, 0xe8, 0xff, 0xa0, 0xff, 0xeb, 0xff, 0xa3, 0xff, 0xed, 0xff, 0xa7, 0xff, 0xee, 0xff, 0xac, 0xff, 0xec, 0xff, 0xb4, 0xff, 0xea, 0xff, 0xbd, 0xff, 0xe9, 0xff, 0xc7, 0xff, 0xe8, 0xff, 0xd0, 0xff, 0xe6, 0xff, 0xd9, 0xff, 0xe4, 0xff, 0xe0, 0xff, 0xe1, 0xff, 0xe6, 0xff, 0xe0, 0xff, 0xec, 0xff, 0xdf, 0xff, 0xf3, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xdc, 0xff, 0x04, 0x00, 0xdb, 0xff, 0x0e, 0x00, 0xda, 0xff, 0x19, 0x00, 0xda, 0xff, 0x23, 0x00, 0xdc, 0xff, 0x2a, 0x00, 0xdd, 0xff, 0x30, 0x00, 0xdd, 0xff, 0x34, 0x00, 0xdc, 0xff, 0x39, 0x00, 0xdb, 0xff, 0x41, 0x00, 0xdb, 0xff, 0x4a, 0x00, 0xdd, 0xff, 0x55, 0x00, 0xe1, 0xff, 0x60, 0x00, 0xe6, 0xff, 0x69, 0x00, 0xeb, 0xff, 0x6e, 0x00, 0xee, 0xff, 0x71, 0x00, 0xf2, 0xff, 0x73, 0x00, 0xf4, 0xff, 0x76, 0x00, 0xf6, 0xff, 0x7a, 0x00, 0xf9, 0xff, 0x7e, 0x00, 0xfc, 0xff, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x84, 0x00, 0x0c, 0x00, 0x82, 0x00, 0x14, 0x00, 0x7e, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x24, 0x00, 0x71, 0x00, 0x2b, 0x00, 0x6a, 0x00, 0x32, 0x00, 0x64, 0x00, 0x39, 0x00, 0x5e, 0x00, 0x40, 0x00, 0x56, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x4d, 0x00, 0x22, 0x00, 0x4f, 0x00, 0x15, 0x00, 0x52, 0x00, 0x09, 0x00, 0x56, 0x00, 0x00, 0x00, 0x5a, 0x00, 0xf7, 0xff, 0x5c, 0x00, 0xef, 0xff, 0x5e, 0x00, 0xe4, 0xff, 0x60, 0x00, 0xd7, 0xff, 0x60, 0x00, 0xc8, 0xff, 0x60, 0x00, 0xba, 0xff, 0x5f, 0x00, 0xad, 0xff, 0x5e, 0x00, 0xa4, 0xff, 0x5d, 0x00, 0x9f, 0xff, 0x5a, 0x00, 0x9c, 0xff, 0x56, 0x00, 0x9a, 0xff, 0x52, 0x00, 0x96, 0xff, 0x4d, 0x00, 0x90, 0xff, 0x48, 0x00, 0x88, 0xff, 0x42, 0x00, 0x7e, 0xff, 0x3c, 0x00, 0x75, 0xff, 0x35, 0x00, 0x71, 0xff, 0x2d, 0x00, 0x71, 0xff, 0x25, 0x00, 0x74, 0xff, 0x1b, 0x00, 0x7a, 0xff, 0x11, 0x00, 0x7e, 0xff, 0x07, 0x00, 0x81, 0xff, 0xfe, 0xff, 0x82, 0xff, 0xf7, 0xff, 0x81, 0xff, 0xf3, 0xff, 0x81, 0xff, 0xf1, 0xff, 0x83, 0xff, 0xef, 0xff, 0x87, 0xff, 0xec, 0xff, 0x8f, 0xff, 0xe8, 0xff, 0x99, 0xff, 0xe4, 0xff, 0xa2, 0xff, 0xdf, 0xff, 0xa9, 0xff, 0xdb, 0xff, 0xaf, 0xff, 0xd9, 0xff, 0xb4, 0xff, 0xda, 0xff, 0xbb, 0xff, 0xdd, 0xff, 0xc4, 0xff, 0xe1, 0xff, 0xce, 0xff, 0xe4, 0xff, 0xd9, 0xff, 0xe5, 0xff, 0xe3, 0xff, 0xe4, 0xff, 0xec, 0xff, 0xe3, 0xff, 0xf3, 0xff, 0xe3, 0xff, 0xfb, 0xff, 0xe4, 0xff, 0x04, 0x00, 0xe8, 0xff, 0x0e, 0x00, 0xec, 0xff, 0x19, 0x00, 0xef, 0xff, 0x24, 0x00, 0xf0, 0xff, 0x2d, 0x00, 0xf1, 0xff, 0x34, 0x00, 0xf2, 0xff, 0x38, 0x00, 0xf5, 0xff, 0x3c, 0x00, 0xf9, 0xff, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x07, 0x00, 0x49, 0x00, 0x0e, 0x00, 0x4e, 0x00, 0x13, 0x00, 0x4f, 0x00, 0x15, 0x00, 0x4d, 0x00, 0x13, 0x00, 0x48, 0x00, 0x10, 0x00, 0x42, 0x00, 0x0d, 0x00, 0x3d, 0x00, 0x0b, 0x00, 0x3c, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x0a, 0x00, 0x3d, 0x00, 0x09, 0x00, 0x3c, 0x00, 0x08, 0x00, 0x38, 0x00, 0x05, 0x00, 0x34, 0x00, 0x01, 0x00, 0x2f, 0x00, 0xff, 0xff, 0x2d, 0x00, 0xfe, 0xff, 0x2d, 0x00, 0xff, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0xfe, 0xff, 0x2b, 0x00, 0xfb, 0xff, 0x26, 0x00, 0xf9, 0xff, 0x1f, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xfb, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x10, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfc, 0xff, 0xf8, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xe3, 0xff, 0xec, 0xff, 0xda, 0xff, 0xe7, 0xff, 0xd1, 0xff, 0xe2, 0xff, 0xca, 0xff, 0xdd, 0xff, 0xc5, 0xff, 0xd7, 0xff, 0xc0, 0xff, 0xd1, 0xff, 0xba, 0xff, 0xcb, 0xff, 0xb5, 0xff, 0xc7, 0xff, 0xaf, 0xff, 0xc3, 0xff, 0xab, 0xff, 0xc1, 0xff, 0xa6, 0xff, 0xbc, 0xff, 0xa2, 0xff, 0xb6, 0xff, 0x9e, 0xff, 0xaf, 0xff, 0x9a, 0xff, 0xa8, 0xff, 0x97, 0xff, 0xa2, 0xff, 0x96, 0xff, 0x9e, 0xff, 0x97, 0xff, 0x9b, 0xff, 0x9a, 0xff, 0x98, 0xff, 0x9d, 0xff, 0x95, 0xff, 0xa1, 0xff, 0x91, 0xff, 0xa5, 0xff, 0x8e, 0xff, 0xa9, 0xff, 0x8c, 0xff, 0xae, 0xff, 0x8c, 0xff, 0xb6, 0xff, 0x8e, 0xff, 0xc2, 0xff, 0x90, 0xff, 0xd0, 0xff, 0x93, 0xff, 0xe0, 0xff, 0x94, 0xff, 0xef, 0xff, 0x96, 0xff, 0xfc, 0xff, 0x98, 0xff, 0x07, 0x00, 0x9e, 0xff, 0x11, 0x00, 0xa6, 0xff, 0x1a, 0x00, 0xb1, 0xff, 0x25, 0x00, 0xbd, 0xff, 0x31, 0x00, 0xc9, 0xff, 0x3e, 0x00, 0xd4, 0xff, 0x49, 0x00, 0xdd, 0xff, 0x53, 0x00, 0xe3, 0xff, 0x5c, 0x00, 0xe7, 0xff, 0x62, 0x00, 0xec, 0xff, 0x67, 0x00, 0xf1, 0xff, 0x6b, 0x00, 0xf9, 0xff, 0x6f, 0x00, 0x00, 0x00, 0x72, 0x00, 0x07, 0x00, 0x75, 0x00, 0x0c, 0x00, 0x77, 0x00, 0x0f, 0x00, 0x78, 0x00, 0x11, 0x00, 0x79, 0x00, 0x13, 0x00, 0x7a, 0x00, 0x16, 0x00, 0x7b, 0x00, 0x1a, 0x00, 0x7b, 0x00, 0x1f, 0x00, 0x78, 0x00, 0x26, 0x00, 0x75, 0x00, 0x2e, 0x00, 0x71, 0x00, 0x35, 0x00, 0x6f, 0x00, 0x3a, 0x00, 0x6e, 0x00, 0x3f, 0x00, 0x6d, 0x00, 0x42, 0x00, 0x6b, 0x00, 0x43, 0x00, 0x67, 0x00, 0x45, 0x00, 0x61, 0x00, 0x46, 0x00, 0x59, 0x00, 0x49, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x51, 0x00, 0x3c, 0x00, 0x55, 0x00, 0x34, 0x00, 0x57, 0x00, 0x2f, 0x00, 0x56, 0x00, 0x2a, 0x00, 0x52, 0x00, 0x25, 0x00, 0x4a, 0x00, 0x1f, 0x00, 0x41, 0x00, 0x17, 0x00, 0x3a, 0x00, 0x0e, 0x00, 0x37, 0x00, 0x04, 0x00, 0x37, 0x00, 0xfb, 0xff, 0x38, 0x00, 0xf3, 0xff, 0x39, 0x00, 0xec, 0xff, 0x37, 0x00, 0xe6, 0xff, 0x33, 0x00, 0xe2, 0xff, 0x2b, 0x00, 0xde, 0xff, 0x23, 0x00, 0xd9, 0xff, 0x1a, 0x00, 0xd4, 0xff, 0x14, 0x00, 0xcd, 0xff, 0x10, 0x00, 0xc4, 0xff, 0x0d, 0x00, 0xba, 0xff, 0x0b, 0x00, 0xb1, 0xff, 0x06, 0x00, 0xa9, 0xff, 0x01, 0x00, 0xa3, 0xff, 0xf9, 0xff, 0xa0, 0xff, 0xf2, 0xff, 0x9f, 0xff, 0xea, 0xff, 0x9e, 0xff, 0xe4, 0xff, 0x9d, 0xff, 0xdf, 0xff, 0x9a, 0xff, 0xda, 0xff, 0x96, 0xff, 0xd7, 0xff, 0x92, 0xff, 0xd3, 0xff, 0x8f, 0xff, 0xd1, 0xff, 0x8f, 0xff, 0xcf, 0xff, 0x92, 0xff, 0xcd, 0xff, 0x98, 0xff, 0xcc, 0xff, 0xa0, 0xff, 0xcb, 0xff, 0xa9, 0xff, 0xcb, 0xff, 0xb0, 0xff, 0xcb, 0xff, 0xb6, 0xff, 0xce, 0xff, 0xbb, 0xff, 0xd2, 0xff, 0xbf, 0xff, 0xd8, 0xff, 0xc4, 0xff, 0xdf, 0xff, 0xcb, 0xff, 0xe4, 0xff, 0xd4, 0xff, 0xe8, 0xff, 0xe0, 0xff, 0xea, 0xff, 0xec, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xef, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x3a, 0x00, 0x22, 0x00, 0x41, 0x00, 0x26, 0x00, 0x47, 0x00, 0x2b, 0x00, 0x4a, 0x00, 0x31, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x4e, 0x00, 0x3a, 0x00, 0x50, 0x00, 0x3e, 0x00, 0x51, 0x00, 0x40, 0x00, 0x52, 0x00, 0x44, 0x00, 0x51, 0x00, 0x48, 0x00, 0x4f, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x49, 0x00, 0x56, 0x00, 0x48, 0x00, 0x59, 0x00, 0x47, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x5c, 0x00, 0x49, 0x00, 0x5b, 0x00, 0x4a, 0x00, 0x5a, 0x00, 0x4a, 0x00, 0x59, 0x00, 0x47, 0x00, 0x5a, 0x00, 0x44, 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x3b, 0x00, 0x5a, 0x00, 0x37, 0x00, 0x58, 0x00, 0x33, 0x00, 0x54, 0x00, 0x2e, 0x00, 0x4d, 0x00, 0x29, 0x00, 0x46, 0x00, 0x22, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x37, 0x00, 0x16, 0x00, 0x32, 0x00, 0x10, 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2b, 0x00, 0xf5, 0xff, 0x26, 0x00, 0xe8, 0xff, 0x1d, 0x00, 0xdd, 0xff, 0x11, 0x00, 0xd5, 0xff, 0x04, 0x00, 0xcf, 0xff, 0xf7, 0xff, 0xcc, 0xff, 0xee, 0xff, 0xca, 0xff, 0xe8, 0xff, 0xc7, 0xff, 0xe5, 0xff, 0xc2, 0xff, 0xe3, 0xff, 0xbc, 0xff, 0xe0, 0xff, 0xb5, 0xff, 0xd9, 0xff, 0xb0, 0xff, 0xcf, 0xff, 0xab, 0xff, 0xc2, 0xff, 0xaa, 0xff, 0xb6, 0xff, 0xa9, 0xff, 0xad, 0xff, 0xa8, 0xff, 0xa7, 0xff, 0xa6, 0xff, 0xa4, 0xff, 0xa4, 0xff, 0xa2, 0xff, 0xa1, 0xff, 0xa0, 0xff, 0x9e, 0xff, 0x9c, 0xff, 0x9d, 0xff, 0x97, 0xff, 0x9e, 0xff, 0x90, 0xff, 0xa1, 0xff, 0x8b, 0xff, 0xa4, 0xff, 0x88, 0xff, 0xa7, 0xff, 0x87, 0xff, 0xab, 0xff, 0x89, 0xff, 0xb1, 0xff, 0x8b, 0xff, 0xb8, 0xff, 0x8e, 0xff, 0xc2, 0xff, 0x92, 0xff, 0xcc, 0xff, 0x95, 0xff, 0xd5, 0xff, 0x98, 0xff, 0xdd, 0xff, 0x9a, 0xff, 0xe2, 0xff, 0x9c, 0xff, 0xe5, 0xff, 0x9e, 0xff, 0xe9, 0xff, 0xa3, 0xff, 0xee, 0xff, 0xaa, 0xff, 0xf4, 0xff, 0xb3, 0xff, 0xfc, 0xff, 0xbd, 0xff, 0x03, 0x00, 0xc9, 0xff, 0x08, 0x00, 0xd5, 0xff, 0x0b, 0x00, 0xde, 0xff, 0x0d, 0x00, 0xe6, 0xff, 0x0e, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x11, 0x00, 0x05, 0x00, 0x13, 0x00, 0x11, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x35, 0x00, 0x24, 0x00, 0x3c, 0x00, 0x29, 0x00, 0x40, 0x00, 0x2d, 0x00, 0x43, 0x00, 0x30, 0x00, 0x45, 0x00, 0x30, 0x00, 0x48, 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x2d, 0x00, 0x50, 0x00, 0x2d, 0x00, 0x54, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x2f, 0x00, 0x5a, 0x00, 0x30, 0x00, 0x5a, 0x00, 0x30, 0x00, 0x57, 0x00, 0x2e, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x53, 0x00, 0x27, 0x00, 0x53, 0x00, 0x23, 0x00, 0x52, 0x00, 0x21, 0x00, 0x50, 0x00, 0x1e, 0x00, 0x4d, 0x00, 0x1b, 0x00, 0x4b, 0x00, 0x17, 0x00, 0x4a, 0x00, 0x11, 0x00, 0x48, 0x00, 0x0c, 0x00, 0x45, 0x00, 0x07, 0x00, 0x3f, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0xff, 0xff, 0x29, 0x00, 0x00, 0x00, 0x24, 0x00, 0xff, 0xff, 0x21, 0x00, 0xfb, 0xff, 0x20, 0x00, 0xf4, 0xff, 0x1c, 0x00, 0xec, 0xff, 0x17, 0x00, 0xe6, 0xff, 0x0e, 0x00, 0xe3, 0xff, 0x03, 0x00, 0xe3, 0xff, 0xf7, 0xff, 0xe5, 0xff, 0xed, 0xff, 0xe8, 0xff, 0xe6, 0xff, 0xe8, 0xff, 0xe3, 0xff, 0xe6, 0xff, 0xe2, 0xff, 0xe2, 0xff, 0xe1, 0xff, 0xdc, 0xff, 0xdf, 0xff, 0xd8, 0xff, 0xda, 0xff, 0xd8, 0xff, 0xd5, 0xff, 0xda, 0xff, 0xd0, 0xff, 0xe0, 0xff, 0xcc, 0xff, 0xe6, 0xff, 0xc9, 0xff, 0xeb, 0xff, 0xc8, 0xff, 0xed, 0xff, 0xc7, 0xff, 0xec, 0xff, 0xc7, 0xff, 0xe8, 0xff, 0xc8, 0xff, 0xe6, 0xff, 0xc8, 0xff, 0xe6, 0xff, 0xc9, 0xff, 0xe9, 0xff, 0xcb, 0xff, 0xf1, 0xff, 0xce, 0xff, 0xf9, 0xff, 0xd2, 0xff, 0x01, 0x00, 0xd6, 0xff, 0x06, 0x00, 0xda, 0xff, 0x09, 0x00, 0xdc, 0xff, 0x09, 0x00, 0xe0, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x06, 0x00, 0xee, 0xff, 0x07, 0x00, 0xf6, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x11, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x05, 0x00, 0x24, 0x00, 0x09, 0x00, 0x2d, 0x00, 0x0e, 0x00, 0x32, 0x00, 0x15, 0x00, 0x34, 0x00, 0x1d, 0x00, 0x33, 0x00, 0x26, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x34, 0x00, 0x37, 0x00, 0x38, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x51, 0x00, 0x43, 0x00, 0x52, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x48, 0x00, 0x4a, 0x00, 0x48, 0x00, 0x46, 0x00, 0x47, 0x00, 0x44, 0x00, 0x46, 0x00, 0x45, 0x00, 0x47, 0x00, 0x49, 0x00, 0x48, 0x00, 0x4d, 0x00, 0x49, 0x00, 0x4f, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x48, 0x00, 0x40, 0x00, 0x40, 0x00, 0x3b, 0x00, 0x38, 0x00, 0x36, 0x00, 0x32, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x35, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x27, 0x00, 0x2d, 0x00, 0x23, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x1e, 0x00, 0x11, 0x00, 0x18, 0x00, 0x05, 0x00, 0x11, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xea, 0xff, 0xfe, 0xff, 0xe7, 0xff, 0xf6, 0xff, 0xe5, 0xff, 0xef, 0xff, 0xe5, 0xff, 0xe7, 0xff, 0xe3, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xd9, 0xff, 0xda, 0xff, 0xd2, 0xff, 0xd2, 0xff, 0xcb, 0xff, 0xca, 0xff, 0xc3, 0xff, 0xc4, 0xff, 0xba, 0xff, 0xc0, 0xff, 0xb2, 0xff, 0xc0, 0xff, 0xac, 0xff, 0xc2, 0xff, 0xa7, 0xff, 0xc4, 0xff, 0xa4, 0xff, 0xc5, 0xff, 0xa1, 0xff, 0xc5, 0xff, 0x9d, 0xff, 0xc2, 0xff, 0x99, 0xff, 0xbf, 0xff, 0x94, 0xff, 0xbd, 0xff, 0x8f, 0xff, 0xbc, 0xff, 0x8c, 0xff, 0xbd, 0xff, 0x8c, 0xff, 0xbf, 0xff, 0x8e, 0xff, 0xc3, 0xff, 0x93, 0xff, 0xc7, 0xff, 0x97, 0xff, 0xcc, 0xff, 0x9b, 0xff, 0xd2, 0xff, 0x9e, 0xff, 0xd8, 0xff, 0xa0, 0xff, 0xde, 0xff, 0xa3, 0xff, 0xe6, 0xff, 0xa7, 0xff, 0xee, 0xff, 0xad, 0xff, 0xf5, 0xff, 0xb5, 0xff, 0xfa, 0xff, 0xbe, 0xff, 0xff, 0xff, 0xc8, 0xff, 0x05, 0x00, 0xd2, 0xff, 0x0b, 0x00, 0xdb, 0xff, 0x13, 0x00, 0xe4, 0xff, 0x1c, 0x00, 0xeb, 0xff, 0x24, 0x00, 0xf0, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x30, 0x00, 0xf9, 0xff, 0x32, 0x00, 0xfd, 0xff, 0x33, 0x00, 0x01, 0x00, 0x33, 0x00, 0x06, 0x00, 0x33, 0x00, 0x0b, 0x00, 0x34, 0x00, 0x10, 0x00, 0x36, 0x00, 0x15, 0x00, 0x37, 0x00, 0x19, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x19, 0x00, 0x3c, 0x00, 0x18, 0x00, 0x3c, 0x00, 0x18, 0x00, 0x3b, 0x00, 0x18, 0x00, 0x3a, 0x00, 0x19, 0x00, 0x37, 0x00, 0x1a, 0x00, 0x35, 0x00, 0x1a, 0x00, 0x32, 0x00, 0x18, 0x00, 0x30, 0x00, 0x16, 0x00, 0x2f, 0x00, 0x12, 0x00, 0x2f, 0x00, 0x0e, 0x00, 0x2f, 0x00, 0x0a, 0x00, 0x2f, 0x00, 0x08, 0x00, 0x2d, 0x00, 0x06, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x25, 0x00, 0x01, 0x00, 0x1f, 0x00, 0xfe, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x15, 0x00, 0xfb, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x0c, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xf8, 0xff, 0xe1, 0xff, 0xf6, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xcf, 0xff, 0xec, 0xff, 0xc4, 0xff, 0xe7, 0xff, 0xbc, 0xff, 0xe3, 0xff, 0xb8, 0xff, 0xe1, 0xff, 0xb9, 0xff, 0xe1, 0xff, 0xbb, 0xff, 0xe0, 0xff, 0xbd, 0xff, 0xde, 0xff, 0xbb, 0xff, 0xda, 0xff, 0xb7, 0xff, 0xd4, 0xff, 0xb2, 0xff, 0xcf, 0xff, 0xaf, 0xff, 0xcc, 0xff, 0xae, 0xff, 0xcb, 0xff, 0xb2, 0xff, 0xcd, 0xff, 0xb9, 0xff, 0xd1, 0xff, 0xc1, 0xff, 0xd7, 0xff, 0xc7, 0xff, 0xdc, 0xff, 0xcb, 0xff, 0xe1, 0xff, 0xcd, 0xff, 0xe4, 0xff, 0xcf, 0xff, 0xe6, 0xff, 0xd0, 0xff, 0xe9, 0xff, 0xd4, 0xff, 0xed, 0xff, 0xda, 0xff, 0xf4, 0xff, 0xe0, 0xff, 0xfd, 0xff, 0xe7, 0xff, 0x08, 0x00, 0xec, 0xff, 0x12, 0x00, 0xef, 0xff, 0x1c, 0x00, 0xf0, 0xff, 0x23, 0x00, 0xf1, 0xff, 0x28, 0x00, 0xf2, 0xff, 0x2c, 0x00, 0xf4, 0xff, 0x2f, 0x00, 0xf6, 0xff, 0x32, 0x00, 0xf9, 0xff, 0x35, 0x00, 0xfd, 0xff, 0x3a, 0x00, 0x01, 0x00, 0x40, 0x00, 0x06, 0x00, 0x45, 0x00, 0x0c, 0x00, 0x49, 0x00, 0x10, 0x00, 0x4a, 0x00, 0x14, 0x00, 0x49, 0x00, 0x15, 0x00, 0x47, 0x00, 0x15, 0x00, 0x46, 0x00, 0x16, 0x00, 0x46, 0x00, 0x18, 0x00, 0x49, 0x00, 0x1d, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x4f, 0x00, 0x2d, 0x00, 0x51, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x3b, 0x00, 0x4c, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x40, 0x00, 0x48, 0x00, 0x40, 0x00, 0x49, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x42, 0x00, 0x51, 0x00, 0x46, 0x00, 0x55, 0x00, 0x48, 0x00, 0x58, 0x00, 0x48, 0x00, 0x57, 0x00, 0x45, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x46, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x28, 0x00, 0x3b, 0x00, 0x22, 0x00, 0x38, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x15, 0x00, 0x30, 0x00, 0x0b, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x26, 0x00, 0xf3, 0xff, 0x20, 0x00, 0xe6, 0xff, 0x18, 0x00, 0xd9, 0xff, 0x10, 0x00, 0xce, 0xff, 0x0a, 0x00, 0xc6, 0xff, 0x06, 0x00, 0xbf, 0xff, 0x04, 0x00, 0xb9, 0xff, 0x01, 0x00, 0xb4, 0xff, 0xfe, 0xff, 0xae, 0xff, 0xf9, 0xff, 0xa8, 0xff, 0xf3, 0xff, 0xa3, 0xff, 0xec, 0xff, 0x9e, 0xff, 0xe4, 0xff, 0x9b, 0xff, 0xdd, 0xff, 0x99, 0xff, 0xd7, 0xff, 0x97, 0xff, 0xd2, 0xff, 0x96, 0xff, 0xcf, 0xff, 0x95, 0xff, 0xcf, 0xff, 0x96, 0xff, 0xcf, 0xff, 0x97, 0xff, 0xcf, 0xff, 0x99, 0xff, 0xcd, 0xff, 0x9a, 0xff, 0xc9, 0xff, 0x9b, 0xff, 0xc5, 0xff, 0x9b, 0xff, 0xc2, 0xff, 0x9b, 0xff, 0xc1, 0xff, 0x9c, 0xff, 0xc1, 0xff, 0x9f, 0xff, 0xc5, 0xff, 0xa2, 0xff, 0xcc, 0xff, 0xa7, 0xff, 0xd2, 0xff, 0xaa, 0xff, 0xd6, 0xff, 0xac, 0xff, 0xd8, 0xff, 0xad, 0xff, 0xd7, 0xff, 0xaf, 0xff, 0xd6, 0xff, 0xb2, 0xff, 0xd6, 0xff, 0xb7, 0xff, 0xd8, 0xff, 0xbe, 0xff, 0xdb, 0xff, 0xc5, 0xff, 0xdf, 0xff, 0xcd, 0xff, 0xe3, 0xff, 0xd3, 0xff, 0xe6, 0xff, 0xd8, 0xff, 0xe8, 0xff, 0xdc, 0xff, 0xe8, 0xff, 0xe1, 0xff, 0xe9, 0xff, 0xe6, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x0a, 0x00, 0x04, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x0c, 0x00, 0x23, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x2a, 0x00, 0x0b, 0x00, 0x2b, 0x00, 0x0b, 0x00, 0x2c, 0x00, 0x0e, 0x00, 0x2e, 0x00, 0x12, 0x00, 0x33, 0x00, 0x17, 0x00, 0x39, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x20, 0x00, 0x43, 0x00, 0x20, 0x00, 0x43, 0x00, 0x1c, 0x00, 0x3f, 0x00, 0x16, 0x00, 0x39, 0x00, 0x10, 0x00, 0x33, 0x00, 0x0d, 0x00, 0x2d, 0x00, 0x0e, 0x00, 0x2b, 0x00, 0x12, 0x00, 0x2a, 0x00, 0x17, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x16, 0x00, 0x14, 0x00, 0x14, 0x00, 0x11, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x10, 0x00, 0x16, 0x00, 0x13, 0x00, 0x15, 0x00, 0x15, 0x00, 0x12, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x03, 0x00, 0x0f, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xef, 0xff, 0x01, 0x00, 0xea, 0xff, 0x02, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xdd, 0xff, 0xff, 0xff, 0xd8, 0xff, 0xfc, 0xff, 0xd3, 0xff, 0xf9, 0xff, 0xd0, 0xff, 0xf7, 0xff, 0xce, 0xff, 0xf5, 0xff, 0xcb, 0xff, 0xf4, 0xff, 0xc9, 0xff, 0xf4, 0xff, 0xc8, 0xff, 0xf5, 0xff, 0xc7, 0xff, 0xf6, 0xff, 0xc8, 0xff, 0xf7, 0xff, 0xc9, 0xff, 0xf7, 0xff, 0xca, 0xff, 0xf5, 0xff, 0xcc, 0xff, 0xf4, 0xff, 0xcd, 0xff, 0xf4, 0xff, 0xce, 0xff, 0xf6, 0xff, 0xd1, 0xff, 0xfa, 0xff, 0xd5, 0xff, 0xfe, 0xff, 0xd9, 0xff, 0x04, 0x00, 0xde, 0xff, 0x08, 0x00, 0xe2, 0xff, 0x0b, 0x00, 0xe6, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xf0, 0xff, 0x0c, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x0e, 0x00, 0x07, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x11, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x26, 0x00, 0x13, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x31, 0x00, 0x17, 0x00, 0x33, 0x00, 0x20, 0x00, 0x34, 0x00, 0x2c, 0x00, 0x35, 0x00, 0x38, 0x00, 0x37, 0x00, 0x40, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x3f, 0x00, 0x43, 0x00, 0x43, 0x00, 0x40, 0x00, 0x47, 0x00, 0x3d, 0x00, 0x4b, 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x50, 0x00, 0x42, 0x00, 0x52, 0x00, 0x47, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x50, 0x00, 0x58, 0x00, 0x52, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x4e, 0x00, 0x59, 0x00, 0x4b, 0x00, 0x57, 0x00, 0x48, 0x00, 0x56, 0x00, 0x47, 0x00, 0x54, 0x00, 0x46, 0x00, 0x52, 0x00, 0x48, 0x00, 0x51, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x47, 0x00, 0x46, 0x00, 0x41, 0x00, 0x40, 0x00, 0x3b, 0x00, 0x38, 0x00, 0x37, 0x00, 0x30, 0x00, 0x34, 0x00, 0x29, 0x00, 0x33, 0x00, 0x24, 0x00, 0x32, 0x00, 0x20, 0x00, 0x30, 0x00, 0x1d, 0x00, 0x2c, 0x00, 0x18, 0x00, 0x25, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x02, 0x00, 0x10, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xed, 0xff, 0x09, 0x00, 0xe9, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x04, 0x00, 0xe5, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xf8, 0xff, 0xe5, 0xff, 0xf2, 0xff, 0xe4, 0xff, 0xed, 0xff, 0xe2, 0xff, 0xeb, 0xff, 0xe2, 0xff, 0xe9, 0xff, 0xe2, 0xff, 0xe8, 0xff, 0xe4, 0xff, 0xe4, 0xff, 0xe5, 0xff, 0xdf, 0xff, 0xe5, 0xff, 0xd8, 0xff, 0xe5, 0xff, 0xd0, 0xff, 0xe5, 0xff, 0xca, 0xff, 0xe5, 0xff, 0xc6, 0xff, 0xe5, 0xff, 0xc5, 0xff, 0xe4, 0xff, 0xc4, 0xff, 0xe2, 0xff, 0xc4, 0xff, 0xdf, 0xff, 0xc4, 0xff, 0xdd, 0xff, 0xc3, 0xff, 0xdd, 0xff, 0xc2, 0xff, 0xdf, 0xff, 0xc0, 0xff, 0xe1, 0xff, 0xbd, 0xff, 0xe3, 0xff, 0xbb, 0xff, 0xe4, 0xff, 0xbb, 0xff, 0xe2, 0xff, 0xbb, 0xff, 0xde, 0xff, 0xbe, 0xff, 0xda, 0xff, 0xc3, 0xff, 0xd8, 0xff, 0xc8, 0xff, 0xd8, 0xff, 0xcd, 0xff, 0xdb, 0xff, 0xd0, 0xff, 0xe0, 0xff, 0xd1, 0xff, 0xe5, 0xff, 0xd0, 0xff, 0xe8, 0xff, 0xce, 0xff, 0xe9, 0xff, 0xcf, 0xff, 0xe7, 0xff, 0xd2, 0xff, 0xe4, 0xff, 0xd8, 0xff, 0xe2, 0xff, 0xe0, 0xff, 0xe3, 0xff, 0xe7, 0xff, 0xe5, 0xff, 0xec, 0xff, 0xea, 0xff, 0xed, 0xff, 0xee, 0xff, 0xec, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xf3, 0xff, 0xe7, 0xff, 0xf4, 0xff, 0xea, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x13, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x07, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xf6, 0xff, 0x0b, 0x00, 0xef, 0xff, 0x0b, 0x00, 0xec, 0xff, 0x09, 0x00, 0xed, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf2, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xd7, 0xff, 0xf7, 0xff, 0xce, 0xff, 0xf8, 0xff, 0xca, 0xff, 0xf7, 0xff, 0xca, 0xff, 0xf5, 0xff, 0xcd, 0xff, 0xf0, 0xff, 0xd0, 0xff, 0xea, 0xff, 0xd0, 0xff, 0xe4, 0xff, 0xcb, 0xff, 0xe0, 0xff, 0xc2, 0xff, 0xde, 0xff, 0xb8, 0xff, 0xdf, 0xff, 0xb0, 0xff, 0xe2, 0xff, 0xae, 0xff, 0xe5, 0xff, 0xb1, 0xff, 0xe6, 0xff, 0xb8, 0xff, 0xe4, 0xff, 0xc1, 0xff, 0xdf, 0xff, 0xc8, 0xff, 0xd8, 0xff, 0xce, 0xff, 0xd2, 0xff, 0xd1, 0xff, 0xd0, 0xff, 0xd2, 0xff, 0xd3, 0xff, 0xd2, 0xff, 0xda, 0xff, 0xd3, 0xff, 0xe2, 0xff, 0xd7, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xe8, 0xff, 0xe8, 0xff, 0xe3, 0xff, 0xf1, 0xff, 0xdc, 0xff, 0xf8, 0xff, 0xd7, 0xff, 0xfc, 0xff, 0xd6, 0xff, 0xfd, 0xff, 0xdb, 0xff, 0xfd, 0xff, 0xe4, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0x01, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xec, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x0a, 0x00, 0xe6, 0xff, 0x09, 0x00, 0xe9, 0xff, 0x09, 0x00, 0xf2, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0x09, 0x00, 0x10, 0x00, 0x10, 0x00, 0x15, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x23, 0x00, 0x08, 0x00, 0x26, 0x00, 0x08, 0x00, 0x27, 0x00, 0x0c, 0x00, 0x27, 0x00, 0x15, 0x00, 0x28, 0x00, 0x20, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x30, 0x00, 0x33, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x24, 0x00, 0x36, 0x00, 0x1a, 0x00, 0x38, 0x00, 0x14, 0x00, 0x3a, 0x00, 0x14, 0x00, 0x3c, 0x00, 0x18, 0x00, 0x3c, 0x00, 0x1d, 0x00, 0x39, 0x00, 0x22, 0x00, 0x35, 0x00, 0x22, 0x00, 0x30, 0x00, 0x1d, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x29, 0x00, 0x09, 0x00, 0x27, 0x00, 0x02, 0x00, 0x25, 0x00, 0x01, 0x00, 0x21, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x07, 0x00, 0x18, 0x00, 0x06, 0x00, 0x13, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x09, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x01, 0x00, 0x0b, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x0e, 0x00, 0xf6, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x02, 0x00, 0x07, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xf6, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x0e, 0x00, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0xff, 0x02, 0x00, 0xf0, 0xff, 0xfe, 0xff, 0xef, 0xff, 0xfe, 0xff, 0xed, 0xff, 0x02, 0x00, 0xea, 0xff, 0x06, 0x00, 0xe8, 0xff, 0x0a, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xe8, 0xff, 0x08, 0x00, 0xe8, 0xff, 0x03, 0x00, 0xe8, 0xff, 0xfe, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xee, 0xff, 0xf5, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xf0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xee, 0xff, 0x07, 0x00, 0xec, 0xff, 0x0c, 0x00, 0xe9, 0xff, 0x11, 0x00, 0xe7, 0xff, 0x16, 0x00, 0xe7, 0xff, 0x1a, 0x00, 0xe9, 0xff, 0x1c, 0x00, 0xee, 0xff, 0x1d, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0xf6, 0xff, 0x1f, 0x00, 0xf7, 0xff, 0x22, 0x00, 0xf7, 0xff, 0x27, 0x00, 0xf4, 0xff, 0x2b, 0x00, 0xf3, 0xff, 0x2d, 0x00, 0xf2, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x27, 0x00, 0xf9, 0xff, 0x21, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17, 0x00, 0xfc, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x1b, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xed, 0xff, 0x19, 0x00, 0xec, 0xff, 0x14, 0x00, 0xed, 0xff, 0x0d, 0x00, 0xef, 0xff, 0x08, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xec, 0xff, 0x0f, 0x00, 0xe9, 0xff, 0x15, 0x00, 0xe6, 0xff, 0x19, 0x00, 0xe5, 0xff, 0x1b, 0x00, 0xe6, 0xff, 0x1a, 0x00, 0xe9, 0xff, 0x18, 0x00, 0xec, 0xff, 0x14, 0x00, 0xee, 0xff, 0x10, 0x00, 0xef, 0xff, 0x0f, 0x00, 0xed, 0xff, 0x11, 0x00, 0xea, 0xff, 0x15, 0x00, 0xe8, 0xff, 0x1a, 0x00, 0xe6, 0xff, 0x1e, 0x00, 0xe5, 0xff, 0x1d, 0x00, 0xe4, 0xff, 0x19, 0x00, 0xe5, 0xff, 0x11, 0x00, 0xe5, 0xff, 0x08, 0x00, 0xe5, 0xff, 0xff, 0xff, 0xe4, 0xff, 0xf9, 0xff, 0xe3, 0xff, 0xf6, 0xff, 0xe2, 0xff, 0xf5, 0xff, 0xe1, 0xff, 0xf6, 0xff, 0xdf, 0xff, 0xf5, 0xff, 0xde, 0xff, 0xf2, 0xff, 0xde, 0xff, 0xec, 0xff, 0xe0, 0xff, 0xe4, 0xff, 0xe3, 0xff, 0xdc, 0xff, 0xe7, 0xff, 0xd7, 0xff, 0xea, 0xff, 0xd6, 0xff, 0xed, 0xff, 0xd9, 0xff, 0xee, 0xff, 0xdf, 0xff, 0xed, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xea, 0xff, 0xef, 0xff, 0xea, 0xff, 0xef, 0xff, 0xec, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf6, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x10, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x06, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x11, 0x00, 0x09, 0x00, 0x16, 0x00, 0x08, 0x00, 0x19, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfc, 0xff, 0x1e, 0x00, 0xf9, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x27, 0x00, 0xf9, 0xff, 0x2c, 0x00, 0xfb, 0xff, 0x31, 0x00, 0xfd, 0xff, 0x36, 0x00, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x04, 0x00, 0x48, 0x00, 0x08, 0x00, 0x46, 0x00, 0x0c, 0x00, 0x45, 0x00, 0x0f, 0x00, 0x45, 0x00, 0x10, 0x00, 0x44, 0x00, 0x0f, 0x00, 0x41, 0x00, 0x0c, 0x00, 0x3b, 0x00, 0x08, 0x00, 0x33, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xf4, 0xff, 0x13, 0x00, 0xf4, 0xff, 0x15, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf5, 0xff, 0x1a, 0x00, 0xf6, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x09, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xee, 0xff, 0x05, 0x00, 0xe8, 0xff, 0x07, 0x00, 0xe3, 0xff, 0x09, 0x00, 0xde, 0xff, 0x0a, 0x00, 0xdb, 0xff, 0x08, 0x00, 0xda, 0xff, 0x03, 0x00, 0xd9, 0xff, 0xff, 0xff, 0xd7, 0xff, 0xfb, 0xff, 0xd5, 0xff, 0xfa, 0xff, 0xd1, 0xff, 0xfa, 0xff, 0xcb, 0xff, 0xfb, 0xff, 0xc5, 0xff, 0xfd, 0xff, 0xc2, 0xff, 0xfd, 0xff, 0xc2, 0xff, 0xfd, 0xff, 0xc5, 0xff, 0xfb, 0xff, 0xcb, 0xff, 0xfa, 0xff, 0xd0, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xf8, 0xff, 0xd6, 0xff, 0xf7, 0xff, 0xd6, 0xff, 0xf6, 0xff, 0xd6, 0xff, 0xf4, 0xff, 0xd8, 0xff, 0xf3, 0xff, 0xdc, 0xff, 0xf1, 0xff, 0xe4, 0xff, 0xef, 0xff, 0xec, 0xff, 0xed, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xfd, 0xff, 0xec, 0xff, 0x02, 0x00, 0xec, 0xff, 0x06, 0x00, 0xed, 0xff, 0x08, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xf1, 0xff, 0x0c, 0x00, 0xf2, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x11, 0x00, 0xf4, 0xff, 0x13, 0x00, 0xf4, 0xff, 0x16, 0x00, 0xf4, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x1d, 0x00, 0xfa, 0xff, 0x20, 0x00, 0xff, 0xff, 0x22, 0x00, 0x04, 0x00, 0x22, 0x00, 0x07, 0x00, 0x20, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x18, 0x00, 0x02, 0x00, 0x16, 0x00, 0xff, 0xff, 0x16, 0x00, 0xfe, 0xff, 0x1a, 0x00, 0xff, 0xff, 0x1e, 0x00, 0x04, 0x00, 0x22, 0x00, 0x09, 0x00, 0x24, 0x00, 0x0c, 0x00, 0x23, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x0b, 0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x00, 0x06, 0x00, 0x21, 0x00, 0x05, 0x00, 0x24, 0x00, 0x06, 0x00, 0x27, 0x00, 0x07, 0x00, 0x28, 0x00, 0x07, 0x00, 0x28, 0x00, 0x06, 0x00, 0x27, 0x00, 0x04, 0x00, 0x25, 0x00, 0xff, 0xff, 0x23, 0x00, 0xfb, 0xff, 0x22, 0x00, 0xf7, 0xff, 0x20, 0x00, 0xf4, 0xff, 0x1e, 0x00, 0xf2, 0xff, 0x1c, 0x00, 0xef, 0xff, 0x19, 0x00, 0xe9, 0xff, 0x17, 0x00, 0xe3, 0xff, 0x16, 0x00, 0xdd, 0xff, 0x16, 0x00, 0xd8, 0xff, 0x15, 0x00, 0xd4, 0xff, 0x14, 0x00, 0xd2, 0xff, 0x11, 0x00, 0xd1, 0xff, 0x0d, 0x00, 0xd0, 0xff, 0x08, 0x00, 0xcf, 0xff, 0x04, 0x00, 0xcd, 0xff, 0x03, 0x00, 0xcc, 0xff, 0x03, 0x00, 0xcc, 0xff, 0x05, 0x00, 0xce, 0xff, 0x06, 0x00, 0xcf, 0xff, 0x06, 0x00, 0xd0, 0xff, 0x03, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xce, 0xff, 0xfa, 0xff, 0xcd, 0xff, 0xf6, 0xff, 0xcd, 0xff, 0xf3, 0xff, 0xce, 0xff, 0xf3, 0xff, 0xd0, 0xff, 0xf4, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf9, 0xff, 0xd0, 0xff, 0xfa, 0xff, 0xcd, 0xff, 0xf9, 0xff, 0xcb, 0xff, 0xf7, 0xff, 0xc9, 0xff, 0xf3, 0xff, 0xc9, 0xff, 0xf0, 0xff, 0xca, 0xff, 0xed, 0xff, 0xcc, 0xff, 0xec, 0xff, 0xce, 0xff, 0xee, 0xff, 0xd0, 0xff, 0xf2, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd3, 0xff, 0xfb, 0xff, 0xd6, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x01, 0x00, 0xe1, 0xff, 0x03, 0x00, 0xe7, 0xff, 0x04, 0x00, 0xed, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x06, 0x00, 0xf5, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0x01, 0x00, 0x11, 0x00, 0x06, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x12, 0x00, 0x16, 0x00, 0x13, 0x00, 0x17, 0x00, 0x13, 0x00, 0x18, 0x00, 0x13, 0x00, 0x18, 0x00, 0x13, 0x00, 0x19, 0x00, 0x14, 0x00, 0x19, 0x00, 0x15, 0x00, 0x19, 0x00, 0x13, 0x00, 0x18, 0x00, 0x12, 0x00, 0x15, 0x00, 0x10, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x09, 0x00, 0x17, 0x00, 0x09, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x21, 0x00, 0x04, 0x00, 0x27, 0x00, 0xff, 0xff, 0x2c, 0x00, 0xf9, 0xff, 0x2e, 0x00, 0xf4, 0xff, 0x2e, 0x00, 0xf3, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x27, 0x00, 0xf8, 0xff, 0x22, 0x00, 0xfc, 0xff, 0x1f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfe, 0xff, 0x20, 0x00, 0xfc, 0xff, 0x22, 0x00, 0xf8, 0xff, 0x22, 0x00, 0xf3, 0xff, 0x1e, 0x00, 0xf0, 0xff, 0x18, 0x00, 0xef, 0xff, 0x11, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xef, 0xff, 0x06, 0x00, 0xef, 0xff, 0x04, 0x00, 0xed, 0xff, 0x04, 0x00, 0xeb, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x05, 0x00, 0xe2, 0xff, 0x04, 0x00, 0xde, 0xff, 0x00, 0x00, 0xdb, 0xff, 0xfb, 0xff, 0xd9, 0xff, 0xf6, 0xff, 0xd7, 0xff, 0xf4, 0xff, 0xd5, 0xff, 0xf4, 0xff, 0xd2, 0xff, 0xf6, 0xff, 0xcf, 0xff, 0xfa, 0xff, 0xcd, 0xff, 0xfd, 0xff, 0xcb, 0xff, 0x00, 0x00, 0xcc, 0xff, 0x00, 0x00, 0xcf, 0xff, 0xfe, 0xff, 0xd3, 0xff, 0xfa, 0xff, 0xd8, 0xff, 0xf7, 0xff, 0xdd, 0xff, 0xf5, 0xff, 0xe0, 0xff, 0xf6, 0xff, 0xe3, 0xff, 0xf9, 0xff, 0xe4, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x04, 0x00, 0xec, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x05, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x14, 0x00, 0xfd, 0xff, 0x15, 0x00, 0x02, 0x00, 0x16, 0x00, 0x07, 0x00, 0x19, 0x00, 0x09, 0x00, 0x1d, 0x00, 0x09, 0x00, 0x22, 0x00, 0x08, 0x00, 0x25, 0x00, 0x06, 0x00, 0x27, 0x00, 0x06, 0x00, 0x26, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x1e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x18, 0x00, 0x26, 0x00, 0x19, 0x00, 0x26, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x1b, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x20, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x07, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x16, 0x00, 0x04, 0x00, 0x10, 0x00, 0x05, 0x00, 0x08, 0x00, 0x07, 0x00, 0x01, 0x00, 0x09, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xed, 0xff, 0xfb, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xf4, 0xff, 0xec, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xe6, 0xff, 0xf9, 0xff, 0xe4, 0xff, 0xf4, 0xff, 0xe4, 0xff, 0xec, 0xff, 0xe7, 0xff, 0xe2, 0xff, 0xec, 0xff, 0xda, 0xff, 0xf1, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xd8, 0xff, 0xf4, 0xff, 0xdb, 0xff, 0xf1, 0xff, 0xdb, 0xff, 0xf0, 0xff, 0xd8, 0xff, 0xf0, 0xff, 0xd2, 0xff, 0xf3, 0xff, 0xca, 0xff, 0xf6, 0xff, 0xc3, 0xff, 0xfa, 0xff, 0xbf, 0xff, 0xfb, 0xff, 0xc0, 0xff, 0xf9, 0xff, 0xc4, 0xff, 0xf5, 0xff, 0xca, 0xff, 0xf2, 0xff, 0xd1, 0xff, 0xf1, 0xff, 0xd6, 0xff, 0xf2, 0xff, 0xd9, 0xff, 0xf6, 0xff, 0xd8, 0xff, 0xfb, 0xff, 0xd6, 0xff, 0xfe, 0xff, 0xd5, 0xff, 0x00, 0x00, 0xd6, 0xff, 0x00, 0x00, 0xdb, 0xff, 0xfd, 0xff, 0xe4, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x0a, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x10, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x1a, 0x00, 0x19, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x22, 0x00, 0x16, 0x00, 0x24, 0x00, 0x19, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x23, 0x00, 0x1f, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x2b, 0x00, 0x1e, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x32, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x33, 0x00, 0x38, 0x00, 0x32, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x39, 0x00, 0x26, 0x00, 0x38, 0x00, 0x1f, 0x00, 0x37, 0x00, 0x1a, 0x00, 0x36, 0x00, 0x18, 0x00, 0x36, 0x00, 0x18, 0x00, 0x35, 0x00, 0x19, 0x00, 0x35, 0x00, 0x19, 0x00, 0x34, 0x00, 0x17, 0x00, 0x32, 0x00, 0x13, 0x00, 0x2e, 0x00, 0x0e, 0x00, 0x28, 0x00, 0x07, 0x00, 0x20, 0x00, 0x02, 0x00, 0x18, 0x00, 0xff, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xec, 0xff, 0xf1, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xe2, 0xff, 0xef, 0xff, 0xdd, 0xff, 0xf1, 0xff, 0xda, 0xff, 0xf4, 0xff, 0xd9, 0xff, 0xf6, 0xff, 0xdc, 0xff, 0xf7, 0xff, 0xe1, 0xff, 0xf7, 0xff, 0xe7, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xef, 0xff, 0xfa, 0xff, 0xf0, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x15, 0x00, 0xef, 0xff, 0x1c, 0x00, 0xeb, 0xff, 0x22, 0x00, 0xe8, 0xff, 0x25, 0x00, 0xe7, 0xff, 0x26, 0x00, 0xe9, 0xff, 0x26, 0x00, 0xeb, 0xff, 0x26, 0x00, 0xec, 0xff, 0x26, 0x00, 0xec, 0xff, 0x28, 0x00, 0xe8, 0xff, 0x2a, 0x00, 0xe3, 0xff, 0x2c, 0x00, 0xde, 0xff, 0x2e, 0x00, 0xda, 0xff, 0x2d, 0x00, 0xd8, 0xff, 0x2a, 0x00, 0xd8, 0xff, 0x25, 0x00, 0xda, 0xff, 0x20, 0x00, 0xdc, 0xff, 0x1a, 0x00, 0xde, 0xff, 0x14, 0x00, 0xde, 0xff, 0x10, 0x00, 0xdc, 0xff, 0x0b, 0x00, 0xd9, 0xff, 0x08, 0x00, 0xd6, 0xff, 0x04, 0x00, 0xd5, 0xff, 0x00, 0x00, 0xd7, 0xff, 0xfa, 0xff, 0xda, 0xff, 0xf4, 0xff, 0xe0, 0xff, 0xed, 0xff, 0xe5, 0xff, 0xe6, 0xff, 0xe9, 0xff, 0xe0, 0xff, 0xea, 0xff, 0xdc, 0xff, 0xe8, 0xff, 0xd9, 0xff, 0xe7, 0xff, 0xd9, 0xff, 0xe6, 0xff, 0xda, 0xff, 0xe8, 0xff, 0xda, 0xff, 0xed, 0xff, 0xd9, 0xff, 0xf3, 0xff, 0xd6, 0xff, 0xfa, 0xff, 0xd2, 0xff, 0x01, 0x00, 0xce, 0xff, 0x05, 0x00, 0xcb, 0xff, 0x06, 0x00, 0xcb, 0xff, 0x05, 0x00, 0xce, 0xff, 0x03, 0x00, 0xd2, 0xff, 0x03, 0x00, 0xd4, 0xff, 0x05, 0x00, 0xd4, 0xff, 0x09, 0x00, 0xd0, 0xff, 0x0f, 0x00, 0xcc, 0xff, 0x13, 0x00, 0xc7, 0xff, 0x16, 0x00, 0xc5, 0xff, 0x17, 0x00, 0xc7, 0xff, 0x17, 0x00, 0xcb, 0xff, 0x17, 0x00, 0xd1, 0xff, 0x18, 0x00, 0xd4, 0xff, 0x1b, 0x00, 0xd6, 0xff, 0x1e, 0x00, 0xd6, 0xff, 0x21, 0x00, 0xd6, 0xff, 0x21, 0x00, 0xd8, 0xff, 0x1e, 0x00, 0xde, 0xff, 0x1a, 0x00, 0xe7, 0xff, 0x17, 0x00, 0xf1, 0xff, 0x15, 0x00, 0xfb, 0xff, 0x16, 0x00, 0x02, 0x00, 0x18, 0x00, 0x06, 0x00, 0x19, 0x00, 0x08, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x0b, 0x00, 0x2b, 0x00, 0x0b, 0x00, 0x35, 0x00, 0x0c, 0x00, 0x3b, 0x00, 0x0d, 0x00, 0x3d, 0x00, 0x0c, 0x00, 0x3c, 0x00, 0x09, 0x00, 0x3a, 0x00, 0x05, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3b, 0x00, 0xfb, 0xff, 0x3f, 0x00, 0xf6, 0xff, 0x44, 0x00, 0xf3, 0xff, 0x49, 0x00, 0xf0, 0xff, 0x4c, 0x00, 0xee, 0xff, 0x4c, 0x00, 0xed, 0xff, 0x49, 0x00, 0xed, 0xff, 0x43, 0x00, 0xec, 0xff, 0x3c, 0x00, 0xea, 0xff, 0x36, 0x00, 0xe6, 0xff, 0x32, 0x00, 0xe0, 0xff, 0x30, 0x00, 0xd9, 0xff, 0x2f, 0x00, 0xd2, 0xff, 0x2e, 0x00, 0xcc, 0xff, 0x2c, 0x00, 0xca, 0xff, 0x28, 0x00, 0xcb, 0xff, 0x23, 0x00, 0xce, 0xff, 0x1c, 0x00, 0xd1, 0xff, 0x16, 0x00, 0xd1, 0xff, 0x10, 0x00, 0xce, 0xff, 0x0c, 0x00, 0xc9, 0xff, 0x09, 0x00, 0xc4, 0xff, 0x07, 0x00, 0xc1, 0xff, 0x05, 0x00, 0xc2, 0xff, 0x04, 0x00, 0xc7, 0xff, 0x02, 0x00, 0xce, 0xff, 0xfe, 0xff, 0xd6, 0xff, 0xfa, 0xff, 0xdb, 0xff, 0xf5, 0xff, 0xde, 0xff, 0xf0, 0xff, 0xdd, 0xff, 0xed, 0xff, 0xdc, 0xff, 0xea, 0xff, 0xdb, 0xff, 0xe8, 0xff, 0xdf, 0xff, 0xe5, 0xff, 0xe7, 0xff, 0xe1, 0xff, 0xf2, 0xff, 0xdc, 0xff, 0xfd, 0xff, 0xd7, 0xff, 0x07, 0x00, 0xd0, 0xff, 0x0f, 0x00, 0xc9, 0xff, 0x13, 0x00, 0xc3, 0xff, 0x14, 0x00, 0xbf, 0xff, 0x14, 0x00, 0xbd, 0xff, 0x14, 0x00, 0xbf, 0xff, 0x14, 0x00, 0xc2, 0xff, 0x17, 0x00, 0xc6, 0xff, 0x1d, 0x00, 0xc8, 0xff, 0x23, 0x00, 0xc9, 0xff, 0x2a, 0x00, 0xca, 0xff, 0x30, 0x00, 0xca, 0xff, 0x32, 0x00, 0xcc, 0xff, 0x31, 0x00, 0xd0, 0xff, 0x2e, 0x00, 0xd5, 0xff, 0x2b, 0x00, 0xde, 0xff, 0x2a, 0x00, 0xe7, 0xff, 0x2c, 0x00, 0xf1, 0xff, 0x30, 0x00, 0xf9, 0xff, 0x34, 0x00, 0xfd, 0xff, 0x38, 0x00, 0xff, 0xff, 0x39, 0x00, 0xff, 0xff, 0x37, 0x00, 0xff, 0xff, 0x31, 0x00, 0x01, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x28, 0x00, 0x0a, 0x00, 0x27, 0x00, 0x10, 0x00, 0x29, 0x00, 0x14, 0x00, 0x2c, 0x00, 0x16, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x2e, 0x00, 0x14, 0x00, 0x2b, 0x00, 0x13, 0x00, 0x28, 0x00, 0x14, 0x00, 0x26, 0x00, 0x17, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x26, 0x00, 0x22, 0x00, 0x27, 0x00, 0x27, 0x00, 0x28, 0x00, 0x28, 0x00, 0x27, 0x00, 0x28, 0x00, 0x25, 0x00, 0x26, 0x00, 0x21, 0x00, 0x25, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x2f, 0x00, 0x19, 0x00, 0x32, 0x00, 0x15, 0x00, 0x32, 0x00, 0x11, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x2b, 0x00, 0x08, 0x00, 0x26, 0x00, 0x06, 0x00, 0x22, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x18, 0x00, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xf8, 0xff, 0xe9, 0xff, 0xf8, 0xff, 0xe4, 0xff, 0xf8, 0xff, 0xdf, 0xff, 0xf8, 0xff, 0xda, 0xff, 0xfa, 0xff, 0xd7, 0xff, 0xfc, 0xff, 0xd3, 0xff, 0xfd, 0xff, 0xd0, 0xff, 0xfd, 0xff, 0xce, 0xff, 0xfd, 0xff, 0xcc, 0xff, 0xfb, 0xff, 0xcc, 0xff, 0xf9, 0xff, 0xcc, 0xff, 0xf8, 0xff, 0xce, 0xff, 0xf9, 0xff, 0xd1, 0xff, 0xfa, 0xff, 0xd4, 0xff, 0xfb, 0xff, 0xd6, 0xff, 0xfd, 0xff, 0xd6, 0xff, 0xff, 0xff, 0xd6, 0xff, 0x00, 0x00, 0xd6, 0xff, 0x01, 0x00, 0xd7, 0xff, 0x00, 0x00, 0xd9, 0xff, 0xff, 0xff, 0xde, 0xff, 0xfe, 0xff, 0xe3, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xfd, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xed, 0xff, 0x00, 0x00, 0xed, 0xff, 0x01, 0x00, 0xec, 0xff, 0x01, 0x00, 0xec, 0xff, 0xff, 0xff, 0xef, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x13, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x21, 0x00, 0x03, 0x00, 0x24, 0x00, 0x05, 0x00, 0x26, 0x00, 0x07, 0x00, 0x25, 0x00, 0x07, 0x00, 0x24, 0x00, 0x06, 0x00, 0x23, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2b, 0x00, 0xfd, 0xff, 0x33, 0x00, 0xfc, 0xff, 0x3a, 0x00, 0xfb, 0xff, 0x3f, 0x00, 0xfb, 0xff, 0x41, 0x00, 0xf9, 0xff, 0x40, 0x00, 0xf6, 0xff, 0x3c, 0x00, 0xf1, 0xff, 0x38, 0x00, 0xeb, 0xff, 0x34, 0x00, 0xe6, 0xff, 0x31, 0x00, 0xe2, 0xff, 0x31, 0x00, 0xe0, 0xff, 0x32, 0x00, 0xdf, 0xff, 0x34, 0x00, 0xdf, 0xff, 0x34, 0x00, 0xde, 0xff, 0x34, 0x00, 0xda, 0xff, 0x31, 0x00, 0xd6, 0xff, 0x2b, 0x00, 0xd1, 0xff, 0x25, 0x00, 0xcd, 0xff, 0x1f, 0x00, 0xcb, 0xff, 0x1a, 0x00, 0xcb, 0xff, 0x19, 0x00, 0xcc, 0xff, 0x19, 0x00, 0xce, 0xff, 0x1a, 0x00, 0xd0, 0xff, 0x1a, 0x00, 0xd3, 0xff, 0x18, 0x00, 0xd6, 0xff, 0x13, 0x00, 0xd9, 0xff, 0x0e, 0x00, 0xdb, 0xff, 0x07, 0x00, 0xdd, 0xff, 0x02, 0x00, 0xdf, 0xff, 0xfc, 0xff, 0xe2, 0xff, 0xf8, 0xff, 0xe4, 0xff, 0xf6, 0xff, 0xe8, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xee, 0xff, 0xef, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xe5, 0xff, 0xf6, 0xff, 0xdf, 0xff, 0xf9, 0xff, 0xd9, 0xff, 0xfa, 0xff, 0xd4, 0xff, 0xfc, 0xff, 0xd1, 0xff, 0xfe, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xd0, 0xff, 0x01, 0x00, 0xd1, 0xff, 0x02, 0x00, 0xd2, 0xff, 0x02, 0x00, 0xd1, 0xff, 0x02, 0x00, 0xce, 0xff, 0x03, 0x00, 0xca, 0xff, 0x04, 0x00, 0xc6, 0xff, 0x05, 0x00, 0xc4, 0xff, 0x07, 0x00, 0xc3, 0xff, 0x08, 0x00, 0xc5, 0xff, 0x09, 0x00, 0xc8, 0xff, 0x0a, 0x00, 0xcc, 0xff, 0x0b, 0x00, 0xcf, 0xff, 0x0d, 0x00, 0xd0, 0xff, 0x10, 0x00, 0xcf, 0xff, 0x13, 0x00, 0xcd, 0xff, 0x15, 0x00, 0xcc, 0xff, 0x16, 0x00, 0xce, 0xff, 0x16, 0x00, 0xd2, 0xff, 0x15, 0x00, 0xd7, 0xff, 0x14, 0x00, 0xdd, 0xff, 0x15, 0x00, 0xe1, 0xff, 0x18, 0x00, 0xe4, 0xff, 0x1d, 0x00, 0xe4, 0xff, 0x22, 0x00, 0xe3, 0xff, 0x25, 0x00, 0xe2, 0xff, 0x25, 0x00, 0xe1, 0xff, 0x23, 0x00, 0xe3, 0xff, 0x1f, 0x00, 0xe7, 0xff, 0x1a, 0x00, 0xed, 0xff, 0x16, 0x00, 0xf2, 0xff, 0x13, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf7, 0xff, 0x12, 0x00, 0xf7, 0xff, 0x14, 0x00, 0xf7, 0xff, 0x16, 0x00, 0xf7, 0xff, 0x15, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0x02, 0x00, 0x08, 0x00, 0x06, 0x00, 0x04, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x1d, 0x00, 0x02, 0x00, 0x1f, 0x00, 0xfb, 0xff, 0x20, 0x00, 0xf4, 0xff, 0x20, 0x00, 0xf1, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xf1, 0xff, 0x19, 0x00, 0xf3, 0xff, 0x17, 0x00, 0xf4, 0xff, 0x15, 0x00, 0xf2, 0xff, 0x15, 0x00, 0xee, 0xff, 0x16, 0x00, 0xe9, 0xff, 0x17, 0x00, 0xe5, 0xff, 0x18, 0x00, 0xe4, 0xff, 0x16, 0x00, 0xe6, 0xff, 0x13, 0x00, 0xea, 0xff, 0x0f, 0x00, 0xed, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x13, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf6, 0xff, 0x19, 0x00, 0xfb, 0xff, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x05, 0x00, 0x16, 0x00, 0x08, 0x00, 0x16, 0x00, 0x08, 0x00, 0x17, 0x00, 0x06, 0x00, 0x18, 0x00, 0x03, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x18, 0x00, 0x04, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x11, 0x00, 0x10, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x09, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x13, 0x00, 0x14, 0x00, 0x17, 0x00, 0x14, 0x00, 0x19, 0x00, 0x13, 0x00, 0x18, 0x00, 0x13, 0x00, 0x16, 0x00, 0x13, 0x00, 0x14, 0x00, 0x12, 0x00, 0x13, 0x00, 0x11, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x23, 0x00, 0x05, 0x00, 0x25, 0x00, 0x01, 0x00, 0x24, 0x00, 0xfd, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x1f, 0x00, 0xf6, 0xff, 0x1d, 0x00, 0xf4, 0xff, 0x1c, 0x00, 0xf0, 0xff, 0x1e, 0x00, 0xec, 0xff, 0x1f, 0x00, 0xe7, 0xff, 0x20, 0x00, 0xe3, 0xff, 0x20, 0x00, 0xe1, 0xff, 0x1d, 0x00, 0xe1, 0xff, 0x18, 0x00, 0xe2, 0xff, 0x14, 0x00, 0xe5, 0xff, 0x0f, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xe8, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x03, 0x00, 0xe2, 0xff, 0x02, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe1, 0xff, 0xfc, 0xff, 0xe4, 0xff, 0xf7, 0xff, 0xe9, 0xff, 0xf1, 0xff, 0xee, 0xff, 0xeb, 0xff, 0xf2, 0xff, 0xe5, 0xff, 0xf3, 0xff, 0xe0, 0xff, 0xf2, 0xff, 0xdd, 0xff, 0xf1, 0xff, 0xdb, 0xff, 0xf0, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xd8, 0xff, 0xf4, 0xff, 0xd7, 0xff, 0xf7, 0xff, 0xd4, 0xff, 0xfb, 0xff, 0xd1, 0xff, 0xfd, 0xff, 0xcd, 0xff, 0xfe, 0xff, 0xc9, 0xff, 0xfe, 0xff, 0xc7, 0xff, 0xfd, 0xff, 0xc7, 0xff, 0xfc, 0xff, 0xc9, 0xff, 0xfc, 0xff, 0xcc, 0xff, 0xfd, 0xff, 0xce, 0xff, 0xfe, 0xff, 0xd0, 0xff, 0x00, 0x00, 0xd0, 0xff, 0x01, 0x00, 0xcf, 0xff, 0x01, 0x00, 0xce, 0xff, 0x01, 0x00, 0xcd, 0xff, 0x01, 0x00, 0xcc, 0xff, 0x02, 0x00, 0xcc, 0xff, 0x04, 0x00, 0xcd, 0xff, 0x06, 0x00, 0xcf, 0xff, 0x07, 0x00, 0xd1, 0xff, 0x09, 0x00, 0xd3, 0xff, 0x0b, 0x00, 0xd4, 0xff, 0x0d, 0x00, 0xd4, 0xff, 0x11, 0x00, 0xd4, 0xff, 0x14, 0x00, 0xd4, 0xff, 0x16, 0x00, 0xd7, 0xff, 0x17, 0x00, 0xdb, 0xff, 0x18, 0x00, 0xe0, 0xff, 0x1a, 0x00, 0xe5, 0xff, 0x1c, 0x00, 0xea, 0xff, 0x1f, 0x00, 0xef, 0xff, 0x22, 0x00, 0xf4, 0xff, 0x24, 0x00, 0xf8, 0xff, 0x24, 0x00, 0xfd, 0xff, 0x22, 0x00, 0x02, 0x00, 0x20, 0x00, 0x07, 0x00, 0x1d, 0x00, 0x0c, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x18, 0x00, 0x23, 0x00, 0x14, 0x00, 0x24, 0x00, 0x10, 0x00, 0x23, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x0e, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x21, 0x00, 0xfe, 0xff, 0x22, 0x00, 0xfa, 0xff, 0x21, 0x00, 0xf7, 0xff, 0x1e, 0x00, 0xf4, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x16, 0x00, 0xef, 0xff, 0x13, 0x00, 0xed, 0xff, 0x12, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xe5, 0xff, 0x13, 0x00, 0xe1, 0xff, 0x13, 0x00, 0xde, 0xff, 0x12, 0x00, 0xdb, 0xff, 0x0f, 0x00, 0xd9, 0xff, 0x0b, 0x00, 0xd8, 0xff, 0x06, 0x00, 0xd6, 0xff, 0x03, 0x00, 0xd5, 0xff, 0x01, 0x00, 0xd4, 0xff, 0x01, 0x00, 0xd3, 0xff, 0x01, 0x00, 0xd3, 0xff, 0x01, 0x00, 0xd3, 0xff, 0x00, 0x00, 0xd2, 0xff, 0xff, 0xff, 0xd2, 0xff, 0xfd, 0xff, 0xd3, 0xff, 0xfa, 0xff, 0xd4, 0xff, 0xf5, 0xff, 0xd6, 0xff, 0xef, 0xff, 0xd7, 0xff, 0xe9, 0xff, 0xd8, 0xff, 0xe4, 0xff, 0xd9, 0xff, 0xe1, 0xff, 0xdc, 0xff, 0xde, 0xff, 0xe0, 0xff, 0xdc, 0xff, 0xe5, 0xff, 0xda, 0xff, 0xea, 0xff, 0xd8, 0xff, 0xed, 0xff, 0xd6, 0xff, 0xef, 0xff, 0xd4, 0xff, 0xf0, 0xff, 0xd4, 0xff, 0xf0, 0xff, 0xd5, 0xff, 0xf2, 0xff, 0xd7, 0xff, 0xf5, 0xff, 0xda, 0xff, 0xfa, 0xff, 0xde, 0xff, 0x00, 0x00, 0xe1, 0xff, 0x06, 0x00, 0xe5, 0xff, 0x0a, 0x00, 0xe9, 0xff, 0x0b, 0x00, 0xee, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0x01, 0x00, 0x11, 0x00, 0x02, 0x00, 0x17, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x02, 0x00, 0x22, 0x00, 0x02, 0x00, 0x23, 0x00, 0x02, 0x00, 0x22, 0x00, 0x04, 0x00, 0x20, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x06, 0x00, 0x20, 0x00, 0x05, 0x00, 0x23, 0x00, 0x03, 0x00, 0x26, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x25, 0x00, 0x03, 0x00, 0x20, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x06, 0x00, 0x16, 0x00, 0x02, 0x00, 0x19, 0x00, 0xfe, 0xff, 0x1b, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf5, 0xff, 0x1c, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xec, 0xff, 0x1d, 0x00, 0xe9, 0xff, 0x1d, 0x00, 0xe7, 0xff, 0x1d, 0x00, 0xe5, 0xff, 0x1e, 0x00, 0xe5, 0xff, 0x1f, 0x00, 0xe5, 0xff, 0x20, 0x00, 0xe5, 0xff, 0x20, 0x00, 0xe4, 0xff, 0x20, 0x00, 0xe1, 0xff, 0x1f, 0x00, 0xdd, 0xff, 0x1f, 0x00, 0xd9, 0xff, 0x20, 0x00, 0xd5, 0xff, 0x21, 0x00, 0xd4, 0xff, 0x22, 0x00, 0xd4, 0xff, 0x23, 0x00, 0xd5, 0xff, 0x23, 0x00, 0xd6, 0xff, 0x22, 0x00, 0xd7, 0xff, 0x21, 0x00, 0xd8, 0xff, 0x1f, 0x00, 0xd9, 0xff, 0x1d, 0x00, 0xd9, 0xff, 0x1a, 0x00, 0xd9, 0xff, 0x19, 0x00, 0xda, 0xff, 0x18, 0x00, 0xdd, 0xff, 0x17, 0x00, 0xe1, 0xff, 0x14, 0x00, 0xe6, 0xff, 0x10, 0x00, 0xec, 0xff, 0x0a, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x23, 0x00, 0xf0, 0xff, 0x2b, 0x00, 0xeb, 0xff, 0x30, 0x00, 0xe6, 0xff, 0x32, 0x00, 0xe1, 0xff, 0x33, 0x00, 0xdf, 0xff, 0x32, 0x00, 0xde, 0xff, 0x32, 0x00, 0xde, 0xff, 0x33, 0x00, 0xdd, 0xff, 0x36, 0x00, 0xdb, 0xff, 0x3b, 0x00, 0xd9, 0xff, 0x41, 0x00, 0xd6, 0xff, 0x44, 0x00, 0xd4, 0xff, 0x45, 0x00, 0xd3, 0xff, 0x43, 0x00, 0xd3, 0xff, 0x3e, 0x00, 0xd6, 0xff, 0x3a, 0x00, 0xda, 0xff, 0x37, 0x00, 0xdf, 0xff, 0x37, 0x00, 0xe4, 0xff, 0x38, 0x00, 0xe8, 0xff, 0x3a, 0x00, 0xec, 0xff, 0x3b, 0x00, 0xf1, 0xff, 0x3b, 0x00, 0xf6, 0xff, 0x39, 0x00, 0xfd, 0xff, 0x37, 0x00, 0x04, 0x00, 0x35, 0x00, 0x0b, 0x00, 0x36, 0x00, 0x11, 0x00, 0x37, 0x00, 0x17, 0x00, 0x38, 0x00, 0x1b, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x22, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x29, 0x00, 0x28, 0x00, 0x25, 0x00, 0x2b, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x13, 0x00, 0x22, 0x00, 0x0b, 0x00, 0x20, 0x00, 0x03, 0x00, 0x1f, 0x00, 0xfd, 0xff, 0x1e, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf0, 0xff, 0x15, 0x00, 0xea, 0xff, 0x12, 0x00, 0xe5, 0xff, 0x11, 0x00, 0xe0, 0xff, 0x10, 0x00, 0xdd, 0xff, 0x0f, 0x00, 0xdb, 0xff, 0x0d, 0x00, 0xdb, 0xff, 0x0b, 0x00, 0xda, 0xff, 0x08, 0x00, 0xda, 0xff, 0x06, 0x00, 0xd9, 0xff, 0x04, 0x00, 0xd8, 0xff, 0x04, 0x00, 0xd6, 0xff, 0x04, 0x00, 0xd3, 0xff, 0x03, 0x00, 0xd1, 0xff, 0x02, 0x00, 0xce, 0xff, 0x00, 0x00, 0xcc, 0xff, 0xfd, 0xff, 0xcb, 0xff, 0xfb, 0xff, 0xca, 0xff, 0xfb, 0xff, 0xcc, 0xff, 0xfb, 0xff, 0xce, 0xff, 0xfc, 0xff, 0xd1, 0xff, 0xfb, 0xff, 0xd3, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xf6, 0xff, 0xd2, 0xff, 0xf2, 0xff, 0xcf, 0xff, 0xee, 0xff, 0xcd, 0xff, 0xeb, 0xff, 0xcb, 0xff, 0xea, 0xff, 0xcd, 0xff, 0xe9, 0xff, 0xd2, 0xff, 0xe8, 0xff, 0xd9, 0xff, 0xe7, 0xff, 0xe1, 0xff, 0xe5, 0xff, 0xe8, 0xff, 0xe3, 0xff, 0xed, 0xff, 0xe0, 0xff, 0xf0, 0xff, 0xde, 0xff, 0xf2, 0xff, 0xdb, 0xff, 0xf4, 0xff, 0xd8, 0xff, 0xf7, 0xff, 0xd7, 0xff, 0xfc, 0xff, 0xd8, 0xff, 0x01, 0x00, 0xda, 0xff, 0x08, 0x00, 0xdd, 0xff, 0x0d, 0x00, 0xe0, 0xff, 0x12, 0x00, 0xe1, 0xff, 0x15, 0x00, 0xe0, 0xff, 0x17, 0x00, 0xdd, 0xff, 0x1a, 0x00, 0xda, 0xff, 0x1c, 0x00, 0xd8, 0xff, 0x1d, 0x00, 0xd8, 0xff, 0x1e, 0x00, 0xdb, 0xff, 0x1f, 0x00, 0xe1, 0xff, 0x21, 0x00, 0xe7, 0xff, 0x23, 0x00, 0xed, 0xff, 0x24, 0x00, 0xf0, 0xff, 0x25, 0x00, 0xf0, 0xff, 0x24, 0x00, 0xef, 0xff, 0x21, 0x00, 0xed, 0xff, 0x1d, 0x00, 0xee, 0xff, 0x19, 0x00, 0xf1, 0xff, 0x16, 0x00, 0xf8, 0xff, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x07, 0x00, 0x16, 0x00, 0x04, 0x00, 0x19, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x20, 0x00, 0x03, 0x00, 0x22, 0x00, 0x02, 0x00, 0x22, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xfe, 0xff, 0x1c, 0x00, 0xfc, 0xff, 0x18, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xf8, 0xff, 0x13, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x12, 0x00, 0xf1, 0xff, 0x12, 0x00, 0xee, 0xff, 0x10, 0x00, 0xed, 0xff, 0x0d, 0x00, 0xed, 0xff, 0x09, 0x00, 0xed, 0xff, 0x04, 0x00, 0xec, 0xff, 0x01, 0x00, 0xeb, 0xff, 0xff, 0xff, 0xea, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x01, 0x00, 0xe7, 0xff, 0x01, 0x00, 0xe7, 0xff, 0x01, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xea, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfc, 0xff, 0xeb, 0xff, 0xfc, 0xff, 0xea, 0xff, 0xfd, 0xff, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x01, 0x00, 0xec, 0xff, 0x01, 0x00, 0xee, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xf8, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xec, 0xff, 0xf5, 0xff, 0xee, 0xff, 0xf6, 0xff, 0xf0, 0xff, 0xf6, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xff, 0xff, 0x16, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x08, 0x00, 0x1e, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x20, 0x00, 0x10, 0x00, 0x20, 0x00, 0x12, 0x00, 0x21, 0x00, 0x15, 0x00, 0x22, 0x00, 0x16, 0x00, 0x23, 0x00, 0x17, 0x00, 0x23, 0x00, 0x16, 0x00, 0x22, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x0b, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x1b, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x09, 0x00, 0x20, 0x00, 0x08, 0x00, 0x22, 0x00, 0x05, 0x00, 0x23, 0x00, 0x01, 0x00, 0x22, 0x00, 0xfc, 0xff, 0x21, 0x00, 0xf6, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x1e, 0x00, 0xeb, 0xff, 0x1f, 0x00, 0xe8, 0xff, 0x21, 0x00, 0xe6, 0xff, 0x24, 0x00, 0xe5, 0xff, 0x28, 0x00, 0xe4, 0xff, 0x29, 0x00, 0xe3, 0xff, 0x27, 0x00, 0xe0, 0xff, 0x23, 0x00, 0xdd, 0xff, 0x1c, 0x00, 0xd9, 0xff, 0x15, 0x00, 0xd5, 0xff, 0x0e, 0x00, 0xd2, 0xff, 0x0a, 0x00, 0xd1, 0xff, 0x08, 0x00, 0xd1, 0xff, 0x06, 0x00, 0xd2, 0xff, 0x04, 0x00, 0xd3, 0xff, 0xff, 0xff, 0xd4, 0xff, 0xf9, 0xff, 0xd5, 0xff, 0xef, 0xff, 0xd6, 0xff, 0xe4, 0xff, 0xd7, 0xff, 0xda, 0xff, 0xd7, 0xff, 0xd1, 0xff, 0xd8, 0xff, 0xcb, 0xff, 0xda, 0xff, 0xc8, 0xff, 0xde, 0xff, 0xc8, 0xff, 0xe2, 0xff, 0xc9, 0xff, 0xe6, 0xff, 0xc9, 0xff, 0xea, 0xff, 0xc6, 0xff, 0xed, 0xff, 0xc2, 0xff, 0xee, 0xff, 0xbd, 0xff, 0xef, 0xff, 0xb9, 0xff, 0xf0, 0xff, 0xb7, 0xff, 0xf2, 0xff, 0xb8, 0xff, 0xf5, 0xff, 0xbc, 0xff, 0xf9, 0xff, 0xc3, 0xff, 0xfe, 0xff, 0xc9, 0xff, 0x03, 0x00, 0xcf, 0xff, 0x07, 0x00, 0xd2, 0xff, 0x0a, 0x00, 0xd4, 0xff, 0x0b, 0x00, 0xd5, 0xff, 0x0b, 0x00, 0xd7, 0xff, 0x0c, 0x00, 0xd9, 0xff, 0x0f, 0x00, 0xdd, 0xff, 0x13, 0x00, 0xe3, 0xff, 0x17, 0x00, 0xe8, 0xff, 0x1c, 0x00, 0xed, 0xff, 0x20, 0x00, 0xef, 0xff, 0x23, 0x00, 0xef, 0xff, 0x25, 0x00, 0xed, 0xff, 0x25, 0x00, 0xec, 0xff, 0x24, 0x00, 0xec, 0xff, 0x24, 0x00, 0xee, 0xff, 0x25, 0x00, 0xf2, 0xff, 0x27, 0x00, 0xf8, 0xff, 0x29, 0x00, 0xfd, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0x25, 0x00, 0xff, 0xff, 0x22, 0x00, 0xfe, 0xff, 0x20, 0x00, 0xff, 0xff, 0x1f, 0x00, 0x02, 0x00, 0x20, 0x00, 0x07, 0x00, 0x21, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x00, 0x14, 0x00, 0x1e, 0x00, 0x15, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x1b, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x1b, 0x00, 0x14, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x19, 0x00, 0x13, 0x00, 0x18, 0x00, 0x13, 0x00, 0x18, 0x00, 0x12, 0x00, 0x17, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xf7, 0xff, 0x09, 0x00, 0xf3, 0xff, 0x08, 0x00, 0xee, 0xff, 0x06, 0x00, 0xea, 0xff, 0x03, 0x00, 0xe7, 0xff, 0x00, 0x00, 0xe4, 0xff, 0xfc, 0xff, 0xe2, 0xff, 0xfa, 0xff, 0xe0, 0xff, 0xf9, 0xff, 0xdc, 0xff, 0xf8, 0xff, 0xd8, 0xff, 0xf8, 0xff, 0xd4, 0xff, 0xf6, 0xff, 0xd0, 0xff, 0xf3, 0xff, 0xcd, 0xff, 0xf0, 0xff, 0xcd, 0xff, 0xef, 0xff, 0xce, 0xff, 0xf1, 0xff, 0xd1, 0xff, 0xf4, 0xff, 0xd3, 0xff, 0xf8, 0xff, 0xd5, 0xff, 0xfa, 0xff, 0xd4, 0xff, 0xfa, 0xff, 0xd3, 0xff, 0xf9, 0xff, 0xd2, 0xff, 0xf7, 0xff, 0xd2, 0xff, 0xf6, 0xff, 0xd5, 0xff, 0xf7, 0xff, 0xda, 0xff, 0xfa, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xe6, 0xff, 0x05, 0x00, 0xea, 0xff, 0x08, 0x00, 0xed, 0xff, 0x09, 0x00, 0xed, 0xff, 0x07, 0x00, 0xed, 0xff, 0x05, 0x00, 0xed, 0xff, 0x02, 0x00, 0xef, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x13, 0x00, 0x02, 0x00, 0x14, 0x00, 0x09, 0x00, 0x14, 0x00, 0x10, 0x00, 0x14, 0x00, 0x17, 0x00, 0x13, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x20, 0x00, 0x11, 0x00, 0x22, 0x00, 0x0f, 0x00, 0x24, 0x00, 0x0d, 0x00, 0x27, 0x00, 0x0b, 0x00, 0x2c, 0x00, 0x0b, 0x00, 0x32, 0x00, 0x0b, 0x00, 0x3a, 0x00, 0x0b, 0x00, 0x41, 0x00, 0x0a, 0x00, 0x47, 0x00, 0x08, 0x00, 0x4b, 0x00, 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0xfc, 0xff, 0x4d, 0x00, 0xfa, 0xff, 0x4c, 0x00, 0xf8, 0xff, 0x4b, 0x00, 0xf9, 0xff, 0x4a, 0x00, 0xf9, 0xff, 0x4a, 0x00, 0xf9, 0xff, 0x49, 0x00, 0xf7, 0xff, 0x47, 0x00, 0xf2, 0xff, 0x44, 0x00, 0xed, 0xff, 0x41, 0x00, 0xe9, 0xff, 0x3e, 0x00, 0xe6, 0xff, 0x3a, 0x00, 0xe5, 0xff, 0x35, 0x00, 0xe4, 0xff, 0x2f, 0x00, 0xe4, 0xff, 0x2a, 0x00, 0xe3, 0xff, 0x24, 0x00, 0xe1, 0xff, 0x20, 0x00, 0xde, 0xff, 0x1d, 0x00, 0xdb, 0xff, 0x1b, 0x00, 0xd9, 0xff, 0x19, 0x00, 0xd9, 0xff, 0x17, 0x00, 0xd9, 0xff, 0x13, 0x00, 0xdb, 0xff, 0x0d, 0x00, 0xdc, 0xff, 0x06, 0x00, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xfa, 0xff, 0xdd, 0xff, 0xf9, 0xff, 0xde, 0xff, 0xfb, 0xff, 0xdf, 0xff, 0xfe, 0xff, 0xe0, 0xff, 0x01, 0x00, 0xe1, 0xff, 0x02, 0x00, 0xe2, 0xff, 0x00, 0x00, 0xe4, 0xff, 0xfc, 0xff, 0xe6, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xee, 0xff, 0x02, 0x00, 0xee, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0c, 0x00, 0xf7, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x11, 0x00, 0xf3, 0xff, 0x13, 0x00, 0xf3, 0xff, 0x15, 0x00, 0xf5, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf9, 0xff, 0x1e, 0x00, 0xfc, 0xff, 0x22, 0x00, 0xfd, 0xff, 0x25, 0x00, 0xfd, 0xff, 0x26, 0x00, 0xfc, 0xff, 0x26, 0x00, 0xfa, 0xff, 0x26, 0x00, 0xf9, 0xff, 0x26, 0x00, 0xf9, 0xff, 0x27, 0x00, 0xfb, 0xff, 0x29, 0x00, 0xfe, 0xff, 0x2c, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x29, 0x00, 0x08, 0x00, 0x25, 0x00, 0x09, 0x00, 0x22, 0x00, 0x09, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x05, 0x00, 0x05, 0x00, 0x02, 0x00, 0x01, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xef, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xe9, 0xff, 0xf6, 0xff, 0xe7, 0xff, 0xf6, 0xff, 0xe5, 0xff, 0xf7, 0xff, 0xe2, 0xff, 0xf8, 0xff, 0xe0, 0xff, 0xf9, 0xff, 0xde, 0xff, 0xf9, 0xff, 0xdc, 0xff, 0xf7, 0xff, 0xda, 0xff, 0xf4, 0xff, 0xda, 0xff, 0xf3, 0xff, 0xd9, 0xff, 0xf2, 0xff, 0xd9, 0xff, 0xf3, 0xff, 0xd8, 0xff, 0xf5, 0xff, 0xd7, 0xff, 0xf8, 0xff, 0xd5, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xfa, 0xff, 0xd4, 0xff, 0xfa, 0xff, 0xd5, 0xff, 0xfa, 0xff, 0xd8, 0xff, 0xfa, 0xff, 0xdd, 0xff, 0xfa, 0xff, 0xe2, 0xff, 0xfa, 0xff, 0xe5, 0xff, 0xfb, 0xff, 0xe8, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x02, 0x00, 0xe6, 0xff, 0x04, 0x00, 0xe7, 0xff, 0x05, 0x00, 0xeb, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x06, 0x00, 0xff, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x0f, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x11, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xff, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xf5, 0xff, 0x12, 0x00, 0xf4, 0xff, 0x12, 0x00, 0xf5, 0xff, 0x12, 0x00, 0xf6, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xf5, 0xff, 0x11, 0x00, 0xf1, 0xff, 0x12, 0x00, 0xed, 0xff, 0x12, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xe7, 0xff, 0x11, 0x00, 0xe7, 0xff, 0x10, 0x00, 0xe8, 0xff, 0x0f, 0x00, 0xe9, 0xff, 0x0e, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x0e, 0x00, 0xe6, 0xff, 0x0e, 0x00, 0xe5, 0xff, 0x0e, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x0a, 0x00, 0xe6, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x05, 0x00, 0xec, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0d, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf2, 0xff, 0x0d, 0x00, 0xf2, 0xff, 0x0f, 0x00, 0xf1, 0xff, 0x12, 0x00, 0xef, 0xff, 0x15, 0x00, 0xed, 0xff, 0x16, 0x00, 0xeb, 0xff, 0x16, 0x00, 0xeb, 0xff, 0x13, 0x00, 0xea, 0xff, 0x10, 0x00, 0xea, 0xff, 0x0d, 0x00, 0xeb, 0xff, 0x0a, 0x00, 0xed, 0xff, 0x07, 0x00, 0xef, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x07, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfb, 0xff, 0x17, 0x00, 0xfc, 0xff, 0x1c, 0x00, 0xfd, 0xff, 0x20, 0x00, 0xff, 0xff, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0xfe, 0xff, 0x25, 0x00, 0xfc, 0xff, 0x26, 0x00, 0xf9, 0xff, 0x27, 0x00, 0xf7, 0xff, 0x29, 0x00, 0xf7, 0xff, 0x2b, 0x00, 0xf9, 0xff, 0x2e, 0x00, 0xfa, 0xff, 0x30, 0x00, 0xfb, 0xff, 0x31, 0x00, 0xf9, 0xff, 0x32, 0x00, 0xf6, 0xff, 0x32, 0x00, 0xf1, 0xff, 0x31, 0x00, 0xec, 0xff, 0x30, 0x00, 0xea, 0xff, 0x2e, 0x00, 0xeb, 0xff, 0x2c, 0x00, 0xec, 0xff, 0x2b, 0x00, 0xee, 0xff, 0x2a, 0x00, 0xef, 0xff, 0x28, 0x00, 0xed, 0xff, 0x25, 0x00, 0xe9, 0xff, 0x22, 0x00, 0xe5, 0xff, 0x1e, 0x00, 0xe2, 0xff, 0x1a, 0x00, 0xe0, 0xff, 0x15, 0x00, 0xe1, 0xff, 0x10, 0x00, 0xe3, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x06, 0x00, 0xe6, 0xff, 0x02, 0x00, 0xe5, 0xff, 0xfe, 0xff, 0xe4, 0xff, 0xfb, 0xff, 0xe2, 0xff, 0xf7, 0xff, 0xe1, 0xff, 0xf2, 0xff, 0xe2, 0xff, 0xec, 0xff, 0xe6, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xe1, 0xff, 0xf4, 0xff, 0xde, 0xff, 0xfc, 0xff, 0xdc, 0xff, 0x02, 0x00, 0xdc, 0xff, 0x07, 0x00, 0xdc, 0xff, 0x0a, 0x00, 0xdb, 0xff, 0x0c, 0x00, 0xda, 0xff, 0x0e, 0x00, 0xd8, 0xff, 0x10, 0x00, 0xd5, 0xff, 0x14, 0x00, 0xd2, 0xff, 0x1a, 0x00, 0xd1, 0xff, 0x22, 0x00, 0xd0, 0xff, 0x29, 0x00, 0xd2, 0xff, 0x2f, 0x00, 0xd4, 0xff, 0x31, 0x00, 0xd5, 0xff, 0x30, 0x00, 0xd7, 0xff, 0x2d, 0x00, 0xd7, 0xff, 0x28, 0x00, 0xd7, 0xff, 0x24, 0x00, 0xd7, 0xff, 0x23, 0x00, 0xd7, 0xff, 0x25, 0x00, 0xd8, 0xff, 0x27, 0x00, 0xda, 0xff, 0x28, 0x00, 0xdd, 0xff, 0x26, 0x00, 0xe1, 0xff, 0x21, 0x00, 0xe3, 0xff, 0x1a, 0x00, 0xe4, 0xff, 0x13, 0x00, 0xe3, 0xff, 0x0d, 0x00, 0xe1, 0xff, 0x0a, 0x00, 0xdf, 0xff, 0x09, 0x00, 0xe0, 0xff, 0x0a, 0x00, 0xe2, 0xff, 0x0b, 0x00, 0xe7, 0xff, 0x0a, 0x00, 0xed, 0xff, 0x08, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf5, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x02, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x13, 0x00, 0x07, 0x00, 0x19, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xfc, 0xff, 0x20, 0x00, 0xfb, 0xff, 0x23, 0x00, 0xfa, 0xff, 0x26, 0x00, 0xfb, 0xff, 0x2a, 0x00, 0xfc, 0xff, 0x2d, 0x00, 0xfb, 0xff, 0x2e, 0x00, 0xf8, 0xff, 0x2f, 0x00, 0xf4, 0xff, 0x2e, 0x00, 0xef, 0xff, 0x2c, 0x00, 0xeb, 0xff, 0x2a, 0x00, 0xe8, 0xff, 0x29, 0x00, 0xe6, 0xff, 0x28, 0x00, 0xe5, 0xff, 0x27, 0x00, 0xe4, 0xff, 0x27, 0x00, 0xe3, 0xff, 0x26, 0x00, 0xe1, 0xff, 0x25, 0x00, 0xe0, 0xff, 0x23, 0x00, 0xe0, 0xff, 0x20, 0x00, 0xe0, 0xff, 0x1c, 0x00, 0xe0, 0xff, 0x18, 0x00, 0xe1, 0xff, 0x14, 0x00, 0xe2, 0xff, 0x11, 0x00, 0xe3, 0xff, 0x0f, 0x00, 0xe3, 0xff, 0x0d, 0x00, 0xe3, 0xff, 0x0a, 0x00, 0xe5, 0xff, 0x06, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xee, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xed, 0xff, 0x01, 0x00, 0xe8, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x08, 0x00, 0xe5, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x0f, 0x00, 0xe1, 0xff, 0x13, 0x00, 0xde, 0xff, 0x18, 0x00, 0xd9, 0xff, 0x1d, 0x00, 0xd3, 0xff, 0x22, 0x00, 0xcf, 0xff, 0x26, 0x00, 0xcc, 0xff, 0x28, 0x00, 0xca, 0xff, 0x28, 0x00, 0xc8, 0xff, 0x27, 0x00, 0xc6, 0xff, 0x27, 0x00, 0xc5, 0xff, 0x26, 0x00, 0xc3, 0xff, 0x25, 0x00, 0xc0, 0xff, 0x25, 0x00, 0xbe, 0xff, 0x25, 0x00, 0xbc, 0xff, 0x25, 0x00, 0xbc, 0xff, 0x26, 0x00, 0xbd, 0xff, 0x26, 0x00, 0xc0, 0xff, 0x25, 0x00, 0xc4, 0xff, 0x23, 0x00, 0xc9, 0xff, 0x20, 0x00, 0xce, 0xff, 0x1d, 0x00, 0xd3, 0xff, 0x1a, 0x00, 0xd8, 0xff, 0x19, 0x00, 0xdb, 0xff, 0x18, 0x00, 0xdd, 0xff, 0x18, 0x00, 0xdf, 0xff, 0x18, 0x00, 0xe3, 0xff, 0x17, 0x00, 0xe8, 0xff, 0x16, 0x00, 0xf0, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x11, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x09, 0x00, 0x05, 0x00, 0x07, 0x00, 0x04, 0x00, 0x09, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x15, 0x00, 0xff, 0xff, 0x1c, 0x00, 0xfc, 0xff, 0x20, 0x00, 0xfa, 0xff, 0x21, 0x00, 0xf7, 0xff, 0x1f, 0x00, 0xf5, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xef, 0xff, 0x1d, 0x00, 0xec, 0xff, 0x21, 0x00, 0xe9, 0xff, 0x27, 0x00, 0xe6, 0xff, 0x2c, 0x00, 0xe2, 0xff, 0x30, 0x00, 0xdd, 0xff, 0x30, 0x00, 0xd9, 0xff, 0x2f, 0x00, 0xd4, 0xff, 0x2d, 0x00, 0xd2, 0xff, 0x2c, 0x00, 0xd0, 0xff, 0x2d, 0x00, 0xd1, 0xff, 0x30, 0x00, 0xd2, 0xff, 0x33, 0x00, 0xd4, 0xff, 0x36, 0x00, 0xd5, 0xff, 0x38, 0x00, 0xd5, 0xff, 0x38, 0x00, 0xd5, 0xff, 0x36, 0x00, 0xd5, 0xff, 0x33, 0x00, 0xd6, 0xff, 0x31, 0x00, 0xd9, 0xff, 0x2f, 0x00, 0xdd, 0xff, 0x2e, 0x00, 0xe2, 0xff, 0x2e, 0x00, 0xe7, 0xff, 0x2c, 0x00, 0xec, 0xff, 0x2b, 0x00, 0xef, 0xff, 0x28, 0x00, 0xf3, 0xff, 0x25, 0x00, 0xf6, 0xff, 0x21, 0x00, 0xf8, 0xff, 0x1c, 0x00, 0xfa, 0xff, 0x17, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x05, 0x00, 0x01, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xef, 0xff, 0x07, 0x00, 0xeb, 0xff, 0x07, 0x00, 0xea, 0xff, 0x07, 0x00, 0xea, 0xff, 0x0a, 0x00, 0xeb, 0xff, 0x0e, 0x00, 0xec, 0xff, 0x11, 0x00, 0xec, 0xff, 0x13, 0x00, 0xeb, 0xff, 0x13, 0x00, 0xea, 0xff, 0x13, 0x00, 0xe8, 0xff, 0x11, 0x00, 0xe8, 0xff, 0x11, 0x00, 0xea, 0xff, 0x12, 0x00, 0xed, 0xff, 0x15, 0x00, 0xf1, 0xff, 0x19, 0x00, 0xf4, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1e, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf9, 0xff, 0x1e, 0x00, 0xfa, 0xff, 0x1d, 0x00, 0xfb, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x18, 0x00, 0xff, 0xff, 0x16, 0x00, 0x01, 0x00, 0x14, 0x00, 0x02, 0x00, 0x12, 0x00, 0x03, 0x00, 0x11, 0x00, 0x04, 0x00, 0x10, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x0b, 0x00, 0xef, 0xff, 0x0b, 0x00, 0xed, 0xff, 0x0b, 0x00, 0xea, 0xff, 0x0b, 0x00, 0xe6, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x0d, 0x00, 0xe2, 0xff, 0x0f, 0x00, 0xe2, 0xff, 0x11, 0x00, 0xe3, 0xff, 0x12, 0x00, 0xe4, 0xff, 0x12, 0x00, 0xe3, 0xff, 0x10, 0x00, 0xe1, 0xff, 0x0e, 0x00, 0xde, 0xff, 0x0c, 0x00, 0xdd, 0xff, 0x0b, 0x00, 0xdb, 0xff, 0x0a, 0x00, 0xdb, 0xff, 0x0b, 0x00, 0xdc, 0xff, 0x0a, 0x00, 0xdd, 0xff, 0x08, 0x00, 0xde, 0xff, 0x04, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xfb, 0xff, 0xe1, 0xff, 0xf7, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xe4, 0xff, 0xf5, 0xff, 0xe6, 0xff, 0xf4, 0xff, 0xe8, 0xff, 0xf3, 0xff, 0xea, 0xff, 0xf0, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xee, 0xff, 0xe6, 0xff, 0xf1, 0xff, 0xe1, 0xff, 0xf5, 0xff, 0xdd, 0xff, 0xfa, 0xff, 0xdb, 0xff, 0xfe, 0xff, 0xda, 0xff, 0x02, 0x00, 0xda, 0xff, 0x05, 0x00, 0xda, 0xff, 0x07, 0x00, 0xdb, 0xff, 0x0a, 0x00, 0xda, 0xff, 0x0d, 0x00, 0xda, 0xff, 0x11, 0x00, 0xd9, 0xff, 0x15, 0x00, 0xd9, 0xff, 0x19, 0x00, 0xda, 0xff, 0x1d, 0x00, 0xdb, 0xff, 0x1f, 0x00, 0xdc, 0xff, 0x21, 0x00, 0xde, 0xff, 0x22, 0x00, 0xe1, 0xff, 0x24, 0x00, 0xe3, 0xff, 0x27, 0x00, 0xe5, 0xff, 0x29, 0x00, 0xe7, 0xff, 0x2b, 0x00, 0xe8, 0xff, 0x2c, 0x00, 0xea, 0xff, 0x2d, 0x00, 0xeb, 0xff, 0x2d, 0x00, 0xec, 0xff, 0x2e, 0x00, 0xee, 0xff, 0x30, 0x00, 0xf0, 0xff, 0x32, 0x00, 0xf2, 0xff, 0x33, 0x00, 0xf4, 0xff, 0x34, 0x00, 0xf4, 0xff, 0x34, 0x00, 0xf5, 0xff, 0x32, 0x00, 0xf7, 0xff, 0x30, 0x00, 0xf9, 0xff, 0x2e, 0x00, 0xfc, 0xff, 0x2d, 0x00, 0xff, 0xff, 0x2d, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x07, 0x00, 0x2e, 0x00, 0x0b, 0x00, 0x2d, 0x00, 0x0e, 0x00, 0x2b, 0x00, 0x10, 0x00, 0x28, 0x00, 0x13, 0x00, 0x25, 0x00, 0x16, 0x00, 0x21, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x22, 0x00, 0x19, 0x00, 0x26, 0x00, 0x16, 0x00, 0x29, 0x00, 0x14, 0x00, 0x2b, 0x00, 0x10, 0x00, 0x2d, 0x00, 0x0c, 0x00, 0x2e, 0x00, 0x07, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x2e, 0x00, 0xfd, 0xff, 0x2e, 0x00, 0xf9, 0xff, 0x2d, 0x00, 0xf6, 0xff, 0x2c, 0x00, 0xf4, 0xff, 0x2b, 0x00, 0xf1, 0xff, 0x29, 0x00, 0xee, 0xff, 0x27, 0x00, 0xea, 0xff, 0x24, 0x00, 0xe7, 0xff, 0x21, 0x00, 0xe4, 0xff, 0x1e, 0x00, 0xe1, 0xff, 0x1b, 0x00, 0xde, 0xff, 0x17, 0x00, 0xdb, 0xff, 0x13, 0x00, 0xd7, 0xff, 0x0e, 0x00, 0xd5, 0xff, 0x08, 0x00, 0xd5, 0xff, 0x02, 0x00, 0xd6, 0xff, 0xfc, 0xff, 0xd7, 0xff, 0xf7, 0xff, 0xd9, 0xff, 0xf3, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xd8, 0xff, 0xef, 0xff, 0xd6, 0xff, 0xed, 0xff, 0xd3, 0xff, 0xea, 0xff, 0xd2, 0xff, 0xe6, 0xff, 0xd2, 0xff, 0xe1, 0xff, 0xd5, 0xff, 0xdc, 0xff, 0xd8, 0xff, 0xd6, 0xff, 0xdc, 0xff, 0xd0, 0xff, 0xdf, 0xff, 0xcc, 0xff, 0xe1, 0xff, 0xcb, 0xff, 0xe1, 0xff, 0xca, 0xff, 0xe1, 0xff, 0xca, 0xff, 0xe1, 0xff, 0xca, 0xff, 0xe4, 0xff, 0xc8, 0xff, 0xe8, 0xff, 0xc6, 0xff, 0xec, 0xff, 0xc5, 0xff, 0xf0, 0xff, 0xc4, 0xff, 0xf3, 0xff, 0xc6, 0xff, 0xf6, 0xff, 0xc9, 0xff, 0xf7, 0xff, 0xcd, 0xff, 0xfa, 0xff, 0xd3, 0xff, 0xfd, 0xff, 0xd8, 0xff, 0x00, 0x00, 0xde, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x08, 0x00, 0xe4, 0xff, 0x0b, 0x00, 0xe5, 0xff, 0x0e, 0x00, 0xe6, 0xff, 0x10, 0x00, 0xe8, 0xff, 0x13, 0x00, 0xeb, 0xff, 0x16, 0x00, 0xf0, 0xff, 0x1b, 0x00, 0xf6, 0xff, 0x1e, 0x00, 0xfc, 0xff, 0x21, 0x00, 0x02, 0x00, 0x22, 0x00, 0x05, 0x00, 0x23, 0x00, 0x08, 0x00, 0x23, 0x00, 0x09, 0x00, 0x23, 0x00, 0x0a, 0x00, 0x24, 0x00, 0x0c, 0x00, 0x25, 0x00, 0x10, 0x00, 0x26, 0x00, 0x16, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x24, 0x00, 0x21, 0x00, 0x2a, 0x00, 0x1d, 0x00, 0x2e, 0x00, 0x19, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x2f, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x13, 0x00, 0x2f, 0x00, 0x11, 0x00, 0x31, 0x00, 0x0f, 0x00, 0x34, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x0b, 0x00, 0x3a, 0x00, 0x09, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x3a, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x36, 0x00, 0xfe, 0xff, 0x33, 0x00, 0xfc, 0xff, 0x31, 0x00, 0xfb, 0xff, 0x30, 0x00, 0xfb, 0xff, 0x30, 0x00, 0xfb, 0xff, 0x2f, 0x00, 0xfa, 0xff, 0x2d, 0x00, 0xf6, 0xff, 0x2a, 0x00, 0xf1, 0xff, 0x27, 0x00, 0xec, 0xff, 0x24, 0x00, 0xe6, 0xff, 0x20, 0x00, 0xe1, 0xff, 0x1d, 0x00, 0xde, 0xff, 0x19, 0x00, 0xdd, 0xff, 0x15, 0x00, 0xdd, 0xff, 0x11, 0x00, 0xdd, 0xff, 0x0c, 0x00, 0xdb, 0xff, 0x08, 0x00, 0xd8, 0xff, 0x03, 0x00, 0xd4, 0xff, 0xfe, 0xff, 0xd2, 0xff, 0xfa, 0xff, 0xd1, 0xff, 0xf6, 0xff, 0xd2, 0xff, 0xf4, 0xff, 0xd5, 0xff, 0xf3, 0xff, 0xd8, 0xff, 0xf2, 0xff, 0xda, 0xff, 0xf0, 0xff, 0xdb, 0xff, 0xee, 0xff, 0xda, 0xff, 0xec, 0xff, 0xda, 0xff, 0xea, 0xff, 0xdc, 0xff, 0xea, 0xff, 0xdf, 0xff, 0xe9, 0xff, 0xe4, 0xff, 0xe9, 0xff, 0xea, 0xff, 0xe9, 0xff, 0xef, 0xff, 0xe9, 0xff, 0xf3, 0xff, 0xe8, 0xff, 0xf6, 0xff, 0xe6, 0xff, 0xfa, 0xff, 0xe4, 0xff, 0xfe, 0xff, 0xe3, 0xff, 0x03, 0x00, 0xe2, 0xff, 0x09, 0x00, 0xe2, 0xff, 0x0f, 0x00, 0xe3, 0xff, 0x15, 0x00, 0xe3, 0xff, 0x19, 0x00, 0xe4, 0xff, 0x1c, 0x00, 0xe3, 0xff, 0x20, 0x00, 0xe3, 0xff, 0x23, 0x00, 0xe4, 0xff, 0x27, 0x00, 0xe5, 0xff, 0x2b, 0x00, 0xe8, 0xff, 0x2e, 0x00, 0xeb, 0xff, 0x2f, 0x00, 0xef, 0xff, 0x2f, 0x00, 0xf2, 0xff, 0x2e, 0x00, 0xf3, 0xff, 0x2c, 0x00, 0xf4, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x2b, 0x00, 0xf6, 0xff, 0x2c, 0x00, 0xf8, 0xff, 0x2b, 0x00, 0xfb, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x27, 0x00, 0x09, 0x00, 0x25, 0x00, 0x0d, 0x00, 0x24, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x0f, 0x00, 0x23, 0x00, 0x0f, 0x00, 0x23, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x19, 0x00, 0x18, 0x00, 0x17, 0x00, 0x1b, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x1d, 0x00, 0xff, 0xff, 0x1c, 0x00, 0xfa, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf6, 0xff, 0x1f, 0x00, 0xf4, 0xff, 0x21, 0x00, 0xf1, 0xff, 0x22, 0x00, 0xee, 0xff, 0x21, 0x00, 0xeb, 0xff, 0x20, 0x00, 0xe7, 0xff, 0x1d, 0x00, 0xe4, 0xff, 0x1a, 0x00, 0xe2, 0xff, 0x19, 0x00, 0xe0, 0xff, 0x18, 0x00, 0xde, 0xff, 0x18, 0x00, 0xdc, 0xff, 0x18, 0x00, 0xdb, 0xff, 0x18, 0x00, 0xda, 0xff, 0x17, 0x00, 0xda, 0xff, 0x15, 0x00, 0xd9, 0xff, 0x13, 0x00, 0xd8, 0xff, 0x0f, 0x00, 0xd6, 0xff, 0x0b, 0x00, 0xd3, 0xff, 0x07, 0x00, 0xd1, 0xff, 0x04, 0x00, 0xd0, 0xff, 0x02, 0x00, 0xd0, 0xff, 0x01, 0x00, 0xd2, 0xff, 0x00, 0x00, 0xd5, 0xff, 0x00, 0x00, 0xd8, 0xff, 0xfe, 0xff, 0xda, 0xff, 0xfc, 0xff, 0xdb, 0xff, 0xf8, 0xff, 0xdb, 0xff, 0xf3, 0xff, 0xdb, 0xff, 0xef, 0xff, 0xdd, 0xff, 0xec, 0xff, 0xe1, 0xff, 0xeb, 0xff, 0xe6, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xeb, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xec, 0xff, 0xf5, 0xff, 0xea, 0xff, 0xf8, 0xff, 0xe8, 0xff, 0xfb, 0xff, 0xe5, 0xff, 0xff, 0xff, 0xe3, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x0b, 0x00, 0xe2, 0xff, 0x10, 0x00, 0xe3, 0xff, 0x15, 0x00, 0xe4, 0xff, 0x18, 0x00, 0xe5, 0xff, 0x1a, 0x00, 0xe6, 0xff, 0x1d, 0x00, 0xe5, 0xff, 0x20, 0x00, 0xe4, 0xff, 0x23, 0x00, 0xe2, 0xff, 0x27, 0x00, 0xe1, 0xff, 0x2a, 0x00, 0xe0, 0xff, 0x2c, 0x00, 0xdf, 0xff, 0x2b, 0x00, 0xde, 0xff, 0x2a, 0x00, 0xde, 0xff, 0x29, 0x00, 0xdd, 0xff, 0x29, 0x00, 0xdd, 0xff, 0x29, 0x00, 0xdc, 0xff, 0x2a, 0x00, 0xdc, 0xff, 0x2b, 0x00, 0xdc, 0xff, 0x2a, 0x00, 0xdd, 0xff, 0x27, 0x00, 0xdd, 0xff, 0x23, 0x00, 0xdf, 0xff, 0x1e, 0x00, 0xe2, 0xff, 0x1a, 0x00, 0xe6, 0xff, 0x18, 0x00, 0xeb, 0xff, 0x17, 0x00, 0xf0, 0xff, 0x16, 0x00, 0xf5, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x10, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x09, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xf7, 0xff, 0x12, 0x00, 0xf5, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x0d, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xec, 0xff, 0x08, 0x00, 0xea, 0xff, 0x07, 0x00, 0xe7, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x08, 0x00, 0xe5, 0xff, 0x08, 0x00, 0xe3, 0xff, 0x08, 0x00, 0xe1, 0xff, 0x05, 0x00, 0xdf, 0xff, 0x01, 0x00, 0xdb, 0xff, 0xfc, 0xff, 0xd7, 0xff, 0xf9, 0xff, 0xd4, 0xff, 0xf7, 0xff, 0xd2, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf7, 0xff, 0xd1, 0xff, 0xf5, 0xff, 0xd3, 0xff, 0xf4, 0xff, 0xd7, 0xff, 0xf3, 0xff, 0xdc, 0xff, 0xf4, 0xff, 0xe2, 0xff, 0xf6, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x17, 0x00, 0xfe, 0xff, 0x1b, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x04, 0x00, 0x21, 0x00, 0x05, 0x00, 0x22, 0x00, 0x06, 0x00, 0x24, 0x00, 0x04, 0x00, 0x26, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0x00, 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x04, 0x00, 0x29, 0x00, 0x08, 0x00, 0x27, 0x00, 0x0b, 0x00, 0x26, 0x00, 0x0d, 0x00, 0x23, 0x00, 0x0d, 0x00, 0x21, 0x00, 0x0c, 0x00, 0x1e, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x1a, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17, 0x00, 0x13, 0x00, 0x19, 0x00, 0x10, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x1a, 0x00, 0x0b, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x1b, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x09, 0x00, 0x18, 0x00, 0x09, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x06, 0x00, 0x08, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf5, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xee, 0xff, 0xf4, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xe5, 0xff, 0xfb, 0xff, 0xe3, 0xff, 0xfb, 0xff, 0xe1, 0xff, 0xfa, 0xff, 0xe0, 0xff, 0xf9, 0xff, 0xdf, 0xff, 0xf8, 0xff, 0xdf, 0xff, 0xf9, 0xff, 0xdf, 0xff, 0xfa, 0xff, 0xdf, 0xff, 0xfd, 0xff, 0xde, 0xff, 0x01, 0x00, 0xde, 0xff, 0x03, 0x00, 0xdd, 0xff, 0x03, 0x00, 0xde, 0xff, 0x01, 0x00, 0xdf, 0xff, 0xfe, 0xff, 0xe1, 0xff, 0xfb, 0xff, 0xe3, 0xff, 0xf9, 0xff, 0xe5, 0xff, 0xfa, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xe9, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xed, 0xff, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0x01, 0x00, 0x06, 0x00, 0x04, 0x00, 0x09, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x11, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x07, 0x00, 0x16, 0x00, 0x02, 0x00, 0x15, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x15, 0x00, 0xfb, 0xff, 0x17, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x18, 0x00, 0xf5, 0xff, 0x16, 0x00, 0xf4, 0xff, 0x14, 0x00, 0xf6, 0xff, 0x11, 0x00, 0xf7, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x0b, 0x00, 0x02, 0x00, 0x08, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x0c, 0x00, 0xf1, 0xff, 0x0c, 0x00, 0xf1, 0xff, 0x0d, 0x00, 0xf0, 0xff, 0x0e, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xee, 0xff, 0x0e, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xe5, 0xff, 0x09, 0x00, 0xe0, 0xff, 0x07, 0x00, 0xdb, 0xff, 0x07, 0x00, 0xd9, 0xff, 0x07, 0x00, 0xd8, 0xff, 0x09, 0x00, 0xda, 0xff, 0x0b, 0x00, 0xdb, 0xff, 0x0c, 0x00, 0xdb, 0xff, 0x0c, 0x00, 0xda, 0xff, 0x0c, 0x00, 0xd8, 0xff, 0x0c, 0x00, 0xd6, 0xff, 0x0c, 0x00, 0xd3, 0xff, 0x0e, 0x00, 0xd2, 0xff, 0x10, 0x00, 0xd3, 0xff, 0x13, 0x00, 0xd5, 0xff, 0x16, 0x00, 0xd8, 0xff, 0x19, 0x00, 0xdb, 0xff, 0x1c, 0x00, 0xdc, 0xff, 0x1e, 0x00, 0xdc, 0xff, 0x21, 0x00, 0xda, 0xff, 0x22, 0x00, 0xd9, 0xff, 0x23, 0x00, 0xda, 0xff, 0x22, 0x00, 0xdd, 0xff, 0x20, 0x00, 0xe1, 0xff, 0x1f, 0x00, 0xe6, 0xff, 0x1f, 0x00, 0xea, 0xff, 0x1f, 0x00, 0xed, 0xff, 0x1f, 0x00, 0xee, 0xff, 0x1e, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x08, 0x00, 0x17, 0x00, 0x08, 0x00, 0x19, 0x00, 0x06, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0xfd, 0xff, 0x24, 0x00, 0xfb, 0xff, 0x28, 0x00, 0xfa, 0xff, 0x2c, 0x00, 0xfa, 0xff, 0x2f, 0x00, 0xf9, 0xff, 0x30, 0x00, 0xf8, 0xff, 0x2f, 0x00, 0xf7, 0xff, 0x2d, 0x00, 0xf6, 0xff, 0x2c, 0x00, 0xf4, 0xff, 0x2a, 0x00, 0xf3, 0xff, 0x2a, 0x00, 0xf3, 0xff, 0x2b, 0x00, 0xf3, 0xff, 0x2c, 0x00, 0xf3, 0xff, 0x2d, 0x00, 0xf3, 0xff, 0x2c, 0x00, 0xf2, 0xff, 0x2b, 0x00, 0xf2, 0xff, 0x28, 0x00, 0xf2, 0xff, 0x25, 0x00, 0xf2, 0xff, 0x21, 0x00, 0xf1, 0xff, 0x1e, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xef, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x1b, 0x00, 0xec, 0xff, 0x19, 0x00, 0xea, 0xff, 0x17, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xe9, 0xff, 0x0e, 0x00, 0xe8, 0xff, 0x09, 0x00, 0xe7, 0xff, 0x06, 0x00, 0xe6, 0xff, 0x03, 0x00, 0xe4, 0xff, 0x02, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xe4, 0xff, 0xfc, 0xff, 0xe4, 0xff, 0xf7, 0xff, 0xe6, 0xff, 0xf0, 0xff, 0xe7, 0xff, 0xe9, 0xff, 0xe9, 0xff, 0xe3, 0xff, 0xea, 0xff, 0xdf, 0xff, 0xea, 0xff, 0xde, 0xff, 0xea, 0xff, 0xdd, 0xff, 0xeb, 0xff, 0xdd, 0xff, 0xed, 0xff, 0xdb, 0xff, 0xf1, 0xff, 0xd8, 0xff, 0xf5, 0xff, 0xd4, 0xff, 0xf8, 0xff, 0xd0, 0xff, 0xf9, 0xff, 0xcd, 0xff, 0xfa, 0xff, 0xcb, 0xff, 0xf9, 0xff, 0xcb, 0xff, 0xf9, 0xff, 0xcc, 0xff, 0xf9, 0xff, 0xcd, 0xff, 0xfa, 0xff, 0xcf, 0xff, 0xfb, 0xff, 0xd0, 0xff, 0xfe, 0xff, 0xd1, 0xff, 0x00, 0x00, 0xd2, 0xff, 0x03, 0x00, 0xd3, 0xff, 0x05, 0x00, 0xd4, 0xff, 0x06, 0x00, 0xd6, 0xff, 0x08, 0x00, 0xd8, 0xff, 0x09, 0x00, 0xd9, 0xff, 0x0b, 0x00, 0xdb, 0xff, 0x0c, 0x00, 0xde, 0xff, 0x0d, 0x00, 0xe1, 0xff, 0x0f, 0x00, 0xe6, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x11, 0x00, 0xf0, 0xff, 0x11, 0x00, 0xf3, 0xff, 0x11, 0x00, 0xf6, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x11, 0x00, 0x05, 0x00, 0x16, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0xfc, 0xff, 0x23, 0x00, 0xf9, 0xff, 0x26, 0x00, 0xf6, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x30, 0x00, 0xf4, 0xff, 0x35, 0x00, 0xf4, 0xff, 0x37, 0x00, 0xf3, 0xff, 0x37, 0x00, 0xf2, 0xff, 0x35, 0x00, 0xf0, 0xff, 0x32, 0x00, 0xef, 0xff, 0x2e, 0x00, 0xed, 0xff, 0x2b, 0x00, 0xec, 0xff, 0x2a, 0x00, 0xed, 0xff, 0x2a, 0x00, 0xee, 0xff, 0x2a, 0x00, 0xf0, 0xff, 0x29, 0x00, 0xf1, 0xff, 0x28, 0x00, 0xf2, 0xff, 0x24, 0x00, 0xf4, 0xff, 0x1e, 0x00, 0xf7, 0xff, 0x16, 0x00, 0xfb, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x07, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf2, 0xff, 0x0a, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xe7, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x0a, 0x00, 0xe3, 0xff, 0x08, 0x00, 0xe3, 0xff, 0x07, 0x00, 0xe3, 0xff, 0x07, 0x00, 0xe1, 0xff, 0x07, 0x00, 0xde, 0xff, 0x08, 0x00, 0xd9, 0xff, 0x09, 0x00, 0xd4, 0xff, 0x09, 0x00, 0xd1, 0xff, 0x08, 0x00, 0xcf, 0xff, 0x08, 0x00, 0xd0, 0xff, 0x08, 0x00, 0xd0, 0xff, 0x09, 0x00, 0xd0, 0xff, 0x0c, 0x00, 0xd0, 0xff, 0x0f, 0x00, 0xce, 0xff, 0x12, 0x00, 0xcd, 0xff, 0x13, 0x00, 0xcd, 0xff, 0x14, 0x00, 0xcf, 0xff, 0x14, 0x00, 0xd2, 0xff, 0x13, 0x00, 0xd5, 0xff, 0x12, 0x00, 0xd7, 0xff, 0x11, 0x00, 0xda, 0xff, 0x10, 0x00, 0xdc, 0xff, 0x0f, 0x00, 0xdf, 0xff, 0x0c, 0x00, 0xe3, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x17, 0x00, 0xf0, 0xff, 0x1d, 0x00, 0xed, 0xff, 0x23, 0x00, 0xeb, 0xff, 0x2a, 0x00, 0xeb, 0xff, 0x2f, 0x00, 0xeb, 0xff, 0x34, 0x00, 0xeb, 0xff, 0x38, 0x00, 0xea, 0xff, 0x3b, 0x00, 0xe8, 0xff, 0x3d, 0x00, 0xe7, 0xff, 0x3f, 0x00, 0xe7, 0xff, 0x40, 0x00, 0xe6, 0xff, 0x40, 0x00, 0xe6, 0xff, 0x40, 0x00, 0xe5, 0xff, 0x40, 0x00, 0xe3, 0xff, 0x40, 0x00, 0xe2, 0xff, 0x41, 0x00, 0xe1, 0xff, 0x41, 0x00, 0xe2, 0xff, 0x41, 0x00, 0xe4, 0xff, 0x40, 0x00, 0xe6, 0xff, 0x3d, 0x00, 0xe9, 0xff, 0x3a, 0x00, 0xea, 0xff, 0x36, 0x00, 0xeb, 0xff, 0x32, 0x00, 0xea, 0xff, 0x2d, 0x00, 0xea, 0xff, 0x2a, 0x00, 0xeb, 0xff, 0x26, 0x00, 0xed, 0xff, 0x23, 0x00, 0xf0, 0xff, 0x20, 0x00, 0xf2, 0xff, 0x1c, 0x00, 0xf3, 0xff, 0x18, 0x00, 0xf3, 0xff, 0x12, 0x00, 0xf2, 0xff, 0x0b, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf1, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe2, 0xff, 0xfc, 0xff, 0xdc, 0xff, 0xfd, 0xff, 0xd5, 0xff, 0xff, 0xff, 0xce, 0xff, 0x02, 0x00, 0xc8, 0xff, 0x06, 0x00, 0xc5, 0xff, 0x0a, 0x00, 0xc3, 0xff, 0x0d, 0x00, 0xc2, 0xff, 0x0f, 0x00, 0xc2, 0xff, 0x11, 0x00, 0xc0, 0xff, 0x12, 0x00, 0xbc, 0xff, 0x12, 0x00, 0xb7, 0xff, 0x13, 0x00, 0xb3, 0xff, 0x13, 0x00, 0xaf, 0xff, 0x12, 0x00, 0xae, 0xff, 0x10, 0x00, 0xb0, 0xff, 0x0e, 0x00, 0xb4, 0xff, 0x0c, 0x00, 0xb9, 0xff, 0x0a, 0x00, 0xbd, 0xff, 0x0a, 0x00, 0xc0, 0xff, 0x0b, 0x00, 0xc2, 0xff, 0x0b, 0x00, 0xc3, 0xff, 0x0b, 0x00, 0xc5, 0xff, 0x0b, 0x00, 0xc8, 0xff, 0x0b, 0x00, 0xcc, 0xff, 0x0b, 0x00, 0xd3, 0xff, 0x0d, 0x00, 0xda, 0xff, 0x0e, 0x00, 0xe1, 0xff, 0x0f, 0x00, 0xe8, 0xff, 0x10, 0x00, 0xee, 0xff, 0x10, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xff, 0xff, 0x10, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x1a, 0x00, 0x09, 0x00, 0x21, 0x00, 0x07, 0x00, 0x28, 0x00, 0x04, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x36, 0x00, 0x01, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x46, 0x00, 0x01, 0x00, 0x46, 0x00, 0x02, 0x00, 0x46, 0x00, 0x04, 0x00, 0x48, 0x00, 0x05, 0x00, 0x49, 0x00, 0x05, 0x00, 0x4a, 0x00, 0x06, 0x00, 0x4a, 0x00, 0x07, 0x00, 0x49, 0x00, 0x08, 0x00, 0x46, 0x00, 0x0b, 0x00, 0x40, 0x00, 0x0e, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x34, 0x00, 0x12, 0x00, 0x2f, 0x00, 0x13, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x28, 0x00, 0x13, 0x00, 0x25, 0x00, 0x12, 0x00, 0x21, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x11, 0x00, 0x18, 0x00, 0x13, 0x00, 0x12, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x07, 0x00, 0x19, 0x00, 0x02, 0x00, 0x19, 0x00, 0xfe, 0xff, 0x19, 0x00, 0xfa, 0xff, 0x19, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x1b, 0x00, 0xf1, 0xff, 0x1d, 0x00, 0xed, 0xff, 0x1e, 0x00, 0xe9, 0xff, 0x1e, 0x00, 0xe5, 0xff, 0x1e, 0x00, 0xe0, 0xff, 0x1d, 0x00, 0xdc, 0xff, 0x1b, 0x00, 0xd7, 0xff, 0x19, 0x00, 0xd4, 0xff, 0x18, 0x00, 0xd1, 0xff, 0x17, 0x00, 0xcf, 0xff, 0x17, 0x00, 0xcc, 0xff, 0x16, 0x00, 0xca, 0xff, 0x15, 0x00, 0xc7, 0xff, 0x13, 0x00, 0xc5, 0xff, 0x11, 0x00, 0xc3, 0xff, 0x10, 0x00, 0xc2, 0xff, 0x0f, 0x00, 0xc1, 0xff, 0x0e, 0x00, 0xc0, 0xff, 0x0d, 0x00, 0xc0, 0xff, 0x0a, 0x00, 0xc1, 0xff, 0x06, 0x00, 0xc2, 0xff, 0x01, 0x00, 0xc3, 0xff, 0xfe, 0xff, 0xc5, 0xff, 0xfc, 0xff, 0xc7, 0xff, 0xfc, 0xff, 0xcb, 0xff, 0xfe, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xd4, 0xff, 0xfd, 0xff, 0xda, 0xff, 0xfa, 0xff, 0xe1, 0xff, 0xf4, 0xff, 0xe9, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xed, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf6, 0xff, 0x14, 0x00, 0xf7, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x1f, 0x00, 0xf5, 0xff, 0x25, 0x00, 0xf5, 0xff, 0x2b, 0x00, 0xf5, 0xff, 0x31, 0x00, 0xf7, 0xff, 0x36, 0x00, 0xfa, 0xff, 0x3a, 0x00, 0xfc, 0xff, 0x3b, 0x00, 0xfe, 0xff, 0x3c, 0x00, 0xff, 0xff, 0x3d, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x41, 0x00, 0xfa, 0xff, 0x44, 0x00, 0xf8, 0xff, 0x47, 0x00, 0xf6, 0xff, 0x4a, 0x00, 0xf5, 0xff, 0x4b, 0x00, 0xf6, 0xff, 0x4c, 0x00, 0xf6, 0xff, 0x4b, 0x00, 0xf5, 0xff, 0x4a, 0x00, 0xf3, 0xff, 0x4a, 0x00, 0xef, 0xff, 0x49, 0x00, 0xeb, 0xff, 0x48, 0x00, 0xe8, 0xff, 0x46, 0x00, 0xe6, 0xff, 0x43, 0x00, 0xe6, 0xff, 0x40, 0x00, 0xe7, 0xff, 0x3c, 0x00, 0xe9, 0xff, 0x38, 0x00, 0xea, 0xff, 0x34, 0x00, 0xeb, 0xff, 0x30, 0x00, 0xeb, 0xff, 0x2c, 0x00, 0xeb, 0xff, 0x27, 0x00, 0xec, 0xff, 0x22, 0x00, 0xee, 0xff, 0x1d, 0x00, 0xf0, 0xff, 0x19, 0x00, 0xf3, 0xff, 0x15, 0x00, 0xf4, 0xff, 0x12, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf4, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf7, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf3, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xe4, 0xff, 0xed, 0xff, 0xe1, 0xff, 0xeb, 0xff, 0xde, 0xff, 0xec, 0xff, 0xd9, 0xff, 0xed, 0xff, 0xd3, 0xff, 0xee, 0xff, 0xcd, 0xff, 0xed, 0xff, 0xc7, 0xff, 0xea, 0xff, 0xc4, 0xff, 0xe5, 0xff, 0xc2, 0xff, 0xe2, 0xff, 0xc3, 0xff, 0xe0, 0xff, 0xc6, 0xff, 0xdf, 0xff, 0xca, 0xff, 0xe1, 0xff, 0xcc, 0xff, 0xe3, 0xff, 0xcd, 0xff, 0xe5, 0xff, 0xcc, 0xff, 0xe5, 0xff, 0xcb, 0xff, 0xe4, 0xff, 0xcb, 0xff, 0xe3, 0xff, 0xcb, 0xff, 0xe1, 0xff, 0xce, 0xff, 0xe0, 0xff, 0xd2, 0xff, 0xe1, 0xff, 0xd7, 0xff, 0xe3, 0xff, 0xdc, 0xff, 0xe4, 0xff, 0xe1, 0xff, 0xe6, 0xff, 0xe4, 0xff, 0xe8, 0xff, 0xe6, 0xff, 0xe9, 0xff, 0xe8, 0xff, 0xea, 0xff, 0xea, 0xff, 0xeb, 0xff, 0xed, 0xff, 0xec, 0xff, 0xf0, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xfd, 0xff, 0xee, 0xff, 0x02, 0x00, 0xee, 0xff, 0x08, 0x00, 0xef, 0xff, 0x0d, 0x00, 0xf0, 0xff, 0x12, 0x00, 0xf1, 0xff, 0x15, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf6, 0xff, 0x1a, 0x00, 0xf8, 0xff, 0x1c, 0x00, 0xfb, 0xff, 0x1f, 0x00, 0xfe, 0xff, 0x22, 0x00, 0x01, 0x00, 0x25, 0x00, 0x03, 0x00, 0x27, 0x00, 0x06, 0x00, 0x28, 0x00, 0x09, 0x00, 0x29, 0x00, 0x0d, 0x00, 0x2a, 0x00, 0x11, 0x00, 0x29, 0x00, 0x17, 0x00, 0x2a, 0x00, 0x1d, 0x00, 0x2a, 0x00, 0x22, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x2c, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2b, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x26, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x31, 0x00, 0x23, 0x00, 0x34, 0x00, 0x21, 0x00, 0x37, 0x00, 0x1f, 0x00, 0x38, 0x00, 0x1b, 0x00, 0x37, 0x00, 0x16, 0x00, 0x34, 0x00, 0x10, 0x00, 0x30, 0x00, 0x0a, 0x00, 0x2d, 0x00, 0x04, 0x00, 0x2c, 0x00, 0xfe, 0xff, 0x2c, 0x00, 0xf8, 0xff, 0x2c, 0x00, 0xf2, 0xff, 0x2b, 0x00, 0xeb, 0xff, 0x29, 0x00, 0xe4, 0xff, 0x25, 0x00, 0xdc, 0xff, 0x21, 0x00, 0xd4, 0xff, 0x1d, 0x00, 0xcd, 0xff, 0x1b, 0x00, 0xc8, 0xff, 0x19, 0x00, 0xc4, 0xff, 0x18, 0x00, 0xc1, 0xff, 0x17, 0x00, 0xbd, 0xff, 0x16, 0x00, 0xba, 0xff, 0x13, 0x00, 0xb6, 0xff, 0x10, 0x00, 0xb2, 0xff, 0x0e, 0x00, 0xb0, 0xff, 0x0c, 0x00, 0xae, 0xff, 0x0a, 0x00, 0xac, 0xff, 0x08, 0x00, 0xac, 0xff, 0x05, 0x00, 0xad, 0xff, 0x02, 0x00, 0xae, 0xff, 0xff, 0xff, 0xb0, 0xff, 0xfd, 0xff, 0xb2, 0xff, 0xfc, 0xff, 0xb5, 0xff, 0xfc, 0xff, 0xb8, 0xff, 0xfd, 0xff, 0xbc, 0xff, 0xfd, 0xff, 0xc0, 0xff, 0xfc, 0xff, 0xc5, 0xff, 0xfa, 0xff, 0xca, 0xff, 0xf7, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xd4, 0xff, 0xf1, 0xff, 0xd9, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xee, 0xff, 0xe5, 0xff, 0xee, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0x01, 0x00, 0xe6, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x09, 0x00, 0xe6, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x11, 0x00, 0xeb, 0xff, 0x14, 0x00, 0xed, 0xff, 0x17, 0x00, 0xef, 0xff, 0x1a, 0x00, 0xef, 0xff, 0x1d, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0xf1, 0xff, 0x21, 0x00, 0xf3, 0xff, 0x24, 0x00, 0xf6, 0xff, 0x27, 0x00, 0xfa, 0xff, 0x2a, 0x00, 0xff, 0xff, 0x2e, 0x00, 0x04, 0x00, 0x32, 0x00, 0x09, 0x00, 0x35, 0x00, 0x0d, 0x00, 0x37, 0x00, 0x10, 0x00, 0x37, 0x00, 0x12, 0x00, 0x37, 0x00, 0x14, 0x00, 0x37, 0x00, 0x16, 0x00, 0x38, 0x00, 0x18, 0x00, 0x3b, 0x00, 0x1b, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x40, 0x00, 0x21, 0x00, 0x41, 0x00, 0x23, 0x00, 0x3e, 0x00, 0x24, 0x00, 0x3a, 0x00, 0x23, 0x00, 0x35, 0x00, 0x21, 0x00, 0x30, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x1d, 0x00, 0x27, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x1f, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x03, 0x00, 0x12, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x0b, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xeb, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x05, 0x00, 0xe3, 0xff, 0x02, 0x00, 0xe0, 0xff, 0xfd, 0xff, 0xdd, 0xff, 0xf9, 0xff, 0xda, 0xff, 0xf6, 0xff, 0xd8, 0xff, 0xf3, 0xff, 0xd4, 0xff, 0xf0, 0xff, 0xd1, 0xff, 0xed, 0xff, 0xcf, 0xff, 0xe9, 0xff, 0xcd, 0xff, 0xe5, 0xff, 0xcc, 0xff, 0xe1, 0xff, 0xcc, 0xff, 0xdd, 0xff, 0xcd, 0xff, 0xda, 0xff, 0xcd, 0xff, 0xd8, 0xff, 0xcd, 0xff, 0xd7, 0xff, 0xcc, 0xff, 0xd6, 0xff, 0xcc, 0xff, 0xd4, 0xff, 0xcc, 0xff, 0xd1, 0xff, 0xcd, 0xff, 0xce, 0xff, 0xd0, 0xff, 0xca, 0xff, 0xd4, 0xff, 0xc8, 0xff, 0xd7, 0xff, 0xc6, 0xff, 0xdb, 0xff, 0xc5, 0xff, 0xde, 0xff, 0xc4, 0xff, 0xe1, 0xff, 0xc3, 0xff, 0xe4, 0xff, 0xc2, 0xff, 0xe7, 0xff, 0xc2, 0xff, 0xeb, 0xff, 0xc2, 0xff, 0xef, 0xff, 0xc3, 0xff, 0xf4, 0xff, 0xc5, 0xff, 0xf9, 0xff, 0xc7, 0xff, 0xfe, 0xff, 0xc9, 0xff, 0x02, 0x00, 0xcc, 0xff, 0x07, 0x00, 0xce, 0xff, 0x0c, 0x00, 0xd1, 0xff, 0x11, 0x00, 0xd5, 0xff, 0x16, 0x00, 0xdb, 0xff, 0x1b, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xe5, 0xff, 0x23, 0x00, 0xea, 0xff, 0x27, 0x00, 0xed, 0xff, 0x2a, 0x00, 0xf0, 0xff, 0x2e, 0x00, 0xf3, 0xff, 0x31, 0x00, 0xf8, 0xff, 0x34, 0x00, 0xfd, 0xff, 0x37, 0x00, 0x03, 0x00, 0x39, 0x00, 0x09, 0x00, 0x3a, 0x00, 0x0d, 0x00, 0x3a, 0x00, 0x10, 0x00, 0x3a, 0x00, 0x13, 0x00, 0x3a, 0x00, 0x16, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x37, 0x00, 0x1f, 0x00, 0x34, 0x00, 0x24, 0x00, 0x30, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2b, 0x00, 0x31, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x29, 0x00, 0x37, 0x00, 0x26, 0x00, 0x38, 0x00, 0x23, 0x00, 0x3a, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x1d, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x1c, 0x00, 0x41, 0x00, 0x1c, 0x00, 0x42, 0x00, 0x1c, 0x00, 0x42, 0x00, 0x1a, 0x00, 0x42, 0x00, 0x18, 0x00, 0x41, 0x00, 0x14, 0x00, 0x3f, 0x00, 0x0f, 0x00, 0x3c, 0x00, 0x0b, 0x00, 0x3a, 0x00, 0x06, 0x00, 0x38, 0x00, 0x02, 0x00, 0x38, 0x00, 0xff, 0xff, 0x38, 0x00, 0xfc, 0xff, 0x37, 0x00, 0xf8, 0xff, 0x35, 0x00, 0xf4, 0xff, 0x31, 0x00, 0xef, 0xff, 0x2d, 0x00, 0xea, 0xff, 0x28, 0x00, 0xe6, 0xff, 0x23, 0x00, 0xe3, 0xff, 0x1e, 0x00, 0xe1, 0xff, 0x1a, 0x00, 0xe0, 0xff, 0x16, 0x00, 0xdf, 0xff, 0x12, 0x00, 0xdf, 0xff, 0x0d, 0x00, 0xdf, 0xff, 0x06, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xf8, 0xff, 0xe0, 0xff, 0xf2, 0xff, 0xe0, 0xff, 0xee, 0xff, 0xe2, 0xff, 0xec, 0xff, 0xe4, 0xff, 0xeb, 0xff, 0xe8, 0xff, 0xe9, 0xff, 0xed, 0xff, 0xe7, 0xff, 0xf3, 0xff, 0xe4, 0xff, 0xf9, 0xff, 0xe0, 0xff, 0xfe, 0xff, 0xdd, 0xff, 0x02, 0x00, 0xdb, 0xff, 0x05, 0x00, 0xda, 0xff, 0x07, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xda, 0xff, 0x0e, 0x00, 0xda, 0xff, 0x12, 0x00, 0xda, 0xff, 0x17, 0x00, 0xda, 0xff, 0x1c, 0x00, 0xd9, 0xff, 0x20, 0x00, 0xd9, 0xff, 0x23, 0x00, 0xd9, 0xff, 0x24, 0x00, 0xda, 0xff, 0x25, 0x00, 0xdc, 0xff, 0x24, 0x00, 0xdf, 0xff, 0x23, 0x00, 0xe2, 0xff, 0x24, 0x00, 0xe5, 0xff, 0x24, 0x00, 0xe8, 0xff, 0x25, 0x00, 0xe9, 0xff, 0x26, 0x00, 0xeb, 0xff, 0x25, 0x00, 0xed, 0xff, 0x24, 0x00, 0xf1, 0xff, 0x23, 0x00, 0xf5, 0xff, 0x22, 0x00, 0xfa, 0xff, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x05, 0x00, 0x22, 0x00, 0x08, 0x00, 0x23, 0x00, 0x09, 0x00, 0x23, 0x00, 0x09, 0x00, 0x23, 0x00, 0x08, 0x00, 0x23, 0x00, 0x08, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x22, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x14, 0x00, 0x20, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x17, 0x00, 0x14, 0x00, 0x13, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x1d, 0x00, 0xfd, 0xff, 0x1d, 0x00, 0xf8, 0xff, 0x1b, 0x00, 0xf3, 0xff, 0x17, 0x00, 0xee, 0xff, 0x12, 0x00, 0xea, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x0a, 0x00, 0xe0, 0xff, 0x08, 0x00, 0xd9, 0xff, 0x07, 0x00, 0xd3, 0xff, 0x06, 0x00, 0xcd, 0xff, 0x03, 0x00, 0xca, 0xff, 0x00, 0x00, 0xc9, 0xff, 0xfb, 0xff, 0xc8, 0xff, 0xf6, 0xff, 0xc8, 0xff, 0xf2, 0xff, 0xc8, 0xff, 0xee, 0xff, 0xc7, 0xff, 0xea, 0xff, 0xc5, 0xff, 0xe8, 0xff, 0xc4, 0xff, 0xe6, 0xff, 0xc3, 0xff, 0xe5, 0xff, 0xc3, 0xff, 0xe4, 0xff, 0xc6, 0xff, 0xe3, 0xff, 0xca, 0xff, 0xe0, 0xff, 0xce, 0xff, 0xdd, 0xff, 0xd1, 0xff, 0xd9, 0xff, 0xd2, 0xff, 0xd6, 0xff, 0xd1, 0xff, 0xd3, 0xff, 0xcf, 0xff, 0xd1, 0xff, 0xce, 0xff, 0xd2, 0xff, 0xcf, 0xff, 0xd3, 0xff, 0xd2, 0xff, 0xd4, 0xff, 0xd6, 0xff, 0xd5, 0xff, 0xda, 0xff, 0xd4, 0xff, 0xdd, 0xff, 0xd3, 0xff, 0xdf, 0xff, 0xd2, 0xff, 0xe0, 0xff, 0xd1, 0xff, 0xe0, 0xff, 0xd2, 0xff, 0xe0, 0xff, 0xd3, 0xff, 0xe1, 0xff, 0xd5, 0xff, 0xe5, 0xff, 0xd8, 0xff, 0xea, 0xff, 0xdb, 0xff, 0xf0, 0xff, 0xdd, 0xff, 0xf5, 0xff, 0xdf, 0xff, 0xfa, 0xff, 0xe1, 0xff, 0xfe, 0xff, 0xe4, 0xff, 0x01, 0x00, 0xe7, 0xff, 0x03, 0x00, 0xeb, 0xff, 0x04, 0x00, 0xef, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x09, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x17, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x21, 0x00, 0x08, 0x00, 0x24, 0x00, 0x0b, 0x00, 0x25, 0x00, 0x0e, 0x00, 0x25, 0x00, 0x11, 0x00, 0x24, 0x00, 0x14, 0x00, 0x24, 0x00, 0x18, 0x00, 0x24, 0x00, 0x1c, 0x00, 0x25, 0x00, 0x1e, 0x00, 0x27, 0x00, 0x20, 0x00, 0x28, 0x00, 0x20, 0x00, 0x27, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x1f, 0x00, 0x21, 0x00, 0x20, 0x00, 0x1c, 0x00, 0x23, 0x00, 0x17, 0x00, 0x26, 0x00, 0x14, 0x00, 0x29, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x0b, 0x00, 0x25, 0x00, 0x07, 0x00, 0x22, 0x00, 0x03, 0x00, 0x21, 0x00, 0xff, 0xff, 0x23, 0x00, 0xfc, 0xff, 0x25, 0x00, 0xf9, 0xff, 0x27, 0x00, 0xf8, 0xff, 0x28, 0x00, 0xf7, 0xff, 0x25, 0x00, 0xf5, 0xff, 0x21, 0x00, 0xf4, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x18, 0x00, 0xf0, 0xff, 0x15, 0x00, 0xed, 0xff, 0x15, 0x00, 0xea, 0xff, 0x15, 0x00, 0xe7, 0xff, 0x14, 0x00, 0xe4, 0xff, 0x13, 0x00, 0xe1, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0a, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xde, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xfc, 0xff, 0xdc, 0xff, 0xfa, 0xff, 0xda, 0xff, 0xf9, 0xff, 0xd8, 0xff, 0xf8, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xd5, 0xff, 0xf0, 0xff, 0xd5, 0xff, 0xeb, 0xff, 0xd6, 0xff, 0xe6, 0xff, 0xd9, 0xff, 0xe2, 0xff, 0xdb, 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xdd, 0xff, 0xde, 0xff, 0xde, 0xff, 0xdf, 0xff, 0xde, 0xff, 0xe2, 0xff, 0xdd, 0xff, 0xe5, 0xff, 0xdc, 0xff, 0xe9, 0xff, 0xdc, 0xff, 0xec, 0xff, 0xdc, 0xff, 0xed, 0xff, 0xdf, 0xff, 0xee, 0xff, 0xe1, 0xff, 0xf0, 0xff, 0xe5, 0xff, 0xf3, 0xff, 0xe9, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xfb, 0xff, 0xef, 0xff, 0x00, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf1, 0xff, 0x08, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf6, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xfe, 0xff, 0x1a, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x22, 0x00, 0x09, 0x00, 0x25, 0x00, 0x0b, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x2a, 0x00, 0x0d, 0x00, 0x2c, 0x00, 0x0f, 0x00, 0x2c, 0x00, 0x12, 0x00, 0x2c, 0x00, 0x17, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x2d, 0x00, 0x25, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x28, 0x00, 0x28, 0x00, 0x24, 0x00, 0x29, 0x00, 0x20, 0x00, 0x2b, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x1a, 0x00, 0x2b, 0x00, 0x19, 0x00, 0x29, 0x00, 0x17, 0x00, 0x27, 0x00, 0x13, 0x00, 0x24, 0x00, 0x0e, 0x00, 0x22, 0x00, 0x08, 0x00, 0x21, 0x00, 0x02, 0x00, 0x20, 0x00, 0xff, 0xff, 0x20, 0x00, 0xfd, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1e, 0x00, 0xfb, 0xff, 0x1c, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xf7, 0xff, 0x16, 0x00, 0xf4, 0xff, 0x13, 0x00, 0xf1, 0xff, 0x10, 0x00, 0xee, 0xff, 0x0e, 0x00, 0xec, 0xff, 0x0c, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xec, 0xff, 0x09, 0x00, 0xed, 0xff, 0x05, 0x00, 0xee, 0xff, 0x01, 0x00, 0xee, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xed, 0xff, 0xf2, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe8, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfe, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xe6, 0xff, 0x02, 0x00, 0xe4, 0xff, 0x06, 0x00, 0xe2, 0xff, 0x0c, 0x00, 0xe0, 0xff, 0x12, 0x00, 0xde, 0xff, 0x16, 0x00, 0xdd, 0xff, 0x1a, 0x00, 0xde, 0xff, 0x1d, 0x00, 0xdf, 0xff, 0x1f, 0x00, 0xe1, 0xff, 0x21, 0x00, 0xe3, 0xff, 0x23, 0x00, 0xe6, 0xff, 0x26, 0x00, 0xe8, 0xff, 0x29, 0x00, 0xeb, 0xff, 0x2d, 0x00, 0xef, 0xff, 0x31, 0x00, 0xf3, 0xff, 0x35, 0x00, 0xf8, 0xff, 0x38, 0x00, 0xfc, 0xff, 0x3a, 0x00, 0x01, 0x00, 0x3b, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x09, 0x00, 0x39, 0x00, 0x0c, 0x00, 0x38, 0x00, 0x0f, 0x00, 0x36, 0x00, 0x12, 0x00, 0x35, 0x00, 0x14, 0x00, 0x35, 0x00, 0x16, 0x00, 0x34, 0x00, 0x17, 0x00, 0x32, 0x00, 0x17, 0x00, 0x2f, 0x00, 0x17, 0x00, 0x2a, 0x00, 0x18, 0x00, 0x24, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x17, 0x00, 0x17, 0x00, 0x13, 0x00, 0x16, 0x00, 0x11, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0xfa, 0xff, 0x17, 0x00, 0xf4, 0xff, 0x16, 0x00, 0xf0, 0xff, 0x14, 0x00, 0xee, 0xff, 0x11, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xeb, 0xff, 0x0b, 0x00, 0xea, 0xff, 0x08, 0x00, 0xe8, 0xff, 0x06, 0x00, 0xe5, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x02, 0x00, 0xdf, 0xff, 0xfe, 0xff, 0xdc, 0xff, 0xfa, 0xff, 0xd9, 0xff, 0xf6, 0xff, 0xd8, 0xff, 0xf2, 0xff, 0xd7, 0xff, 0xef, 0xff, 0xd7, 0xff, 0xed, 0xff, 0xd8, 0xff, 0xeb, 0xff, 0xd9, 0xff, 0xe9, 0xff, 0xd9, 0xff, 0xe7, 0xff, 0xd9, 0xff, 0xe5, 0xff, 0xd8, 0xff, 0xe2, 0xff, 0xd6, 0xff, 0xe0, 0xff, 0xd3, 0xff, 0xde, 0xff, 0xd3, 0xff, 0xdc, 0xff, 0xd6, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xdb, 0xff, 0xe1, 0xff, 0xdc, 0xff, 0xe7, 0xff, 0xdb, 0xff, 0xeb, 0xff, 0xda, 0xff, 0xec, 0xff, 0xd9, 0xff, 0xeb, 0xff, 0xd8, 0xff, 0xea, 0xff, 0xd7, 0xff, 0xeb, 0xff, 0xd6, 0xff, 0xee, 0xff, 0xd6, 0xff, 0xf2, 0xff, 0xd6, 0xff, 0xf8, 0xff, 0xd7, 0xff, 0xfc, 0xff, 0xd8, 0xff, 0xfe, 0xff, 0xda, 0xff, 0xfc, 0xff, 0xdc, 0xff, 0xf9, 0xff, 0xdd, 0xff, 0xf5, 0xff, 0xdf, 0xff, 0xf3, 0xff, 0xe1, 0xff, 0xf3, 0xff, 0xe3, 0xff, 0xf5, 0xff, 0xe5, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xf9, 0xff, 0xe9, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf5, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf5, 0xff, 0x0b, 0x00, 0xf6, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x0f, 0x00, 0xf2, 0xff, 0x10, 0x00, 0xef, 0xff, 0x11, 0x00, 0xed, 0xff, 0x14, 0x00, 0xed, 0xff, 0x17, 0x00, 0xee, 0xff, 0x1a, 0x00, 0xf0, 0xff, 0x1d, 0x00, 0xf2, 0xff, 0x1e, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0xf2, 0xff, 0x1c, 0x00, 0xee, 0xff, 0x1b, 0x00, 0xe9, 0xff, 0x19, 0x00, 0xe5, 0xff, 0x19, 0x00, 0xe2, 0xff, 0x1a, 0x00, 0xe2, 0xff, 0x1b, 0x00, 0xe3, 0xff, 0x1c, 0x00, 0xe5, 0xff, 0x1c, 0x00, 0xe7, 0xff, 0x1b, 0x00, 0xe6, 0xff, 0x1a, 0x00, 0xe5, 0xff, 0x19, 0x00, 0xe2, 0xff, 0x18, 0x00, 0xe1, 0xff, 0x17, 0x00, 0xe2, 0xff, 0x16, 0x00, 0xe5, 0xff, 0x15, 0x00, 0xe9, 0xff, 0x15, 0x00, 0xee, 0xff, 0x14, 0x00, 0xf3, 0xff, 0x14, 0x00, 0xf7, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x08, 0x00, 0x07, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, 0x14, 0x00, 0x01, 0x00, 0x16, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0xfd, 0xff, 0x1a, 0x00, 0xf8, 0xff, 0x1b, 0x00, 0xf2, 0xff, 0x1d, 0x00, 0xed, 0xff, 0x1f, 0x00, 0xea, 0xff, 0x22, 0x00, 0xea, 0xff, 0x26, 0x00, 0xeb, 0xff, 0x29, 0x00, 0xee, 0xff, 0x2b, 0x00, 0xef, 0xff, 0x2c, 0x00, 0xee, 0xff, 0x2b, 0x00, 0xec, 0xff, 0x29, 0x00, 0xe9, 0xff, 0x28, 0x00, 0xe6, 0xff, 0x28, 0x00, 0xe5, 0xff, 0x29, 0x00, 0xe5, 0xff, 0x2b, 0x00, 0xe6, 0xff, 0x2d, 0x00, 0xe8, 0xff, 0x2e, 0x00, 0xea, 0xff, 0x2d, 0x00, 0xeb, 0xff, 0x2b, 0x00, 0xed, 0xff, 0x28, 0x00, 0xee, 0xff, 0x26, 0x00, 0xf0, 0xff, 0x26, 0x00, 0xf2, 0xff, 0x27, 0x00, 0xf5, 0xff, 0x29, 0x00, 0xf7, 0xff, 0x2b, 0x00, 0xf9, 0xff, 0x2c, 0x00, 0xfc, 0xff, 0x2b, 0x00, 0x00, 0x00, 0x29, 0x00, 0x04, 0x00, 0x25, 0x00, 0x07, 0x00, 0x22, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x0d, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x11, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x15, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x08, 0x00, 0x14, 0x00, 0x03, 0x00, 0x14, 0x00, 0xff, 0xff, 0x14, 0x00, 0xfc, 0xff, 0x14, 0x00, 0xfb, 0xff, 0x16, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x1b, 0x00, 0xf1, 0xff, 0x1b, 0x00, 0xef, 0xff, 0x19, 0x00, 0xec, 0xff, 0x18, 0x00, 0xeb, 0xff, 0x17, 0x00, 0xea, 0xff, 0x17, 0x00, 0xe9, 0xff, 0x19, 0x00, 0xe9, 0xff, 0x1c, 0x00, 0xea, 0xff, 0x1f, 0x00, 0xeb, 0xff, 0x21, 0x00, 0xec, 0xff, 0x21, 0x00, 0xeb, 0xff, 0x20, 0x00, 0xea, 0xff, 0x1e, 0x00, 0xe9, 0xff, 0x1d, 0x00, 0xe8, 0xff, 0x1d, 0x00, 0xe8, 0xff, 0x1d, 0x00, 0xe8, 0xff, 0x1e, 0x00, 0xea, 0xff, 0x1e, 0x00, 0xeb, 0xff, 0x1e, 0x00, 0xed, 0xff, 0x1c, 0x00, 0xee, 0xff, 0x1a, 0x00, 0xed, 0xff, 0x17, 0x00, 0xec, 0xff, 0x13, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x0d, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xee, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x09, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x01, 0x00, 0xf3, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xf5, 0xff, 0xf3, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xee, 0xff, 0x06, 0x00, 0xe9, 0xff, 0x09, 0x00, 0xe5, 0xff, 0x0a, 0x00, 0xe5, 0xff, 0x0b, 0x00, 0xe6, 0xff, 0x0c, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xed, 0xff, 0x10, 0x00, 0xec, 0xff, 0x11, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xe6, 0xff, 0x12, 0x00, 0xe4, 0xff, 0x11, 0x00, 0xe4, 0xff, 0x0f, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x0a, 0x00, 0xeb, 0xff, 0x08, 0x00, 0xed, 0xff, 0x06, 0x00, 0xee, 0xff, 0x04, 0x00, 0xee, 0xff, 0x03, 0x00, 0xed, 0xff, 0x01, 0x00, 0xec, 0xff, 0xfe, 0xff, 0xec, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xf9, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0x01, 0x00, 0xef, 0xff, 0x03, 0x00, 0xed, 0xff, 0x03, 0x00, 0xeb, 0xff, 0x02, 0x00, 0xea, 0xff, 0x02, 0x00, 0xe9, 0xff, 0x03, 0x00, 0xe9, 0xff, 0x06, 0x00, 0xe9, 0xff, 0x0a, 0x00, 0xe9, 0xff, 0x0e, 0x00, 0xe9, 0xff, 0x11, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xe9, 0xff, 0x0f, 0x00, 0xea, 0xff, 0x0b, 0x00, 0xea, 0xff, 0x07, 0x00, 0xeb, 0xff, 0x03, 0x00, 0xec, 0xff, 0x02, 0x00, 0xec, 0xff, 0x03, 0x00, 0xed, 0xff, 0x04, 0x00, 0xee, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x02, 0x00, 0xf3, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x16, 0x00, 0x02, 0x00, 0x16, 0x00, 0x04, 0x00, 0x15, 0x00, 0x05, 0x00, 0x12, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x09, 0x00, 0x16, 0x00, 0x05, 0x00, 0x17, 0x00, 0x01, 0x00, 0x18, 0x00, 0xfc, 0xff, 0x1a, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf8, 0xff, 0x1c, 0x00, 0xfa, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x1a, 0x00, 0xfa, 0xff, 0x1a, 0x00, 0xf9, 0xff, 0x1b, 0x00, 0xf7, 0xff, 0x1b, 0x00, 0xf7, 0xff, 0x1b, 0x00, 0xf8, 0xff, 0x1a, 0x00, 0xfb, 0xff, 0x17, 0x00, 0xff, 0xff, 0x14, 0x00, 0x02, 0x00, 0x12, 0x00, 0x04, 0x00, 0x11, 0x00, 0x05, 0x00, 0x13, 0x00, 0x04, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x03, 0x00, 0x16, 0x00, 0x03, 0x00, 0x13, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x09, 0x00, 0xef, 0xff, 0x0c, 0x00, 0xee, 0xff, 0x0f, 0x00, 0xed, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe6, 0xff, 0x0a, 0x00, 0xe4, 0xff, 0x08, 0x00, 0xe2, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x08, 0x00, 0xdf, 0xff, 0x0b, 0x00, 0xdf, 0xff, 0x0e, 0x00, 0xdf, 0xff, 0x10, 0x00, 0xe1, 0xff, 0x10, 0x00, 0xe3, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x04, 0x00, 0xe8, 0xff, 0x01, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xe9, 0xff, 0x02, 0x00, 0xeb, 0xff, 0x04, 0x00, 0xef, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfd, 0xff, 0xfc, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xee, 0xff, 0x03, 0x00, 0xed, 0xff, 0x03, 0x00, 0xed, 0xff, 0x04, 0x00, 0xed, 0xff, 0x06, 0x00, 0xed, 0xff, 0x08, 0x00, 0xeb, 0xff, 0x0b, 0x00, 0xe8, 0xff, 0x0c, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe1, 0xff, 0x0d, 0x00, 0xde, 0xff, 0x0c, 0x00, 0xdc, 0xff, 0x0b, 0x00, 0xdc, 0xff, 0x0b, 0x00, 0xde, 0xff, 0x0b, 0x00, 0xe0, 0xff, 0x0b, 0x00, 0xe1, 0xff, 0x0c, 0x00, 0xe1, 0xff, 0x0d, 0x00, 0xe0, 0xff, 0x0e, 0x00, 0xde, 0xff, 0x0f, 0x00, 0xdc, 0xff, 0x10, 0x00, 0xdb, 0xff, 0x11, 0x00, 0xda, 0xff, 0x12, 0x00, 0xda, 0xff, 0x13, 0x00, 0xdb, 0xff, 0x14, 0x00, 0xdc, 0xff, 0x15, 0x00, 0xdd, 0xff, 0x16, 0x00, 0xdc, 0xff, 0x16, 0x00, 0xdb, 0xff, 0x17, 0x00, 0xd9, 0xff, 0x16, 0x00, 0xd8, 0xff, 0x15, 0x00, 0xd9, 0xff, 0x14, 0x00, 0xda, 0xff, 0x13, 0x00, 0xdc, 0xff, 0x13, 0x00, 0xdf, 0xff, 0x13, 0x00, 0xe0, 0xff, 0x14, 0x00, 0xe0, 0xff, 0x13, 0x00, 0xe0, 0xff, 0x11, 0x00, 0xdf, 0xff, 0x0e, 0x00, 0xde, 0xff, 0x0b, 0x00, 0xdf, 0xff, 0x08, 0x00, 0xe2, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x03, 0x00, 0xe8, 0xff, 0x01, 0x00, 0xeb, 0xff, 0xff, 0xff, 0xec, 0xff, 0xfc, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xee, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xed, 0xff, 0xff, 0xff, 0xeb, 0xff, 0x03, 0x00, 0xe8, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x06, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe2, 0xff, 0x08, 0x00, 0xe2, 0xff, 0x0a, 0x00, 0xe1, 0xff, 0x0d, 0x00, 0xe2, 0xff, 0x10, 0x00, 0xe2, 0xff, 0x13, 0x00, 0xe3, 0xff, 0x15, 0x00, 0xe3, 0xff, 0x16, 0x00, 0xe4, 0xff, 0x15, 0x00, 0xe5, 0xff, 0x13, 0x00, 0xe7, 0xff, 0x11, 0x00, 0xe7, 0xff, 0x10, 0x00, 0xe8, 0xff, 0x0f, 0x00, 0xe8, 0xff, 0x0f, 0x00, 0xe8, 0xff, 0x10, 0x00, 0xea, 0xff, 0x11, 0x00, 0xed, 0xff, 0x12, 0x00, 0xf0, 0xff, 0x11, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf6, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf7, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x14, 0x00, 0x01, 0x00, 0x14, 0x00, 0x05, 0x00, 0x14, 0x00, 0x09, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x11, 0x00, 0x14, 0x00, 0x14, 0x00, 0x15, 0x00, 0x17, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x1d, 0x00, 0x14, 0x00, 0x20, 0x00, 0x13, 0x00, 0x24, 0x00, 0x12, 0x00, 0x27, 0x00, 0x10, 0x00, 0x2a, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x0f, 0x00, 0x2a, 0x00, 0x0f, 0x00, 0x29, 0x00, 0x10, 0x00, 0x28, 0x00, 0x10, 0x00, 0x27, 0x00, 0x10, 0x00, 0x27, 0x00, 0x0e, 0x00, 0x26, 0x00, 0x0c, 0x00, 0x26, 0x00, 0x0a, 0x00, 0x24, 0x00, 0x0a, 0x00, 0x21, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x0b, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0d, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfb, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x16, 0x00, 0xf8, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x18, 0x00, 0xf3, 0xff, 0x18, 0x00, 0xf1, 0xff, 0x18, 0x00, 0xf0, 0xff, 0x18, 0x00, 0xf0, 0xff, 0x19, 0x00, 0xf1, 0xff, 0x1b, 0x00, 0xf1, 0xff, 0x1d, 0x00, 0xf1, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x21, 0x00, 0xee, 0xff, 0x21, 0x00, 0xec, 0xff, 0x1f, 0x00, 0xeb, 0xff, 0x1d, 0x00, 0xeb, 0xff, 0x1c, 0x00, 0xec, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x1b, 0x00, 0xee, 0xff, 0x1b, 0x00, 0xee, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x1b, 0x00, 0xec, 0xff, 0x19, 0x00, 0xeb, 0xff, 0x16, 0x00, 0xea, 0xff, 0x14, 0x00, 0xea, 0xff, 0x12, 0x00, 0xea, 0xff, 0x12, 0x00, 0xea, 0xff, 0x12, 0x00, 0xec, 0xff, 0x12, 0x00, 0xee, 0xff, 0x12, 0x00, 0xf1, 0xff, 0x12, 0x00, 0xf4, 0xff, 0x11, 0x00, 0xf7, 0xff, 0x0f, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x07, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x1f, 0x00, 0xff, 0xff, 0x21, 0x00, 0xfd, 0xff, 0x22, 0x00, 0xfb, 0xff, 0x24, 0x00, 0xf9, 0xff, 0x25, 0x00, 0xf8, 0xff, 0x25, 0x00, 0xf7, 0xff, 0x25, 0x00, 0xf6, 0xff, 0x25, 0x00, 0xf4, 0xff, 0x24, 0x00, 0xf2, 0xff, 0x23, 0x00, 0xf0, 0xff, 0x20, 0x00, 0xef, 0xff, 0x1e, 0x00, 0xee, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x19, 0x00, 0xec, 0xff, 0x18, 0x00, 0xeb, 0xff, 0x17, 0x00, 0xeb, 0xff, 0x16, 0x00, 0xea, 0xff, 0x15, 0x00, 0xeb, 0xff, 0x13, 0x00, 0xeb, 0xff, 0x0f, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xed, 0xff, 0x06, 0x00, 0xec, 0xff, 0x02, 0x00, 0xeb, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0xfb, 0xff, 0xe9, 0xff, 0xf6, 0xff, 0xe9, 0xff, 0xf1, 0xff, 0xea, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xe2, 0xff, 0xed, 0xff, 0xdf, 0xff, 0xec, 0xff, 0xdc, 0xff, 0xeb, 0xff, 0xda, 0xff, 0xea, 0xff, 0xd8, 0xff, 0xeb, 0xff, 0xd4, 0xff, 0xed, 0xff, 0xd0, 0xff, 0xef, 0xff, 0xcc, 0xff, 0xf3, 0xff, 0xc9, 0xff, 0xf6, 0xff, 0xc7, 0xff, 0xf7, 0xff, 0xc7, 0xff, 0xf7, 0xff, 0xc7, 0xff, 0xf5, 0xff, 0xc7, 0xff, 0xf3, 0xff, 0xc8, 0xff, 0xf2, 0xff, 0xc8, 0xff, 0xf2, 0xff, 0xc8, 0xff, 0xf4, 0xff, 0xc9, 0xff, 0xf7, 0xff, 0xcb, 0xff, 0xf9, 0xff, 0xcd, 0xff, 0xfb, 0xff, 0xcf, 0xff, 0xfb, 0xff, 0xd1, 0xff, 0xfa, 0xff, 0xd2, 0xff, 0xf8, 0xff, 0xd3, 0xff, 0xf6, 0xff, 0xd4, 0xff, 0xf4, 0xff, 0xd6, 0xff, 0xf4, 0xff, 0xd9, 0xff, 0xf4, 0xff, 0xdc, 0xff, 0xf4, 0xff, 0xe0, 0xff, 0xf4, 0xff, 0xe3, 0xff, 0xf4, 0xff, 0xe6, 0xff, 0xf3, 0xff, 0xe9, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xee, 0xff, 0xed, 0xff, 0xf2, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xfe, 0xff, 0xe6, 0xff, 0x02, 0x00, 0xe5, 0xff, 0x07, 0x00, 0xe5, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x0f, 0x00, 0xe3, 0xff, 0x13, 0x00, 0xe1, 0xff, 0x16, 0x00, 0xdf, 0xff, 0x1a, 0x00, 0xdd, 0xff, 0x1f, 0x00, 0xdb, 0xff, 0x23, 0x00, 0xdb, 0xff, 0x28, 0x00, 0xdd, 0xff, 0x2c, 0x00, 0xdf, 0xff, 0x31, 0x00, 0xe1, 0xff, 0x35, 0x00, 0xe2, 0xff, 0x39, 0x00, 0xe1, 0xff, 0x3b, 0x00, 0xe0, 0xff, 0x3c, 0x00, 0xdf, 0xff, 0x3d, 0x00, 0xdf, 0xff, 0x3d, 0x00, 0xe0, 0xff, 0x3e, 0x00, 0xe2, 0xff, 0x3e, 0x00, 0xe5, 0xff, 0x3c, 0x00, 0xe9, 0xff, 0x39, 0x00, 0xec, 0xff, 0x35, 0x00, 0xef, 0xff, 0x31, 0x00, 0xf0, 0xff, 0x2c, 0x00, 0xf1, 0xff, 0x27, 0x00, 0xf2, 0xff, 0x23, 0x00, 0xf3, 0xff, 0x1e, 0x00, 0xf5, 0xff, 0x1a, 0x00, 0xf7, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xef, 0xff, 0x05, 0x00, 0xec, 0xff, 0x06, 0x00, 0xea, 0xff, 0x07, 0x00, 0xe8, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x09, 0x00, 0xe6, 0xff, 0x09, 0x00, 0xe6, 0xff, 0x09, 0x00, 0xe5, 0xff, 0x09, 0x00, 0xe4, 0xff, 0x0a, 0x00, 0xe2, 0xff, 0x0c, 0x00, 0xe1, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x12, 0x00, 0xe0, 0xff, 0x14, 0x00, 0xe0, 0xff, 0x16, 0x00, 0xdf, 0xff, 0x17, 0x00, 0xde, 0xff, 0x17, 0x00, 0xdc, 0xff, 0x18, 0x00, 0xda, 0xff, 0x19, 0x00, 0xd9, 0xff, 0x1c, 0x00, 0xd9, 0xff, 0x1f, 0x00, 0xd9, 0xff, 0x22, 0x00, 0xdb, 0xff, 0x24, 0x00, 0xdd, 0xff, 0x24, 0x00, 0xdf, 0xff, 0x23, 0x00, 0xdf, 0xff, 0x22, 0x00, 0xdf, 0xff, 0x20, 0x00, 0xdf, 0xff, 0x20, 0x00, 0xdf, 0xff, 0x21, 0x00, 0xe1, 0xff, 0x22, 0x00, 0xe4, 0xff, 0x23, 0x00, 0xe8, 0xff, 0x23, 0x00, 0xed, 0xff, 0x22, 0x00, 0xf1, 0xff, 0x1e, 0x00, 0xf3, 0xff, 0x1a, 0x00, 0xf5, 0xff, 0x17, 0x00, 0xf7, 0xff, 0x15, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xfe, 0xff, 0x16, 0x00, 0x04, 0x00, 0x19, 0x00, 0x0a, 0x00, 0x1a, 0x00, 0x10, 0x00, 0x19, 0x00, 0x16, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x21, 0x00, 0x0c, 0x00, 0x25, 0x00, 0x0d, 0x00, 0x29, 0x00, 0x0d, 0x00, 0x2d, 0x00, 0x0f, 0x00, 0x32, 0x00, 0x10, 0x00, 0x35, 0x00, 0x0f, 0x00, 0x37, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x0b, 0x00, 0x39, 0x00, 0x08, 0x00, 0x39, 0x00, 0x04, 0x00, 0x39, 0x00, 0x02, 0x00, 0x38, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x02, 0x00, 0x32, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x22, 0x00, 0xfd, 0xff, 0x1d, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf1, 0xff, 0x03, 0x00, 0xef, 0xff, 0x02, 0x00, 0xee, 0xff, 0x00, 0x00, 0xed, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xfe, 0xff, 0xec, 0xff, 0x00, 0x00, 0xec, 0xff, 0x03, 0x00, 0xeb, 0xff, 0x04, 0x00, 0xea, 0xff, 0x03, 0x00, 0xea, 0xff, 0x01, 0x00, 0xea, 0xff, 0x00, 0x00, 0xeb, 0xff, 0xff, 0xff, 0xec, 0xff, 0xff, 0xff, 0xee, 0xff, 0x01, 0x00, 0xef, 0xff, 0x04, 0x00, 0xef, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x09, 0x00, 0x02, 0x00, 0x0b, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xf5, 0xff, 0x12, 0x00, 0xf4, 0xff, 0x15, 0x00, 0xf5, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x21, 0x00, 0xf8, 0xff, 0x21, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf5, 0xff, 0x1b, 0x00, 0xf4, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x19, 0x00, 0xf2, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf1, 0xff, 0x19, 0x00, 0xf0, 0xff, 0x16, 0x00, 0xef, 0xff, 0x13, 0x00, 0xef, 0xff, 0x11, 0x00, 0xef, 0xff, 0x10, 0x00, 0xf0, 0xff, 0x10, 0x00, 0xf1, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf6, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xed, 0xff, 0x04, 0x00, 0xeb, 0xff, 0x04, 0x00, 0xe8, 0xff, 0x04, 0x00, 0xe5, 0xff, 0x05, 0x00, 0xe1, 0xff, 0x06, 0x00, 0xde, 0xff, 0x07, 0x00, 0xdc, 0xff, 0x08, 0x00, 0xda, 0xff, 0x08, 0x00, 0xd9, 0xff, 0x07, 0x00, 0xd9, 0xff, 0x06, 0x00, 0xd8, 0xff, 0x04, 0x00, 0xd7, 0xff, 0x03, 0x00, 0xd6, 0xff, 0x03, 0x00, 0xd6, 0xff, 0x04, 0x00, 0xd6, 0xff, 0x05, 0x00, 0xd8, 0xff, 0x06, 0x00, 0xda, 0xff, 0x07, 0x00, 0xdd, 0xff, 0x08, 0x00, 0xe0, 0xff, 0x07, 0x00, 0xe4, 0xff, 0x05, 0x00, 0xe7, 0xff, 0x02, 0x00, 0xe9, 0xff, 0x00, 0x00, 0xec, 0xff, 0xff, 0xff, 0xee, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xfb, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x00, 0x09, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0xfd, 0xff, 0x17, 0x00, 0xfb, 0xff, 0x18, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xf8, 0xff, 0x17, 0x00, 0xf8, 0xff, 0x17, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xfb, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x1f, 0x00, 0xfb, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x24, 0x00, 0xf6, 0xff, 0x24, 0x00, 0xf4, 0xff, 0x23, 0x00, 0xf4, 0xff, 0x21, 0x00, 0xf4, 0xff, 0x1f, 0x00, 0xf6, 0xff, 0x1e, 0x00, 0xf8, 0xff, 0x1d, 0x00, 0xfb, 0xff, 0x1d, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xfe, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x18, 0x00, 0xfc, 0xff, 0x15, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x0c, 0x00, 0x02, 0x00, 0x09, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xec, 0xff, 0xfc, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf4, 0xff, 0xef, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xee, 0xff, 0xed, 0xff, 0xed, 0xff, 0xeb, 0xff, 0xec, 0xff, 0xe8, 0xff, 0xec, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xe6, 0xff, 0xec, 0xff, 0xe7, 0xff, 0xec, 0xff, 0xe9, 0xff, 0xea, 0xff, 0xec, 0xff, 0xe8, 0xff, 0xed, 0xff, 0xe6, 0xff, 0xee, 0xff, 0xe5, 0xff, 0xee, 0xff, 0xe5, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe8, 0xff, 0xf2, 0xff, 0xe9, 0xff, 0xf4, 0xff, 0xea, 0xff, 0xf8, 0xff, 0xe9, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0x00, 0x00, 0xe6, 0xff, 0x03, 0x00, 0xe5, 0xff, 0x05, 0x00, 0xe4, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x05, 0x00, 0xe7, 0xff, 0x04, 0x00, 0xea, 0xff, 0x04, 0x00, 0xec, 0xff, 0x04, 0x00, 0xee, 0xff, 0x04, 0x00, 0xef, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xfa, 0xff, 0x14, 0x00, 0xfb, 0xff, 0x17, 0x00, 0xfa, 0xff, 0x1b, 0x00, 0xf8, 0xff, 0x20, 0x00, 0xf6, 0xff, 0x25, 0x00, 0xf5, 0xff, 0x29, 0x00, 0xf6, 0xff, 0x2b, 0x00, 0xf8, 0xff, 0x2d, 0x00, 0xfa, 0xff, 0x2e, 0x00, 0xfc, 0xff, 0x2e, 0x00, 0xfc, 0xff, 0x2f, 0x00, 0xfc, 0xff, 0x31, 0x00, 0xf9, 0xff, 0x33, 0x00, 0xf7, 0xff, 0x36, 0x00, 0xf4, 0xff, 0x38, 0x00, 0xf3, 0xff, 0x39, 0x00, 0xf3, 0xff, 0x39, 0x00, 0xf4, 0xff, 0x37, 0x00, 0xf4, 0xff, 0x33, 0x00, 0xf5, 0xff, 0x30, 0x00, 0xf4, 0xff, 0x2d, 0x00, 0xf2, 0xff, 0x2b, 0x00, 0xf0, 0xff, 0x2b, 0x00, 0xef, 0xff, 0x2b, 0x00, 0xee, 0xff, 0x2c, 0x00, 0xee, 0xff, 0x2b, 0x00, 0xef, 0xff, 0x29, 0x00, 0xf0, 0xff, 0x25, 0x00, 0xf1, 0xff, 0x22, 0x00, 0xf3, 0xff, 0x1e, 0x00, 0xf3, 0xff, 0x1c, 0x00, 0xf4, 0xff, 0x1b, 0x00, 0xf5, 0xff, 0x1b, 0x00, 0xf5, 0xff, 0x1c, 0x00, 0xf6, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1b, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xfc, 0xff, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x02, 0x00, 0x0a, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x12, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xf6, 0xff, 0x0e, 0x00, 0xf5, 0xff, 0x0a, 0x00, 0xf5, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x0a, 0x00, 0xef, 0xff, 0x0d, 0x00, 0xed, 0xff, 0x0f, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x0f, 0x00, 0xea, 0xff, 0x0d, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xeb, 0xff, 0x0d, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xed, 0xff, 0x14, 0x00, 0xee, 0xff, 0x18, 0x00, 0xf0, 0xff, 0x1a, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf4, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xf8, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xfa, 0xff, 0x16, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0xff, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xf4, 0xff, 0xe9, 0xff, 0xf4, 0xff, 0xe6, 0xff, 0xf3, 0xff, 0xe3, 0xff, 0xf0, 0xff, 0xe1, 0xff, 0xee, 0xff, 0xe0, 0xff, 0xeb, 0xff, 0xdf, 0xff, 0xe9, 0xff, 0xdf, 0xff, 0xe8, 0xff, 0xde, 0xff, 0xe7, 0xff, 0xdd, 0xff, 0xe7, 0xff, 0xdb, 0xff, 0xe7, 0xff, 0xd7, 0xff, 0xe7, 0xff, 0xd3, 0xff, 0xe7, 0xff, 0xd0, 0xff, 0xe6, 0xff, 0xce, 0xff, 0xe5, 0xff, 0xce, 0xff, 0xe4, 0xff, 0xd0, 0xff, 0xe3, 0xff, 0xd2, 0xff, 0xe4, 0xff, 0xd2, 0xff, 0xe5, 0xff, 0xd0, 0xff, 0xe8, 0xff, 0xcd, 0xff, 0xeb, 0xff, 0xcb, 0xff, 0xee, 0xff, 0xca, 0xff, 0xf0, 0xff, 0xcc, 0xff, 0xf1, 0xff, 0xd1, 0xff, 0xf2, 0xff, 0xd7, 0xff, 0xf3, 0xff, 0xdc, 0xff, 0xf5, 0xff, 0xdf, 0xff, 0xf8, 0xff, 0xe0, 0xff, 0xfc, 0xff, 0xe0, 0xff, 0x01, 0x00, 0xe2, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x08, 0x00, 0xe9, 0xff, 0x0a, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0d, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x09, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x09, 0x00, 0x21, 0x00, 0x07, 0x00, 0x21, 0x00, 0x05, 0x00, 0x20, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x07, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x0e, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x07, 0x00, 0x15, 0x00, 0x04, 0x00, 0x15, 0x00, 0x01, 0x00, 0x14, 0x00, 0x01, 0x00, 0x12, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x09, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xef, 0xff, 0x02, 0x00, 0xec, 0xff, 0x04, 0x00, 0xea, 0xff, 0x07, 0x00, 0xeb, 0xff, 0x0a, 0x00, 0xed, 0xff, 0x0d, 0x00, 0xf1, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x0c, 0x00, 0xf5, 0xff, 0x0a, 0x00, 0xf5, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf3, 0xff, 0x08, 0x00, 0xf5, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x11, 0x00, 0x06, 0x00, 0x13, 0x00, 0x05, 0x00, 0x15, 0x00, 0x06, 0x00, 0x16, 0x00, 0x07, 0x00, 0x17, 0x00, 0x09, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x20, 0x00, 0x12, 0x00, 0x25, 0x00, 0x14, 0x00, 0x2a, 0x00, 0x14, 0x00, 0x2d, 0x00, 0x13, 0x00, 0x30, 0x00, 0x12, 0x00, 0x31, 0x00, 0x11, 0x00, 0x31, 0x00, 0x10, 0x00, 0x31, 0x00, 0x11, 0x00, 0x32, 0x00, 0x12, 0x00, 0x35, 0x00, 0x12, 0x00, 0x38, 0x00, 0x11, 0x00, 0x3a, 0x00, 0x0f, 0x00, 0x3c, 0x00, 0x0c, 0x00, 0x3c, 0x00, 0x09, 0x00, 0x3b, 0x00, 0x07, 0x00, 0x39, 0x00, 0x05, 0x00, 0x36, 0x00, 0x03, 0x00, 0x33, 0x00, 0x02, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x28, 0x00, 0xff, 0xff, 0x25, 0x00, 0xfc, 0xff, 0x21, 0x00, 0xfa, 0xff, 0x1d, 0x00, 0xf8, 0xff, 0x19, 0x00, 0xf7, 0xff, 0x15, 0x00, 0xf7, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xef, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xeb, 0xff, 0xfa, 0xff, 0xe9, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xf8, 0xff, 0xe5, 0xff, 0xf5, 0xff, 0xe2, 0xff, 0xf3, 0xff, 0xe0, 0xff, 0xf1, 0xff, 0xde, 0xff, 0xf0, 0xff, 0xdc, 0xff, 0xf0, 0xff, 0xda, 0xff, 0xf0, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xd8, 0xff, 0xf1, 0xff, 0xd7, 0xff, 0xf1, 0xff, 0xd6, 0xff, 0xf0, 0xff, 0xd5, 0xff, 0xef, 0xff, 0xd4, 0xff, 0xee, 0xff, 0xd4, 0xff, 0xed, 0xff, 0xd3, 0xff, 0xee, 0xff, 0xd3, 0xff, 0xf0, 0xff, 0xd4, 0xff, 0xf3, 0xff, 0xd6, 0xff, 0xf5, 0xff, 0xd9, 0xff, 0xf6, 0xff, 0xdc, 0xff, 0xf6, 0xff, 0xdf, 0xff, 0xf5, 0xff, 0xe1, 0xff, 0xf4, 0xff, 0xe2, 0xff, 0xf2, 0xff, 0xe3, 0xff, 0xf0, 0xff, 0xe6, 0xff, 0xf0, 0xff, 0xe9, 0xff, 0xf0, 0xff, 0xed, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0x0e, 0x00, 0xf6, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x15, 0x00, 0xfc, 0xff, 0x16, 0x00, 0xfe, 0xff, 0x16, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x15, 0x00, 0x05, 0x00, 0x18, 0x00, 0x06, 0x00, 0x18, 0x00, 0x07, 0x00, 0x17, 0x00, 0x07, 0x00, 0x15, 0x00, 0x05, 0x00, 0x12, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0x12, 0x00, 0xff, 0xff, 0x14, 0x00, 0xff, 0xff, 0x16, 0x00, 0xfe, 0xff, 0x17, 0x00, 0xfc, 0xff, 0x17, 0x00, 0xfa, 0xff, 0x16, 0x00, 0xf7, 0xff, 0x13, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x0e, 0x00, 0xf1, 0xff, 0x0c, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf2, 0xff, 0x0b, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xed, 0xff, 0x00, 0x00, 0xec, 0xff, 0x03, 0x00, 0xea, 0xff, 0x05, 0x00, 0xe7, 0xff, 0x08, 0x00, 0xe4, 0xff, 0x0a, 0x00, 0xe1, 0xff, 0x0c, 0x00, 0xde, 0xff, 0x0d, 0x00, 0xde, 0xff, 0x0e, 0x00, 0xdf, 0xff, 0x0f, 0x00, 0xe1, 0xff, 0x11, 0x00, 0xe3, 0xff, 0x13, 0x00, 0xe4, 0xff, 0x15, 0x00, 0xe4, 0xff, 0x16, 0x00, 0xe4, 0xff, 0x15, 0x00, 0xe3, 0xff, 0x13, 0x00, 0xe4, 0xff, 0x11, 0x00, 0xe6, 0xff, 0x10, 0x00, 0xe8, 0xff, 0x0f, 0x00, 0xec, 0xff, 0x0f, 0x00, 0xef, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x10, 0x00, 0xf4, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x09, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x14, 0x00, 0xfd, 0xff, 0x17, 0x00, 0xfd, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xfd, 0xff, 0x1e, 0x00, 0xfd, 0xff, 0x20, 0x00, 0xfc, 0xff, 0x22, 0x00, 0xfc, 0xff, 0x23, 0x00, 0xfb, 0xff, 0x22, 0x00, 0xfb, 0xff, 0x20, 0x00, 0xfa, 0xff, 0x1d, 0x00, 0xfa, 0xff, 0x19, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x08, 0x00, 0xf0, 0xff, 0x08, 0x00, 0xed, 0xff, 0x08, 0x00, 0xeb, 0xff, 0x07, 0x00, 0xea, 0xff, 0x06, 0x00, 0xe9, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x07, 0x00, 0xea, 0xff, 0x08, 0x00, 0xea, 0xff, 0x08, 0x00, 0xea, 0xff, 0x08, 0x00, 0xe9, 0xff, 0x07, 0x00, 0xe8, 0xff, 0x06, 0x00, 0xe6, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x03, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xe5, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xea, 0xff, 0xfb, 0xff, 0xeb, 0xff, 0xfa, 0xff, 0xeb, 0xff, 0xfa, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf5, 0xff, 0xee, 0xff, 0xf3, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xf4, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf2, 0xff, 0x10, 0x00, 0xf1, 0xff, 0x13, 0x00, 0xf0, 0xff, 0x15, 0x00, 0xf0, 0xff, 0x18, 0x00, 0xf1, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf3, 0xff, 0x1a, 0x00, 0xf3, 0xff, 0x1a, 0x00, 0xf3, 0xff, 0x19, 0x00, 0xf3, 0xff, 0x18, 0x00, 0xf4, 0xff, 0x18, 0x00, 0xf5, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x17, 0x00, 0xf8, 0xff, 0x17, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xfc, 0xff, 0x13, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0c, 0x00, 0xf0, 0xff, 0x0c, 0x00, 0xee, 0xff, 0x0c, 0x00, 0xec, 0xff, 0x0c, 0x00, 0xec, 0xff, 0x0d, 0x00, 0xee, 0xff, 0x0f, 0x00, 0xef, 0xff, 0x10, 0x00, 0xf0, 0xff, 0x11, 0x00, 0xef, 0xff, 0x11, 0x00, 0xee, 0xff, 0x11, 0x00, 0xec, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xec, 0xff, 0x11, 0x00, 0xee, 0xff, 0x11, 0x00, 0xf0, 0xff, 0x11, 0x00, 0xf3, 0xff, 0x11, 0x00, 0xf5, 0xff, 0x10, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf7, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfa, 0xff, 0x0b, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf5, 0xff, 0x10, 0x00, 0xf5, 0xff, 0x11, 0x00, 0xf4, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x13, 0x00, 0xf2, 0xff, 0x14, 0x00, 0xf1, 0xff, 0x14, 0x00, 0xef, 0xff, 0x14, 0x00, 0xee, 0xff, 0x14, 0x00, 0xed, 0xff, 0x15, 0x00, 0xee, 0xff, 0x15, 0x00, 0xef, 0xff, 0x15, 0x00, 0xf0, 0xff, 0x14, 0x00, 0xf1, 0xff, 0x13, 0x00, 0xf1, 0xff, 0x11, 0x00, 0xf2, 0xff, 0x0f, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf3, 0xff, 0x09, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xef, 0xff, 0x02, 0x00, 0xeb, 0xff, 0x03, 0x00, 0xe6, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x04, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xdc, 0xff, 0x05, 0x00, 0xda, 0xff, 0x06, 0x00, 0xd9, 0xff, 0x07, 0x00, 0xd8, 0xff, 0x0a, 0x00, 0xd7, 0xff, 0x0c, 0x00, 0xd6, 0xff, 0x0d, 0x00, 0xd5, 0xff, 0x0e, 0x00, 0xd5, 0xff, 0x0f, 0x00, 0xd6, 0xff, 0x0f, 0x00, 0xd7, 0xff, 0x0f, 0x00, 0xd9, 0xff, 0x10, 0x00, 0xdc, 0xff, 0x10, 0x00, 0xde, 0xff, 0x11, 0x00, 0xe1, 0xff, 0x12, 0x00, 0xe3, 0xff, 0x13, 0x00, 0xe4, 0xff, 0x14, 0x00, 0xe5, 0xff, 0x15, 0x00, 0xe7, 0xff, 0x15, 0x00, 0xe9, 0xff, 0x15, 0x00, 0xeb, 0xff, 0x15, 0x00, 0xee, 0xff, 0x14, 0x00, 0xf1, 0xff, 0x13, 0x00, 0xf3, 0xff, 0x12, 0x00, 0xf5, 0xff, 0x12, 0x00, 0xf6, 0xff, 0x13, 0x00, 0xf8, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf6, 0xff, 0x09, 0x00, 0xf5, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x12, 0x00, 0xf1, 0xff, 0x14, 0x00, 0xf0, 0xff, 0x15, 0x00, 0xef, 0xff, 0x16, 0x00, 0xee, 0xff, 0x16, 0x00, 0xee, 0xff, 0x17, 0x00, 0xed, 0xff, 0x18, 0x00, 0xec, 0xff, 0x19, 0x00, 0xea, 0xff, 0x1a, 0x00, 0xe9, 0xff, 0x19, 0x00, 0xe9, 0xff, 0x18, 0x00, 0xea, 0xff, 0x16, 0x00, 0xeb, 0xff, 0x14, 0x00, 0xed, 0xff, 0x11, 0x00, 0xee, 0xff, 0x0f, 0x00, 0xef, 0xff, 0x0e, 0x00, 0xf0, 0xff, 0x0c, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x12, 0x00, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x19, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x07, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x17, 0x00, 0x09, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0b, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x14, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xf9, 0xff, 0x1a, 0x00, 0xf9, 0xff, 0x1b, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xfa, 0xff, 0x1a, 0x00, 0xfb, 0xff, 0x1a, 0x00, 0xfc, 0xff, 0x1a, 0x00, 0xfd, 0xff, 0x1a, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfc, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x1a, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xf7, 0xff, 0x17, 0x00, 0xf5, 0xff, 0x15, 0x00, 0xf4, 0xff, 0x13, 0x00, 0xf3, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x0e, 0x00, 0xf3, 0xff, 0x0d, 0x00, 0xf3, 0xff, 0x0b, 0x00, 0xf2, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xef, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf1, 0xff, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf4, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf3, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xed, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xed, 0xff, 0xf4, 0xff, 0xed, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xec, 0xff, 0xf2, 0xff, 0xed, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xee, 0xff, 0xf5, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xf8, 0xff, 0xea, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xeb, 0xff, 0xf3, 0xff, 0xec, 0xff, 0xf1, 0xff, 0xed, 0xff, 0xf1, 0xff, 0xee, 0xff, 0xf2, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xea, 0xff, 0xf8, 0xff, 0xea, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x10, 0x00, 0x12, 0x00, 0x13, 0x00, 0x12, 0x00, 0x16, 0x00, 0x11, 0x00, 0x18, 0x00, 0x0f, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x09, 0x00, 0x1b, 0x00, 0x07, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x19, 0x00, 0x07, 0x00, 0x18, 0x00, 0x07, 0x00, 0x17, 0x00, 0x07, 0x00, 0x17, 0x00, 0x06, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x01, 0x00, 0x17, 0x00, 0xfe, 0xff, 0x17, 0x00, 0xfd, 0xff, 0x16, 0x00, 0xfd, 0xff, 0x15, 0x00, 0xfd, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x12, 0x00, 0xff, 0xff, 0x11, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x10, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x07, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x12, 0x00, 0x07, 0x00, 0x14, 0x00, 0x07, 0x00, 0x15, 0x00, 0x07, 0x00, 0x16, 0x00, 0x05, 0x00, 0x16, 0x00, 0x03, 0x00, 0x16, 0x00, 0x01, 0x00, 0x16, 0x00, 0xff, 0xff, 0x16, 0x00, 0xfe, 0xff, 0x16, 0x00, 0xfe, 0xff, 0x16, 0x00, 0xff, 0xff, 0x16, 0x00, 0xff, 0xff, 0x15, 0x00, 0xff, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf4, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xed, 0xff, 0xf2, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xf2, 0xff, 0xe8, 0xff, 0xf4, 0xff, 0xe8, 0xff, 0xf7, 0xff, 0xe8, 0xff, 0xfa, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfe, 0xff, 0xe8, 0xff, 0x01, 0x00, 0xea, 0xff, 0x03, 0x00, 0xec, 0xff, 0x05, 0x00, 0xef, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xfa, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x01, 0x00, 0x15, 0x00, 0x02, 0x00, 0x15, 0x00, 0x03, 0x00, 0x15, 0x00, 0x03, 0x00, 0x15, 0x00, 0x04, 0x00, 0x15, 0x00, 0x06, 0x00, 0x16, 0x00, 0x08, 0x00, 0x17, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x10, 0x00, 0x17, 0x00, 0x10, 0x00, 0x16, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf3, 0xff, 0x01, 0x00, 0xf2, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf0, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf4, 0xff, 0xf4, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfe, 0xff, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x15, 0x00, 0x03, 0x00, 0x15, 0x00, 0x05, 0x00, 0x13, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0b, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf2, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x08, 0x00, 0xef, 0xff, 0x06, 0x00, 0xed, 0xff, 0x05, 0x00, 0xeb, 0xff, 0x05, 0x00, 0xe8, 0xff, 0x04, 0x00, 0xe6, 0xff, 0x04, 0x00, 0xe5, 0xff, 0x02, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xe5, 0xff, 0xfe, 0xff, 0xe6, 0xff, 0xfc, 0xff, 0xe6, 0xff, 0xfb, 0xff, 0xe6, 0xff, 0xfa, 0xff, 0xe5, 0xff, 0xf9, 0xff, 0xe5, 0xff, 0xf8, 0xff, 0xe4, 0xff, 0xf7, 0xff, 0xe4, 0xff, 0xf6, 0xff, 0xe4, 0xff, 0xf5, 0xff, 0xe5, 0xff, 0xf3, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe8, 0xff, 0xef, 0xff, 0xe9, 0xff, 0xed, 0xff, 0xea, 0xff, 0xec, 0xff, 0xea, 0xff, 0xea, 0xff, 0xeb, 0xff, 0xe9, 0xff, 0xec, 0xff, 0xe8, 0xff, 0xed, 0xff, 0xe7, 0xff, 0xef, 0xff, 0xe6, 0xff, 0xf1, 0xff, 0xe6, 0xff, 0xf3, 0xff, 0xe6, 0xff, 0xf5, 0xff, 0xe7, 0xff, 0xf7, 0xff, 0xe8, 0xff, 0xf8, 0xff, 0xe9, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x11, 0x00, 0x11, 0x00, 0x14, 0x00, 0x11, 0x00, 0x16, 0x00, 0x10, 0x00, 0x18, 0x00, 0x11, 0x00, 0x18, 0x00, 0x11, 0x00, 0x18, 0x00, 0x10, 0x00, 0x18, 0x00, 0x10, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x10, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0xfe, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x11, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xff, 0xff, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf2, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xea, 0xff, 0xfa, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xfc, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe8, 0xff, 0xfb, 0xff, 0xe7, 0xff, 0xfa, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe6, 0xff, 0xfc, 0xff, 0xe6, 0xff, 0xfd, 0xff, 0xe7, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xfa, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x0f, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xff, 0xff, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0b, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x11, 0x00, 0xf1, 0xff, 0x13, 0x00, 0xf1, 0xff, 0x13, 0x00, 0xf1, 0xff, 0x12, 0x00, 0xf2, 0xff, 0x11, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf2, 0xff, 0x0f, 0x00, 0xf1, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0e, 0x00, 0xf0, 0xff, 0x0c, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xf1, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf5, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfe, 0xff, 0xef, 0xff, 0x00, 0x00, 0xef, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xf6, 0xff, 0x0a, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xff, 0xff, 0x11, 0x00, 0x02, 0x00, 0x12, 0x00, 0x05, 0x00, 0x12, 0x00, 0x08, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x12, 0x00, 0x07, 0x00, 0x15, 0x00, 0x06, 0x00, 0x19, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x1a, 0x00, 0xf7, 0xff, 0x1a, 0x00, 0xf5, 0xff, 0x1b, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0xf2, 0xff, 0x1f, 0x00, 0xf2, 0xff, 0x1f, 0x00, 0xf1, 0xff, 0x1e, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xf1, 0xff, 0x19, 0x00, 0xf0, 0xff, 0x16, 0x00, 0xef, 0xff, 0x13, 0x00, 0xed, 0xff, 0x10, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xeb, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x0a, 0x00, 0xeb, 0xff, 0x07, 0x00, 0xed, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf3, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf3, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x08, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf4, 0xff, 0x0e, 0x00, 0xf4, 0xff, 0x11, 0x00, 0xf6, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xfa, 0xff, 0x14, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x15, 0x00, 0xf8, 0xff, 0x15, 0x00, 0xf7, 0xff, 0x14, 0x00, 0xf8, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xfb, 0xff, 0x14, 0x00, 0xfd, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x14, 0x00, 0xff, 0xff, 0x13, 0x00, 0xff, 0xff, 0x12, 0x00, 0xff, 0xff, 0x10, 0x00, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x09, 0x00, 0x16, 0x00, 0x08, 0x00, 0x16, 0x00, 0x06, 0x00, 0x15, 0x00, 0x05, 0x00, 0x12, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xef, 0xff, 0xe9, 0xff, 0xef, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xe5, 0xff, 0xf5, 0xff, 0xe4, 0xff, 0xf6, 0xff, 0xe3, 0xff, 0xf7, 0xff, 0xe1, 0xff, 0xf7, 0xff, 0xdf, 0xff, 0xf8, 0xff, 0xdd, 0xff, 0xf8, 0xff, 0xdc, 0xff, 0xf9, 0xff, 0xdc, 0xff, 0xfa, 0xff, 0xdd, 0xff, 0xfc, 0xff, 0xde, 0xff, 0xfe, 0xff, 0xde, 0xff, 0x00, 0x00, 0xdf, 0xff, 0x02, 0x00, 0xdf, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xe0, 0xff, 0x05, 0x00, 0xe1, 0xff, 0x06, 0x00, 0xe2, 0xff, 0x06, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x07, 0x00, 0xe8, 0xff, 0x07, 0x00, 0xea, 0xff, 0x08, 0x00, 0xec, 0xff, 0x08, 0x00, 0xee, 0xff, 0x09, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xf6, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x13, 0x00, 0x05, 0x00, 0x15, 0x00, 0x05, 0x00, 0x16, 0x00, 0x05, 0x00, 0x16, 0x00, 0x03, 0x00, 0x16, 0x00, 0x01, 0x00, 0x17, 0x00, 0xff, 0xff, 0x19, 0x00, 0xfc, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x1d, 0x00, 0xfa, 0xff, 0x1f, 0x00, 0xfa, 0xff, 0x20, 0x00, 0xf9, 0xff, 0x20, 0x00, 0xf9, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1e, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf5, 0xff, 0x1c, 0x00, 0xf3, 0xff, 0x1b, 0x00, 0xf2, 0xff, 0x1a, 0x00, 0xf1, 0xff, 0x18, 0x00, 0xf1, 0xff, 0x17, 0x00, 0xf2, 0xff, 0x14, 0x00, 0xf2, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0d, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf4, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf6, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xf0, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf8, 0xff, 0xeb, 0xff, 0xfa, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe5, 0xff, 0xfd, 0xff, 0xe3, 0xff, 0xfe, 0xff, 0xe2, 0xff, 0xff, 0xff, 0xe2, 0xff, 0xff, 0xff, 0xe3, 0xff, 0x01, 0x00, 0xe5, 0xff, 0x03, 0x00, 0xe6, 0xff, 0x05, 0x00, 0xe6, 0xff, 0x08, 0x00, 0xe6, 0xff, 0x0a, 0x00, 0xe5, 0xff, 0x0b, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe7, 0xff, 0x0e, 0x00, 0xea, 0xff, 0x0e, 0x00, 0xed, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x12, 0x00, 0xf5, 0xff, 0x13, 0x00, 0xf7, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x03, 0x00, 0x13, 0x00, 0x06, 0x00, 0x14, 0x00, 0x08, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x09, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x20, 0x00, 0xff, 0xff, 0x20, 0x00, 0xfc, 0xff, 0x21, 0x00, 0xfb, 0xff, 0x22, 0x00, 0xfa, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x23, 0x00, 0xf7, 0xff, 0x23, 0x00, 0xf5, 0xff, 0x24, 0x00, 0xf2, 0xff, 0x23, 0x00, 0xf0, 0xff, 0x22, 0x00, 0xed, 0xff, 0x20, 0x00, 0xeb, 0xff, 0x1e, 0x00, 0xea, 0xff, 0x1b, 0x00, 0xe9, 0xff, 0x18, 0x00, 0xe9, 0xff, 0x15, 0x00, 0xe9, 0xff, 0x12, 0x00, 0xea, 0xff, 0x0f, 0x00, 0xe9, 0xff, 0x0c, 0x00, 0xe8, 0xff, 0x08, 0x00, 0xe6, 0xff, 0x05, 0x00, 0xe4, 0xff, 0x02, 0x00, 0xe3, 0xff, 0xff, 0xff, 0xe2, 0xff, 0xfc, 0xff, 0xe4, 0xff, 0xf9, 0xff, 0xe6, 0xff, 0xf5, 0xff, 0xe8, 0xff, 0xf1, 0xff, 0xea, 0xff, 0xed, 0xff, 0xeb, 0xff, 0xe9, 0xff, 0xeb, 0xff, 0xe7, 0xff, 0xea, 0xff, 0xe5, 0xff, 0xea, 0xff, 0xe4, 0xff, 0xeb, 0xff, 0xe3, 0xff, 0xed, 0xff, 0xe1, 0xff, 0xf1, 0xff, 0xdf, 0xff, 0xf4, 0xff, 0xdd, 0xff, 0xf7, 0xff, 0xdb, 0xff, 0xf8, 0xff, 0xda, 0xff, 0xf8, 0xff, 0xda, 0xff, 0xf7, 0xff, 0xda, 0xff, 0xf7, 0xff, 0xdb, 0xff, 0xf7, 0xff, 0xdb, 0xff, 0xf9, 0xff, 0xdc, 0xff, 0xfb, 0xff, 0xdc, 0xff, 0xfe, 0xff, 0xdc, 0xff, 0x01, 0x00, 0xdc, 0xff, 0x03, 0x00, 0xdd, 0xff, 0x05, 0x00, 0xde, 0xff, 0x06, 0x00, 0xe0, 0xff, 0x07, 0x00, 0xe3, 0xff, 0x08, 0x00, 0xe5, 0xff, 0x09, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xec, 0xff, 0x0e, 0x00, 0xee, 0xff, 0x11, 0x00, 0xf0, 0xff, 0x13, 0x00, 0xf2, 0xff, 0x15, 0x00, 0xf5, 0xff, 0x16, 0x00, 0xf8, 0xff, 0x16, 0x00, 0xfb, 0xff, 0x15, 0x00, 0xff, 0xff, 0x13, 0x00, 0x03, 0x00, 0x12, 0x00, 0x06, 0x00, 0x11, 0x00, 0x09, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x22, 0x00, 0x0b, 0x00, 0x24, 0x00, 0x0b, 0x00, 0x26, 0x00, 0x0c, 0x00, 0x27, 0x00, 0x0c, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x28, 0x00, 0x0b, 0x00, 0x29, 0x00, 0x09, 0x00, 0x2b, 0x00, 0x07, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x2e, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x03, 0x00, 0x2a, 0x00, 0x02, 0x00, 0x27, 0x00, 0xff, 0xff, 0x25, 0x00, 0xfc, 0xff, 0x22, 0x00, 0xf9, 0xff, 0x1f, 0x00, 0xf7, 0xff, 0x1d, 0x00, 0xf5, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x17, 0x00, 0xf3, 0xff, 0x13, 0x00, 0xf2, 0xff, 0x0e, 0x00, 0xf1, 0xff, 0x09, 0x00, 0xef, 0xff, 0x04, 0x00, 0xee, 0xff, 0xff, 0xff, 0xec, 0xff, 0xfb, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xed, 0xff, 0xeb, 0xff, 0xea, 0xff, 0xeb, 0xff, 0xe7, 0xff, 0xea, 0xff, 0xe6, 0xff, 0xea, 0xff, 0xe5, 0xff, 0xeb, 0xff, 0xe6, 0xff, 0xed, 0xff, 0xe6, 0xff, 0xf0, 0xff, 0xe6, 0xff, 0xf3, 0xff, 0xe5, 0xff, 0xf7, 0xff, 0xe3, 0xff, 0xf9, 0xff, 0xe1, 0xff, 0xfa, 0xff, 0xe0, 0xff, 0xfb, 0xff, 0xdf, 0xff, 0xfb, 0xff, 0xdf, 0xff, 0xfc, 0xff, 0xe0, 0xff, 0xfd, 0xff, 0xe1, 0xff, 0x01, 0x00, 0xe2, 0xff, 0x05, 0x00, 0xe2, 0xff, 0x09, 0x00, 0xe2, 0xff, 0x0c, 0x00, 0xe2, 0xff, 0x0e, 0x00, 0xe3, 0xff, 0x0d, 0x00, 0xe4, 0xff, 0x0c, 0x00, 0xe6, 0xff, 0x0b, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xeb, 0xff, 0x0b, 0x00, 0xee, 0xff, 0x0d, 0x00, 0xf2, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x21, 0x00, 0x0e, 0x00, 0x25, 0x00, 0x0d, 0x00, 0x29, 0x00, 0x0d, 0x00, 0x2c, 0x00, 0x0d, 0x00, 0x2e, 0x00, 0x0d, 0x00, 0x2e, 0x00, 0x0e, 0x00, 0x2d, 0x00, 0x0d, 0x00, 0x2a, 0x00, 0x0c, 0x00, 0x27, 0x00, 0x0b, 0x00, 0x25, 0x00, 0x09, 0x00, 0x23, 0x00, 0x07, 0x00, 0x22, 0x00, 0x05, 0x00, 0x22, 0x00, 0x03, 0x00, 0x20, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf6, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf6, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf0, 0xff, 0xf5, 0xff, 0xed, 0xff, 0xf6, 0xff, 0xe9, 0xff, 0xf7, 0xff, 0xe5, 0xff, 0xf7, 0xff, 0xe2, 0xff, 0xf7, 0xff, 0xe0, 0xff, 0xf8, 0xff, 0xe1, 0xff, 0xfa, 0xff, 0xe2, 0xff, 0xfd, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xe4, 0xff, 0x02, 0x00, 0xe3, 0xff, 0x04, 0x00, 0xe1, 0xff, 0x05, 0x00, 0xdf, 0xff, 0x07, 0x00, 0xde, 0xff, 0x08, 0x00, 0xde, 0xff, 0x0a, 0x00, 0xdf, 0xff, 0x0b, 0x00, 0xe2, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x0f, 0x00, 0xe9, 0xff, 0x10, 0x00, 0xec, 0xff, 0x12, 0x00, 0xee, 0xff, 0x12, 0x00, 0xef, 0xff, 0x13, 0x00, 0xf1, 0xff, 0x14, 0x00, 0xf3, 0xff, 0x15, 0x00, 0xf6, 0xff, 0x15, 0x00, 0xfa, 0xff, 0x16, 0x00, 0xfd, 0xff, 0x17, 0x00, 0x01, 0x00, 0x17, 0x00, 0x05, 0x00, 0x17, 0x00, 0x09, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x0f, 0x00, 0x18, 0x00, 0x11, 0x00, 0x17, 0x00, 0x13, 0x00, 0x17, 0x00, 0x14, 0x00, 0x16, 0x00, 0x16, 0x00, 0x15, 0x00, 0x19, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x1e, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x0b, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x20, 0x00, 0x07, 0x00, 0x20, 0x00, 0x06, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xff, 0xff, 0x1a, 0x00, 0xfb, 0xff, 0x18, 0x00, 0xf9, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x18, 0x00, 0xf6, 0xff, 0x17, 0x00, 0xf6, 0xff, 0x16, 0x00, 0xf5, 0xff, 0x14, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x0d, 0x00, 0xf0, 0xff, 0x0a, 0x00, 0xee, 0xff, 0x08, 0x00, 0xee, 0xff, 0x06, 0x00, 0xee, 0xff, 0x05, 0x00, 0xef, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf5, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf2, 0xff, 0xef, 0xff, 0xf2, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf3, 0xff, 0xe8, 0xff, 0xf4, 0xff, 0xe6, 0xff, 0xf4, 0xff, 0xe3, 0xff, 0xf5, 0xff, 0xe1, 0xff, 0xf5, 0xff, 0xde, 0xff, 0xf4, 0xff, 0xdc, 0xff, 0xf3, 0xff, 0xdb, 0xff, 0xf2, 0xff, 0xd9, 0xff, 0xf1, 0xff, 0xd8, 0xff, 0xf1, 0xff, 0xd7, 0xff, 0xf1, 0xff, 0xd6, 0xff, 0xf3, 0xff, 0xd7, 0xff, 0xf5, 0xff, 0xd8, 0xff, 0xf8, 0xff, 0xd8, 0xff, 0xf9, 0xff, 0xd8, 0xff, 0xfa, 0xff, 0xd9, 0xff, 0xf9, 0xff, 0xd9, 0xff, 0xf8, 0xff, 0xda, 0xff, 0xf8, 0xff, 0xdb, 0xff, 0xfa, 0xff, 0xdc, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0x01, 0x00, 0xe1, 0xff, 0x04, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x08, 0x00, 0xe7, 0xff, 0x08, 0x00, 0xe8, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x08, 0x00, 0xea, 0xff, 0x09, 0x00, 0xed, 0xff, 0x0b, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x0e, 0x00, 0xf7, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x12, 0x00, 0x03, 0x00, 0x15, 0x00, 0x02, 0x00, 0x17, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0xff, 0xff, 0x1a, 0x00, 0xfe, 0xff, 0x1a, 0x00, 0xfd, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xfd, 0xff, 0x1d, 0x00, 0xfd, 0xff, 0x1d, 0x00, 0xfe, 0xff, 0x1d, 0x00, 0xfe, 0xff, 0x1d, 0x00, 0xfe, 0xff, 0x1b, 0x00, 0xfe, 0xff, 0x1a, 0x00, 0xfc, 0xff, 0x18, 0x00, 0xfb, 0xff, 0x16, 0x00, 0xfa, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x14, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf6, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf1, 0xff, 0x03, 0x00, 0xef, 0xff, 0x02, 0x00, 0xef, 0xff, 0x00, 0x00, 0xef, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xe9, 0xff, 0xf2, 0xff, 0xe8, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xf0, 0xff, 0xea, 0xff, 0xef, 0xff, 0xed, 0xff, 0xee, 0xff, 0xef, 0xff, 0xec, 0xff, 0xf1, 0xff, 0xe9, 0xff, 0xf1, 0xff, 0xe7, 0xff, 0xf1, 0xff, 0xe4, 0xff, 0xf2, 0xff, 0xe2, 0xff, 0xf3, 0xff, 0xe1, 0xff, 0xf5, 0xff, 0xe0, 0xff, 0xf8, 0xff, 0xe0, 0xff, 0xfc, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xe0, 0xff, 0x01, 0x00, 0xdf, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xde, 0xff, 0x04, 0x00, 0xdd, 0xff, 0x04, 0x00, 0xdd, 0xff, 0x03, 0x00, 0xde, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x06, 0x00, 0xe7, 0xff, 0x08, 0x00, 0xea, 0xff, 0x08, 0x00, 0xee, 0xff, 0x08, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xff, 0xff, 0x06, 0x00, 0x03, 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x12, 0x00, 0x06, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x05, 0x00, 0x19, 0x00, 0x06, 0x00, 0x1b, 0x00, 0x09, 0x00, 0x1e, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x0d, 0x00, 0x24, 0x00, 0x0d, 0x00, 0x26, 0x00, 0x0c, 0x00, 0x27, 0x00, 0x0c, 0x00, 0x28, 0x00, 0x0c, 0x00, 0x28, 0x00, 0x0d, 0x00, 0x29, 0x00, 0x0f, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x2a, 0x00, 0x12, 0x00, 0x2b, 0x00, 0x12, 0x00, 0x2b, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x0f, 0x00, 0x2b, 0x00, 0x0e, 0x00, 0x2a, 0x00, 0x0c, 0x00, 0x29, 0x00, 0x0b, 0x00, 0x28, 0x00, 0x0b, 0x00, 0x27, 0x00, 0x0a, 0x00, 0x26, 0x00, 0x09, 0x00, 0x25, 0x00, 0x08, 0x00, 0x24, 0x00, 0x06, 0x00, 0x22, 0x00, 0x05, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0xfe, 0xff, 0x18, 0x00, 0xfc, 0xff, 0x16, 0x00, 0xfb, 0xff, 0x15, 0x00, 0xfb, 0xff, 0x13, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x02, 0x00, 0xf1, 0xff, 0x01, 0x00, 0xf2, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xec, 0xff, 0xef, 0xff, 0xee, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xed, 0xff, 0xf2, 0xff, 0xec, 0xff, 0xf2, 0xff, 0xeb, 0xff, 0xf2, 0xff, 0xea, 0xff, 0xf2, 0xff, 0xea, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf5, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf8, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf8, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfe, 0xff, 0xe6, 0xff, 0xfe, 0xff, 0xe5, 0xff, 0xfd, 0xff, 0xe4, 0xff, 0xfc, 0xff, 0xe4, 0xff, 0xfb, 0xff, 0xe4, 0xff, 0xfa, 0xff, 0xe4, 0xff, 0xfb, 0xff, 0xe3, 0xff, 0xfc, 0xff, 0xe1, 0xff, 0xfd, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x01, 0x00, 0xdf, 0xff, 0x02, 0x00, 0xe0, 0xff, 0x02, 0x00, 0xe2, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xe6, 0xff, 0x01, 0x00, 0xe7, 0xff, 0x03, 0x00, 0xe7, 0xff, 0x06, 0x00, 0xe7, 0xff, 0x0a, 0x00, 0xe8, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x10, 0x00, 0xe9, 0xff, 0x11, 0x00, 0xea, 0xff, 0x11, 0x00, 0xeb, 0xff, 0x10, 0x00, 0xec, 0xff, 0x10, 0x00, 0xed, 0xff, 0x10, 0x00, 0xee, 0xff, 0x11, 0x00, 0xef, 0xff, 0x13, 0x00, 0xf0, 0xff, 0x15, 0x00, 0xf0, 0xff, 0x16, 0x00, 0xf0, 0xff, 0x16, 0x00, 0xf1, 0xff, 0x15, 0x00, 0xf2, 0xff, 0x13, 0x00, 0xf3, 0xff, 0x11, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf6, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x10, 0x00, 0x06, 0x00, 0x11, 0x00, 0x06, 0x00, 0x12, 0x00, 0x05, 0x00, 0x14, 0x00, 0x05, 0x00, 0x16, 0x00, 0x03, 0x00, 0x19, 0x00, 0x01, 0x00, 0x1b, 0x00, 0xff, 0xff, 0x1c, 0x00, 0xfc, 0xff, 0x1d, 0x00, 0xfa, 0xff, 0x1d, 0x00, 0xf9, 0xff, 0x1c, 0x00, 0xf8, 0xff, 0x1c, 0x00, 0xf7, 0xff, 0x1c, 0x00, 0xf6, 0xff, 0x1c, 0x00, 0xf5, 0xff, 0x1c, 0x00, 0xf3, 0xff, 0x1c, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xee, 0xff, 0x1a, 0x00, 0xeb, 0xff, 0x18, 0x00, 0xea, 0xff, 0x15, 0x00, 0xe8, 0xff, 0x13, 0x00, 0xe7, 0xff, 0x11, 0x00, 0xe7, 0xff, 0x10, 0x00, 0xe7, 0xff, 0x0f, 0x00, 0xe6, 0xff, 0x0d, 0x00, 0xe5, 0xff, 0x0b, 0x00, 0xe4, 0xff, 0x09, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe4, 0xff, 0x05, 0x00, 0xe5, 0xff, 0x04, 0x00, 0xe7, 0xff, 0x02, 0x00, 0xe9, 0xff, 0xff, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfb, 0xff, 0xef, 0xff, 0xfa, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xf3, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0x00, 0x00, 0xf1, 0xff, 0x02, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x08, 0x00, 0xf1, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x0a, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0e, 0x00, 0xf5, 0xff, 0x10, 0x00, 0xf7, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x12, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x14, 0x00, 0xfc, 0xff, 0x15, 0x00, 0xff, 0xff, 0x16, 0x00, 0x01, 0x00, 0x16, 0x00, 0x03, 0x00, 0x16, 0x00, 0x05, 0x00, 0x16, 0x00, 0x06, 0x00, 0x16, 0x00, 0x07, 0x00, 0x16, 0x00, 0x09, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x10, 0x00, 0x11, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x17, 0x00, 0x08, 0x00, 0x19, 0x00, 0x07, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x20, 0x00, 0xff, 0xff, 0x21, 0x00, 0xfd, 0xff, 0x23, 0x00, 0xfc, 0xff, 0x25, 0x00, 0xfb, 0xff, 0x26, 0x00, 0xfb, 0xff, 0x27, 0x00, 0xfa, 0xff, 0x26, 0x00, 0xfa, 0xff, 0x25, 0x00, 0xf9, 0xff, 0x24, 0x00, 0xf7, 0xff, 0x22, 0x00, 0xf6, 0xff, 0x22, 0x00, 0xf5, 0xff, 0x22, 0x00, 0xf4, 0xff, 0x21, 0x00, 0xf3, 0xff, 0x20, 0x00, 0xf2, 0xff, 0x1e, 0x00, 0xf1, 0xff, 0x1a, 0x00, 0xef, 0xff, 0x17, 0x00, 0xed, 0xff, 0x13, 0x00, 0xec, 0xff, 0x0f, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x09, 0x00, 0xea, 0xff, 0x07, 0x00, 0xe9, 0xff, 0x04, 0x00, 0xe9, 0xff, 0x01, 0x00, 0xe9, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0xfb, 0xff, 0xe8, 0xff, 0xf7, 0xff, 0xe8, 0xff, 0xf4, 0xff, 0xe9, 0xff, 0xf0, 0xff, 0xea, 0xff, 0xec, 0xff, 0xec, 0xff, 0xe9, 0xff, 0xee, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe6, 0xff, 0xf2, 0xff, 0xe5, 0xff, 0xf4, 0xff, 0xe4, 0xff, 0xf5, 0xff, 0xe4, 0xff, 0xf7, 0xff, 0xe4, 0xff, 0xf9, 0xff, 0xe3, 0xff, 0xfc, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x03, 0x00, 0xde, 0xff, 0x06, 0x00, 0xdf, 0xff, 0x09, 0x00, 0xe0, 0xff, 0x0b, 0x00, 0xe1, 0xff, 0x0d, 0x00, 0xe2, 0xff, 0x0f, 0x00, 0xe3, 0xff, 0x11, 0x00, 0xe2, 0xff, 0x13, 0x00, 0xe0, 0xff, 0x15, 0x00, 0xdf, 0xff, 0x18, 0x00, 0xdf, 0xff, 0x1a, 0x00, 0xdf, 0xff, 0x1b, 0x00, 0xe1, 0xff, 0x1c, 0x00, 0xe3, 0xff, 0x1d, 0x00, 0xe5, 0xff, 0x1d, 0x00, 0xe6, 0xff, 0x1d, 0x00, 0xe7, 0xff, 0x1c, 0x00, 0xe7, 0xff, 0x1c, 0x00, 0xe7, 0xff, 0x1c, 0x00, 0xe8, 0xff, 0x1c, 0x00, 0xe9, 0xff, 0x1c, 0x00, 0xeb, 0xff, 0x1b, 0x00, 0xed, 0xff, 0x1a, 0x00, 0xf0, 0xff, 0x18, 0x00, 0xf4, 0xff, 0x16, 0x00, 0xf7, 0xff, 0x14, 0x00, 0xfb, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xff, 0xff, 0x12, 0x00, 0x01, 0x00, 0x12, 0x00, 0x02, 0x00, 0x12, 0x00, 0x04, 0x00, 0x11, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x09, 0x00, 0x13, 0x00, 0x09, 0x00, 0x13, 0x00, 0x08, 0x00, 0x12, 0x00, 0x07, 0x00, 0x11, 0x00, 0x05, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12, 0x00, 0xff, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xf7, 0xff, 0x10, 0x00, 0xf5, 0xff, 0x0f, 0x00, 0xf3, 0xff, 0x0e, 0x00, 0xf1, 0xff, 0x0d, 0x00, 0xef, 0xff, 0x0d, 0x00, 0xed, 0xff, 0x0d, 0x00, 0xeb, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x0c, 0x00, 0xe6, 0xff, 0x0c, 0x00, 0xe4, 0xff, 0x0b, 0x00, 0xe2, 0xff, 0x0b, 0x00, 0xe1, 0xff, 0x0b, 0x00, 0xe1, 0xff, 0x0b, 0x00, 0xe1, 0xff, 0x0a, 0x00, 0xe2, 0xff, 0x0a, 0x00, 0xe3, 0xff, 0x09, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe4, 0xff, 0x06, 0x00, 0xe4, 0xff, 0x05, 0x00, 0xe4, 0xff, 0x04, 0x00, 0xe4, 0xff, 0x03, 0x00, 0xe6, 0xff, 0x01, 0x00, 0xe8, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfb, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xee, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xfd, 0xff, 0xec, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xea, 0xff, 0x01, 0x00, 0xea, 0xff, 0x03, 0x00, 0xe9, 0xff, 0x06, 0x00, 0xe8, 0xff, 0x09, 0x00, 0xe8, 0xff, 0x0b, 0x00, 0xe7, 0xff, 0x0c, 0x00, 0xe7, 0xff, 0x0c, 0x00, 0xe8, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x0d, 0x00, 0xeb, 0xff, 0x0d, 0x00, 0xed, 0xff, 0x0f, 0x00, 0xee, 0xff, 0x11, 0x00, 0xef, 0xff, 0x12, 0x00, 0xef, 0xff, 0x13, 0x00, 0xef, 0xff, 0x12, 0x00, 0xf0, 0xff, 0x11, 0x00, 0xf1, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf6, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x11, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x10, 0x00, 0x06, 0x00, 0x11, 0x00, 0x03, 0x00, 0x12, 0x00, 0x01, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x14, 0x00, 0xfc, 0xff, 0x15, 0x00, 0xf9, 0xff, 0x17, 0x00, 0xf7, 0xff, 0x18, 0x00, 0xf4, 0xff, 0x19, 0x00, 0xf0, 0xff, 0x19, 0x00, 0xed, 0xff, 0x19, 0x00, 0xeb, 0xff, 0x18, 0x00, 0xe9, 0xff, 0x18, 0x00, 0xe7, 0xff, 0x19, 0x00, 0xe6, 0xff, 0x1a, 0x00, 0xe4, 0xff, 0x1a, 0x00, 0xe2, 0xff, 0x1b, 0x00, 0xe0, 0xff, 0x1a, 0x00, 0xde, 0xff, 0x18, 0x00, 0xdd, 0xff, 0x15, 0x00, 0xdd, 0xff, 0x13, 0x00, 0xdd, 0xff, 0x11, 0x00, 0xde, 0xff, 0x10, 0x00, 0xdf, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0e, 0x00, 0xe1, 0xff, 0x0c, 0x00, 0xe2, 0xff, 0x0a, 0x00, 0xe3, 0xff, 0x08, 0x00, 0xe5, 0xff, 0x05, 0x00, 0xe8, 0xff, 0x03, 0x00, 0xeb, 0xff, 0x02, 0x00, 0xee, 0xff, 0x01, 0x00, 0xf1, 0xff, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x11, 0x00, 0xf7, 0xff, 0x13, 0x00, 0xf7, 0xff, 0x15, 0x00, 0xf6, 0xff, 0x16, 0x00, 0xf5, 0xff, 0x18, 0x00, 0xf5, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x1d, 0x00, 0xf4, 0xff, 0x1f, 0x00, 0xf4, 0xff, 0x22, 0x00, 0xf4, 0xff, 0x25, 0x00, 0xf4, 0xff, 0x28, 0x00, 0xf3, 0xff, 0x29, 0x00, 0xf2, 0xff, 0x2a, 0x00, 0xf1, 0xff, 0x2b, 0x00, 0xf0, 0xff, 0x2b, 0x00, 0xf0, 0xff, 0x2b, 0x00, 0xf0, 0xff, 0x2c, 0x00, 0xf2, 0xff, 0x2d, 0x00, 0xf4, 0xff, 0x2d, 0x00, 0xf6, 0xff, 0x2d, 0x00, 0xf6, 0xff, 0x2c, 0x00, 0xf7, 0xff, 0x2a, 0x00, 0xf6, 0xff, 0x27, 0x00, 0xf6, 0xff, 0x24, 0x00, 0xf6, 0xff, 0x21, 0x00, 0xf7, 0xff, 0x1e, 0x00, 0xf9, 0xff, 0x1b, 0x00, 0xfb, 0xff, 0x18, 0x00, 0xfe, 0xff, 0x15, 0x00, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xf2, 0xff, 0x09, 0x00, 0xf1, 0xff, 0x09, 0x00, 0xef, 0xff, 0x08, 0x00, 0xed, 0xff, 0x07, 0x00, 0xea, 0xff, 0x07, 0x00, 0xe8, 0xff, 0x07, 0x00, 0xe6, 0xff, 0x08, 0x00, 0xe5, 0xff, 0x08, 0x00, 0xe4, 0xff, 0x08, 0x00, 0xe4, 0xff, 0x07, 0x00, 0xe3, 0xff, 0x06, 0x00, 0xe2, 0xff, 0x04, 0x00, 0xe2, 0xff, 0x02, 0x00, 0xe1, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xe1, 0xff, 0x02, 0x00, 0xe2, 0xff, 0x03, 0x00, 0xe4, 0xff, 0x02, 0x00, 0xe5, 0xff, 0x02, 0x00, 0xe6, 0xff, 0x01, 0x00, 0xe6, 0xff, 0x00, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xe9, 0xff, 0x01, 0x00, 0xeb, 0xff, 0x02, 0x00, 0xed, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x10, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x16, 0x00, 0xf9, 0xff, 0x19, 0x00, 0xfb, 0xff, 0x1b, 0x00, 0xfd, 0xff, 0x1c, 0x00, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xff, 0xff, 0x1d, 0x00, 0xff, 0xff, 0x1d, 0x00, 0xfe, 0xff, 0x1e, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x02, 0x00, 0x18, 0x00, 0x02, 0x00, 0x15, 0x00, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x11, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x05, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0a, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf2, 0xff, 0x0d, 0x00, 0xef, 0xff, 0x0c, 0x00, 0xec, 0xff, 0x0b, 0x00, 0xe9, 0xff, 0x0b, 0x00, 0xe7, 0xff, 0x0b, 0x00, 0xe6, 0xff, 0x0c, 0x00, 0xe5, 0xff, 0x0d, 0x00, 0xe3, 0xff, 0x0e, 0x00, 0xe1, 0xff, 0x0f, 0x00, 0xdf, 0xff, 0x0f, 0x00, 0xde, 0xff, 0x0f, 0x00, 0xdc, 0xff, 0x0e, 0x00, 0xdb, 0xff, 0x0d, 0x00, 0xda, 0xff, 0x0c, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xda, 0xff, 0x0a, 0x00, 0xdb, 0xff, 0x09, 0x00, 0xdc, 0xff, 0x08, 0x00, 0xde, 0xff, 0x06, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xe2, 0xff, 0x01, 0x00, 0xe3, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xfe, 0xff, 0xe4, 0xff, 0xfe, 0xff, 0xe5, 0xff, 0xfe, 0xff, 0xe8, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf6, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x0d, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x12, 0x00, 0xf3, 0xff, 0x14, 0x00, 0xf4, 0xff, 0x16, 0x00, 0xf6, 0xff, 0x17, 0x00, 0xf7, 0xff, 0x18, 0x00, 0xf7, 0xff, 0x19, 0x00, 0xf6, 0xff, 0x1a, 0x00, 0xf4, 0xff, 0x1a, 0x00, 0xf2, 0xff, 0x1b, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xf1, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x1d, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0xf4, 0xff, 0x1d, 0x00, 0xf3, 0xff, 0x1d, 0x00, 0xf2, 0xff, 0x1d, 0x00, 0xf1, 0xff, 0x1d, 0x00, 0xf0, 0xff, 0x1d, 0x00, 0xef, 0xff, 0x1d, 0x00, 0xf0, 0xff, 0x1c, 0x00, 0xf2, 0xff, 0x1a, 0x00, 0xf5, 0xff, 0x17, 0x00, 0xf7, 0xff, 0x14, 0x00, 0xf8, 0xff, 0x11, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x09, 0x00, 0xf5, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf7, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfa, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xea, 0xff, 0xfe, 0xff, 0xea, 0xff, 0xfe, 0xff, 0xea, 0xff, 0xfd, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xed, 0xff, 0x00, 0x00, 0xee, 0xff, 0x01, 0x00, 0xef, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0x03, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x10, 0x00, 0x05, 0x00, 0x13, 0x00, 0x05, 0x00, 0x15, 0x00, 0x04, 0x00, 0x17, 0x00, 0x04, 0x00, 0x18, 0x00, 0x04, 0x00, 0x18, 0x00, 0x04, 0x00, 0x18, 0x00, 0x04, 0x00, 0x18, 0x00, 0x04, 0x00, 0x18, 0x00, 0x03, 0x00, 0x18, 0x00, 0x02, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x18, 0x00, 0x02, 0x00, 0x18, 0x00, 0x02, 0x00, 0x18, 0x00, 0x02, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0xff, 0xff, 0x19, 0x00, 0xfe, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x18, 0x00, 0xfd, 0xff, 0x17, 0x00, 0xfd, 0xff, 0x15, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x10, 0x00, 0xf7, 0xff, 0x0e, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xf4, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf2, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xee, 0xff, 0xf5, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xe8, 0xff, 0xf8, 0xff, 0xe6, 0xff, 0xfa, 0xff, 0xe4, 0xff, 0xfc, 0xff, 0xe3, 0xff, 0xfe, 0xff, 0xe2, 0xff, 0x00, 0x00, 0xe1, 0xff, 0x02, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x04, 0x00, 0xde, 0xff, 0x06, 0x00, 0xdd, 0xff, 0x07, 0x00, 0xdc, 0xff, 0x09, 0x00, 0xdc, 0xff, 0x0b, 0x00, 0xdc, 0xff, 0x0d, 0x00, 0xdc, 0xff, 0x0e, 0x00, 0xdd, 0xff, 0x0f, 0x00, 0xde, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0e, 0x00, 0xe1, 0xff, 0x0e, 0x00, 0xe3, 0xff, 0x0e, 0x00, 0xe5, 0xff, 0x0e, 0x00, 0xe6, 0xff, 0x0e, 0x00, 0xe7, 0xff, 0x0d, 0x00, 0xe8, 0xff, 0x0c, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xeb, 0xff, 0x0b, 0x00, 0xed, 0xff, 0x0b, 0x00, 0xef, 0xff, 0x0b, 0x00, 0xf1, 0xff, 0x0c, 0x00, 0xf2, 0xff, 0x0d, 0x00, 0xf3, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x0d, 0x00, 0xf4, 0xff, 0x0d, 0x00, 0xf5, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x11, 0x00, 0xff, 0xff, 0x10, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x17, 0x00, 0x09, 0x00, 0x18, 0x00, 0x08, 0x00, 0x18, 0x00, 0x06, 0x00, 0x18, 0x00, 0x04, 0x00, 0x17, 0x00, 0x02, 0x00, 0x16, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0xff, 0x14, 0x00, 0xfe, 0xff, 0x13, 0x00, 0xfd, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x11, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf5, 0xff, 0x0e, 0x00, 0xf5, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf4, 0xff, 0x0a, 0x00, 0xf5, 0xff, 0x09, 0x00, 0xf5, 0xff, 0x08, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x08, 0x00, 0xf3, 0xff, 0x0a, 0x00, 0xf3, 0xff, 0x0b, 0x00, 0xf3, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x0b, 0x00, 0xf7, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0c, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x08, 0x00, 0x11, 0x00, 0x05, 0x00, 0x11, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x02, 0x00, 0xef, 0xff, 0x00, 0x00, 0xef, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xe9, 0xff, 0xf4, 0xff, 0xe8, 0xff, 0xf4, 0xff, 0xe7, 0xff, 0xf3, 0xff, 0xe7, 0xff, 0xf2, 0xff, 0xe7, 0xff, 0xf0, 0xff, 0xe8, 0xff, 0xef, 0xff, 0xe9, 0xff, 0xee, 0xff, 0xea, 0xff, 0xee, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xec, 0xff, 0xee, 0xff, 0xec, 0xff, 0xee, 0xff, 0xed, 0xff, 0xee, 0xff, 0xed, 0xff, 0xee, 0xff, 0xee, 0xff, 0xee, 0xff, 0xee, 0xff, 0xee, 0xff, 0xef, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xf0, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x10, 0x00, 0x07, 0x00, 0x11, 0x00, 0x07, 0x00, 0x13, 0x00, 0x07, 0x00, 0x15, 0x00, 0x08, 0x00, 0x15, 0x00, 0x08, 0x00, 0x15, 0x00, 0x07, 0x00, 0x14, 0x00, 0x05, 0x00, 0x14, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0xfe, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x0e, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfd, 0xff, 0xec, 0xff, 0xfe, 0xff, 0xec, 0xff, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xff, 0xea, 0xff, 0x00, 0x00, 0xe9, 0xff, 0x00, 0x00, 0xe8, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xec, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xef, 0xff, 0xfe, 0xff, 0xf0, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x02, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0e, 0x00, 0x01, 0x00, 0x10, 0x00, 0x04, 0x00, 0x11, 0x00, 0x06, 0x00, 0x12, 0x00, 0x09, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x08, 0x00, 0x14, 0x00, 0x05, 0x00, 0x13, 0x00, 0x04, 0x00, 0x12, 0x00, 0x02, 0x00, 0x11, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf5, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf2, 0xff, 0xf0, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xf0, 0xff, 0xed, 0xff, 0xee, 0xff, 0xed, 0xff, 0xed, 0xff, 0xed, 0xff, 0xec, 0xff, 0xee, 0xff, 0xeb, 0xff, 0xef, 0xff, 0xeb, 0xff, 0xf0, 0xff, 0xeb, 0xff, 0xf2, 0xff, 0xeb, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xeb, 0xff, 0xf4, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xe9, 0xff, 0xf7, 0xff, 0xe9, 0xff, 0xf9, 0xff, 0xe9, 0xff, 0xfb, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xff, 0xff, 0xef, 0xff, 0x02, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x08, 0x00, 0xf6, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x11, 0x00, 0x04, 0x00, 0x12, 0x00, 0x05, 0x00, 0x13, 0x00, 0x05, 0x00, 0x13, 0x00, 0x05, 0x00, 0x13, 0x00, 0x06, 0x00, 0x13, 0x00, 0x08, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x09, 0x00, 0x11, 0x00, 0x08, 0x00, 0x12, 0x00, 0x06, 0x00, 0x11, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xff, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xfc, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x02, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf2, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x13, 0x00, 0x09, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x09, 0x00, 0x17, 0x00, 0x08, 0x00, 0x18, 0x00, 0x07, 0x00, 0x18, 0x00, 0x08, 0x00, 0x19, 0x00, 0x09, 0x00, 0x19, 0x00, 0x09, 0x00, 0x17, 0x00, 0x09, 0x00, 0x16, 0x00, 0x08, 0x00, 0x14, 0x00, 0x07, 0x00, 0x13, 0x00, 0x06, 0x00, 0x12, 0x00, 0x05, 0x00, 0x10, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xf1, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xef, 0xff, 0xf2, 0xff, 0xee, 0xff, 0xf1, 0xff, 0xed, 0xff, 0xf1, 0xff, 0xec, 0xff, 0xf0, 0xff, 0xec, 0xff, 0xef, 0xff, 0xeb, 0xff, 0xee, 0xff, 0xec, 0xff, 0xee, 0xff, 0xec, 0xff, 0xee, 0xff, 0xec, 0xff, 0xed, 0xff, 0xeb, 0xff, 0xed, 0xff, 0xea, 0xff, 0xee, 0xff, 0xe9, 0xff, 0xef, 0xff, 0xe8, 0xff, 0xf1, 0xff, 0xe8, 0xff, 0xf3, 0xff, 0xe9, 0xff, 0xf4, 0xff, 0xea, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xee, 0xff, 0xf6, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x09, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x02, 0x00, 0x17, 0x00, 0x03, 0x00, 0x18, 0x00, 0x04, 0x00, 0x19, 0x00, 0x05, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x06, 0x00, 0x1e, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x0c, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x09, 0x00, 0x01, 0x00, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x08, 0x00, 0x12, 0x00, 0x07, 0x00, 0x12, 0x00, 0x06, 0x00, 0x12, 0x00, 0x06, 0x00, 0x12, 0x00, 0x05, 0x00, 0x11, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf6, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xf0, 0xff, 0xf4, 0xff, 0xf0, 0xff, 0xf3, 0xff, 0xef, 0xff, 0xf1, 0xff, 0xee, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xf0, 0xff, 0xee, 0xff, 0xf0, 0xff, 0xef, 0xff, 0xf1, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xef, 0xff, 0xf4, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf6, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xef, 0xff, 0x06, 0x00, 0xed, 0xff, 0x06, 0x00, 0xec, 0xff, 0x06, 0x00, 0xeb, 0xff, 0x06, 0x00, 0xeb, 0xff, 0x07, 0x00, 0xec, 0xff, 0x08, 0x00, 0xed, 0xff, 0x08, 0x00, 0xee, 0xff, 0x08, 0x00, 0xef, 0xff, 0x08, 0x00, 0xef, 0xff, 0x07, 0x00, 0xee, 0xff, 0x06, 0x00, 0xee, 0xff, 0x05, 0x00, 0xee, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfb, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x11, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xf8, 0xff, 0x14, 0x00, 0xf7, 0xff, 0x13, 0x00, 0xf7, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xf9, 0xff, 0x0f, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x09, 0x00, 0x03, 0x00, 0x07, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xef, 0xff, 0x08, 0x00, 0xef, 0xff, 0x08, 0x00, 0xee, 0xff, 0x09, 0x00, 0xef, 0xff, 0x0a, 0x00, 0xf0, 0xff, 0x0b, 0x00, 0xf2, 0xff, 0x0c, 0x00, 0xf4, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x0b, 0x00, 0xf7, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf6, 0xff, 0x0c, 0x00, 0xf6, 0xff, 0x0d, 0x00, 0xf6, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x00, 0x08, 0x00, 0x05, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x09, 0x00, 0x05, 0x00, 0x09, 0x00, 0x04, 0x00, 0x09, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf3, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xef, 0xff, 0x06, 0x00, 0xee, 0xff, 0x06, 0x00, 0xed, 0xff, 0x05, 0x00, 0xed, 0xff, 0x04, 0x00, 0xed, 0xff, 0x04, 0x00, 0xec, 0xff, 0x03, 0x00, 0xeb, 0xff, 0x03, 0x00, 0xea, 0xff, 0x03, 0x00, 0xe9, 0xff, 0x03, 0x00, 0xe8, 0xff, 0x02, 0x00, 0xe8, 0xff, 0x02, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xe9, 0xff, 0xff, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf2, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xef, 0xff, 0x05, 0x00, 0xef, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xef, 0xff, 0x06, 0x00, 0xef, 0xff, 0x06, 0x00, 0xed, 0xff, 0x08, 0x00, 0xec, 0xff, 0x09, 0x00, 0xea, 0xff, 0x0b, 0x00, 0xea, 0xff, 0x0c, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe9, 0xff, 0x0c, 0x00, 0xe9, 0xff, 0x0c, 0x00, 0xe9, 0xff, 0x0d, 0x00, 0xe9, 0xff, 0x0e, 0x00, 0xe9, 0xff, 0x0f, 0x00, 0xe9, 0xff, 0x10, 0x00, 0xe9, 0xff, 0x11, 0x00, 0xe9, 0xff, 0x10, 0x00, 0xea, 0xff, 0x10, 0x00, 0xeb, 0xff, 0x0f, 0x00, 0xec, 0xff, 0x0f, 0x00, 0xed, 0xff, 0x0f, 0x00, 0xee, 0xff, 0x10, 0x00, 0xf0, 0xff, 0x10, 0x00, 0xf1, 0xff, 0x10, 0x00, 0xf1, 0xff, 0x10, 0x00, 0xf2, 0xff, 0x10, 0x00, 0xf3, 0xff, 0x10, 0x00, 0xf4, 0xff, 0x10, 0x00, 0xf6, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x09, 0x00, 0x09, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x11, 0x00, 0xfc, 0xff, 0x12, 0x00, 0xfb, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x11, 0x00, 0xfa, 0xff, 0x10, 0x00, 0xfa, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x10, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xf8, 0xff, 0x10, 0x00, 0xf8, 0xff, 0x0e, 0x00, 0xf8, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x04, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xef, 0xff, 0x06, 0x00, 0xef, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x11, 0x00, 0x01, 0x00, 0x12, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x15, 0x00, 0x02, 0x00, 0x16, 0x00, 0x02, 0x00, 0x16, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xff, 0x12, 0x00, 0xfe, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf4, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf0, 0xff, 0xfa, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xfb, 0xff, 0xed, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xef, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x11, 0x00, 0x04, 0x00, 0x12, 0x00, 0x03, 0x00, 0x12, 0x00, 0x02, 0x00, 0x11, 0x00, 0x01, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x00, 0x11, 0x00, 0x04, 0x00, 0x11, 0x00, 0x05, 0x00, 0x10, 0x00, 0x06, 0x00, 0x10, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x10, 0x00, 0x06, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x05, 0x00, 0x11, 0x00, 0x04, 0x00, 0x11, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x09, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf2, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf8, 0xff, 0xf3, 0xff, 0xf9, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x10, 0x00, 0x06, 0x00, 0x10, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf3, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf7, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xf8, 0xff, 0xe9, 0xff, 0xf9, 0xff, 0xe8, 0xff, 0xfa, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe7, 0xff, 0xfb, 0xff, 0xe7, 0xff, 0xfa, 0xff, 0xe7, 0xff, 0xf9, 0xff, 0xe7, 0xff, 0xf9, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xe8, 0xff, 0xf9, 0xff, 0xe8, 0xff, 0xfa, 0xff, 0xe9, 0xff, 0xfb, 0xff, 0xea, 0xff, 0xfd, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xec, 0xff, 0xfe, 0xff, 0xed, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x11, 0x00, 0x09, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x09, 0x00, 0x15, 0x00, 0x09, 0x00, 0x16, 0x00, 0x08, 0x00, 0x17, 0x00, 0x07, 0x00, 0x16, 0x00, 0x06, 0x00, 0x15, 0x00, 0x06, 0x00, 0x14, 0x00, 0x06, 0x00, 0x12, 0x00, 0x06, 0x00, 0x10, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x09, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x07, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0xff, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfb, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xf8, 0xff, 0xf3, 0xff, 0xf6, 0xff, 0xf3, 0xff, 0xf5, 0xff, 0xf2, 0xff, 0xf4, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xef, 0xff, 0xf5, 0xff, 0xec, 0xff, 0xf5, 0xff, 0xeb, 0xff, 0xf5, 0xff, 0xea, 0xff, 0xf4, 0xff, 0xea, 0xff, 0xf2, 0xff, 0xea, 0xff, 0xf1, 0xff, 0xeb, 0xff, 0xf1, 0xff, 0xec, 0xff, 0xf2, 0xff, 0xec, 0xff, 0xf3, 0xff, 0xeb, 0xff, 0xf5, 0xff, 0xeb, 0xff, 0xf6, 0xff, 0xea, 0xff, 0xf7, 0xff, 0xea, 0xff, 0xf7, 0xff, 0xeb, 0xff, 0xf7, 0xff, 0xec, 0xff, 0xf6, 0xff, 0xed, 0xff, 0xf6, 0xff, 0xef, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf9, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x14, 0x00, 0x08, 0x00, 0x18, 0x00, 0x09, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x0c, 0x00, 0x21, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x0b, 0x00, 0x21, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x08, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf2, 0xff, 0xff, 0xff, 0xf2, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf3, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xef, 0xff, 0xf7, 0xff, 0xf1, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf7, 0xff, 0xf3, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xef, 0xff, 0xfe, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xff, 0x00, 0x00, 0xee, 0xff, 0x00, 0x00, 0xed, 0xff, 0x00, 0x00, 0xec, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, 0xe8, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x00, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xe9, 0xff, 0x01, 0x00, 0xe9, 0xff, 0x01, 0x00, 0xea, 0xff, 0x01, 0x00, 0xe9, 0xff, 0x00, 0x00, 0xe8, 0xff, 0x00, 0x00, 0xe7, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xea, 0xff, 0xff, 0xff, 0xec, 0xff, 0xff, 0xff, 0xee, 0xff, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x11, 0x00, 0x06, 0x00, 0x12, 0x00, 0x06, 0x00, 0x12, 0x00, 0x06, 0x00, 0x11, 0x00, 0x06, 0x00, 0x10, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x0a, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x0c, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x04, 0x00, 0xf1, 0xff, 0x03, 0x00, 0xf1, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xef, 0xff, 0xff, 0xff, 0xee, 0xff, 0xfe, 0xff, 0xed, 0xff, 0xfd, 0xff, 0xed, 0xff, 0xfc, 0xff, 0xed, 0xff, 0xfb, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xef, 0xff, 0xf9, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf6, 0xff, 0xf3, 0xff, 0xf4, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf3, 0xff, 0xf2, 0xff, 0xf3, 0xff, 0xf1, 0xff, 0xf4, 0xff, 0xf1, 0xff, 0xf5, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xef, 0xff, 0xf9, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xee, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xfa, 0xff, 0xee, 0xff, 0xfb, 0xff, 0xef, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x09, 0x00, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x11, 0x00, 0xff, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x07, 0x00, 0xf4, 0xff, 0x09, 0x00, 0xf4, 0xff, 0x0a, 0x00, 0xf4, 0xff, 0x0b, 0x00, 0xf5, 0xff, 0x0c, 0x00, 0xf7, 0xff, 0x0d, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0xf9, 0xff, 0x11, 0x00, 0xf9, 0xff, 0x12, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xf9, 0xff, 0x13, 0x00, 0xfa, 0xff, 0x13, 0x00, 0xfb, 0xff, 0x12, 0x00, 0xfc, 0xff, 0x11, 0x00, 0xfe, 0xff, 0x11, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x00, 0x11, 0x00, 0x05, 0x00, 0x11, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf1, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xee, 0xff, 0x00, 0x00, 0xec, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfc, 0xff, 0xea, 0xff, 0xfa, 0xff, 0xeb, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xee, 0xff, 0xf8, 0xff, 0xef, 0xff, 0xf8, 0xff, 0xf0, 0xff, 0xf9, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf2, 0xff, 0xf8, 0xff, 0xf3, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf5, 0xff, 0xf6, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xf3, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x0e, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0x10, 0x00, 0xff, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x12, 0x00, 0xfd, 0xff, 0x11, 0x00, 0xfd, 0xff, 0x10, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x09, 0x00, 0xf7, 0xff, 0x0a, 0x00, 0xf7, 0xff, 0x0b, 0x00, 0xf7, 0xff, 0x0c, 0x00, 0xf8, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0d, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x10, 0x00, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf2, 0xff, 0x03, 0x00, 0xf1, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x05, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xf0, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x05, 0x00, 0xf2, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x05, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x03, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x10, 0x00, 0x07, 0x00, 0x10, 0x00, 0x06, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0b, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf4, 0xff, 0x06, 0x00, 0xf3, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf2, 0xff, 0x07, 0x00, 0xf1, 0xff, 0x06, 0x00, 0xf1, 0xff, 0x04, 0x00, 0xf0, 0xff, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xef, 0xff, 0xfe, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xf0, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf6, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfa, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x04, 0x00, 0x09, 0x00, 0x05, 0x00, 0x09, 0x00, 0x07, 0x00, 0x09, 0x00, 0x08, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x09, 0x00, 0x04, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf5, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xef, 0xff, 0xfb, 0xff, 0xee, 0xff, 0xf9, 0xff, 0xec, 0xff, 0xf9, 0xff, 0xeb, 0xff, 0xf8, 0xff, 0xea, 0xff, 0xf9, 0xff, 0xea, 0xff, 0xfa, 0xff, 0xea, 0xff, 0xfb, 0xff, 0xeb, 0xff, 0xfb, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xec, 0xff, 0xfa, 0xff, 0xed, 0xff, 0xf9, 0xff, 0xed, 0xff, 0xf8, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xed, 0xff, 0xf7, 0xff, 0xee, 0xff, 0xf7, 0xff, 0xf0, 0xff, 0xf7, 0xff, 0xf2, 0xff, 0xf7, 0xff, 0xf4, 0xff, 0xf7, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf7, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x05, 0x00, 0x10, 0x00, 0x05, 0x00, 0x10, 0x00, 0x04, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf5, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff, 0xff, 0xed, 0xff, 0x00, 0x00, 0xed, 0xff, 0x01, 0x00, 0xed, 0xff, 0x02, 0x00, 0xed, 0xff, 0x02, 0x00, 0xed, 0xff, 0x02, 0x00, 0xee, 0xff, 0x02, 0x00, 0xef, 0xff, 0x01, 0x00, 0xf1, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf4, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0e, 0x00, 0xfd, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf6, 0xff, 0xfb, 0xff, 0xf4, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfa, 0xff, 0xf1, 0xff, 0xfb, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfe, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xf1, 0xff, 0x00, 0x00, 0xf1, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x10, 0x00, 0x09, 0x00, 0x11, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x09, 0x00, 0x16, 0x00, 0x08, 0x00, 0x17, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x19, 0x00, 0x08, 0x00, 0x19, 0x00, 0x09, 0x00, 0x19, 0x00, 0x08, 0x00, 0x18, 0x00, 0x07, 0x00, 0x16, 0x00, 0x06, 0x00, 0x14, 0x00, 0x04, 0x00, 0x13, 0x00, 0x03, 0x00, 0x12, 0x00, 0x02, 0x00, 0x12, 0x00, 0x02, 0x00, 0x11, 0x00, 0x02, 0x00, 0x11, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xec, 0xff, 0xfe, 0xff, 0xec, 0xff, 0xfe, 0xff, 0xeb, 0xff, 0xfe, 0xff, 0xea, 0xff, 0xfe, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe9, 0xff, 0xfd, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe8, 0xff, 0xfc, 0xff, 0xe9, 0xff, 0xfc, 0xff, 0xeb, 0xff, 0xfd, 0xff, 0xec, 0xff, 0xfd, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xef, 0xff, 0xfd, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf4, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xff, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xf9, 0xff, 0xf6, 0xff, 0xf8, 0xff, 0xf5, 0xff, 0xf8, 0xff, 0xf4, 0xff, 0xf9, 0xff, 0xf3, 0xff, 0xfa, 0xff, 0xf3, 0xff, 0xfb, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf2, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xfc, 0xff, 0xf1, 0xff, 0xfd, 0xff, 0xf2, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x09, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf6, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfa, 0xff, 0xf7, 0xff, 0xfb, 0xff, 0xf6, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfe, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf4, 0xff, 0x01, 0x00, 0xf3, 0xff, 0x01, 0x00, 0xf3, 0xff, 0x02, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf4, 0xff, 0x04, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x08, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf8, 0xff, 0x0a, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf8, 0xff, 0x0b, 0x00, 0xf9, 0xff, 0x0c, 0x00, 0xfa, 0xff, 0x0c, 0x00, 0xfb, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0xff, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfb, 0xff, 0x0a, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x05, 0x00, 0xf4, 0xff, 0x04, 0x00, 0xf3, 0xff, 0x03, 0x00, 0xf2, 0xff, 0x02, 0x00, 0xf2, 0xff, 0x01, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf2, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf3, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xfe, 0xff, 0xf2, 0xff, 0xfd, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf3, 0xff, 0xfc, 0xff, 0xf4, 0xff, 0xfc, 0xff, 0xf5, 0xff, 0xfc, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x05, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf5, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x08, 0x00, 0xf8, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x0b, 0x00, 0xf9, 0xff, 0x0c, 0x00, 0xf8, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x0d, 0x00, 0xf9, 0xff, 0x0e, 0x00, 0xfa, 0xff, 0x0e, 0x00, 0xfb, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x0e, 0x00, 0xfc, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x09, 0x00, 0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf4, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfd, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x09, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0xff, 0xff, 0x0d, 0x00, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfd, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf3, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x03, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x0a, 0x00, 0xfc, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfc, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfd, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0d, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfe, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0b, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf9, 0xff, 0xf8, 0xff, 0xfa, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x09, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xf9, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x09, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x01, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf5, 0xff, 0x02, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf6, 0xff, 0x03, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf7, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf7, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x06, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf6, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf7, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff, 0xff, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf5, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf6, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfc, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf8, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x07, 0x00, 0xf9, 0xff, 0x08, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xf9, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x09, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x08, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x09, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x09, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x09, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfc, 0xff, 0x08, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x07, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x03, 0x00, 0x09, 0x00, 0x03, 0x00, 0x09, 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xfa, 0xff, 0x06, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf9, 0xff, 0x05, 0x00, 0xf8, 0xff, 0x04, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x02, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x01, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xf9, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfd, 0xff, 0xf9, 0xff, 0xfe, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfc, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x00, 0xfb, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xfa, 0xff, 0x04, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x03, 0x00, 0xf9, 0xff, 0x02, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfe, 0xff, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf8, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xf9, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x03, 0x00, 0x09, 0x00, 0x03, 0x00, 0x09, 0x00, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x09, 0x00, 0xff, 0xff, 0x08, 0x00, 0xff, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfb, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfc, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfd, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x05, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x08, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x09, 0x00, 0xfe, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x02, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x01, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x02, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfa, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x05, 0x00, 0xff, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfe, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x07, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x06, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x04, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfc, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x02, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xff, 0xff, 0x04, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x02, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x72, 0x65, 0x67, 0x6e, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x6d, 0xff, 0xce, 0xe1, 0x45, 0x11, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x50, 0x6f, 0x70, 0x5f, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x65, 0x64, 0x5f, 0x32, 0x00, 0x00, 0x58, 0x99, 0xd6, 0x39, 0x01, 0x00, 0x00, 0x00, 0x90, 0x6e, 0xc5, 0xbc, 0xa6, 0x7f, 0x00, 0x00, 0x75, 0x6d, 0x69, 0x64, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x6d, 0xff, 0xce, 0xe1, 0x45, 0x11, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + NSUInteger length = sizeof(bytes) / sizeof(Byte); + return [NSData dataWithBytesNoCopy:(void *)bytes length:length freeWhenDone:NO]; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeControl+Internal.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeControl+Internal.h new file mode 100644 index 0000000..13890a6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeControl+Internal.h @@ -0,0 +1,27 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKLikeControl.h" + +@interface FBSDKLikeControl () + +- (NSDictionary *)analyticsParameters; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.h new file mode 100644 index 0000000..9d7748f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import + +@protocol FBSDKLikeDialogDelegate; + +@interface FBSDKLikeDialog : NSObject + ++ (instancetype)likeWithObjectID:(NSString *)objectID + objectType:(FBSDKLikeObjectType)objectType + delegate:(id)delegate; + +@property (nonatomic, weak) id delegate; +@property (nonatomic, copy) NSString *objectID; +@property (nonatomic, assign) FBSDKLikeObjectType objectType; +@property (nonatomic, assign) BOOL shouldFailOnDataError; +@property (nonatomic, weak) UIViewController *fromViewController; + +- (BOOL)canLike; +- (BOOL)like; +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +@protocol FBSDKLikeDialogDelegate + +- (void)likeDialog:(FBSDKLikeDialog *)likeDialog didCompleteWithResults:(NSDictionary *)results; +- (void)likeDialog:(FBSDKLikeDialog *)likeDialog didFailWithError:(NSError *)error; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.m new file mode 100644 index 0000000..ea2abf6 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.m @@ -0,0 +1,159 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKLikeDialog.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" + +@implementation FBSDKLikeDialog + +#define FBSDK_LIKE_METHOD_MIN_VERSION @"20140410" +#define FBSDK_LIKE_METHOD_NAME @"like" +#define FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_LIKE @"like" +#define FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_UNLIKE @"unlike" + +#pragma mark - Class Methods + ++ (void)initialize +{ + if ([FBSDKLikeDialog class] == self) { + [FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL]; + } +} + ++ (instancetype)likeWithObjectID:(NSString *)objectID + objectType:(FBSDKLikeObjectType)objectType + delegate:(id)delegate +{ + FBSDKLikeDialog *dialog = [[self alloc] init]; + dialog.objectID = objectID; + dialog.objectType = objectType; + dialog.delegate = delegate; + [dialog like]; + return dialog; +} + +#pragma mark - Public Methods + +- (BOOL)canLike +{ + return YES; +} + +- (BOOL)like +{ + NSError *error; + if (![self canLike]) { + error = [FBSDKShareError errorWithCode:FBSDKShareDialogNotAvailableErrorCode + message:@"Like dialog is not available."]; + [_delegate likeDialog:self didFailWithError:error]; + return NO; + } + if (![self validateWithError:&error]) { + [_delegate likeDialog:self didFailWithError:error]; + return NO; + } + + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [FBSDKInternalUtility dictionary:parameters setObject:self.objectID forKey:@"object_id"]; + [FBSDKInternalUtility dictionary:parameters + setObject:NSStringFromFBSDKLikeObjectType(self.objectType) + forKey:@"object_type"]; + FBSDKBridgeAPIRequest * webRequest = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeWeb + scheme:FBSDK_SHARE_JS_DIALOG_SCHEME + methodName:FBSDK_LIKE_METHOD_NAME + methodVersion:nil + parameters:parameters + userInfo:nil]; + FBSDKBridgeAPICallbackBlock completionBlock = ^(FBSDKBridgeAPIResponse *response) { + [self _handleCompletionWithDialogResults:response.responseParameters error:response.error]; + }; + + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useSafariViewController = [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameLike]; + if ([self _canLikeNative]) { + FBSDKBridgeAPIRequest *nativeRequest = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeNative + scheme:FBSDK_CANOPENURL_FACEBOOK + methodName:FBSDK_LIKE_METHOD_NAME + methodVersion:FBSDK_LIKE_METHOD_MIN_VERSION + parameters:parameters + userInfo:nil]; + void (^networkCompletionBlock)(FBSDKBridgeAPIResponse *) = ^(FBSDKBridgeAPIResponse *response) { + if (response.error.code == FBSDKAppVersionUnsupportedErrorCode) { + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:webRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:completionBlock]; + } else { + completionBlock(response); + } + }; + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:nativeRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:networkCompletionBlock]; + } else { + [[FBSDKApplicationDelegate sharedInstance] openBridgeAPIRequest:webRequest + useSafariViewController:useSafariViewController + fromViewController:self.fromViewController + completionBlock:completionBlock]; + } + + return YES; +} + +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef +{ + if (![self.objectID length]) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"objectID" message:nil]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + +#pragma mark - Helper Methods + +- (BOOL)_canLikeNative +{ + FBSDKServerConfiguration *configuration = [FBSDKServerConfigurationManager cachedServerConfiguration]; + BOOL useNativeDialog = [configuration useNativeDialogForDialogName:FBSDKDialogConfigurationNameLike]; + return (useNativeDialog && [FBSDKInternalUtility isFacebookAppInstalled]); +} + +- (void)_handleCompletionWithDialogResults:(NSDictionary *)results error:(NSError *)error +{ + if (!_delegate) { + return; + } + NSString *completionGesture = results[FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY]; + if (completionGesture && !error) { + [_delegate likeDialog:self didCompleteWithResults:[results copy]]; + } else { + [_delegate likeDialog:self didFailWithError:error]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.h new file mode 100644 index 0000000..b3b6965 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKMessengerIcon : FBSDKIcon + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.m new file mode 100644 index 0000000..2f5a22f --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.m @@ -0,0 +1,50 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMessengerIcon.h" + +@implementation FBSDKMessengerIcon + +- (CGPathRef)pathWithSize:(CGSize)size +{ + CGAffineTransform transformValue = CGAffineTransformMakeScale(size.width / 61.0, size.height / 61.0); + const CGAffineTransform *transform = &transformValue; + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, transform, 30.001, 0.962); + CGPathAddCurveToPoint(path, transform, 13.439, 0.962, 0.014, 13.462, 0.014, 28.882); + CGPathAddCurveToPoint(path, transform, 0.014, 37.165, 3.892, 44.516, 10.046, 49.549); + CGPathAddLineToPoint(path, transform, 10.046, 61.176); + CGPathAddLineToPoint(path, transform, 19.351, 54.722); + CGPathAddCurveToPoint(path, transform, 22.662, 55.870, 26.250, 56.502, 30.002, 56.502); + CGPathAddCurveToPoint(path, transform, 46.565, 56.502, 59.990, 44.301, 59.990, 28.882); + CGPathAddCurveToPoint(path, transform, 59.989, 13.462, 46.564, 0.962, 30.001, 0.962); + CGPathCloseSubpath(path); + CGPathMoveToPoint(path, transform, 33.159, 37.473); + CGPathAddLineToPoint(path, transform, 25.403, 29.484); + CGPathAddLineToPoint(path, transform, 10.467, 37.674); + CGPathAddLineToPoint(path, transform, 26.843, 20.445); + CGPathAddLineToPoint(path, transform, 34.599, 28.433); + CGPathAddLineToPoint(path, transform, 49.535, 20.244); + CGPathAddLineToPoint(path, transform, 33.159, 37.473); + CGPathCloseSubpath(path); + CGPathRef result = CGPathCreateCopy(path); + CGPathRelease(path); + return CFAutorelease(result); +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareDefines.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareDefines.h new file mode 100644 index 0000000..2d647fb --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareDefines.h @@ -0,0 +1,30 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#define FBSDK_SHARE_JS_DIALOG_SCHEME @"web" +#define FBSDK_SHARE_METHOD_NAME @"share" +#define FBSDK_SHARE_OPEN_GRAPH_METHOD_NAME @"ogshare" +#define FBSDK_SHARE_RESULT_COMPLETION_GESTURE_KEY @"completionGesture" +#define FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_CANCEL @"cancel" +#define FBSDK_SHARE_RESULT_COMPLETION_GESTURE_VALUE_POST @"post" +#define FBSDK_SHARE_RESULT_DID_COMPLETE_KEY @"didComplete" +#define FBSDK_SHARE_RESULT_POST_ID_KEY @"postId" +#define FBSDK_SHARE_WEB_PARAM_POST_ID_KEY @"post_id" +#define FBSDK_SHARE_WEB_SCHEME @"https" diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.h new file mode 100644 index 0000000..ad83522 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKCoreKit+Internal.h" + +@interface FBSDKShareError : FBSDKError + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.m new file mode 100644 index 0000000..46896cc --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.m @@ -0,0 +1,30 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareError.h" + +#import "FBSDKShareConstants.h" + +@implementation FBSDKShareError + ++ (NSString *)errorDomain +{ + return FBSDKShareErrorDomain; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareKit+Internal.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareKit+Internal.h new file mode 100644 index 0000000..5c75377 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareKit+Internal.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKShareDefines.h" +#import "FBSDKShareError.h" +#import "FBSDKShareOpenGraphValueContainer+Internal.h" +#import "FBSDKShareUtility.h" diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareLinkContent+Internal.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareLinkContent+Internal.h new file mode 100644 index 0000000..c9269de --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareLinkContent+Internal.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareLinkContent.h" + +@interface FBSDKShareLinkContent () + +// Deprecated parameters for Feed Dialog - for usage with Unity only. +@property (nonatomic, copy) NSDictionary *feedParameters; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareOpenGraphValueContainer+Internal.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareOpenGraphValueContainer+Internal.h new file mode 100644 index 0000000..5d9382e --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareOpenGraphValueContainer+Internal.h @@ -0,0 +1,29 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@interface FBSDKShareOpenGraphValueContainer () + +- (NSDictionary *)allProperties; +- (BOOL)isEqualToShareOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object; +- (BOOL)requireKeyNamespace; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.h b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.h new file mode 100644 index 0000000..82ac804 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import + +@interface FBSDKShareUtility : NSObject + ++ (void)assertCollection:(id)collection ofClass:itemClass name:(NSString *)name; ++ (void)assertOpenGraphKey:(id)key requireNamespace:(BOOL)requireNamespace; ++ (void)assertOpenGraphValue:(id)value; ++ (void)assertOpenGraphValues:(NSDictionary *)dictionary requireKeyNamespace:(BOOL)requireKeyNamespace; ++ (id)convertOpenGraphValue:(id)value; ++ (BOOL)buildWebShareContent:(id)content + methodName:(NSString *__autoreleasing *)methodNameRef + parameters:(NSDictionary *__autoreleasing *)parametersRef + error:(NSError *__autoreleasing *)errorRef; ++ (NSDictionary *)convertOpenGraphValues:(NSDictionary *)dictionary; ++ (NSDictionary *)feedShareDictionaryForContent:(id)content; ++ (NSDictionary *)parametersForShareContent:(id)shareContent + shouldFailOnDataError:(BOOL)shouldFailOnDataError; ++ (void)testShareContent:(id)shareContent + containsMedia:(BOOL *)containsMediaRef + containsPhotos:(BOOL *)containsPhotosRef; ++ (BOOL)validateAppInviteContent:(FBSDKAppInviteContent *)appInviteContent error:(NSError *__autoreleasing *)errorRef; ++ (BOOL)validateGameRequestContent:(FBSDKGameRequestContent *)gameRequestContent error:(NSError *__autoreleasing *)errorRef; ++ (BOOL)validateShareContent:(id)shareContent error:(NSError *__autoreleasing *)errorRef; ++ (BOOL)validateShareLinkContent:(FBSDKShareLinkContent *)linkContent error:(NSError *__autoreleasing *)errorRef; ++ (BOOL)validateShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent + error:(NSError *__autoreleasing *)errorRef; ++ (BOOL)validateSharePhotoContent:(FBSDKSharePhotoContent *)photoContent error:(NSError *__autoreleasing *)errorRef; ++ (NSString *)getOpenGraphNameAndNamespaceFromFullName:(NSString *)fullName namespace:(NSString **)namespace; + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.m b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.m new file mode 100644 index 0000000..8c296e0 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.m @@ -0,0 +1,727 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKShareUtility.h" + +#import "FBSDKCoreKit+Internal.h" +#import "FBSDKShareConstants.h" +#import "FBSDKShareError.h" +#import "FBSDKShareLinkContent+Internal.h" +#import "FBSDKShareOpenGraphContent.h" +#import "FBSDKShareOpenGraphObject.h" +#import "FBSDKSharePhoto.h" +#import "FBSDKSharePhotoContent.h" +#import "FBSDKShareVideo.h" +#import "FBSDKShareVideoContent.h" +#import "FBSDKSharingContent.h" + +@implementation FBSDKShareUtility + +#pragma mark - Class Methods + ++ (void)assertCollection:(id)collection ofClass:itemClass name:(NSString *)name +{ + for (id item in collection) { + if (![item isKindOfClass:itemClass]) { + NSString *reason = [[NSString alloc] initWithFormat: + @"Invalid value found in %@: %@ - %@", + name, + item, + collection]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + } +} + ++ (void)assertOpenGraphKey:(id)key requireNamespace:(BOOL)requireNamespace +{ + if (![key isKindOfClass:[NSString class]]) { + NSString *reason = [[NSString alloc] initWithFormat:@"Invalid key found in Open Graph dictionary: %@", key]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + if (!requireNamespace) { + return; + } + NSArray *components = [key componentsSeparatedByString:@":"]; + if ([components count] < 2) { + NSString *reason = [[NSString alloc] initWithFormat:@"Open Graph keys must be namespaced: %@", key]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + for (NSString *component in components) { + if (![component length]) { + NSString *reason = [[NSString alloc] initWithFormat:@"Invalid key found in Open Graph dictionary: %@", key]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + } +} + ++ (void)assertOpenGraphValue:(id)value +{ + if ([self _isOpenGraphValue:value]) { + return; + } + if ([value isKindOfClass:[NSDictionary class]]) { + [self assertOpenGraphValues:(NSDictionary *)value requireKeyNamespace:YES]; + return; + } + if ([value isKindOfClass:[NSArray class]]) { + for (id subValue in (NSArray *)value) { + [self assertOpenGraphValue:subValue]; + } + return; + } + NSString *reason = [[NSString alloc] initWithFormat:@"Invalid Open Graph value found: %@", value]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; +} + ++ (void)assertOpenGraphValues:(NSDictionary *)dictionary requireKeyNamespace:(BOOL)requireKeyNamespace +{ + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + [self assertOpenGraphKey:key requireNamespace:requireKeyNamespace]; + [self assertOpenGraphValue:value]; + }]; +} + ++ (BOOL)buildWebShareContent:(id)content + methodName:(NSString *__autoreleasing *)methodNameRef + parameters:(NSDictionary *__autoreleasing *)parametersRef + error:(NSError *__autoreleasing *)errorRef +{ + NSString *methodName = nil; + NSDictionary *parameters = nil; + if ([content isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + methodName = @"share_open_graph"; + FBSDKShareOpenGraphContent *openGraphContent = (FBSDKShareOpenGraphContent *)content; + FBSDKShareOpenGraphAction *action = openGraphContent.action; + NSDictionary *properties = [self _convertOpenGraphValueContainer:action requireNamespace:NO]; + NSString *propertiesJSON = [FBSDKInternalUtility JSONStringForObject:properties + error:errorRef + invalidObjectHandler:NULL]; + parameters = @{ + @"action_type": action.actionType, + @"action_properties": propertiesJSON, + }; + } else if ([content isKindOfClass:[FBSDKShareLinkContent class]]) { + FBSDKShareLinkContent *linkContent = (FBSDKShareLinkContent *)content; + methodName = @"share"; + if (linkContent.contentURL != nil) { + parameters = @{ @"href": linkContent.contentURL.absoluteString }; + } + } + if (methodNameRef != NULL) { + *methodNameRef = methodName; + } + if (parametersRef != NULL) { + *parametersRef = parameters; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + ++ (id)convertOpenGraphValue:(id)value +{ + if ([self _isOpenGraphValue:value]) { + return value; + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *properties = (NSDictionary *)value; + if ([FBSDKTypeUtility stringValue:properties[@"type"]]) { + return [FBSDKShareOpenGraphObject objectWithProperties:properties]; + } else { + NSURL *imageURL = [FBSDKTypeUtility URLValue:properties[@"url"]]; + if (imageURL) { + FBSDKSharePhoto *sharePhoto = [FBSDKSharePhoto photoWithImageURL:imageURL + userGenerated:[FBSDKTypeUtility boolValue:properties[@"user_generated"]]]; + sharePhoto.caption = [FBSDKTypeUtility stringValue:properties[@"caption"]]; + return sharePhoto; + } else { + return nil; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + for (id subValue in (NSArray *)value) { + [FBSDKInternalUtility array:array addObject:[self convertOpenGraphValue:subValue]]; + } + return [array copy]; + } else { + return nil; + } +} + ++ (NSDictionary *)convertOpenGraphValues:(NSDictionary *)dictionary +{ + NSMutableDictionary *convertedDictionary = [[NSMutableDictionary alloc] init]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [FBSDKInternalUtility dictionary:convertedDictionary setObject:[self convertOpenGraphValue:obj] forKey:key]; + }]; + return [convertedDictionary copy]; +} + ++ (NSDictionary *)feedShareDictionaryForContent:(id)content +{ + NSMutableDictionary *parameters = nil; + if ([content isKindOfClass:[FBSDKShareLinkContent class]]) { + FBSDKShareLinkContent *linkContent = (FBSDKShareLinkContent *)content; + parameters = [[NSMutableDictionary alloc] initWithDictionary:linkContent.feedParameters]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentDescription forKey:@"description"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentURL forKey:@"link"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentTitle forKey:@"name"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.imageURL forKey:@"picture"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.ref forKey:@"ref"]; + } + return [parameters copy]; +} + ++ (NSDictionary *)parametersForShareContent:(id)shareContent + shouldFailOnDataError:(BOOL)shouldFailOnDataError +{ + NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init]; + [self _addToParameters:parameters forShareContent:shareContent]; + parameters[@"dataFailuresFatal"] = @(shouldFailOnDataError); + if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + [self _addToParameters:parameters forShareLinkContent:(FBSDKShareLinkContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + [self _addToParameters:parameters forSharePhotoContent:(FBSDKSharePhotoContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + [self _addToParameters:parameters forShareVideoContent:(FBSDKShareVideoContent *)shareContent]; + } else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + [self _addToParameters:parameters forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)shareContent]; + } + return [parameters copy]; +} + ++ (void)testShareContent:(id)shareContent + containsMedia:(BOOL *)containsMediaRef + containsPhotos:(BOOL *)containsPhotosRef +{ + BOOL containsMedia = NO; + BOOL containsPhotos = NO; + if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + containsMedia = NO; + containsPhotos = NO; + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + containsMedia = YES; + containsPhotos = NO; + } else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + [self _testObject:((FBSDKSharePhotoContent *)shareContent).photos + containsMedia:&containsMedia + containsPhotos:&containsPhotos]; + } else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + [self _testOpenGraphValueContainer:((FBSDKShareOpenGraphContent *)shareContent).action + containsMedia:&containsMedia + containsPhotos:&containsPhotos]; + } + if (containsMediaRef != NULL) { + *containsMediaRef = containsMedia; + } + if (containsPhotosRef != NULL) { + *containsPhotosRef = containsPhotos; + } +} + ++ (BOOL)validateAppInviteContent:(FBSDKAppInviteContent *)appInviteContent error:(NSError *__autoreleasing *)errorRef +{ + return ([self _validateRequiredValue:appInviteContent name:@"content" error:errorRef] && + [self _validateRequiredValue:appInviteContent.appLinkURL name:@"appLinkURL" error:errorRef] && + [self _validateNetworkURL:appInviteContent.appLinkURL name:@"appLinkURL" error:errorRef] && + [self _validateNetworkURL:appInviteContent.appInvitePreviewImageURL name:@"appInvitePreviewImageURL" error:errorRef]); +} + ++ (BOOL)validateGameRequestContent:(FBSDKGameRequestContent *)gameRequestContent error:(NSError *__autoreleasing *)errorRef +{ + if (![self _validateRequiredValue:gameRequestContent name:@"content" error:errorRef] + || ![self _validateRequiredValue:gameRequestContent.message name:@"message" error:errorRef]) { + return NO; + } + BOOL mustHaveobjectID = gameRequestContent.actionType == FBSDKGameRequestActionTypeSend + || gameRequestContent.actionType == FBSDKGameRequestActionTypeAskFor; + BOOL hasobjectID = [gameRequestContent.objectID length] > 0; + if (mustHaveobjectID ^ hasobjectID) { + if (errorRef != NULL) { + NSString *message = @"The objectID is required when the actionType is either send or askfor."; + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"objectID" message:message]; + } + return NO; + } + BOOL hasTo = [gameRequestContent.recipients count] > 0; + BOOL hasFilters = gameRequestContent.filters != FBSDKGameRequestFilterNone; + BOOL hasSuggestions = [gameRequestContent.recipientSuggestions count] > 0; + if (hasTo && hasFilters) { + if (errorRef != NULL) { + NSString *message = @"Cannot specify to and filters at the same time."; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"recipients" value:gameRequestContent.recipients message:message]; + } + return NO; + } + if (hasTo && hasSuggestions) { + if (errorRef != NULL) { + NSString *message = @"Cannot specify to and suggestions at the same time."; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"recipients" value:gameRequestContent.recipients message:message]; + } + return NO; + } + + if (hasFilters && hasSuggestions) { + if (errorRef != NULL) { + NSString *message = @"Cannot specify filters and suggestions at the same time."; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"recipientSuggestions" value:gameRequestContent.recipientSuggestions message:message]; + } + return NO; + } + + if ([gameRequestContent.data length] > 255) { + if (errorRef != NULL) { + NSString *message = @"The data cannot be longer than 255 characters"; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"data" value:gameRequestContent.data message:message]; + } + return NO; + } + + if (errorRef != NULL) { + *errorRef = nil; + } + + return [self _validateArgumentWithName:@"actionType" + value:gameRequestContent.actionType + isIn:@[@(FBSDKGameRequestActionTypeNone), + @(FBSDKGameRequestActionTypeSend), + @(FBSDKGameRequestActionTypeAskFor), + @(FBSDKGameRequestActionTypeTurn)] + error:errorRef] + && [self _validateArgumentWithName:@"filters" + value:gameRequestContent.filters + isIn:@[@(FBSDKGameRequestFilterNone), + @(FBSDKGameRequestFilterAppUsers), + @(FBSDKGameRequestFilterAppNonUsers)] + error:errorRef]; +} + ++ (BOOL)validateShareContent:(id)shareContent error:(NSError *__autoreleasing *)errorRef +{ + if (![self _validateRequiredValue:shareContent name:@"shareContent" error:errorRef]) { + return NO; + } else if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) { + return [self validateShareLinkContent:(FBSDKShareLinkContent *)shareContent error:errorRef]; + } else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) { + return [self validateSharePhotoContent:(FBSDKSharePhotoContent *)shareContent error:errorRef]; + } else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) { + return [self validateShareVideoContent:(FBSDKShareVideoContent *)shareContent error:errorRef]; + } else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + return [self validateShareOpenGraphContent:(FBSDKShareOpenGraphContent *)shareContent error:errorRef]; + } else { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" value:shareContent message:nil]; + } + return NO; + } +} + ++ (BOOL)validateShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent + error:(NSError *__autoreleasing *)errorRef +{ + FBSDKShareOpenGraphAction *action = openGraphContent.action; + NSString *previewPropertyName = openGraphContent.previewPropertyName; + id object = action[previewPropertyName]; + return ([self _validateRequiredValue:openGraphContent name:@"shareContent" error:errorRef] && + [self _validateRequiredValue:action name:@"action" error:errorRef] && + [self _validateRequiredValue:previewPropertyName name:@"previewPropertyName" error:errorRef] && + [self _validateRequiredValue:object name:previewPropertyName error:errorRef]); +} + ++ (BOOL)validateSharePhotoContent:(FBSDKSharePhotoContent *)photoContent error:(NSError *__autoreleasing *)errorRef +{ + NSArray *photos = photoContent.photos; + if (![self _validateRequiredValue:photoContent name:@"shareContent" error:errorRef] || + ![self _validateArray:photos minCount:1 maxCount:6 name:@"photos" error:errorRef]) { + return NO; + } + for (FBSDKSharePhoto *photo in photos) { + if (!photo.image) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"photos" + value:photos + message:@"photos must have UIImages"]; + } + return NO; + } + } + return YES; +} + ++ (BOOL)validateShareLinkContent:(FBSDKShareLinkContent *)linkContent error:(NSError *__autoreleasing *)errorRef +{ + return ([self _validateRequiredValue:linkContent name:@"shareContent" error:errorRef] && + [self _validateNetworkURL:linkContent.contentURL name:@"contentURL" error:errorRef] && + [self _validateNetworkURL:linkContent.imageURL name:@"imageURL" error:errorRef]); +} + ++ (BOOL)validateShareVideoContent:(FBSDKShareVideoContent *)videoContent error:(NSError *__autoreleasing *)errorRef +{ + FBSDKShareVideo *video = videoContent.video; + NSURL *videoURL = video.videoURL; + return ([self _validateRequiredValue:videoContent name:@"videoContent" error:errorRef] && + [self _validateRequiredValue:video name:@"video" error:errorRef] && + [self _validateRequiredValue:videoURL name:@"videoURL" error:errorRef] && + [self _validateAssetLibraryURL:videoURL name:@"videoURL" error:errorRef]); +} + +#pragma mark - Object Lifecycle + +- (instancetype)init +{ + FBSDK_NO_DESIGNATED_INITIALIZER(); + return nil; +} + +#pragma mark - Helper Methods + ++ (void)_addToParameters:(NSMutableDictionary *)parameters forShareContent:(id)shareContent +{ + if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) { + FBSDKShareOpenGraphAction *action = ((FBSDKShareOpenGraphContent *)shareContent).action; + [action setArray:shareContent.peopleIDs forKey:@"tags"]; + [action setString:shareContent.placeID forKey:@"place"]; + [action setString:shareContent.ref forKey:@"ref"]; + } else { + [FBSDKInternalUtility dictionary:parameters setObject:shareContent.peopleIDs forKey:@"tags"]; + [FBSDKInternalUtility dictionary:parameters setObject:shareContent.placeID forKey:@"place"]; + [FBSDKInternalUtility dictionary:parameters setObject:shareContent.ref forKey:@"ref"]; + } +} + ++ (void)_addToParameters:(NSMutableDictionary *)parameters +forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent +{ + NSString *previewPropertyName = [self getOpenGraphNameAndNamespaceFromFullName:openGraphContent.previewPropertyName namespace:nil]; + [FBSDKInternalUtility dictionary:parameters + setObject:previewPropertyName + forKey:@"previewPropertyName"]; + [FBSDKInternalUtility dictionary:parameters setObject:openGraphContent.action.actionType forKey:@"actionType"]; + [FBSDKInternalUtility dictionary:parameters + setObject:[self _convertOpenGraphValueContainer:openGraphContent.action requireNamespace:NO] + forKey:@"action"]; +} + ++ (void)_addToParameters:(NSMutableDictionary *)parameters + forSharePhotoContent:(FBSDKSharePhotoContent *)photoContent +{ + [FBSDKInternalUtility dictionary:parameters + setObject:[photoContent.photos valueForKeyPath:@"image"] + forKey:@"photos"]; +} + ++ (void)_addToParameters:(NSMutableDictionary *)parameters + forShareLinkContent:(FBSDKShareLinkContent *)linkContent +{ + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentURL forKey:@"link"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentTitle forKey:@"name"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentDescription forKey:@"description"]; + [FBSDKInternalUtility dictionary:parameters setObject:linkContent.imageURL forKey:@"picture"]; +} + ++ (void)_addToParameters:(NSMutableDictionary *)parameters + forShareVideoContent:(FBSDKShareVideoContent *)videoContent +{ + NSMutableDictionary *videoParameters = [[NSMutableDictionary alloc] init]; + FBSDKShareVideo *video = videoContent.video; + NSURL *videoURL = video.videoURL; + if (videoURL) { + videoParameters[@"assetURL"] = videoURL; + } + [FBSDKInternalUtility dictionary:videoParameters + setObject:[self _convertPhoto:videoContent.previewPhoto] + forKey:@"previewPhoto"]; + parameters[@"video"] = videoParameters; +} + ++ (id)_convertObject:(id)object +{ + if ([object isKindOfClass:[FBSDKShareOpenGraphValueContainer class]]) { + object = [self _convertOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object requireNamespace:YES]; + } else if ([object isKindOfClass:[FBSDKSharePhoto class]]) { + object = [self _convertPhoto:(FBSDKSharePhoto *)object]; + } else if ([object isKindOfClass:[NSArray class]]) { + NSMutableArray *array = [[NSMutableArray alloc] init]; + for (id item in (NSArray *)object) { + [FBSDKInternalUtility array:array addObject:[self _convertObject:item]]; + } + object = array; + } + return object; +} + ++ (NSDictionary *)_convertOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)container + requireNamespace:(BOOL)requireNamespace +{ + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + [container enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) { + // if we have an FBSDKShareOpenGraphObject and a type, then we are creating a new object instance; set the flag + if ([key isEqualToString:@"og:type"] && [container isKindOfClass:[FBSDKShareOpenGraphObject class]]) { + dictionary[@"fbsdk:create_object"] = @YES; + dictionary[key] = object; + } + id value = [self _convertObject:object]; + if (value) { + NSString *namespace; + key = [self getOpenGraphNameAndNamespaceFromFullName:key namespace:&namespace]; + + if (requireNamespace) { + if ([namespace isEqualToString:@"og"]) { + dictionary[key] = value; + } else { + data[key] = value; + } + } else { + dictionary[key] = value; + } + } + }]; + if ([data count]) { + dictionary[@"data"] = data; + } + return dictionary; +} + ++ (NSString *)getOpenGraphNameAndNamespaceFromFullName:(NSString *)fullName namespace:(NSString **)namespace { + if (namespace) { + *namespace = nil; + } + + if ([fullName isEqualToString:@"fb:explicitly_shared"]) { + return fullName; + } + + NSUInteger index = [fullName rangeOfString:@":"].location; + if ((index != NSNotFound) && (fullName.length > index + 1)) { + if (namespace) { + *namespace = [fullName substringToIndex:index]; + } + + return [fullName substringFromIndex:index + 1]; + } + + return fullName; +} + ++ (NSDictionary *)_convertPhoto:(FBSDKSharePhoto *)photo +{ + if (!photo) { + return nil; + } + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + dictionary[@"user_generated"] = @(photo.userGenerated); + [FBSDKInternalUtility dictionary:dictionary setObject:photo.caption forKey:@"caption"]; + + [FBSDKInternalUtility dictionary:dictionary setObject:photo.image ?: photo.imageURL.absoluteString forKey:@"url"]; + return dictionary; +} + ++ (BOOL)_isOpenGraphValue:(id)value +{ + return ((value == nil) || + [value isKindOfClass:[NSNull class]] || + [value isKindOfClass:[NSNumber class]] || + [value isKindOfClass:[NSString class]] || + [value isKindOfClass:[NSURL class]] || + [value isKindOfClass:[FBSDKSharePhoto class]] || + [value isKindOfClass:[FBSDKShareOpenGraphObject class]]); +} + ++ (void)_testObject:(id)object containsMedia:(BOOL *)containsMediaRef containsPhotos:(BOOL *)containsPhotosRef +{ + BOOL containsMedia = NO; + BOOL containsPhotos = NO; + if ([object isKindOfClass:[FBSDKSharePhoto class]]) { + containsMedia = (((FBSDKSharePhoto *)object).image != nil); + containsPhotos = YES; + } else if ([object isKindOfClass:[FBSDKShareOpenGraphValueContainer class]]) { + [self _testOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object + containsMedia:&containsMedia + containsPhotos:&containsPhotos]; + } else if ([object isKindOfClass:[NSArray class]]) { + for (id item in (NSArray *)object) { + BOOL itemContainsMedia = NO; + BOOL itemContainsPhotos = NO; + [self _testObject:item containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos]; + containsMedia |= itemContainsMedia; + containsPhotos |= itemContainsPhotos; + if (containsMedia && containsPhotos) { + break; + } + } + } + if (containsMediaRef != NULL) { + *containsMediaRef = containsMedia; + } + if (containsPhotosRef != NULL) { + *containsPhotosRef = containsPhotos; + } +} + ++ (void)_testOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)container + containsMedia:(BOOL *)containsMediaRef + containsPhotos:(BOOL *)containsPhotosRef +{ + __block BOOL containsMedia = NO; + __block BOOL containsPhotos = NO; + [container enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) { + BOOL itemContainsMedia = NO; + BOOL itemContainsPhotos = NO; + [self _testObject:object containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos]; + containsMedia |= itemContainsMedia; + containsPhotos |= itemContainsPhotos; + if (containsMedia && containsPhotos) { + *stop = YES; + } + }]; + if (containsMediaRef != NULL) { + *containsMediaRef = containsMedia; + } + if (containsPhotosRef != NULL) { + *containsPhotosRef = containsPhotos; + } +} + ++ (BOOL)_validateArray:(NSArray *)array + minCount:(NSUInteger)minCount + maxCount:(NSUInteger)maxCount + name:(NSString *)name + error:(NSError *__autoreleasing *)errorRef +{ + NSUInteger count = [array count]; + if ((count < minCount) || (count > maxCount)) { + if (errorRef != NULL) { + NSString *message = [[NSString alloc] initWithFormat:@"%@ must have %lu to %lu values", + name, + (unsigned long)minCount, + (unsigned long)maxCount]; + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:array message:message]; + } + return NO; + } else { + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; + } +} + ++ (BOOL)_validateAssetLibraryURL:(NSURL *)URL name:(NSString *)name error:(NSError *__autoreleasing *)errorRef +{ + if (!URL || [[URL.scheme lowercaseString] isEqualToString:@"assets-library"]) { + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; + } else { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:URL message:nil]; + } + return NO; + } +} + ++ (BOOL)_validateFileURL:(NSURL *)URL name:(NSString *)name error:(NSError *__autoreleasing *)errorRef +{ + if (!URL) { + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; + } + if (!URL.isFileURL) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:URL message:nil]; + } + return NO; + } + // ensure that the file exists. per the latest spec for NSFileManager, we should not be checking for file existance, + // so they have removed that option for URLs and discourage it for paths, so we just construct a mapped NSData. + NSError *fileError; + if (![[NSData alloc] initWithContentsOfURL:URL + options:NSDataReadingMapped + error:&fileError]) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:name + value:URL + message:@"Error reading file" + underlyingError:fileError]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + ++ (BOOL)_validateNetworkURL:(NSURL *)URL name:(NSString *)name error:(NSError *__autoreleasing *)errorRef +{ + if (!URL || [FBSDKInternalUtility isBrowserURL:URL]) { + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; + } else { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:URL message:nil]; + } + return NO; + } +} + ++ (BOOL)_validateRequiredValue:(id)value name:(NSString *)name error:(NSError *__autoreleasing *)errorRef +{ + if (!value || + ([value isKindOfClass:[NSString class]] && ![(NSString *)value length]) || + ([value isKindOfClass:[NSArray class]] && ![(NSArray *)value count]) || + ([value isKindOfClass:[NSDictionary class]] && ![(NSDictionary *)value count])) { + if (errorRef != NULL) { + *errorRef = [FBSDKShareError requiredArgumentErrorWithName:name message:nil]; + } + return NO; + } + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; +} + ++ (BOOL)_validateArgumentWithName:(NSString *)argumentName + value:(NSUInteger)value + isIn:(NSArray *)possibleValues + error:(NSError *__autoreleasing *)errorRef +{ + for (NSNumber *possibleValue in possibleValues) { + if (value == [possibleValue unsignedIntegerValue]) { + if (errorRef != NULL) { + *errorRef = nil; + } + return YES; + } + } + if (errorRef != NULL) { + *errorRef = [FBSDKShareError invalidArgumentErrorWithName:argumentName value:@(value) message:nil]; + } + return NO; +} + +@end diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/LICENSE b/Unit-2-Journal/Pods/FBSDKShareKit/LICENSE new file mode 100644 index 0000000..bdb9fc5 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/LICENSE @@ -0,0 +1,17 @@ +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Unit-2-Journal/Pods/FBSDKShareKit/README.mdown b/Unit-2-Journal/Pods/FBSDKShareKit/README.mdown new file mode 100644 index 0000000..d14a5e4 --- /dev/null +++ b/Unit-2-Journal/Pods/FBSDKShareKit/README.mdown @@ -0,0 +1,46 @@ +Facebook SDK for iOS +==================== + +This open-source library allows you to integrate Facebook into your iOS app. + +Learn more about the provided samples, documentation, integrating the SDK into your app, accessing source code, and more at https://developers.facebook.com/docs/ios + +NOTE: By default, the Facebook SDK for iOS is installed in ~/Documents/FacebookSDK + +TRY IT OUT +---------- +1. Download the SDK at https://developers.facebook.com/docs/ios or via Cocoapods by adding the 'FBSDKCoreKit', 'FBSDKLoginKit', and 'FBSDKShareKit' pods. +2. Test your install: build and run the project at ~/Documents/FacebookSDK/Samples/Scrumptious/Scrumptious.xcodeproj +3. Check-out the tutorials available online at: https://developers.facebook.com/docs/ios/getting-started +4. Start coding! Visit https://developers.facebook.com/docs/ios for tutorials and reference documentation. + +FEATURES +-------- +* Login - https://developers.facebook.com/docs/facebook-login +* Sharing - https://developers.facebook.com/docs/sharing +* App Links - https://developers.facebook.com/docs/applinks +* Graph API - https://developers.facebook.com/docs/ios/graph +* Analytics for Apps - https://developers.facebook.com/docs/analytics + +GIVE FEEDBACK +------------- +Please report bugs or issues to https://developers.facebook.com/bugs/ + +You can also join the Facebook Developers Group on Facebook (https://www.facebook.com/groups/fbdevelopers/) or ask questions on Stack Overflow (http://facebook.stackoverflow.com) + +LICENSE +------- +See the LICENSE file. + +DEVELOPER TERMS +--------------- + +- By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including information about people’s use of your app. Facebook will use information received in accordance with our Data Use Policy [https://www.facebook.com/about/privacy/], including to provide you with insights about the effectiveness of your ads and the use of your app. These integrations also enable us and our partners to serve ads on and off Facebook. + +- You may limit your sharing of information with us by updating the Insights control in the developer tool [https://developers.facebook.com/apps/{app_id}/settings/advanced]. + +- If you use a Facebook integration, including to share information with us, you agree and confirm that you have provided appropriate and sufficiently prominent notice to and obtained the appropriate consent from your users regarding such collection, use, and disclosure (including, at a minimum, through your privacy policy). You further agree that you will not share information with us about children under the age of 13. + +- You agree to comply with all applicable laws and regulations and also agree to our Terms , including our Platform Policies .and Advertising Guidelines, as applicable . + +By using the Facebook SDK for iOS you agree to these terms. diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h new file mode 100644 index 0000000..93f0e62 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h @@ -0,0 +1,20 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +@interface YALSpringAnimation : CAKeyframeAnimation + ++ (instancetype)animationWithKeyPath:(NSString *)keyPath + duration:(CFTimeInterval)duration + damping:(double)damping + velocity:(double)velocity + fromValue:(double)fromValue + toValue:(double)toValue; + ++ (instancetype)animationForRoundedRectPathWithduration:(CFTimeInterval)duration + damping:(double)damping + velocity:(double)velocity + fromValue:(CGRect)fromValue + toValue:(CGRect)toValue; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.m new file mode 100644 index 0000000..0030796 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.m @@ -0,0 +1,114 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "YALSpringAnimation.h" +#import + +static const NSUInteger kNumberOfPoints = 500; +static const double kDampingMutiplier = 10; +static const double kVelocityMutiplier = 10; + +double yal_normalizeAnimationValue(double value, double damping, double velocity); + +@implementation YALSpringAnimation + ++ (instancetype)animationWithKeyPath:(NSString *)keyPath + duration:(CFTimeInterval)duration + damping:(double)damping + velocity:(double)velocity + fromValue:(double)fromValue + toValue:(double)toValue +{ + YALSpringAnimation *animation = [self.class animationWithKeyPath:keyPath]; + + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + animation.duration = duration; + animation.values = [self animationValuesFromValue:fromValue + toValue:toValue + withDamping:damping + andVelocity:velocity]; + return animation; +} + ++ (instancetype)animationForRoundedRectPathWithduration:(CFTimeInterval)duration + damping:(double)damping + velocity:(double)velocity + fromValue:(CGRect)fromValue + toValue:(CGRect)toValue +{ + YALSpringAnimation *animation = [self.class animationWithKeyPath:@"path"]; + + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; + animation.duration = duration; + animation.values = [self animationValuesForPathFromValue:fromValue + toValue:toValue + withDamping:damping + andVelocity:velocity]; + return animation; +} + ++ (NSArray *)animationValuesForPathFromValue:(CGRect)fromValue + toValue:(CGRect)toValue + withDamping:(double)damping + andVelocity:(double)velocity +{ + NSArray *xValues = [self animationValuesFromValue:fromValue.origin.x + toValue:toValue.origin.x + withDamping:damping + andVelocity:velocity]; + NSArray *widthValues = [self animationValuesFromValue:fromValue.size.width + toValue:toValue.size.width + withDamping:damping + andVelocity:velocity]; + NSMutableArray *pathValues = [NSMutableArray new]; + CGFloat cornerRadius = fromValue.size.height / 2.f; + CGRect rect = fromValue; + + for (NSInteger i = 0; i < xValues.count; ++i) { + CGFloat x = [(NSNumber *)xValues[i] floatValue]; + CGFloat width = [(NSNumber *)widthValues[i] floatValue]; + + rect.origin.x = x; + rect.size.width = width; + + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius]; + [pathValues addObject:(id)path.CGPath]; + } + + return [NSArray arrayWithArray:pathValues]; +} + +/* + * code below borrowed SpringAnimation.swift from:https://github.com/evgenyneu/SpringAnimationCALayer + */ + ++ (NSArray *)animationValuesFromValue:(double)fromValue + toValue:(double)toValue + withDamping:(double)damping + andVelocity:(double)velocity +{ + NSMutableArray *values = [NSMutableArray new]; + CGFloat distanceBetweenValues = toValue - fromValue; + velocity *= kVelocityMutiplier; + damping *= kDampingMutiplier; + + for (double i = 0; i < kNumberOfPoints; ++i) { + double x = i / kNumberOfPoints; + double normalizedValue = yal_normalizeAnimationValue(x, damping, velocity); + double value = toValue - distanceBetweenValues * normalizedValue; + [values addObject:@(value)]; + } + + // with different arguments alghorithm above produces values where + // last values not equal to toValue therefore line below is required(not a perfect fix for issue but will do for now) + [values addObject:@(toValue)]; + + return [NSArray arrayWithArray:values]; +} + +@end + +double yal_normalizeAnimationValue(double value, double damping, double velocity) { + return pow(M_E, -damping * value) * cos(velocity * value); +} diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h new file mode 100644 index 0000000..b68e135 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h @@ -0,0 +1,16 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +@interface CAAnimation (YALTabBarViewAnimations) + ++ (CAAnimation *)animationForAdditionalButton; ++ (CAAnimation *)animationForExtraLeftBarItem; ++ (CAAnimation *)animationForExtraRightBarItem; ++ (CAAnimation *)animationForTabBarExpandFromRect:(CGRect)fromRect toRect:(CGRect)toRect; ++ (CAAnimation *)animationForTabBarCollapseFromRect:(CGRect)fromRect toRect:(CGRect)toRect; ++ (CAAnimation *)animationForCenterButtonExpand; ++ (CAAnimation *)animationForCenterButtonCollapse; ++ (CAAnimation *)showSelectedDotAnimation; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.m new file mode 100644 index 0000000..a427913 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.m @@ -0,0 +1,144 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "CAAnimation+YALTabBarViewAnimations.h" +#import "YALSpringAnimation.h" +#import "YALAnimatingTabBarConstants.h" + +@implementation CAAnimation (YALTabBarViewAnimations) + +#pragma mark - Additional buttons animations + ++ (CAAnimation *)animationForAdditionalButton { + CABasicAnimation *scaleX = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"]; + scaleX.fromValue = @(kYALAdditionalButtonsAnimationsParameters.scaleX.fromValue); + scaleX.toValue = @(kYALAdditionalButtonsAnimationsParameters.scaleX.toValue); + scaleX.duration = kYALAdditionalButtonsAnimationsParameters.scaleX.duration; + + CABasicAnimation *scaleY = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"]; + scaleY.fromValue = @(kYALAdditionalButtonsAnimationsParameters.scaleY.fromValue); + scaleY.toValue = @(kYALAdditionalButtonsAnimationsParameters.scaleY.toValue); + scaleY.duration = kYALAdditionalButtonsAnimationsParameters.scaleY.duration; + + CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + rotation.fromValue = @(kYALAdditionalButtonsAnimationsParameters.rotation.fromValue); + rotation.toValue = @(kYALAdditionalButtonsAnimationsParameters.rotation.toValue); + rotation.duration = kYALAdditionalButtonsAnimationsParameters.rotation.duration; + rotation.fillMode = kCAFillModeForwards; + rotation.removedOnCompletion = NO; + + YALSpringAnimation *bouncedRotation = [self rotationBouncedAnimationFromValue:kYALAdditionalButtonsAnimationsParameters.bounce.fromValue + toValue:kYALAdditionalButtonsAnimationsParameters.bounce.toValue]; + bouncedRotation.beginTime = kYALAdditionalButtonsAnimationsParameters.bounce.beginTime; + + return [self groupWithAnimations:@[scaleX, scaleY, rotation, bouncedRotation] andDuration:kYALExpandAnimationDuration]; +} + +#pragma mark - Extra buttons animations + ++ (CAAnimation *)animationForExtraLeftBarItem { + return [YALSpringAnimation animationWithKeyPath:@"transform.rotation.z" + duration:kYALExtraLeftTabBarItemAnimationParameters.duration + damping:kYALExtraLeftTabBarItemAnimationParameters.damping + velocity:kYALExtraLeftTabBarItemAnimationParameters.velocity + fromValue:kYALExtraLeftTabBarItemAnimationParameters.fromValue + toValue:kYALExtraLeftTabBarItemAnimationParameters.toValue]; +} + ++ (CAAnimation *)animationForExtraRightBarItem { + return [YALSpringAnimation animationWithKeyPath:@"transform.rotation.z" + duration:kYALExtraRightTabBarItemAnimationParameters.duration + damping:kYALExtraRightTabBarItemAnimationParameters.damping + velocity:kYALExtraRightTabBarItemAnimationParameters.velocity + fromValue:kYALExtraRightTabBarItemAnimationParameters.fromValue + toValue:kYALExtraRightTabBarItemAnimationParameters.toValue]; +} + +#pragma mark - Tab bar view animations + ++ (CAAnimation *)animationForTabBarExpandFromRect:(CGRect)fromRect toRect:(CGRect)toRect { + return [YALSpringAnimation animationForRoundedRectPathWithduration:kYALTabBarExpandAnimationParameters.duration + damping:kYALTabBarExpandAnimationParameters.damping + velocity:kYALTabBarExpandAnimationParameters.velocity + fromValue:fromRect + toValue:toRect]; +} + ++ (CAAnimation *)animationForTabBarCollapseFromRect:(CGRect)fromRect toRect:(CGRect)toRect { + return [YALSpringAnimation animationForRoundedRectPathWithduration:kYALTabBarCollapseAnimationParameters.duration + damping:kYALTabBarCollapseAnimationParameters.damping + velocity:kYALTabBarCollapseAnimationParameters.velocity + fromValue:fromRect + toValue:toRect]; +} + +#pragma mark - Center button animation + ++ (CAAnimation *)animationForCenterButtonExpand { + CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + rotation.fromValue = @(kYALCenterButtonExpandAnimationParameters.rotation.fromValue); + rotation.toValue = @(kYALCenterButtonExpandAnimationParameters.rotation.toValue); + rotation.duration = kYALCenterButtonExpandAnimationParameters.rotation.duration; + rotation.fillMode = kCAFillModeForwards; + rotation.removedOnCompletion = NO; + + YALSpringAnimation *bouncedRotation = [self rotationBouncedAnimationFromValue:kYALCenterButtonExpandAnimationParameters.bounce.fromValue + toValue:kYALCenterButtonExpandAnimationParameters.bounce.toValue]; + bouncedRotation.beginTime = kYALCenterButtonExpandAnimationParameters.bounce.beginTime; + + return [self groupWithAnimations:@[rotation, bouncedRotation] andDuration:kYALExpandAnimationDuration]; +} + ++ (CAAnimation *)animationForCenterButtonCollapse { + CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + rotation.fromValue = @(kYALCenterButtonCollapseAnimationParameters.rotation.fromValue); + rotation.toValue = @(kYALCenterButtonCollapseAnimationParameters.rotation.toValue); + rotation.duration = kYALCenterButtonCollapseAnimationParameters.rotation.duration; + rotation.fillMode = kCAFillModeForwards; + rotation.removedOnCompletion = NO; + + YALSpringAnimation *bouncedRotation = [self rotationBouncedAnimationFromValue:kYALCenterButtonCollapseAnimationParameters.bounce.fromValue + toValue:kYALCenterButtonCollapseAnimationParameters.bounce.toValue]; + bouncedRotation.beginTime = kYALCenterButtonCollapseAnimationParameters.bounce.beginTime; + + return [self groupWithAnimations:@[rotation, bouncedRotation] andDuration:kYALExpandAnimationDuration]; +} + ++ (CAAnimation *)showSelectedDotAnimation { + CABasicAnimation *scaleX = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"]; + scaleX.fromValue = @(kYALSelectedDotAnimationsParameters.scaleX.fromValue); + scaleX.toValue = @(kYALSelectedDotAnimationsParameters.scaleX.toValue); + scaleX.duration = kYALSelectedDotAnimationsParameters.scaleX.duration; + + CABasicAnimation *scaleY = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"]; + scaleY.fromValue = @(kYALSelectedDotAnimationsParameters.scaleY.fromValue); + scaleY.toValue = @(kYALSelectedDotAnimationsParameters.scaleY.toValue); + scaleY.duration = kYALSelectedDotAnimationsParameters.scaleY.duration; + + return [self groupWithAnimations:@[scaleX, scaleY] andDuration:kYALExpandAnimationDuration / 2]; +} + +#pragma mark - Helpers - + +#pragma mark Group + ++ (CAAnimationGroup *)groupWithAnimations:(NSArray *)animations andDuration:(CFTimeInterval)duration { + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = duration; + group.animations = animations; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeForwards; + return group; +} + +#pragma mark Rotation bounce animation + ++ (YALSpringAnimation *)rotationBouncedAnimationFromValue:(double)fromValue toValue:(double)toValue { + return [YALSpringAnimation animationWithKeyPath:@"transform.rotation.z" + duration:kYALBounceAnimationParameters.duration + damping:kYALBounceAnimationParameters.damping + velocity:kYALBounceAnimationParameters.velocity + fromValue:fromValue + toValue:toValue]; +} + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h new file mode 100644 index 0000000..aa99ff0 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h @@ -0,0 +1,9 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +@interface CATransaction (TransactionWithAnimationsAndCompletion) + ++ (void)transactionWithAnimations:(void(^)(void))animations andCompletion:(void(^)(void))completion; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.m new file mode 100644 index 0000000..2bd8f31 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.m @@ -0,0 +1,16 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "CATransaction+TransactionWithAnimationsAndCompletion.h" + +@implementation CATransaction (TransactionWithAnimationsAndCompletion) + ++ (void)transactionWithAnimations:(void(^)(void))animations andCompletion:(void(^)(void))completion { + [CATransaction begin]; { + [CATransaction setCompletionBlock:completion]; + if (animations) { + animations(); + } + } [CATransaction commit]; +} + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.h new file mode 100644 index 0000000..f6c1391 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.h @@ -0,0 +1,60 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +extern CGFloat const YALBottomSelectedDotDefaultSize; +extern CGFloat const YALBottomSelectedDotOffset; +extern CGFloat const YALTabBarViewDefaultHeight; +extern CGFloat const YALExtraTabBarItemsDefaultHeight; +extern CGFloat const YALForExtraTabBarItemsDefaultOffset; +extern UIEdgeInsets const YALTabBarViewHDefaultEdgeInsets; +extern UIEdgeInsets const YALTabBarViewItemsDefaultEdgeInsets; + + +extern CFTimeInterval const kYALExpandAnimationDuration; + +typedef struct { + CFTimeInterval beginTime; + CFTimeInterval duration; + double fromValue; + double toValue; + double damping; + double velocity; +} YALAnimationParameters; + +typedef struct { + YALAnimationParameters scaleX; + YALAnimationParameters scaleY; + YALAnimationParameters rotation; + YALAnimationParameters bounce; +} YALAdditionalButtonsAnimationsParameters; + +typedef struct { + YALAnimationParameters rotation; + YALAnimationParameters bounce; +} YALCenterButtonAnimationsParameters; + +typedef struct { + NSTimeInterval duration; + NSTimeInterval delay; + CGFloat damping; + CGFloat velocity; + UIViewAnimationOptions options; +} YALExtraTabBarItemViewAnimationParameters; + +typedef struct { + YALAnimationParameters scaleX; + YALAnimationParameters scaleY; +} YALSelectedDotAnimationsParameters; + +extern YALAdditionalButtonsAnimationsParameters const kYALAdditionalButtonsAnimationsParameters; +extern YALSelectedDotAnimationsParameters const kYALSelectedDotAnimationsParameters; +extern YALAnimationParameters const kYALExtraLeftTabBarItemAnimationParameters; +extern YALAnimationParameters const kYALExtraRightTabBarItemAnimationParameters; +extern YALAnimationParameters const kYALTabBarExpandAnimationParameters; +extern YALAnimationParameters const kYALTabBarCollapseAnimationParameters; +extern YALCenterButtonAnimationsParameters const kYALCenterButtonExpandAnimationParameters; +extern YALCenterButtonAnimationsParameters const kYALCenterButtonCollapseAnimationParameters; +extern YALAnimationParameters const kYALBounceAnimationParameters; +extern YALExtraTabBarItemViewAnimationParameters const kYALShowExtraTabBarItemViewAnimationParameters; +extern YALExtraTabBarItemViewAnimationParameters const kYALHideExtraTabBarItemViewAnimationParameters; \ No newline at end of file diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.m new file mode 100644 index 0000000..f61c2b7 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.m @@ -0,0 +1,122 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "YALAnimatingTabBarConstants.h" + +CGFloat const YALBottomSelectedDotDefaultSize = 4.f; +CGFloat const YALBottomSelectedDotOffset = 16.f; +CGFloat const YALTabBarViewDefaultHeight = 80.f; +CGFloat const YALExtraTabBarItemsDefaultHeight = 48.f; +CGFloat const YALForExtraTabBarItemsDefaultOffset = 15.f; +UIEdgeInsets const YALTabBarViewHDefaultEdgeInsets = {10.f, 14.f, 10.f, 14.f}; +UIEdgeInsets const YALTabBarViewItemsDefaultEdgeInsets = {0.f, 0.f, 0.f, 0.f}; + + +CFTimeInterval const kYALExpandAnimationDuration = 1.0; + +CGFloat const kDegreeToRadiansRatio = M_PI / 180.f; + +YALAnimationParameters const kYALBounceAnimationParameters = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration * 2.0 / 3.0, + .damping = 0.5, + .velocity = 3.0 +}; + +YALAnimationParameters const kYALExtraLeftTabBarItemAnimationParameters = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration * 3.0 / 4.0, + .damping = 0.74, + .velocity = 1.2, + .fromValue = 0.0, + .toValue = M_PI * 2.0 * 2.0 +}; + +YALAnimationParameters const kYALExtraRightTabBarItemAnimationParameters = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration * 3.0 / 4.0, + .damping = 0.74, + .velocity = 1.2, + .fromValue = 0.0, + .toValue = M_PI * 2.0 * -2.0 +}; + +YALAnimationParameters const kYALTabBarExpandAnimationParameters = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 2.0, + .damping = 0.5, + .velocity = 0.6 +}; + +YALAnimationParameters const kYALTabBarCollapseAnimationParameters = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration * 0.6, + .damping = 1, + .velocity = 0.2 +}; + +YALCenterButtonAnimationsParameters const kYALCenterButtonExpandAnimationParameters = (YALCenterButtonAnimationsParameters) { + .rotation = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = M_PI * 2.0 + 45.0 * kDegreeToRadiansRatio + }, + .bounce = (YALAnimationParameters) { + .beginTime = kYALExpandAnimationDuration / 4.0, + .fromValue = 45.0 * kDegreeToRadiansRatio + M_PI / 8.0, + .toValue = 45.0 * kDegreeToRadiansRatio + } +}; + +YALCenterButtonAnimationsParameters const kYALCenterButtonCollapseAnimationParameters = (YALCenterButtonAnimationsParameters) { + .rotation = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = 315.0 * kDegreeToRadiansRatio + }, + .bounce = (YALAnimationParameters) { + .beginTime = kYALExpandAnimationDuration / 4.0, + .fromValue = M_PI / 8.0, + .toValue = 0.0 + } +}; + +YALSelectedDotAnimationsParameters const kYALSelectedDotAnimationsParameters = +(YALSelectedDotAnimationsParameters) { + .scaleX = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = 1.0 + }, + .scaleY = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = 1.0 + } +}; + +YALAdditionalButtonsAnimationsParameters const kYALAdditionalButtonsAnimationsParameters = (YALAdditionalButtonsAnimationsParameters) { + .scaleX = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = 1.0 + }, + .scaleY = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = 1.0 + }, + .rotation = (YALAnimationParameters) { + .duration = kYALExpandAnimationDuration / 4.0, + .fromValue = 0.0, + .toValue = M_PI * 2.0 * 5.0 + }, + .bounce = (YALAnimationParameters) { + .beginTime = kYALExpandAnimationDuration / 4.0, + .fromValue = M_PI / 8.0, + .toValue = 0.0 + } +}; + +YALExtraTabBarItemViewAnimationParameters const kYALShowExtraTabBarItemViewAnimationParameters = (YALExtraTabBarItemViewAnimationParameters) { + .duration = kYALExpandAnimationDuration / 2.0, + .damping = 0.5f, +}; + +YALExtraTabBarItemViewAnimationParameters const kYALHideExtraTabBarItemViewAnimationParameters = (YALExtraTabBarItemViewAnimationParameters) { + .duration = kYALExpandAnimationDuration / 8.0, +}; diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h new file mode 100644 index 0000000..197fc00 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h @@ -0,0 +1,18 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +//view +#import "YALFoldingTabBar.h" + +@interface YALFoldingTabBarController : UITabBarController + +@property (nonatomic, copy) NSArray *leftBarItems; +@property (nonatomic, copy) NSArray *rightBarItems; +@property (nonatomic, strong) UIImage *centerButtonImage; + +@property (nonatomic, assign) CGFloat tabBarViewHeight; + +@property (nonatomic, strong) YALFoldingTabBar *tabBarView; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.m new file mode 100644 index 0000000..481ce43 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.m @@ -0,0 +1,177 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "YALFoldingTabBarController.h" + +//model +#import "YALTabBarItem.h" + +//protocol +#import "YALTabBarInteracting.h" + +#import "YALAnimatingTabBarConstants.h" + +@interface YALFoldingTabBarController () + +@property (nonatomic, assign) YALTabBarState state; + +@end + +@implementation YALFoldingTabBarController + +#pragma mark - Initialization + +- (instancetype)init { + self = [super init]; + if (self) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + [self setup]; + } + return self; +} + +- (void)setup { + self.tabBarViewHeight = YALTabBarViewDefaultHeight; + + [self setupTabBarView]; +} + +#pragma mark - View & LifeCycle + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self.tabBar setBackgroundImage:[[UIImage alloc] init]]; + [self.tabBar setShadowImage:[[UIImage alloc] init]]; + + self.tabBar.hidden = YES; +} + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + CGRect tabFrame = self.tabBar.frame; + tabFrame.size.height = self.tabBarViewHeight; + tabFrame.origin.y = self.view.frame.size.height - self.tabBarViewHeight; + self.tabBar.frame = tabFrame; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + [self updateTabBarViewFrame]; +} + +- (void)setSelectedIndex:(NSUInteger)selectedIndex { + [super setSelectedIndex:selectedIndex]; + + self.tabBarView.selectedTabBarItemIndex = selectedIndex; + [self.tabBarView setNeedsLayout]; +} + +#pragma mark - Private + +- (void)updateTabBarViewFrame { + CGFloat tabBarViewOriginX = self.tabBar.frame.origin.x; + CGFloat tabBarViewOriginY = self.tabBar.frame.origin.y; + CGFloat tabBarViewSizeWidth = CGRectGetWidth(self.tabBar.frame); + + self.tabBarView.frame = CGRectMake(tabBarViewOriginX, tabBarViewOriginY, tabBarViewSizeWidth, self.tabBarViewHeight); + [self.tabBarView setNeedsLayout]; +} + +- (void)setupTabBarView { + self.tabBarView = [[YALFoldingTabBar alloc] initWithFrame:CGRectZero state:self.state]; + + self.tabBarView.dataSource = self; + self.tabBarView.delegate = self; + + [self.view addSubview:self.tabBarView]; +} + +- (id)currentInteractingViewController { + if ([self.selectedViewController isKindOfClass:[UINavigationController class]]) { + return (id)[(UINavigationController *)self.selectedViewController topViewController]; + } else { + return (id)self.selectedViewController; + } +} + +#pragma mark - YALTabBarViewDataSource + +- (NSArray *)leftTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView { + return self.leftBarItems; +} + +- (NSArray *)rightTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView { + return self.rightBarItems; +} + +- (UIImage *)centerImageInTabBarView:(YALFoldingTabBar *)tabBarView { + return self.centerButtonImage; +} + +#pragma mark - YALTabBarViewDelegate + +- (void)tabBarViewWillCollapse:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewWillCollapse)]) { + [viewController tabBarViewWillCollapse]; + } +} + +- (void)tabBarViewDidCollapse:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewDidCollapse)]) { + [viewController tabBarViewDidCollapse]; + } +} + +- (void)tabBarViewWillExpand:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewWillExpand)]) { + [viewController tabBarViewWillExpand]; + } +} + +- (void)tabBarViewDidExpand:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewDidExpand)]) { + [viewController tabBarViewDidExpand]; + } +} + +- (void)extraLeftItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(extraLeftItemDidPress)]) { + [viewController extraLeftItemDidPress]; + } +} + +- (void)extraRightItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView { + idviewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(extraRightItemDidPress)]) { + [viewController extraRightItemDidPress]; + } +} + +- (void)itemInTabBarViewPressed:(YALFoldingTabBar *)tabBarView atIndex:(NSUInteger)index { + self.selectedViewController = [self.viewControllers objectAtIndex:index]; +} + + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.h new file mode 100644 index 0000000..6253fb0 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.h @@ -0,0 +1,16 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import +#import + +@interface YALTabBarItem : NSObject + +@property (nonatomic, strong) UIImage *itemImage; +@property (nonatomic, strong) UIImage *leftImage; +@property (nonatomic, strong) UIImage *rightImage; + +- (instancetype)initWithItemImage:(UIImage *)itemImage + leftItemImage:(UIImage *)leftItemImage + rightItemImage:(UIImage *)rightItemImage; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.m new file mode 100644 index 0000000..2f9b0da --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.m @@ -0,0 +1,25 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "YALTabBarItem.h" + +@interface YALTabBarItem () + +@end + +@implementation YALTabBarItem + +#pragma mark - Initialization + +- (instancetype)initWithItemImage:(UIImage *)itemImage + leftItemImage:(UIImage *)leftItemImage + rightItemImage:(UIImage *)rightItemImage { + self = [super init]; + if (self) { + _itemImage = itemImage; + _leftImage = leftItemImage; + _rightImage = rightItemImage; + } + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h new file mode 100644 index 0000000..811121a --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h @@ -0,0 +1,20 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +@class YALFoldingTabBar; + +@protocol YALTabBarInteracting + +@optional + +- (void)tabBarViewWillCollapse; +- (void)tabBarViewWillExpand; + +- (void)tabBarViewDidCollapse; +- (void)tabBarViewDidExpand; + +- (void)extraLeftItemDidPress; +- (void)extraRightItemDidPress; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h new file mode 100644 index 0000000..7dc9762 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h @@ -0,0 +1,53 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import + +@class YALFoldingTabBar; + +@protocol YALTabBarViewDataSource + +@required +- (NSArray *)leftTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView; +- (NSArray *)rightTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView; +- (UIImage *)centerImageInTabBarView:(YALFoldingTabBar *)tabBarView; + +@end + +@protocol YALTabBarViewDelegate + +@optional +- (void)itemInTabBarViewPressed:(YALFoldingTabBar *)tabBarView atIndex:(NSUInteger)index; + +- (void)tabBarViewWillCollapse:(YALFoldingTabBar *)tabBarView; +- (void)tabBarViewWillExpand:(YALFoldingTabBar *)tabBarView; + +- (void)tabBarViewDidCollapse:(YALFoldingTabBar *)tabBarView; +- (void)tabBarViewDidExpand:(YALFoldingTabBar *)tabBarView; + +- (void)extraLeftItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView; +- (void)extraRightItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView; + +@end + +typedef NS_ENUM(NSUInteger, YALTabBarState) { + YALStateCollapsed, + YALStateExpanded +}; + +@interface YALFoldingTabBar : UIView + +- (instancetype)initWithFrame:(CGRect)frame state:(YALTabBarState)state; + +@property (nonatomic, weak) IBOutlet id dataSource; +@property (nonatomic, weak) IBOutlet id delegate; + +@property (nonatomic, assign, readonly) YALTabBarState state; +@property (nonatomic, assign) NSUInteger selectedTabBarItemIndex; + +@property (nonatomic, copy) UIColor *tabBarColor; +@property (nonatomic, assign) UIEdgeInsets tabBarViewEdgeInsets; +@property (nonatomic, assign) UIEdgeInsets tabBarItemsEdgeInsets; +@property (nonatomic, assign) CGFloat extraTabBarItemHeight; +@property (nonatomic, assign) CGFloat offsetForExtraTabBarItems; + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.m b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.m new file mode 100644 index 0000000..bf95c65 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.m @@ -0,0 +1,660 @@ +// For License please refer to LICENSE file in the root of YALAnimatingTabBarController project + +#import "YALFoldingTabBar.h" + +//model +#import "YALTabBarItem.h" + +#import "CAAnimation+YALTabBarViewAnimations.h" +#import "CATransaction+TransactionWithAnimationsAndCompletion.h" + +typedef NS_ENUM(NSUInteger, YALAnimatingState) { + YALAnimatingStateCollapsing, + YALAnimatingStateExpanding +}; + +#import "YALAnimatingTabBarConstants.h" + +@interface YALFoldingTabBar () + +@property (nonatomic, strong) NSArray *allBarItems; + +@property (nonatomic, assign) YALTabBarState state; +@property (nonatomic, assign) YALAnimatingState animatingState; +@property (nonatomic, assign) BOOL isFinishedCenterButtonAnimation; + +@property (nonatomic, strong) UIButton *centerButton; +@property (nonatomic, strong) UIView *mainView; + +@property (nonatomic, assign) BOOL isAnimated; + +@property (nonatomic, assign) CGRect collapsedFrame; +@property (nonatomic, assign) CGRect expandedFrame; + +@property (nonatomic, assign) CGRect collapsedBounds; +@property (nonatomic, assign) CGRect expandedBounds; + +@property (nonatomic, assign) NSUInteger counter; + +//buttons used instead of native tabBarItems to switch between controllers +@property (nonatomic, strong) NSArray *leftButtonsArray; +@property (nonatomic, strong) NSArray *rightButtonsArray; + +//extra buttons 'tabBarItems' for each 'tabBarItem' +@property (nonatomic, strong) UIButton *extraLeftButton; +@property (nonatomic, strong) UIButton *extraRightButton; + +//model representation of tabBarItems. also contains info for extraBarItems: image, color, etc +@property (nonatomic, strong) NSDictionary *leftTabBarItems; +@property (nonatomic, strong) NSDictionary *rightTabBarItems; + +//array of all buttons just for simple switching between controllers by index +@property (nonatomic, strong) NSArray *allAdditionalButtons; +@property (nonatomic, strong) NSMutableArray *allAdditionalButtonsBottomView; + +@end + +@implementation YALFoldingTabBar + +#pragma mark - Initialations + +- (instancetype)initWithFrame:(CGRect)frame state:(YALTabBarState)state { + self = [super initWithFrame:frame]; + if (self) { + _state = state; + _selectedTabBarItemIndex = 0; + _counter = 0; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self setupUI]; +} + +#pragma mark - Private + +- (void)setupUI { + [self removeViewsBeforeUpdateUI]; + + [self setupMainView]; + [self setupCenterButton]; + + //collapsed frame equals to frame of the centerButton + self.collapsedFrame = self.centerButton.frame; + + [self setupAdditionalTabBarItems]; + + [self updateMaskLayer]; + + [self setupExtraTabBarItems]; + [self setupTabBarItemsViewRepresentation]; + [self setupBarItemsModelRepresentation]; + [self prepareTabBarViewForInitialState]; +} + +- (void)removeViewsBeforeUpdateUI { + + if (self.mainView) { + [self.mainView removeFromSuperview]; + self.mainView = nil; + } + + if (self.extraLeftButton) { + [self.extraLeftButton removeFromSuperview]; + self.extraLeftButton = nil; + } + + if (self.extraRightButton) { + [self.extraRightButton removeFromSuperview]; + self.extraRightButton = nil; + } + + if (self.centerButton) { + [self.centerButton removeFromSuperview]; + self.centerButton = nil; + } +} + +- (void)setupCenterButton { + self.centerButton = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.mainView.frame) - CGRectGetHeight(self.mainView.frame) / 2.0f, + CGRectGetMidY(self.mainView.frame) - CGRectGetHeight(self.mainView.frame) / 2.f, + CGRectGetHeight(self.mainView.frame), + CGRectGetHeight(self.mainView.frame))]; + + self.centerButton.layer.cornerRadius = CGRectGetHeight(self.mainView.bounds) / 2.f; + + if ([self.dataSource respondsToSelector:@selector(centerImageInTabBarView:)]) { + [self.centerButton setImage:[self.dataSource centerImageInTabBarView:self] forState:UIControlStateNormal]; + } + + [self.centerButton addTarget:self action:@selector(centerButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.centerButton.adjustsImageWhenHighlighted = NO; + + [self addSubview:self.centerButton]; +} + +- (void)setupMainView { + self.mainView = [[UIView alloc] initWithFrame:UIEdgeInsetsInsetRect(self.bounds, self.tabBarViewEdgeInsets)]; + + self.expandedFrame = self.mainView.frame; + self.mainView.layer.cornerRadius = CGRectGetHeight(self.mainView.bounds) / 2.f; + self.mainView.layer.masksToBounds = YES; + self.mainView.backgroundColor = self.tabBarColor; + + [self addSubview:self.mainView]; +} + +- (void)setupAdditionalTabBarItems { + NSArray *leftTabBarItems = [self.dataSource leftTabBarItemsInTabBarView:self]; + NSArray *rightTabBarItems = [self.dataSource rightTabBarItemsInTabBarView:self]; + + NSUInteger numberOfLeftTabBarButtonItems = [leftTabBarItems count]; + NSUInteger numberOfRightTabBarButtonItems = [rightTabBarItems count]; + + //calculate available space for left and right side + CGFloat availableSpaceForAdditionalBarButtonItemLeft = CGRectGetWidth(self.mainView.frame) / 2.f - CGRectGetWidth(self.centerButton.frame) / 2.f - self.tabBarItemsEdgeInsets.left; + + CGFloat availableSpaceForAdditionalBarButtonItemRight = CGRectGetWidth(self.mainView.frame) / 2.f - CGRectGetWidth(self.centerButton.frame) / 2.f - self.tabBarItemsEdgeInsets.right; + + CGFloat maxWidthForLeftBarButonItem = availableSpaceForAdditionalBarButtonItemLeft / numberOfLeftTabBarButtonItems; + CGFloat maxWidthForRightBarButonItem = availableSpaceForAdditionalBarButtonItemRight / numberOfRightTabBarButtonItems; + + NSMutableArray * reverseArrayLeft = [NSMutableArray arrayWithCapacity:[self.leftButtonsArray count]]; + + for (id element in [leftTabBarItems reverseObjectEnumerator]) { + [reverseArrayLeft addObject:element]; + } + + NSMutableArray *mutableArray = [NSMutableArray array]; + NSMutableArray *mutableDotsArray = [NSMutableArray array]; + + CGFloat deltaLeft = 0.f; + if (maxWidthForLeftBarButonItem > CGRectGetWidth(self.centerButton.frame)) { + deltaLeft = maxWidthForLeftBarButonItem - CGRectGetWidth(self.centerButton.frame); + } + + CGFloat startPositionLeft = CGRectGetWidth(self.mainView.bounds) / 2.f - CGRectGetWidth(self.centerButton.frame) / 2.f - self.tabBarItemsEdgeInsets.left - deltaLeft / 2.f; + + for (int i = 0; i < numberOfLeftTabBarButtonItems; i++) { + CGFloat buttonOriginX = startPositionLeft - maxWidthForLeftBarButonItem * (i+1); + CGFloat buttonOriginY = 0.f; + + CGFloat buttonWidth = maxWidthForLeftBarButonItem; + CGFloat buttonHeight = CGRectGetHeight(self.mainView.frame); + + startPositionLeft -= self.tabBarItemsEdgeInsets.right; + + YALTabBarItem *item = reverseArrayLeft[i]; + UIImage *image = item.itemImage; + + UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(buttonOriginX, buttonOriginY, buttonWidth, buttonHeight)]; + + if (numberOfLeftTabBarButtonItems == 1) { + CGRect rect = button.frame; + rect.size.width = CGRectGetHeight(self.mainView.frame); + button.bounds = rect; + } + + [button setImage:image forState:UIControlStateNormal]; + [button addTarget:self action:@selector(barItemDidTapped:) forControlEvents:UIControlEventTouchUpInside]; + + if (self.state == YALStateCollapsed) { + button.hidden = YES; + } + + + [mutableArray addObject:button]; + button.adjustsImageWhenHighlighted = NO; + + [self.mainView addSubview:button]; + } + + NSMutableArray * reverseArrayLeftDotViews = [NSMutableArray arrayWithCapacity:[mutableDotsArray count]]; + + for (id element in [mutableDotsArray reverseObjectEnumerator]) { + [reverseArrayLeft addObject:element]; + } + mutableDotsArray = reverseArrayLeftDotViews; + + self.leftButtonsArray = [mutableArray copy]; + + [mutableArray removeAllObjects]; + + CGFloat rightDelta = 0.f; + if (maxWidthForRightBarButonItem > CGRectGetWidth(self.centerButton.frame)) { + rightDelta = maxWidthForRightBarButonItem - CGRectGetWidth(self.centerButton.frame); + } + + CGFloat rightOffset = self.tabBarItemsEdgeInsets.right; + CGFloat startPositionRight = CGRectGetWidth(self.mainView.bounds) / 2.f + CGRectGetWidth(self.centerButton.frame) / 2.f + self.tabBarItemsEdgeInsets.right + + rightDelta / 2.f; + + for (int i = 0; i < numberOfRightTabBarButtonItems; i++) { + CGFloat buttonOriginX = startPositionRight; + CGFloat buttonOriginY = 0.f; + CGFloat buttonWidth = maxWidthForRightBarButonItem; + CGFloat buttonHeight = CGRectGetHeight(self.mainView.frame); + + startPositionRight = buttonOriginX + maxWidthForRightBarButonItem + rightOffset; + + YALTabBarItem *item = rightTabBarItems [i]; + UIImage *image = item.itemImage; + + UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(buttonOriginX, buttonOriginY, buttonWidth, buttonHeight)]; + + if (numberOfLeftTabBarButtonItems == 1) { + CGRect rect = button.frame; + rect.size.width = CGRectGetHeight(self.mainView.frame); + button.bounds = rect; + } + + [button setImage:image forState:UIControlStateNormal]; + [button addTarget:self action:@selector(barItemDidTapped:) forControlEvents:UIControlEventTouchUpInside]; + + if (self.state == YALStateCollapsed) { + button.hidden = YES; + } + [mutableArray addObject:button]; + button.adjustsImageWhenHighlighted = NO; + [self.mainView addSubview:button]; + } + + self.rightButtonsArray = [mutableArray copy]; +} + +//collect all tabBarItems (models) to one array +- (void)setupBarItemsModelRepresentation { + NSMutableArray *tempMutableArrayOfBarItems = [NSMutableArray array]; + + NSArray *leftTabBarItems = [self.dataSource leftTabBarItemsInTabBarView:self]; + NSArray *rightTabBarItems = [self.dataSource rightTabBarItemsInTabBarView:self]; + + for (YALTabBarItem *item in leftTabBarItems) { + [tempMutableArrayOfBarItems addObject:item]; + } + + for (YALTabBarItem *item in rightTabBarItems) { + [tempMutableArrayOfBarItems addObject:item]; + } + + self.allBarItems = [tempMutableArrayOfBarItems copy]; +} + +- (void)setupExtraTabBarItems { + self.extraLeftButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, CGRectGetMidY(self.mainView.frame) - CGRectGetHeight(self.mainView.frame) / 2.f, self.extraTabBarItemHeight, self.extraTabBarItemHeight)]; + self.extraLeftButton.center = CGPointMake( - CGRectGetWidth(self.extraLeftButton.frame) / 2, self.mainView.center.y); + self.extraLeftButton.backgroundColor = self.tabBarColor; + self.extraLeftButton.layer.cornerRadius = CGRectGetWidth(self.extraLeftButton.frame) / 2.f; + self.extraLeftButton.layer.masksToBounds = YES; + + [self.extraLeftButton addTarget:self action:@selector(extraLeftButtonDidPress) forControlEvents:UIControlEventTouchUpInside]; + self.extraLeftButton.hidden = YES; + + [self addSubview:self.extraLeftButton]; + + self.extraRightButton = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.frame) - CGRectGetWidth(self.centerButton.frame), CGRectGetMidY(self.mainView.frame) - CGRectGetHeight(self.mainView.frame) / 2.f, self.extraTabBarItemHeight, self.extraTabBarItemHeight)]; + self.extraRightButton.center = CGPointMake(self.extraRightButton.center.x + CGRectGetWidth(self.extraRightButton.frame) , self.mainView.center.y); + self.extraRightButton.layer.cornerRadius = CGRectGetWidth(self.extraLeftButton.frame) / 2.f; + self.extraLeftButton.layer.masksToBounds = YES; + + self.extraRightButton.backgroundColor = self.tabBarColor; + [self.extraRightButton addTarget:self action:@selector(extraRightButtonDidPress) forControlEvents:UIControlEventTouchUpInside]; + self.extraRightButton.hidden = YES; + + [self addSubview:self.extraRightButton]; +} + +- (void)setupTabBarItemsViewRepresentation { + NSMutableArray *tempArray = [NSMutableArray array]; + NSMutableArray *reverseArray = [NSMutableArray arrayWithCapacity:[self.leftButtonsArray count]]; + + for (id element in [self.leftButtonsArray reverseObjectEnumerator]) { + [reverseArray addObject:element]; + } + + for (UIButton *button in [reverseArray arrayByAddingObjectsFromArray:self.rightButtonsArray]) { + [tempArray addObject:button]; + } + + self.allAdditionalButtons = [tempArray copy]; + + self.allAdditionalButtonsBottomView = [[NSMutableArray alloc] init];; + for (UIButton *button in self.allAdditionalButtons) { + UIView *dotView = [[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, YALBottomSelectedDotDefaultSize,YALBottomSelectedDotDefaultSize)]; + dotView.center = CGPointMake(button.center.x, button.center.y + YALBottomSelectedDotOffset); + dotView.layer.cornerRadius = CGRectGetHeight(dotView.frame) / 2.f; + dotView.backgroundColor = [UIColor blackColor]; + dotView.hidden = YES; + [self.mainView addSubview:dotView]; + [self.allAdditionalButtonsBottomView addObject:dotView]; + } +} + +- (void)prepareTabBarViewForInitialState { + + if (![self hasTabBarItems]) { + return ; + } + + //collapse mainView. tabBarItams are hidden. + if (self.state == YALStateExpanded) { + self.centerButton.transform = CGAffineTransformMakeRotation(M_PI_4); + } + self.mainView.frame = self.expandedFrame; + + //prepare current selected tabBarItem + NSUInteger index = self.selectedTabBarItemIndex; + + if (self.selectedTabBarItemIndex != index) { + UIView *previousSelectedDotView = self.allAdditionalButtonsBottomView [self.selectedTabBarItemIndex]; + previousSelectedDotView.hidden = YES; + [self.allAdditionalButtonsBottomView replaceObjectAtIndex:self.selectedTabBarItemIndex withObject:previousSelectedDotView]; + } + + if (self.state == YALStateExpanded) { + + UIView *previousSelectedDotView = self.allAdditionalButtonsBottomView [self.selectedTabBarItemIndex]; + previousSelectedDotView.hidden = NO; + [self.allAdditionalButtonsBottomView replaceObjectAtIndex:self.selectedTabBarItemIndex withObject:previousSelectedDotView]; + } + + if (self.state == YALStateExpanded && self.selectedTabBarItemIndex == index) { + [self hideExtraLeftTabBarItem]; + [self hideExtraRightTabBarItem]; + } + + self.selectedTabBarItemIndex = index; + + //check if selected view controller needs extraLeftButton or extraRightButton + YALTabBarItem *defaultSelectedTabBarItem = [self.allBarItems objectAtIndex:index]; + [self configureExtraTabBarItemWithModel:defaultSelectedTabBarItem]; + if (self.state == YALStateCollapsed) { + + + if (defaultSelectedTabBarItem.leftImage) { + self.extraLeftButton.center = CGPointMake(self.offsetForExtraTabBarItems + CGRectGetWidth(self.extraLeftButton.frame) / 2.f, self.extraLeftButton.center.y); + } + + if (defaultSelectedTabBarItem.rightImage) { + self.extraRightButton.center = CGPointMake(CGRectGetWidth(self.frame) - self.offsetForExtraTabBarItems - CGRectGetWidth(self.extraRightButton.frame) / 2.f, self.extraRightButton.center.y); + } + } +} + +- (void)configureExtraTabBarItemWithModel:(YALTabBarItem *)item { + if (item.leftImage) { + self.extraLeftButton.hidden = NO; + [self.extraLeftButton setImage:item.leftImage forState:UIControlStateNormal]; + } else { + self.extraLeftButton.hidden = YES; + } + if (item.rightImage) { + self.extraRightButton.hidden = NO; + [self.extraRightButton setImage:item.rightImage forState:UIControlStateNormal]; + } else { + self.extraRightButton.hidden = YES; + } +} + +- (BOOL)hasTabBarItems { + return (self.allBarItems.count); +} + +#pragma mark - Actions + +- (void)centerButtonPressed { + //we should wait until animation cycle is finished + + if (![self hasTabBarItems]) { + return ; + } + + self.counter ++; + + if (!self.isAnimated) { + if (self.state == YALStateCollapsed) { + [self expand]; + } else { + [self collapse]; + } + } else { + if (self.animatingState == YALAnimatingStateCollapsing) { + [self expand]; + } else if (self.animatingState == YALAnimatingStateExpanding) { + [self collapse]; + } + } +} + +- (IBAction)barItemDidTapped:(id)sender { + if (self.isAnimated) { + return; + } + + NSUInteger index = [self.allAdditionalButtons indexOfObject:sender]; + + if (self.selectedTabBarItemIndex != index) { + YALTabBarItem *item = [self.allBarItems objectAtIndex:index]; + [self configureExtraTabBarItemWithModel:item]; + + UIView *previousSelectedDotView = self.allAdditionalButtonsBottomView[self.selectedTabBarItemIndex]; + previousSelectedDotView.hidden = YES; + [self.allAdditionalButtonsBottomView replaceObjectAtIndex:self.selectedTabBarItemIndex withObject:previousSelectedDotView]; + } + + self.selectedTabBarItemIndex = index; + + if ([self.delegate respondsToSelector:@selector(tabBarViewWillCollapse:)]) { + [self.delegate tabBarViewWillCollapse:self]; + } + + [self collapse]; + + if ([self.delegate respondsToSelector:@selector(itemInTabBarViewPressed:atIndex:)]) { + [self.delegate itemInTabBarViewPressed:self atIndex:index]; + } +} + +- (void)extraLeftButtonDidPress { + if ([self.delegate respondsToSelector:@selector(extraLeftItemDidPressInTabBarView:)]) { + [self.delegate extraLeftItemDidPressInTabBarView:self]; + } +} + +- (void)extraRightButtonDidPress { + if ([self.delegate respondsToSelector:@selector(extraRightItemDidPressInTabBarView:)]) { + [self.delegate extraRightItemDidPressInTabBarView:self]; + } +} + +#pragma mark - expand/collapse + +- (void)expand { + self.isFinishedCenterButtonAnimation = NO; + self.animatingState = YALAnimatingStateExpanding; + self.state = YALStateExpanded; + + if ([self.delegate respondsToSelector:@selector(tabBarViewWillExpand:)]) { + [self.delegate tabBarViewWillExpand:self]; + } + + __block NSUInteger counterCurrentValue = self.counter; + + [CATransaction transactionWithAnimations:^{ + self.isAnimated = YES; + [self animateTabBarViewExpand]; + [self hideExtraLeftTabBarItem]; + [self hideExtraRightTabBarItem]; + [self animateCenterButtonExpand]; + [self animateAdditionalButtons]; + [self showSelectedDotView]; + } andCompletion:^{ + if (counterCurrentValue == self.counter) { + if ([self.delegate respondsToSelector:@selector(tabBarViewDidExpand:)]) { + [self.delegate tabBarViewDidExpand:self]; + } + self.isAnimated = NO; + } + }]; +} + +- (void)collapse { + self.isFinishedCenterButtonAnimation = NO; + self.animatingState = YALAnimatingStateCollapsing; + self.state = YALStateCollapsed; + + if ([self.delegate respondsToSelector:@selector(tabBarViewWillCollapse:)]) { + [self.delegate tabBarViewWillCollapse:self]; + } + + __block NSUInteger counterCurrentValue = self.counter; + + [CATransaction transactionWithAnimations:^{ + self.isAnimated = YES; + [self animateTabBarViewCollapse]; + [self showExtraLeftTabBarItem]; + [self showExtraRightTabBarItem]; + [self animateCenterButtonCollapse]; + [self hideSelectedDotView]; + [self animateAdditionalButtons]; + } andCompletion:^{ + if (counterCurrentValue == self.counter) { + if ([self.delegate respondsToSelector:@selector(tabBarViewDidCollapse:)]) { + [self.delegate tabBarViewDidCollapse:self]; + } + } + self.isAnimated = NO; + }]; +} + +- (void)hideSelectedDotView { + UIView *previousSelectedDotView = self.allAdditionalButtonsBottomView[self.selectedTabBarItemIndex]; + previousSelectedDotView.hidden = YES; + [self.allAdditionalButtonsBottomView replaceObjectAtIndex:self.selectedTabBarItemIndex withObject:previousSelectedDotView]; +} + +- (void)showSelectedDotView { + UIView *previousSelectedDotView = self.allAdditionalButtonsBottomView[self.selectedTabBarItemIndex]; + previousSelectedDotView.hidden = NO; + [previousSelectedDotView.layer addAnimation:[CAAnimation showSelectedDotAnimation] forKey:nil]; + [self.allAdditionalButtonsBottomView replaceObjectAtIndex:self.selectedTabBarItemIndex withObject:previousSelectedDotView]; +} + +#pragma mark - Animations + +- (void)animateAdditionalButtons { + for (UIView *button in self.allAdditionalButtons) { + if (button.hidden) { + [button.layer addAnimation:[CAAnimation animationForAdditionalButton] forKey:nil]; + } + + button.hidden = !button.hidden; + } +} + +- (void)animateTabBarViewExpand { + CAAnimation *animation = [CAAnimation animationForTabBarExpandFromRect:self.collapsedBounds toRect:self.expandedBounds]; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + [self.mainView.layer.mask addAnimation:animation forKey:nil]; +} + +- (void)animateTabBarViewCollapse { + CAAnimation *animation = [CAAnimation animationForTabBarCollapseFromRect:self.expandedBounds toRect:self.collapsedBounds]; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + [self.mainView.layer.mask addAnimation:animation forKey:nil]; +} + +- (void)showExtraLeftTabBarItem { + [UIView animateWithDuration:kYALShowExtraTabBarItemViewAnimationParameters.duration + delay:kYALShowExtraTabBarItemViewAnimationParameters.delay + usingSpringWithDamping:kYALShowExtraTabBarItemViewAnimationParameters.damping + initialSpringVelocity:kYALShowExtraTabBarItemViewAnimationParameters.velocity + options:kYALShowExtraTabBarItemViewAnimationParameters.options + animations:^{ + self.extraLeftButton.center = CGPointMake(CGRectGetWidth(self.extraLeftButton.frame) / 2.f + self.offsetForExtraTabBarItems, self.extraLeftButton.center.y); + } completion:NULL]; + + CAAnimation *animation = [CAAnimation animationForExtraLeftBarItem]; + [self.extraLeftButton.layer addAnimation:animation forKey:nil]; +} + +- (void)showExtraRightTabBarItem { + [UIView animateWithDuration:kYALShowExtraTabBarItemViewAnimationParameters.duration + delay:kYALShowExtraTabBarItemViewAnimationParameters.delay + usingSpringWithDamping:kYALShowExtraTabBarItemViewAnimationParameters.damping + initialSpringVelocity:kYALShowExtraTabBarItemViewAnimationParameters.velocity + options:kYALShowExtraTabBarItemViewAnimationParameters.options + animations:^{ + self.extraRightButton.center = CGPointMake(CGRectGetWidth(self.frame) - CGRectGetWidth(self.extraRightButton.frame) / 2.f - self.offsetForExtraTabBarItems, self.extraRightButton.center.y); + } completion:NULL]; + + CAAnimation *animation = [CAAnimation animationForExtraRightBarItem]; + [self.extraRightButton.layer addAnimation:animation forKey:nil]; +} + +- (void)hideExtraLeftTabBarItem { + [UIView animateWithDuration:kYALHideExtraTabBarItemViewAnimationParameters.duration + animations:^{ + self.extraLeftButton.center = CGPointMake( - CGRectGetWidth(self.extraLeftButton.frame) / 2.f, self.extraLeftButton.center.y); + }]; +} + +- (void)hideExtraRightTabBarItem { + [UIView animateWithDuration:kYALHideExtraTabBarItemViewAnimationParameters.duration + animations:^{ + self.extraRightButton.center = CGPointMake(self.extraRightButton.center.x + CGRectGetWidth(self.extraRightButton.frame) + self.offsetForExtraTabBarItems, self.extraRightButton.center.y); + }]; +} + +- (void)animateCenterButtonExpand { + CAAnimation *animation = [CAAnimation animationForCenterButtonExpand]; + [self.centerButton.layer addAnimation:animation forKey:nil]; +} + +- (void)animateCenterButtonCollapse { + CAAnimation *animation = [CAAnimation animationForCenterButtonCollapse]; + [self.centerButton.layer addAnimation:animation forKey:nil]; +} + +#pragma mark - Mutators + +- (void)setCollapsedFrame:(CGRect)collapsedFrame { + _collapsedFrame = collapsedFrame; + + self.collapsedBounds = ({ + CGRect collapsedBounds = collapsedFrame; + collapsedBounds.origin = CGPointZero; + collapsedBounds.origin.x = CGRectGetWidth(self.expandedFrame) / 2 - CGRectGetWidth(collapsedBounds) / 2; + collapsedBounds; + }); + [self updateMaskLayer]; +} + +- (void)setExpandedFrame:(CGRect)expandedFrame { + _expandedFrame = expandedFrame; + + self.expandedBounds = ({ + CGRect expandedBounds = expandedFrame; + expandedBounds.origin = CGPointZero; + expandedBounds; + }); + [self updateMaskLayer]; +} + +#pragma mark - Private + +- (void)updateMaskLayer { + self.mainView.layer.mask = ({ + CAShapeLayer *layer = [CAShapeLayer new]; + CGRect rect = (self.state == YALStateExpanded) ? self.expandedBounds : self.collapsedBounds; + + layer.path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:rect.size.height / 2].CGPath; + + layer; + }); +} + +@end diff --git a/Unit-2-Journal/Pods/FoldingTabBar/LICENSE b/Unit-2-Journal/Pods/FoldingTabBar/LICENSE new file mode 100644 index 0000000..01ace4b --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Yalantis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Unit-2-Journal/Pods/FoldingTabBar/README.md b/Unit-2-Journal/Pods/FoldingTabBar/README.md new file mode 100644 index 0000000..ca5f422 --- /dev/null +++ b/Unit-2-Journal/Pods/FoldingTabBar/README.md @@ -0,0 +1,160 @@ +# FoldingTabBar.iOS + +Folding Tab Bar and Tab Bar Controller + +Made in [![Yalantis](https://raw.githubusercontent.com/Yalantis/FoldingTabBar.iOS/master/Example/Example/Resources/Images/badge_orage_shadow.png)](http://yalantis.com/?utm_source=github) + +Inspired by [this project on Dribbble](https://dribbble.com/shots/2003376-Tab-Bar-Animation) + +Also, read how it was done in our [blog](http://yalantis.com/blog/how_we_created_tab_bar_animation_for_ios/?utm_source=github) + +![Preview](https://d13yacurqjgara.cloudfront.net/users/495792/screenshots/2003376/tab_bar_animation_fin-02.gif) + + +## Requirements +iOS 7.0 + +## Installation + +####[CocoaPods](http://cocoapods.org) +```ruby +pod 'FoldingTabBar', '~> 1.0.1' +``` + +####Manual Installation + +Alternatively you can directly add all the source files from FoldingTabBar folder to your project. + +1. Download the [latest code version](https://github.com/Yalantis/FoldingTabBar.iOS/archive/master.zip) or add the repository as a git submodule to your git-tracked project. +2. Open your project in Xcode, then drag and drop all the folder directories in FoldingTabBar folder onto your project (use the "Product Navigator view"). Make sure to select Copy items when asked if you extracted the code archive outside of your project. + + +##Introduction + +####YALFoldingTabBarController +`YALFoldingTabBarController` is a subclass of `UITabBarController` with custom animating `YALFoldingTabBar`. + +####YALFoldingTabBar +YALFoldingTabBar is a subclass of a standard UIView. We wanted to make this component expand and contract in response to a user tapping. When the component is closed you can only see a central button (“+”). When tapping on it, our custom Tab Bar expands letting other tabBarItems appear, so that the user can switch the controllers. + +Each separate tabBarItem can have two additional buttons on the left and right. These buttons can be used to let a user interact with a selected screen on the YALFoldingTabBarController without even having to leave it. + +####YALTabBarItem +`YALTabBarItem` is a model to configure your tab bar items with images. + + +##Usage + +Option 1: The simplest way is to use `YALFoldingTabBarController` as it is. You can also subclass it if you indend to change the default behaviour. + +Option 2: You can write your own implementation of `UITabBarController `and use `YALFoldingTabBar` or its subclass. + +Here is an instruction of how to use `YALFoldingTabBarController` in the Storyboard. + +1. Add native `UITabBarController` to the storyboard, establish relationships with its view controllers. +2. Choose `YALFoldingTabBarController` as custom class for `UITabBarController`. +3. In AppDelegate method take out an instance of `YALFoldingTabBarController` from the window.rootViewController and supply it with images for the left and right tabBarItems respectively. Also you can add your own image for the center button of `YALFoldingTabBar`. + +```objective-c + YALFoldingTabBarController *tabBarController = (YALFoldingTabBarController *) self.window.rootViewController; + + //prepare leftBarItems + YALTabBarItem *item1 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"nearby_icon"] + leftItemImage:nil + rightItemImage:nil]; + + + YALTabBarItem *item2 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"profile_icon"] + leftItemImage:[UIImage imageNamed:@"edit_icon"] + rightItemImage:nil]; + + tabBarController.leftBarItems = @[item1, item2]; + + //prepare rightBarItems + YALTabBarItem *item3 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"chats_icon"] + leftItemImage:[UIImage imageNamed:@"search_icon"] + rightItemImage:[UIImage imageNamed:@"new_chat_icon"]]; + + + YALTabBarItem *item4 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"settings_icon"] + leftItemImage:nil + rightItemImage:nil]; + +``` + +If you want to handle touches on extra tabBarItems import `YALTabBarInteracting` protocol to the subclass of the proper `UIVIewController` and implement these methods: + +```objective-c +- (void)extraLeftItemDidPressed; +- (void)extraRightItemDidPressed; +``` + If you want to observe contracting and expanding animation states in `YALFoldingTabBar` the following methods of `YALTabBarInteracting` protocol can be implemented: +```objective-c +- (void)tabBarViewWillCollapse; +- (void)tabBarViewWillExpand; + +- (void)tabBarViewDidCollapsed; +- (void)tabBarViewDidExpanded; +``` + +##Important notes +Because we changed the height of the default `UITabBar` you should adjust your content to the bottom of viewcontroller's superview, and ignore Bottom Layout Guide. You should also uncheck 'Under bottom bars' !['](http://i.stack.imgur.com/Owlcz.png) + +You can see how we did it on the example project. + +##Tips for customization +You can make the following configurations for custom tabBar: + +1) Specify height +```objective-c +tabBarController.tabBarViewHeight = YALTabBarViewDefaultHeight; +``` +2) Specify insets and offsets +```objective-c + tabBarController.tabBarView.tabBarViewEdgeInsets = YALTabBarViewHDefaultEdgeInsets; + tabBarController.tabBarView.tabBarItemsEdgeInsets = YALTabBarViewItemsDefaultEdgeInsets; + tabBarController.tabBarView.offsetForExtraTabBarItems = YALForExtraTabBarItemsDefaultOffset; + +``` +3) Specify colors +```objective-c + tabBarController.tabBarView.backgroundColor = [UIColor colorWithRed:94.0/255.0 green:91.0/255.0 blue:149.0/255.0 alpha:1]; + tabBarController.tabBarView.tabBarColor = [UIColor colorWithRed:72.0/255.0 green:211.0/255.0 blue:178.0/255.0 alpha:1]; +``` +4) Specify height for additional left and right buttons +```objective-c + tabBarController.tabBarView.extraTabBarItemHeight = YALExtraTabBarItemsDefaultHeight; +``` + +##License + + The MIT License (MIT) + + Copyright © 2015 Yalantis + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + + + + + + + + diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPClient.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPClient.h new file mode 120000 index 0000000..aee081b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPClient.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPClient.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 0000000..ac762c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h new file mode 120000 index 0000000..c1fccfd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFImageRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h new file mode 120000 index 0000000..9f2188e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFJSONRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..f454e54 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworking.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworking.h new file mode 120000 index 0000000..a5a38da --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h new file mode 120000 index 0000000..4b04bd2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFPropertyListRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 0000000..d9b35fb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h new file mode 120000 index 0000000..9b01587 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFXMLRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 0000000..20b48f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink.h new file mode 120000 index 0000000..3f79bee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLink.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkNavigation.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkNavigation.h new file mode 120000 index 0000000..6962356 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkNavigation.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkNavigation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkResolving.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkResolving.h new file mode 120000 index 0000000..94cc66f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkResolving.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkResolving.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererController.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererController.h new file mode 120000 index 0000000..95067f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererController.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView.h new file mode 120000 index 0000000..cc00897 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView_Internal.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView_Internal.h new file mode 120000 index 0000000..fc68769 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkReturnToRefererView_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkTarget.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkTarget.h new file mode 120000 index 0000000..90a41f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLinkTarget.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkTarget.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink_Internal.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink_Internal.h new file mode 120000 index 0000000..dc060b2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFAppLink_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLink_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationToken.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationToken.h new file mode 120000 index 0000000..0b69486 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationToken.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationToken.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h new file mode 120000 index 0000000..c587ca7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenRegistration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h new file mode 120000 index 0000000..d3d5985 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFDefines.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFDefines.h new file mode 120000 index 0000000..5df18ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFDefines.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFDefines.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFExecutor.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFExecutor.h new file mode 120000 index 0000000..c071e8c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFExecutor.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFExecutor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent.h new file mode 120000 index 0000000..2eb6c11 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFMeasurementEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent_Internal.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent_Internal.h new file mode 120000 index 0000000..98b7d06 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFMeasurementEvent_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFMeasurementEvent_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTask.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTask.h new file mode 120000 index 0000000..5468334 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTask.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTask.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h new file mode 120000 index 0000000..c74760f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTaskCompletionSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL.h new file mode 120000 index 0000000..df21bd9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFURL.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL_Internal.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL_Internal.h new file mode 120000 index 0000000..3a5c5f4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFURL_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFURL_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BFWebViewAppLinkResolver.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFWebViewAppLinkResolver.h new file mode 120000 index 0000000..bf250db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BFWebViewAppLinkResolver.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFWebViewAppLinkResolver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/Bolts.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/Bolts.h new file mode 120000 index 0000000..146ac6e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/Bolts.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/Bolts.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Bolts/BoltsVersion.h b/Unit-2-Journal/Pods/Headers/Private/Bolts/BoltsVersion.h new file mode 120000 index 0000000..0fa0e2d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Bolts/BoltsVersion.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BoltsVersion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAccessToken.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAccessToken.h new file mode 120000 index 0000000..a5b3f97 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAccessToken.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppEvents.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppEvents.h new file mode 120000 index 0000000..95c1d00 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppEvents.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkResolver.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkResolver.h new file mode 120000 index 0000000..69c20f5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkResolver.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkUtility.h new file mode 120000 index 0000000..fef519c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKAppLinkUtility.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKApplicationDelegate.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKApplicationDelegate.h new file mode 120000 index 0000000..e163dc8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKApplicationDelegate.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKButton.h new file mode 120000 index 0000000..806ec62 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKButton.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKConstants.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKConstants.h new file mode 120000 index 0000000..4c08cc8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKConstants.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCopying.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCopying.h new file mode 120000 index 0000000..aa5dc1f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCopying.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit.h new file mode 120000 index 0000000..bfffe4f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents+Internal.h new file mode 120000 index 0000000..bca1f6d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEvents+Internal.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsDeviceInfo.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsDeviceInfo.h new file mode 120000 index 0000000..0117f86 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsDeviceInfo.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsState.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsState.h new file mode 120000 index 0000000..d308fc2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsState.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsStateManager.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsStateManager.h new file mode 120000 index 0000000..96166c9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsStateManager.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsUtility.h new file mode 120000 index 0000000..9e4fe10 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKAppEventsUtility.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKPaymentObserver.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKPaymentObserver.h new file mode 120000 index 0000000..2a1633c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKPaymentObserver.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKTimeSpentData.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKTimeSpentData.h new file mode 120000 index 0000000..86e7c62 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppEvents/FBSDKTimeSpentData.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppLink/FBSDKBoltsMeasurementEventListener.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppLink/FBSDKBoltsMeasurementEventListener.h new file mode 120000 index 0000000..5487fc0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/AppLink/FBSDKBoltsMeasurementEventListener.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Base64/FBSDKBase64.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Base64/FBSDKBase64.h new file mode 120000 index 0000000..813405b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Base64/FBSDKBase64.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPICrypto.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPICrypto.h new file mode 120000 index 0000000..cb0de38 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPICrypto.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocol.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocol.h new file mode 120000 index 0000000..1e29474 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocol.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocolType.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocolType.h new file mode 120000 index 0000000..be98e2d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIProtocolType.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest+Private.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest+Private.h new file mode 120000 index 0000000..683af01 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest+Private.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest.h new file mode 120000 index 0000000..5559ff2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIRequest.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIResponse.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIResponse.h new file mode 120000 index 0000000..b98fda5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKBridgeAPIResponse.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKURLOpening.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKURLOpening.h new file mode 120000 index 0000000..511af8b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/FBSDKURLOpening.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKURLOpening.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h new file mode 120000 index 0000000..7217555 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h @@ -0,0 +1 @@ +../../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h new file mode 120000 index 0000000..81046ef --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h @@ -0,0 +1 @@ +../../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h new file mode 120000 index 0000000..3d5905f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h @@ -0,0 +1 @@ +../../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Cryptography/FBSDKCrypto.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Cryptography/FBSDKCrypto.h new file mode 120000 index 0000000..d252bd1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Cryptography/FBSDKCrypto.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/FBSDKErrorRecoveryAttempter.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/FBSDKErrorRecoveryAttempter.h new file mode 120000 index 0000000..38b6b9a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/FBSDKErrorRecoveryAttempter.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h new file mode 120000 index 0000000..632ac64 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate+Internal.h new file mode 120000 index 0000000..77f5848 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKAudioResourceLoader.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKAudioResourceLoader.h new file mode 120000 index 0000000..2bfc06b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKAudioResourceLoader.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKContainerViewController.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKContainerViewController.h new file mode 120000 index 0000000..e7f5c5a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKContainerViewController.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit+Internal.h new file mode 120000 index 0000000..b008702 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKDynamicFrameworkLoader.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKDynamicFrameworkLoader.h new file mode 120000 index 0000000..a19240e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKDynamicFrameworkLoader.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKError.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKError.h new file mode 120000 index 0000000..6d85e14 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKError.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKInternalUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKInternalUtility.h new file mode 120000 index 0000000..c23bf34 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKInternalUtility.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKLogger.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKLogger.h new file mode 120000 index 0000000..3315142 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKLogger.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMath.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMath.h new file mode 120000 index 0000000..df9ec6b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMath.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMonotonicTime.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMonotonicTime.h new file mode 120000 index 0000000..d2aa09d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKMonotonicTime.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile+Internal.h new file mode 120000 index 0000000..255bbe8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKProfile+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings+Internal.h new file mode 120000 index 0000000..d6f2f9a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSettings+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSystemAccountStoreAdapter.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSystemAccountStoreAdapter.h new file mode 120000 index 0000000..2c6a47b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKSystemAccountStoreAdapter.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTriStateBOOL.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTriStateBOOL.h new file mode 120000 index 0000000..6a410f9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTriStateBOOL.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTypeUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTypeUtility.h new file mode 120000 index 0000000..099c869 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/FBSDKTypeUtility.h @@ -0,0 +1 @@ +../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequest+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequest+Internal.h new file mode 120000 index 0000000..6e01ec1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequest+Internal.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequest+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestBody.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestBody.h new file mode 120000 index 0000000..934a950 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestBody.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestConnection+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestConnection+Internal.h new file mode 120000 index 0000000..91dc9cf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestConnection+Internal.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnection+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestMetadata.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestMetadata.h new file mode 120000 index 0000000..706bcf0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestMetadata.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestPiggybackManager.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestPiggybackManager.h new file mode 120000 index 0000000..08b7d33 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKGraphRequestPiggybackManager.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKURLConnection.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKURLConnection.h new file mode 120000 index 0000000..6c2e53a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/Network/FBSDKURLConnection.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKDialogConfiguration.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKDialogConfiguration.h new file mode 120000 index 0000000..440f996 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKDialogConfiguration.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorConfiguration.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorConfiguration.h new file mode 120000 index 0000000..2dd9eb6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorConfiguration.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h new file mode 120000 index 0000000..7fefef9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration+Internal.h new file mode 120000 index 0000000..c83017c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration+Internal.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration.h new file mode 120000 index 0000000..92b6a91 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfiguration.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h new file mode 120000 index 0000000..ff5429a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager.h new file mode 120000 index 0000000..fce03db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/ServerConfiguration/FBSDKServerConfigurationManager.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCache.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCache.h new file mode 120000 index 0000000..7fd98c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCache.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3.h new file mode 120000 index 0000000..76f7463 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_17.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_17.h new file mode 120000 index 0000000..ab98c04 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_17.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_21.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_21.h new file mode 120000 index 0000000..e5b9041 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV3_21.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV4.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV4.h new file mode 120000 index 0000000..d51e088 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCacheV4.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCaching.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCaching.h new file mode 120000 index 0000000..2847507 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKAccessTokenCaching.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStore.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStore.h new file mode 120000 index 0000000..b4cd9e0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStore.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStoreViaBundleID.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStoreViaBundleID.h new file mode 120000 index 0000000..e487b7c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/TokenCaching/FBSDKKeychainStoreViaBundleID.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKButton+Subclass.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKButton+Subclass.h new file mode 120000 index 0000000..5d7863e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKButton+Subclass.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKCloseIcon.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKCloseIcon.h new file mode 120000 index 0000000..757c858 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKCloseIcon.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKColor.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKColor.h new file mode 120000 index 0000000..7f6cbb5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKColor.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKIcon.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKIcon.h new file mode 120000 index 0000000..d36c18a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKIcon.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKLogo.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKLogo.h new file mode 120000 index 0000000..360f0b0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKLogo.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKMaleSilhouetteIcon.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKMaleSilhouetteIcon.h new file mode 120000 index 0000000..a46a344 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKMaleSilhouetteIcon.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKUIUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKUIUtility.h new file mode 120000 index 0000000..e6fcd41 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKUIUtility.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKViewImpressionTracker.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKViewImpressionTracker.h new file mode 120000 index 0000000..3c37050 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/UI/FBSDKViewImpressionTracker.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialog.h new file mode 120000 index 0000000..c7e0ba3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialog.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialogView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialogView.h new file mode 120000 index 0000000..e0507f4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKCoreKit/WebDialog/FBSDKWebDialogView.h @@ -0,0 +1 @@ +../../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h new file mode 120000 index 0000000..6f019f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequest.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequest.h new file mode 120000 index 0000000..524cb77 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequest.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestConnection.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestConnection.h new file mode 120000 index 0000000..c6cbbfc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestConnection.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h new file mode 120000 index 0000000..9960de2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMacros.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMacros.h new file mode 120000 index 0000000..f9059c1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMacros.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMutableCopying.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMutableCopying.h new file mode 120000 index 0000000..40cf5f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKMutableCopying.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfile.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfile.h new file mode 120000 index 0000000..a9866b1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfile.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfilePictureView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfilePictureView.h new file mode 120000 index 0000000..6f38799 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKProfilePictureView.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKSettings.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKSettings.h new file mode 120000 index 0000000..7edc38f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKSettings.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKTestUsersManager.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKTestUsersManager.h new file mode 120000 index 0000000..5813f89 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKTestUsersManager.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKUtility.h new file mode 120000 index 0000000..efbfaf1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKCoreKit/FBSDKUtility.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h new file mode 120000 index 0000000..2858225 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion+Internal.h new file mode 120000 index 0000000..d780aec --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion.h new file mode 120000 index 0000000..9101505 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginCompletion.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h new file mode 120000 index 0000000..7a07eea --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginError.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginError.h new file mode 120000 index 0000000..ed27b5a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginError.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit+Internal.h new file mode 120000 index 0000000..e7b579c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginKit+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h new file mode 120000 index 0000000..fcd06fa --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager+Internal.h new file mode 120000 index 0000000..fea69ca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h new file mode 120000 index 0000000..05205f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLogger.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLogger.h new file mode 120000 index 0000000..5a06db7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLogger.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult+Internal.h new file mode 120000 index 0000000..ce5d355 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h new file mode 120000 index 0000000..fb21852 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h new file mode 120000 index 0000000..ffe74ad --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginUtility.h new file mode 120000 index 0000000..5431582 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginUtility.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h new file mode 120000 index 0000000..725e375 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/_FBSDKLoginRecoveryAttempter.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/_FBSDKLoginRecoveryAttempter.h new file mode 120000 index 0000000..156bac4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKLoginKit/FBSDKLoginKit/_FBSDKLoginRecoveryAttempter.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h new file mode 120000 index 0000000..67d7080 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h new file mode 120000 index 0000000..0e81d04 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h new file mode 120000 index 0000000..32e79a7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h new file mode 120000 index 0000000..61c47da --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h new file mode 120000 index 0000000..16f9d52 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKCheckmarkIcon.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKCheckmarkIcon.h new file mode 120000 index 0000000..429d4fb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKCheckmarkIcon.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h new file mode 120000 index 0000000..0a8ba29 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h new file mode 120000 index 0000000..3f7906b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestFrictionlessRecipientCache.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestFrictionlessRecipientCache.h new file mode 120000 index 0000000..8d2b1fc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestFrictionlessRecipientCache.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionController.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionController.h new file mode 120000 index 0000000..b17a17a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionController.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionControllerCache.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionControllerCache.h new file mode 120000 index 0000000..f54c62b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeActionControllerCache.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxBorderView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxBorderView.h new file mode 120000 index 0000000..eac03ca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxBorderView.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxView.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxView.h new file mode 120000 index 0000000..2fe6da3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeBoxView.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton+Internal.h new file mode 120000 index 0000000..894b54b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButton+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h new file mode 120000 index 0000000..1e9ecee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButtonPopWAV.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButtonPopWAV.h new file mode 120000 index 0000000..3693592 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButtonPopWAV.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl+Internal.h new file mode 120000 index 0000000..89509cd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeControl+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h new file mode 120000 index 0000000..984a2ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeDialog.h new file mode 120000 index 0000000..5f2ac3b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h new file mode 120000 index 0000000..efe324e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h new file mode 120000 index 0000000..c29f9ee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h new file mode 120000 index 0000000..7451999 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessengerIcon.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessengerIcon.h new file mode 120000 index 0000000..6363326 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKMessengerIcon.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h new file mode 120000 index 0000000..b827828 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h new file mode 120000 index 0000000..2d4e646 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h new file mode 120000 index 0000000..c981a56 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h new file mode 120000 index 0000000..e7e13b5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDefines.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDefines.h new file mode 120000 index 0000000..4314dbc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDefines.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareDefines.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h new file mode 120000 index 0000000..56b9ff9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h new file mode 120000 index 0000000..8e28a21 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareError.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareError.h new file mode 120000 index 0000000..c4a055e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareError.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit+Internal.h new file mode 120000 index 0000000..b6d1c4f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareKit+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h new file mode 120000 index 0000000..4c43211 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent+Internal.h new file mode 120000 index 0000000..15eb00f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareLinkContent+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h new file mode 120000 index 0000000..5d14f07 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h new file mode 120000 index 0000000..8e50e05 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h new file mode 120000 index 0000000..c44ae92 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h new file mode 120000 index 0000000..f8b1179 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer+Internal.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer+Internal.h new file mode 120000 index 0000000..7882df5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer+Internal.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareOpenGraphValueContainer+Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h new file mode 120000 index 0000000..30a0dd3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h new file mode 120000 index 0000000..b025b98 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h new file mode 120000 index 0000000..54fbeba --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareUtility.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareUtility.h new file mode 120000 index 0000000..1654e8c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareUtility.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h new file mode 120000 index 0000000..5fe5d63 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h new file mode 120000 index 0000000..18a9aad --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h new file mode 120000 index 0000000..e649637 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h new file mode 120000 index 0000000..3485485 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h new file mode 120000 index 0000000..c11b781 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h new file mode 120000 index 0000000..4300617 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h new file mode 120000 index 0000000..6645404 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALAnimatingTabBarConstants.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALAnimatingTabBarConstants.h new file mode 120000 index 0000000..59a4e5b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALAnimatingTabBarConstants.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBar.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBar.h new file mode 120000 index 0000000..7c9c72a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBar.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBarController.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBarController.h new file mode 120000 index 0000000..8fb6aca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALFoldingTabBarController.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALSpringAnimation.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALSpringAnimation.h new file mode 120000 index 0000000..3059fd1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALSpringAnimation.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarInteracting.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarInteracting.h new file mode 120000 index 0000000..87b5470 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarInteracting.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarItem.h b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarItem.h new file mode 120000 index 0000000..d2b7d0a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/FoldingTabBar/YALTabBarItem.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h b/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h new file mode 120000 index 0000000..932a9db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h b/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h new file mode 120000 index 0000000..79788f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/BFTask+Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/BFTask+Private.h new file mode 120000 index 0000000..10159b2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/BFTask+Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/BFTask+Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFACL.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACL.h new file mode 120000 index 0000000..7c3c14f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACL.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFACL.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLPrivate.h new file mode 120000 index 0000000..2879692 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ACL/PFACLPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState.h new file mode 120000 index 0000000..d3b8d9b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ACL/State/PFACLState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState_Private.h new file mode 120000 index 0000000..d9dd502 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFACLState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ACL/State/PFACLState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAlertView.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAlertView.h new file mode 120000 index 0000000..85018b0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAlertView.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFAlertView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics.h new file mode 120000 index 0000000..7751f45 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFAnalytics.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsController.h new file mode 120000 index 0000000..e1fc43f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsUtilities.h new file mode 120000 index 0000000..b383f8f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalyticsUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics_Private.h new file mode 120000 index 0000000..defa006 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnalytics_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Analytics/PFAnalytics_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousAuthenticationProvider.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousAuthenticationProvider.h new file mode 120000 index 0000000..14cb5b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousAuthenticationProvider.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils.h new file mode 120000 index 0000000..7b9b437 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFAnonymousUtils.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils_Private.h new file mode 120000 index 0000000..8b4fcef --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAnonymousUtils_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFApplication.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFApplication.h new file mode 120000 index 0000000..b0d8ee6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFApplication.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFApplication.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAssert.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAssert.h new file mode 120000 index 0000000..370352c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAssert.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFAssert.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFAsyncTaskQueue.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAsyncTaskQueue.h new file mode 120000 index 0000000..87cce9d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFAsyncTaskQueue.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFAsyncTaskQueue.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFBase64Encoder.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFBase64Encoder.h new file mode 120000 index 0000000..adae939 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFBase64Encoder.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFBase64Encoder.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFBaseState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFBaseState.h new file mode 120000 index 0000000..6c1b489 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFBaseState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFBaseState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCachedQueryController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCachedQueryController.h new file mode 120000 index 0000000..0712e6e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCachedQueryController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/Controller/PFCachedQueryController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCategoryLoader.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCategoryLoader.h new file mode 120000 index 0000000..7dedc13 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCategoryLoader.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCategoryLoader.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloud.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloud.h new file mode 120000 index 0000000..4070bb1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloud.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFCloud.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloudCodeController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloudCodeController.h new file mode 120000 index 0000000..38ca262 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCloudCodeController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/CloudCode/PFCloudCodeController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache.h new file mode 120000 index 0000000..b9d3183 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCommandCache.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache_Private.h new file mode 120000 index 0000000..aafb22b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandCache_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCommandCache_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandResult.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandResult.h new file mode 120000 index 0000000..2f1114a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandResult.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCommandResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunning.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunning.h new file mode 120000 index 0000000..f2d7c78 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunning.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunningConstants.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunningConstants.h new file mode 120000 index 0000000..3a73786 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandRunningConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandURLRequestConstructor.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandURLRequestConstructor.h new file mode 120000 index 0000000..bb68366 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCommandURLRequestConstructor.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig.h new file mode 120000 index 0000000..919b834 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFConfig.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfigController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfigController.h new file mode 120000 index 0000000..354d1e5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfigController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Config/Controller/PFConfigController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig_Private.h new file mode 120000 index 0000000..64be7b4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConfig_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Config/PFConfig_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFConstants.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConstants.h new file mode 120000 index 0000000..3b96186 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreDataProvider.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreDataProvider.h new file mode 120000 index 0000000..738cd66 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreDataProvider.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCoreDataProvider.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreManager.h new file mode 120000 index 0000000..c856497 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCoreManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFCoreManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentConfigController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentConfigController.h new file mode 120000 index 0000000..aa2f13d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentConfigController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentInstallationController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentInstallationController.h new file mode 120000 index 0000000..c935649 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentInstallationController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentObjectControlling.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentObjectControlling.h new file mode 120000 index 0000000..0d5e144 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentObjectControlling.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentUserController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentUserController.h new file mode 120000 index 0000000..4c70eaa --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFCurrentUserController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFDataProvider.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDataProvider.h new file mode 120000 index 0000000..52db407 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDataProvider.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFDataProvider.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFDateFormatter.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDateFormatter.h new file mode 120000 index 0000000..14af49b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDateFormatter.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFDateFormatter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFDecoder.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDecoder.h new file mode 120000 index 0000000..e8ca6e2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDecoder.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFDecoder.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFDefaultACLController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDefaultACLController.h new file mode 120000 index 0000000..28ee2d0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDefaultACLController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFDevice.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDevice.h new file mode 120000 index 0000000..45f3174 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFDevice.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFDevice.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFEncoder.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEncoder.h new file mode 120000 index 0000000..ccfe72c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEncoder.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFEncoder.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFErrorUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFErrorUtilities.h new file mode 120000 index 0000000..6cc92b4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFErrorUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFErrorUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyPin.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyPin.h new file mode 120000 index 0000000..d7914fd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyPin.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFEventuallyPin.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue.h new file mode 120000 index 0000000..93c4119 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFEventuallyQueue.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue_Private.h new file mode 120000 index 0000000..b7d09c4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFEventuallyQueue_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFEventuallyQueue_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperation.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperation.h new file mode 120000 index 0000000..f0a3bab --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperation.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/FieldOperation/PFFieldOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperationDecoder.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperationDecoder.h new file mode 120000 index 0000000..2cd60fe --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFieldOperationDecoder.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile.h new file mode 120000 index 0000000..05ca154 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFFile.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileController.h new file mode 120000 index 0000000..8c0f296 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/Controller/PFFileController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileDataStream.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileDataStream.h new file mode 120000 index 0000000..54cbb17 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileDataStream.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileManager.h new file mode 120000 index 0000000..09a9757 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFFileManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileStagingController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileStagingController.h new file mode 120000 index 0000000..af38d1e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileStagingController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/Controller/PFFileStagingController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState.h new file mode 120000 index 0000000..f70310a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/State/PFFileState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState_Private.h new file mode 120000 index 0000000..fd636fa --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFileState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/State/PFFileState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile_Private.h new file mode 120000 index 0000000..53b4a61 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFFile_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/PFFile_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPoint.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPoint.h new file mode 120000 index 0000000..e9079fe --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPoint.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFGeoPoint.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPointPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPointPrivate.h new file mode 120000 index 0000000..f151ab9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFGeoPointPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFGeoPointPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPRequest.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPRequest.h new file mode 120000 index 0000000..578b9f2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPRequest.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/HTTPRequest/PFHTTPRequest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPURLRequestConstructor.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPURLRequestConstructor.h new file mode 120000 index 0000000..f2e4304 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHTTPURLRequestConstructor.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFHash.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHash.h new file mode 120000 index 0000000..ecea29b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFHash.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFHash.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallation.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallation.h new file mode 120000 index 0000000..1f2d37a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallation.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFInstallation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationConstants.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationConstants.h new file mode 120000 index 0000000..a4ca8a6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationController.h new file mode 120000 index 0000000..530f6c2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/Controller/PFInstallationController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore.h new file mode 120000 index 0000000..827fb6c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore_Private.h new file mode 120000 index 0000000..acff66f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationIdentifierStore_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationPrivate.h new file mode 120000 index 0000000..fc6ac83 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInstallationPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Installation/PFInstallationPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFInternalUtils.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInternalUtils.h new file mode 120000 index 0000000..a0e19bf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFInternalUtils.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFInternalUtils.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFJSONSerialization.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFJSONSerialization.h new file mode 120000 index 0000000..786edd6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFJSONSerialization.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFJSONSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache.h new file mode 120000 index 0000000..f68af04 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache_Private.h new file mode 120000 index 0000000..d971da7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeyValueCache_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeychainStore.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeychainStore.h new file mode 120000 index 0000000..1609762 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFKeychainStore.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFKeychainStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFLocationManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLocationManager.h new file mode 120000 index 0000000..c534560 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLocationManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFLocationManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogger.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogger.h new file mode 120000 index 0000000..f100f88 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogger.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFLogger.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogging.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogging.h new file mode 120000 index 0000000..0957f9c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFLogging.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFLogging.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMacros.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMacros.h new file mode 120000 index 0000000..be0a4a8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMacros.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFMacros.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLock.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLock.h new file mode 120000 index 0000000..d40b109 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLock.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLockController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLockController.h new file mode 120000 index 0000000..8e59276 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMultiProcessFileLockController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMulticastDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMulticastDelegate.h new file mode 120000 index 0000000..c731e9b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMulticastDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFMulticastDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableACLState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableACLState.h new file mode 120000 index 0000000..05bf135 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableACLState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ACL/State/PFMutableACLState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableFileState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableFileState.h new file mode 120000 index 0000000..d08ab4a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableFileState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/File/State/PFMutableFileState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableObjectState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableObjectState.h new file mode 120000 index 0000000..e715fb4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableObjectState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/State/PFMutableObjectState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutablePushState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutablePushState.h new file mode 120000 index 0000000..3fe0c5d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutablePushState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/State/PFMutablePushState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableQueryState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableQueryState.h new file mode 120000 index 0000000..8e8c7a5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableQueryState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/State/PFMutableQueryState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableRelationState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableRelationState.h new file mode 120000 index 0000000..13a1999 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableRelationState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Relation/State/PFMutableRelationState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableUserState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableUserState.h new file mode 120000 index 0000000..d5dbab7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFMutableUserState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/State/PFMutableUserState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..1ae2fdb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkCommand.h new file mode 120000 index 0000000..2c8a391 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNetworkCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFNetworkCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFNullability.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNullability.h new file mode 120000 index 0000000..d3b6c2e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFNullability.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFNullability.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject+Subclass.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject+Subclass.h new file mode 120000 index 0000000..ccbad16 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject+Subclass.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFObject+Subclass.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject.h new file mode 120000 index 0000000..b00d5bb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObject.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFObject.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectBatchController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectBatchController.h new file mode 120000 index 0000000..ed0585f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectBatchController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectConstants.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectConstants.h new file mode 120000 index 0000000..2834ef6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Constants/PFObjectConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController.h new file mode 120000 index 0000000..19d572b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Controller/PFObjectController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController_Private.h new file mode 120000 index 0000000..3df14b2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectController_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Controller/PFObjectController_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectControlling.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectControlling.h new file mode 120000 index 0000000..facfd09 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectControlling.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Controller/PFObjectControlling.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectEstimatedData.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectEstimatedData.h new file mode 120000 index 0000000..2627e92 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectEstimatedData.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCoder.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCoder.h new file mode 120000 index 0000000..4d9fc61 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCoder.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCodingLogic.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCodingLogic.h new file mode 120000 index 0000000..c5bb3c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFileCodingLogic.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFilePersistenceController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFilePersistenceController.h new file mode 120000 index 0000000..b2f5bb6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectFilePersistenceController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectLocalIdStore.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectLocalIdStore.h new file mode 120000 index 0000000..e2cbdf8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectLocalIdStore.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectPrivate.h new file mode 120000 index 0000000..849167d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/PFObjectPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState.h new file mode 120000 index 0000000..8835423 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/State/PFObjectState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState_Private.h new file mode 120000 index 0000000..0068676 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/State/PFObjectState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassInfo.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassInfo.h new file mode 120000 index 0000000..f408e73 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassInfo.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassingController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassingController.h new file mode 120000 index 0000000..6f54ea8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectSubclassingController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectUtilities.h new file mode 120000 index 0000000..ca1e591 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFObjectUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineObjectController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineObjectController.h new file mode 120000 index 0000000..2450581 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineObjectController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryController.h new file mode 120000 index 0000000..61522e9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryLogic.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryLogic.h new file mode 120000 index 0000000..51de493 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineQueryLogic.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineStore.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineStore.h new file mode 120000 index 0000000..e2a28d5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOfflineStore.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFOperationSet.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOperationSet.h new file mode 120000 index 0000000..b62dded --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFOperationSet.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/OperationSet/PFOperationSet.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver.h new file mode 120000 index 0000000..0cf1120 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver_Private.h new file mode 120000 index 0000000..80578e3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPaymentTransactionObserver_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPin.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPin.h new file mode 120000 index 0000000..a7301b9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPin.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/Pin/PFPin.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningEventuallyQueue.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningEventuallyQueue.h new file mode 120000 index 0000000..5481dca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningEventuallyQueue.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFPinningEventuallyQueue.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningObjectStore.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningObjectStore.h new file mode 120000 index 0000000..5ac2044 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPinningObjectStore.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct+Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct+Private.h new file mode 120000 index 0000000..d698072 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct+Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Product/PFProduct+Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct.h new file mode 120000 index 0000000..f4f4940 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProduct.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFProduct.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFProductsRequestHandler.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProductsRequestHandler.h new file mode 120000 index 0000000..b06ea1d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFProductsRequestHandler.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo.h new file mode 120000 index 0000000..3571a7e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Private.h new file mode 120000 index 0000000..3568406 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Runtime.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Runtime.h new file mode 120000 index 0000000..6c7c2b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPropertyInfo_Runtime.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchase.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchase.h new file mode 120000 index 0000000..8d7cb4a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchase.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFPurchase.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchaseController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchaseController.h new file mode 120000 index 0000000..91f42f4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPurchaseController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPush.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPush.h new file mode 120000 index 0000000..930cb47 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPush.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFPush.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushChannelsController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushChannelsController.h new file mode 120000 index 0000000..84a2d30 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushChannelsController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushController.h new file mode 120000 index 0000000..3f11f0e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/Controller/PFPushController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushManager.h new file mode 120000 index 0000000..04cbb0d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/Manager/PFPushManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushPrivate.h new file mode 120000 index 0000000..d25e5ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/PFPushPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState.h new file mode 120000 index 0000000..686f491 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/State/PFPushState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState_Private.h new file mode 120000 index 0000000..87e61e5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/State/PFPushState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushUtilities.h new file mode 120000 index 0000000..e6460a3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFPushUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Push/Utilites/PFPushUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQuery.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQuery.h new file mode 120000 index 0000000..1ea0442 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQuery.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFQuery.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryController.h new file mode 120000 index 0000000..5635d68 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/Controller/PFQueryController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryPrivate.h new file mode 120000 index 0000000..2f1bf2f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/PFQueryPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState.h new file mode 120000 index 0000000..381352e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/State/PFQueryState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState_Private.h new file mode 120000 index 0000000..97a6657 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/State/PFQueryState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryUtilities.h new file mode 120000 index 0000000..f5c92e2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFQueryUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTAnalyticsCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTAnalyticsCommand.h new file mode 120000 index 0000000..6fe355e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTAnalyticsCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCloudCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCloudCommand.h new file mode 120000 index 0000000..46f5e1f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCloudCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTCloudCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand.h new file mode 120000 index 0000000..4fe070b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand_Private.h new file mode 120000 index 0000000..df23738 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTCommand_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTCommand_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTConfigCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTConfigCommand.h new file mode 120000 index 0000000..f671a72 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTConfigCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTConfigCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTFileCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTFileCommand.h new file mode 120000 index 0000000..e31ba58 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTFileCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTFileCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectBatchCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectBatchCommand.h new file mode 120000 index 0000000..828b203 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectBatchCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectCommand.h new file mode 120000 index 0000000..7de026d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTObjectCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTObjectCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTPushCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTPushCommand.h new file mode 120000 index 0000000..d2a676e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTPushCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTPushCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTQueryCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTQueryCommand.h new file mode 120000 index 0000000..82f2793 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTQueryCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTQueryCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTSessionCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTSessionCommand.h new file mode 120000 index 0000000..e3651cb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTSessionCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTSessionCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTUserCommand.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTUserCommand.h new file mode 120000 index 0000000..9a13083 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRESTUserCommand.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/PFRESTUserCommand.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFReachability.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFReachability.h new file mode 120000 index 0000000..ac4e8fa --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFReachability.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFReachability.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelation.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelation.h new file mode 120000 index 0000000..a3e8444 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelation.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFRelation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationPrivate.h new file mode 120000 index 0000000..0115a6f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Relation/PFRelationPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState.h new file mode 120000 index 0000000..f2659be --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Relation/State/PFRelationState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState_Private.h new file mode 120000 index 0000000..ac2cfe1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRelationState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Relation/State/PFRelationState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFRole.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRole.h new file mode 120000 index 0000000..26cd86c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFRole.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFRole.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase.h new file mode 120000 index 0000000..787b1e8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseController.h new file mode 120000 index 0000000..37b616f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseResult.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseResult.h new file mode 120000 index 0000000..a2c98a3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabaseResult.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase_Private.h new file mode 120000 index 0000000..3165b80 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteDatabase_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteStatement.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteStatement.h new file mode 120000 index 0000000..3ef2050 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSQLiteStatement.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession.h new file mode 120000 index 0000000..4c43360 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFSession.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionController.h new file mode 120000 index 0000000..19acd46 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Session/Controller/PFSessionController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionUtilities.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionUtilities.h new file mode 120000 index 0000000..13ac6c5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSessionUtilities.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession_Private.h new file mode 120000 index 0000000..077e55a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSession_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Session/PFSession_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFSubclassing.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSubclassing.h new file mode 120000 index 0000000..901cadc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFSubclassing.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFSubclassing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFTaskQueue.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFTaskQueue.h new file mode 120000 index 0000000..d7ccda7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFTaskQueue.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFTaskQueue.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFThreadsafety.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFThreadsafety.h new file mode 120000 index 0000000..d670b07 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFThreadsafety.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ThreadSafety/PFThreadsafety.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLConstructor.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLConstructor.h new file mode 120000 index 0000000..6760b55 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLConstructor.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/HTTPRequest/PFURLConstructor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession.h new file mode 120000 index 0000000..767bbbf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner.h new file mode 120000 index 0000000..a5bcf23 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner_Private.h new file mode 120000 index 0000000..4079814 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionCommandRunner_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate.h new file mode 120000 index 0000000..c0c5ccb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate_Private.h new file mode 120000 index 0000000..8d6abcf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionDataTaskDelegate_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionFileDownloadTaskDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionFileDownloadTaskDelegate.h new file mode 120000 index 0000000..61d5d80 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionFileDownloadTaskDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionJSONDataTaskDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionJSONDataTaskDelegate.h new file mode 120000 index 0000000..1933d5b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionJSONDataTaskDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionUploadTaskDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionUploadTaskDelegate.h new file mode 120000 index 0000000..5327ead --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSessionUploadTaskDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession_Private.h new file mode 120000 index 0000000..d3c1649 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFURLSession_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUser.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUser.h new file mode 120000 index 0000000..01e4199 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUser.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFUser.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationController.h new file mode 120000 index 0000000..3b222ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationDelegate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationDelegate.h new file mode 120000 index 0000000..3b6b473 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserAuthenticationDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFUserAuthenticationDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserConstants.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserConstants.h new file mode 120000 index 0000000..2ad9193 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/Constants/PFUserConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserController.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserController.h new file mode 120000 index 0000000..ed6c494 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserController.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/Controller/PFUserController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserFileCodingLogic.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserFileCodingLogic.h new file mode 120000 index 0000000..ca0302d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserFileCodingLogic.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserPrivate.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserPrivate.h new file mode 120000 index 0000000..114e09a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserPrivate.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/PFUserPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState.h new file mode 120000 index 0000000..f18a548 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/State/PFUserState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState_Private.h new file mode 120000 index 0000000..b5b0d81 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFUserState_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/User/State/PFUserState_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/PFWeakValue.h b/Unit-2-Journal/Pods/Headers/Private/Parse/PFWeakValue.h new file mode 120000 index 0000000..7cc66d2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/PFWeakValue.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/PFWeakValue.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/Parse.h b/Unit-2-Journal/Pods/Headers/Private/Parse/Parse.h new file mode 120000 index 0000000..699c11c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/Parse.h @@ -0,0 +1 @@ +../../../Parse/Parse/Parse.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/ParseInternal.h b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseInternal.h new file mode 120000 index 0000000..96a779a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseInternal.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ParseInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/ParseManager.h b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseManager.h new file mode 120000 index 0000000..1644f32 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ParseManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/ParseModule.h b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseModule.h new file mode 120000 index 0000000..9f00abd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/ParseModule.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/ParseModule.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Parse/Parse_Private.h b/Unit-2-Journal/Pods/Headers/Private/Parse/Parse_Private.h new file mode 120000 index 0000000..c149580 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Parse/Parse_Private.h @@ -0,0 +1 @@ +../../../Parse/Parse/Internal/Parse_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h b/Unit-2-Journal/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h new file mode 120000 index 0000000..7768a97 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h @@ -0,0 +1 @@ +../../../RKValueTransformers/Code/RKValueTransformers.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network.h new file mode 120000 index 0000000..5210a78 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network.h @@ -0,0 +1 @@ +../../../RestKit/Code/Network.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h new file mode 120000 index 0000000..2b63c3c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKHTTPRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h new file mode 120000 index 0000000..c5f5677 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKManagedObjectRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectManager.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectManager.h new file mode 120000 index 0000000..f67267f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectManager.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h new file mode 120000 index 0000000..73e232c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectParameterization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h new file mode 120000 index 0000000..e4dbe06 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h new file mode 120000 index 0000000..d0ca904 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperationSubclass.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPaginator.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPaginator.h new file mode 120000 index 0000000..35b421e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPaginator.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPaginator.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h new file mode 120000 index 0000000..73ab1e6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPathMatcher.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h new file mode 120000 index 0000000..7f8e8b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRequestDescriptor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h new file mode 120000 index 0000000..4981d9a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseDescriptor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h new file mode 120000 index 0000000..a2e1586 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseMapperOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRoute.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRoute.h new file mode 120000 index 0000000..39eb2cb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRoute.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRoute.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouteSet.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouteSet.h new file mode 120000 index 0000000..a702bdc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouteSet.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouteSet.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouter.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouter.h new file mode 120000 index 0000000..7187f17 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Network/RKRouter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping.h new file mode 120000 index 0000000..9ca1b53 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping.h @@ -0,0 +1 @@ +../../../RestKit/Code/ObjectMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h new file mode 120000 index 0000000..b196d35 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKAttributeMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h new file mode 120000 index 0000000..67a1caf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKDynamicMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h new file mode 120000 index 0000000..6d6996d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKErrorMessage.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h new file mode 120000 index 0000000..318d5c2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKHTTPUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h new file mode 120000 index 0000000..59e87e2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h new file mode 120000 index 0000000..bd32976 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h new file mode 120000 index 0000000..6aaec37 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h new file mode 120000 index 0000000..68e3925 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingErrors.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h new file mode 120000 index 0000000..6b4d1bf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h new file mode 120000 index 0000000..d463834 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h new file mode 120000 index 0000000..03618d2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h new file mode 120000 index 0000000..d38ebca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h new file mode 120000 index 0000000..2664bd7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 120000 index 0000000..cdac049 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h new file mode 120000 index 0000000..1ee01f3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h new file mode 120000 index 0000000..a3e2a9d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyInspector.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h new file mode 120000 index 0000000..db4bc5c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h new file mode 120000 index 0000000..32b9847 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKRelationshipMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/RestKit.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/RestKit.h new file mode 120000 index 0000000..49e183c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/RestKit.h @@ -0,0 +1 @@ +../../../RestKit/Code/RestKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support.h new file mode 120000 index 0000000..06fa6db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support.h @@ -0,0 +1 @@ +../../../RestKit/Code/Support.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h new file mode 120000 index 0000000..f4e0175 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDictionaryUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h new file mode 120000 index 0000000..44ee028 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDotNetDateFormatter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKErrors.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKErrors.h new file mode 120000 index 0000000..7319216 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKErrors.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLog.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLog.h new file mode 120000 index 0000000..6a428cb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLog.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h new file mode 120000 index 0000000..b8d134c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLumberjackLogger.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h new file mode 120000 index 0000000..b77b8b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypeSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h new file mode 120000 index 0000000..71b36c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypes.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMacros.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMacros.h new file mode 120000 index 0000000..f1d842d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKMacros.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMacros.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h new file mode 120000 index 0000000..537580d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKNSJSONSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h new file mode 120000 index 0000000..1391329 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKOperationStateMachine.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h new file mode 120000 index 0000000..2ef3a20 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKPathUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKSerialization.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKSerialization.h new file mode 120000 index 0000000..b66ce92 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h new file mode 120000 index 0000000..6535c08 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKStringTokenizer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h new file mode 120000 index 0000000..ea62327 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKURLEncodedSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h new file mode 120000 index 0000000..7902c5b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_components_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h new file mode 120000 index 0000000..eff8ca5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_extensions_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h new file mode 120000 index 0000000..39088b8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_logger_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing.h new file mode 120000 index 0000000..1404cdc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing.h @@ -0,0 +1 @@ +../../../RestKit/Code/Testing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKBenchmark.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKBenchmark.h new file mode 120000 index 0000000..e5a9bfd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKBenchmark.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKBenchmark.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKConnectionTestExpectation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKConnectionTestExpectation.h new file mode 120000 index 0000000..6a690f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKConnectionTestExpectation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKConnectionTestExpectation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKMappingTest.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKMappingTest.h new file mode 120000 index 0000000..8bdd3be --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKMappingTest.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKMappingTest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKPropertyMappingTestExpectation.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKPropertyMappingTestExpectation.h new file mode 120000 index 0000000..13cdab9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKPropertyMappingTestExpectation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKPropertyMappingTestExpectation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFactory.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFactory.h new file mode 120000 index 0000000..145b1f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFactory.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestFactory.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFixture.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFixture.h new file mode 120000 index 0000000..26226cd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestFixture.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestFixture.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestHelpers.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestHelpers.h new file mode 120000 index 0000000..44a0b44 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestHelpers.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestHelpers.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestNotificationObserver.h b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestNotificationObserver.h new file mode 120000 index 0000000..d8ed687 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/RestKit/Testing/RKTestNotificationObserver.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestNotificationObserver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/SOCKit/SOCKit.h b/Unit-2-Journal/Pods/Headers/Private/SOCKit/SOCKit.h new file mode 120000 index 0000000..72c5afc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/SOCKit/SOCKit.h @@ -0,0 +1 @@ +../../../SOCKit/SOCKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKEvent.h b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKEvent.h new file mode 120000 index 0000000..e0febb8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKEvent.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKState.h b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKState.h new file mode 120000 index 0000000..6dbd8d3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKState.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKStateMachine.h b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKStateMachine.h new file mode 120000 index 0000000..cfbbd7f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKStateMachine.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKStateMachine.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKTransition.h b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKTransition.h new file mode 120000 index 0000000..d83dc2c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TKTransition.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKTransition.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TransitionKit.h b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TransitionKit.h new file mode 120000 index 0000000..d5b6768 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/TransitionKit/TransitionKit.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TransitionKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h b/Unit-2-Journal/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 120000 index 0000000..d94e2d3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1 @@ +../../../../../RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/FloatConversion.h b/Unit-2-Journal/Pods/Headers/Private/pop/FloatConversion.h new file mode 120000 index 0000000..aea012a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/FloatConversion.h @@ -0,0 +1 @@ +../../../pop/pop/WebCore/FloatConversion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POP.h b/Unit-2-Journal/Pods/Headers/Private/pop/POP.h new file mode 120000 index 0000000..dd15660 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POP.h @@ -0,0 +1 @@ +../../../pop/pop/POP.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAction.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAction.h new file mode 120000 index 0000000..78f9372 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAction.h @@ -0,0 +1 @@ +../../../pop/pop/POPAction.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatableProperty.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatableProperty.h new file mode 120000 index 0000000..48fd8c4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatableProperty.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimatableProperty.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimation.h new file mode 120000 index 0000000..dfe8a85 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEvent.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEvent.h new file mode 120000 index 0000000..5d40492 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEvent.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEventInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEventInternal.h new file mode 120000 index 0000000..8263df6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationEventInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationEventInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationExtras.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationExtras.h new file mode 120000 index 0000000..3a1bc7e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationExtras.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationExtras.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationInternal.h new file mode 120000 index 0000000..6aebf45 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationPrivate.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationPrivate.h new file mode 120000 index 0000000..ea5956d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationPrivate.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationRuntime.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationRuntime.h new file mode 120000 index 0000000..0651d06 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationRuntime.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationRuntime.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracer.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracer.h new file mode 120000 index 0000000..64fff66 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracer.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationTracer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracerInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracerInternal.h new file mode 120000 index 0000000..b76b731 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimationTracerInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationTracerInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimator.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimator.h new file mode 120000 index 0000000..89707ea --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimator.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimator.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatorPrivate.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatorPrivate.h new file mode 120000 index 0000000..89650c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPAnimatorPrivate.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimatorPrivate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimation.h new file mode 120000 index 0000000..50184f2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPBasicAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimationInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimationInternal.h new file mode 120000 index 0000000..fa8cb0b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPBasicAnimationInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPBasicAnimationInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPCGUtils.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPCGUtils.h new file mode 120000 index 0000000..d050fb4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPCGUtils.h @@ -0,0 +1 @@ +../../../pop/pop/POPCGUtils.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPCustomAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPCustomAnimation.h new file mode 120000 index 0000000..5025bd6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPCustomAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPCustomAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimation.h new file mode 120000 index 0000000..dba2796 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPDecayAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimationInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimationInternal.h new file mode 120000 index 0000000..4d5c959 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPDecayAnimationInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPDecayAnimationInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPDefines.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPDefines.h new file mode 120000 index 0000000..4b10036 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPDefines.h @@ -0,0 +1 @@ +../../../pop/pop/POPDefines.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPGeometry.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPGeometry.h new file mode 120000 index 0000000..9b29189 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPGeometry.h @@ -0,0 +1 @@ +../../../pop/pop/POPGeometry.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPLayerExtras.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPLayerExtras.h new file mode 120000 index 0000000..e11f4c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPLayerExtras.h @@ -0,0 +1 @@ +../../../pop/pop/POPLayerExtras.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPMath.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPMath.h new file mode 120000 index 0000000..cc52b21 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPMath.h @@ -0,0 +1 @@ +../../../pop/pop/POPMath.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimation.h new file mode 120000 index 0000000..0fae4c5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPPropertyAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimationInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimationInternal.h new file mode 120000 index 0000000..5783767 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPPropertyAnimationInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPPropertyAnimationInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimation.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimation.h new file mode 120000 index 0000000..152f663 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPSpringAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimationInternal.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimationInternal.h new file mode 120000 index 0000000..afdc982 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringAnimationInternal.h @@ -0,0 +1 @@ +../../../pop/pop/POPSpringAnimationInternal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringSolver.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringSolver.h new file mode 120000 index 0000000..6ed1ee6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPSpringSolver.h @@ -0,0 +1 @@ +../../../pop/pop/POPSpringSolver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/POPVector.h b/Unit-2-Journal/Pods/Headers/Private/pop/POPVector.h new file mode 120000 index 0000000..73f01f9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/POPVector.h @@ -0,0 +1 @@ +../../../pop/pop/POPVector.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/TransformationMatrix.h b/Unit-2-Journal/Pods/Headers/Private/pop/TransformationMatrix.h new file mode 120000 index 0000000..f1232b9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/TransformationMatrix.h @@ -0,0 +1 @@ +../../../pop/pop/WebCore/TransformationMatrix.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Private/pop/UnitBezier.h b/Unit-2-Journal/Pods/Headers/Private/pop/UnitBezier.h new file mode 120000 index 0000000..fbd11a0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Private/pop/UnitBezier.h @@ -0,0 +1 @@ +../../../pop/pop/WebCore/UnitBezier.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPClient.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPClient.h new file mode 120000 index 0000000..aee081b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPClient.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPClient.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 0000000..ac762c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h new file mode 120000 index 0000000..c1fccfd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFImageRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h new file mode 120000 index 0000000..9f2188e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFJSONRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..f454e54 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworking.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworking.h new file mode 120000 index 0000000..a5a38da --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h new file mode 120000 index 0000000..4b04bd2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFPropertyListRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 0000000..d9b35fb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h new file mode 120000 index 0000000..9b01587 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFXMLRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 0000000..20b48f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink.h new file mode 120000 index 0000000..3f79bee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLink.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkNavigation.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkNavigation.h new file mode 120000 index 0000000..6962356 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkNavigation.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkNavigation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkResolving.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkResolving.h new file mode 120000 index 0000000..94cc66f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkResolving.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkResolving.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererController.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererController.h new file mode 120000 index 0000000..95067f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererController.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView.h new file mode 120000 index 0000000..cc00897 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView_Internal.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView_Internal.h new file mode 120000 index 0000000..fc68769 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkReturnToRefererView_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkTarget.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkTarget.h new file mode 120000 index 0000000..90a41f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLinkTarget.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLinkTarget.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink_Internal.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink_Internal.h new file mode 120000 index 0000000..dc060b2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFAppLink_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFAppLink_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationToken.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationToken.h new file mode 120000 index 0000000..0b69486 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationToken.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationToken.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenRegistration.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenRegistration.h new file mode 120000 index 0000000..c587ca7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenRegistration.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenRegistration.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenSource.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenSource.h new file mode 120000 index 0000000..d3d5985 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFCancellationTokenSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFDefines.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFDefines.h new file mode 120000 index 0000000..5df18ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFDefines.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFDefines.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFExecutor.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFExecutor.h new file mode 120000 index 0000000..c071e8c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFExecutor.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFExecutor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent.h new file mode 120000 index 0000000..2eb6c11 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFMeasurementEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent_Internal.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent_Internal.h new file mode 120000 index 0000000..98b7d06 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFMeasurementEvent_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFMeasurementEvent_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTask.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTask.h new file mode 120000 index 0000000..5468334 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTask.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTask.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTaskCompletionSource.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTaskCompletionSource.h new file mode 120000 index 0000000..c74760f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFTaskCompletionSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTaskCompletionSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL.h new file mode 120000 index 0000000..df21bd9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFURL.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL_Internal.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL_Internal.h new file mode 120000 index 0000000..3a5c5f4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFURL_Internal.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFURL_Internal.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BFWebViewAppLinkResolver.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFWebViewAppLinkResolver.h new file mode 120000 index 0000000..bf250db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BFWebViewAppLinkResolver.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/iOS/BFWebViewAppLinkResolver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/Bolts.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/Bolts.h new file mode 120000 index 0000000..146ac6e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/Bolts.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/Bolts.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Bolts/BoltsVersion.h b/Unit-2-Journal/Pods/Headers/Public/Bolts/BoltsVersion.h new file mode 120000 index 0000000..0fa0e2d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Bolts/BoltsVersion.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BoltsVersion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAccessToken.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAccessToken.h new file mode 120000 index 0000000..a5b3f97 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAccessToken.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppEvents.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppEvents.h new file mode 120000 index 0000000..95c1d00 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppEvents.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkResolver.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkResolver.h new file mode 120000 index 0000000..69c20f5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkResolver.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkUtility.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkUtility.h new file mode 120000 index 0000000..fef519c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKAppLinkUtility.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKApplicationDelegate.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKApplicationDelegate.h new file mode 120000 index 0000000..e163dc8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKApplicationDelegate.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKButton.h new file mode 120000 index 0000000..806ec62 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKButton.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKConstants.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKConstants.h new file mode 120000 index 0000000..4c08cc8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKConstants.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCopying.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCopying.h new file mode 120000 index 0000000..aa5dc1f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCopying.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCoreKit.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCoreKit.h new file mode 120000 index 0000000..bfffe4f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKCoreKit.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h new file mode 120000 index 0000000..6f019f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequest.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequest.h new file mode 120000 index 0000000..524cb77 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequest.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestConnection.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestConnection.h new file mode 120000 index 0000000..c6cbbfc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestConnection.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h new file mode 120000 index 0000000..9960de2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMacros.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMacros.h new file mode 120000 index 0000000..f9059c1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMacros.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMutableCopying.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMutableCopying.h new file mode 120000 index 0000000..40cf5f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKMutableCopying.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfile.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfile.h new file mode 120000 index 0000000..a9866b1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfile.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfilePictureView.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfilePictureView.h new file mode 120000 index 0000000..6f38799 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKProfilePictureView.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKSettings.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKSettings.h new file mode 120000 index 0000000..7edc38f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKSettings.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKTestUsersManager.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKTestUsersManager.h new file mode 120000 index 0000000..5813f89 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKTestUsersManager.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKUtility.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKUtility.h new file mode 120000 index 0000000..efbfaf1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKCoreKit/FBSDKUtility.h @@ -0,0 +1 @@ +../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h new file mode 120000 index 0000000..2858225 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h new file mode 120000 index 0000000..7a07eea --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h new file mode 120000 index 0000000..fcd06fa --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h new file mode 120000 index 0000000..05205f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h new file mode 120000 index 0000000..fb21852 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h new file mode 120000 index 0000000..ffe74ad --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h new file mode 120000 index 0000000..725e375 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h @@ -0,0 +1 @@ +../../../../FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h new file mode 120000 index 0000000..67d7080 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h new file mode 120000 index 0000000..0e81d04 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h new file mode 120000 index 0000000..32e79a7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h new file mode 120000 index 0000000..61c47da --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h new file mode 120000 index 0000000..16f9d52 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h new file mode 120000 index 0000000..0a8ba29 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h new file mode 120000 index 0000000..3f7906b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h new file mode 120000 index 0000000..1e9ecee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h new file mode 120000 index 0000000..984a2ff --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h new file mode 120000 index 0000000..efe324e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h new file mode 120000 index 0000000..c29f9ee --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h new file mode 120000 index 0000000..7451999 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h new file mode 120000 index 0000000..b827828 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h new file mode 120000 index 0000000..2d4e646 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h new file mode 120000 index 0000000..c981a56 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h new file mode 120000 index 0000000..e7e13b5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h new file mode 120000 index 0000000..56b9ff9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h new file mode 120000 index 0000000..8e28a21 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h new file mode 120000 index 0000000..4c43211 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h new file mode 120000 index 0000000..5d14f07 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h new file mode 120000 index 0000000..8e50e05 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h new file mode 120000 index 0000000..c44ae92 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h new file mode 120000 index 0000000..f8b1179 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h new file mode 120000 index 0000000..30a0dd3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h new file mode 120000 index 0000000..b025b98 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h new file mode 120000 index 0000000..54fbeba --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h new file mode 120000 index 0000000..5fe5d63 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h new file mode 120000 index 0000000..18a9aad --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h new file mode 120000 index 0000000..e649637 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h new file mode 120000 index 0000000..3485485 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h new file mode 120000 index 0000000..c11b781 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h @@ -0,0 +1 @@ +../../../../FBSDKShareKit/FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h new file mode 120000 index 0000000..4300617 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CAAnimation+YALTabBarViewAnimations.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h new file mode 120000 index 0000000..6645404 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/CATransaction+TransactionWithAnimationsAndCompletion.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALAnimatingTabBarConstants.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALAnimatingTabBarConstants.h new file mode 120000 index 0000000..59a4e5b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALAnimatingTabBarConstants.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Constants/YALAnimatingTabBarConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBar.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBar.h new file mode 120000 index 0000000..7c9c72a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBar.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBarController.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBarController.h new file mode 120000 index 0000000..8fb6aca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALFoldingTabBarController.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALSpringAnimation.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALSpringAnimation.h new file mode 120000 index 0000000..3059fd1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALSpringAnimation.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarInteracting.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarInteracting.h new file mode 120000 index 0000000..87b5470 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarInteracting.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarItem.h b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarItem.h new file mode 120000 index 0000000..d2b7d0a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/FoldingTabBar/YALTabBarItem.h @@ -0,0 +1 @@ +../../../FoldingTabBar/FoldingTabBar/Model/TabBarItem/YALTabBarItem.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h b/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h new file mode 120000 index 0000000..932a9db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h b/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h new file mode 120000 index 0000000..79788f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFACL.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFACL.h new file mode 120000 index 0000000..7c3c14f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFACL.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFACL.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnalytics.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnalytics.h new file mode 120000 index 0000000..7751f45 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnalytics.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFAnalytics.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnonymousUtils.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnonymousUtils.h new file mode 120000 index 0000000..7b9b437 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFAnonymousUtils.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFAnonymousUtils.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFCloud.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFCloud.h new file mode 120000 index 0000000..4070bb1 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFCloud.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFCloud.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFConfig.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFConfig.h new file mode 120000 index 0000000..919b834 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFConfig.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFConfig.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFConstants.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFConstants.h new file mode 120000 index 0000000..3b96186 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFConstants.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFConstants.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFFile.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFFile.h new file mode 120000 index 0000000..05ca154 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFFile.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFFile.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFGeoPoint.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFGeoPoint.h new file mode 120000 index 0000000..e9079fe --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFGeoPoint.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFGeoPoint.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFInstallation.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFInstallation.h new file mode 120000 index 0000000..1f2d37a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFInstallation.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFInstallation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..1ae2fdb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFNullability.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFNullability.h new file mode 120000 index 0000000..d3b6c2e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFNullability.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFNullability.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject+Subclass.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject+Subclass.h new file mode 120000 index 0000000..ccbad16 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject+Subclass.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFObject+Subclass.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject.h new file mode 120000 index 0000000..b00d5bb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFObject.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFObject.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFProduct.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFProduct.h new file mode 120000 index 0000000..f4f4940 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFProduct.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFProduct.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFPurchase.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFPurchase.h new file mode 120000 index 0000000..8d7cb4a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFPurchase.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFPurchase.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFPush.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFPush.h new file mode 120000 index 0000000..930cb47 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFPush.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFPush.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFQuery.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFQuery.h new file mode 120000 index 0000000..1ea0442 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFQuery.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFQuery.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFRelation.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFRelation.h new file mode 120000 index 0000000..a3e8444 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFRelation.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFRelation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFRole.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFRole.h new file mode 120000 index 0000000..26cd86c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFRole.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFRole.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFSession.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFSession.h new file mode 120000 index 0000000..4c43360 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFSession.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFSession.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFSubclassing.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFSubclassing.h new file mode 120000 index 0000000..901cadc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFSubclassing.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFSubclassing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFUser.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFUser.h new file mode 120000 index 0000000..01e4199 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFUser.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFUser.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/PFUserAuthenticationDelegate.h b/Unit-2-Journal/Pods/Headers/Public/Parse/PFUserAuthenticationDelegate.h new file mode 120000 index 0000000..3b6b473 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/PFUserAuthenticationDelegate.h @@ -0,0 +1 @@ +../../../Parse/Parse/PFUserAuthenticationDelegate.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Parse/Parse.h b/Unit-2-Journal/Pods/Headers/Public/Parse/Parse.h new file mode 120000 index 0000000..699c11c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Parse/Parse.h @@ -0,0 +1 @@ +../../../Parse/Parse/Parse.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h b/Unit-2-Journal/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h new file mode 120000 index 0000000..7768a97 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h @@ -0,0 +1 @@ +../../../RKValueTransformers/Code/RKValueTransformers.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network.h new file mode 120000 index 0000000..5210a78 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network.h @@ -0,0 +1 @@ +../../../RestKit/Code/Network.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h new file mode 120000 index 0000000..2b63c3c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKHTTPRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h new file mode 120000 index 0000000..c5f5677 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKManagedObjectRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectManager.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectManager.h new file mode 120000 index 0000000..f67267f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectManager.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectManager.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h new file mode 120000 index 0000000..73e232c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectParameterization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h new file mode 120000 index 0000000..e4dbe06 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h new file mode 120000 index 0000000..d0ca904 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperationSubclass.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPaginator.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPaginator.h new file mode 120000 index 0000000..35b421e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPaginator.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPaginator.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h new file mode 120000 index 0000000..73ab1e6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPathMatcher.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h new file mode 120000 index 0000000..7f8e8b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRequestDescriptor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h new file mode 120000 index 0000000..4981d9a --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseDescriptor.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h new file mode 120000 index 0000000..a2e1586 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseMapperOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRoute.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRoute.h new file mode 120000 index 0000000..39eb2cb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRoute.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRoute.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouteSet.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouteSet.h new file mode 120000 index 0000000..a702bdc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouteSet.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouteSet.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouter.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouter.h new file mode 120000 index 0000000..7187f17 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Network/RKRouter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping.h new file mode 120000 index 0000000..9ca1b53 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping.h @@ -0,0 +1 @@ +../../../RestKit/Code/ObjectMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h new file mode 120000 index 0000000..b196d35 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKAttributeMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h new file mode 120000 index 0000000..67a1caf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKDynamicMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h new file mode 120000 index 0000000..6d6996d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKErrorMessage.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h new file mode 120000 index 0000000..318d5c2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKHTTPUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h new file mode 120000 index 0000000..59e87e2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h new file mode 120000 index 0000000..bd32976 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation_Private.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h new file mode 120000 index 0000000..6aaec37 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h new file mode 120000 index 0000000..68e3925 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingErrors.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h new file mode 120000 index 0000000..6b4d1bf --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h new file mode 120000 index 0000000..d463834 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h new file mode 120000 index 0000000..03618d2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingResult.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h new file mode 120000 index 0000000..d38ebca --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h new file mode 120000 index 0000000..2664bd7 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 120000 index 0000000..cdac049 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h new file mode 120000 index 0000000..1ee01f3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h new file mode 120000 index 0000000..a3e2a9d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyInspector.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h new file mode 120000 index 0000000..db4bc5c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h new file mode 120000 index 0000000..32b9847 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKRelationshipMapping.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/RestKit.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/RestKit.h new file mode 120000 index 0000000..49e183c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/RestKit.h @@ -0,0 +1 @@ +../../../RestKit/Code/RestKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support.h new file mode 120000 index 0000000..06fa6db --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support.h @@ -0,0 +1 @@ +../../../RestKit/Code/Support.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h new file mode 120000 index 0000000..f4e0175 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDictionaryUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h new file mode 120000 index 0000000..44ee028 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDotNetDateFormatter.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKErrors.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKErrors.h new file mode 120000 index 0000000..7319216 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKErrors.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLog.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLog.h new file mode 120000 index 0000000..6a428cb --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLog.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLog.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h new file mode 120000 index 0000000..b8d134c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLumberjackLogger.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h new file mode 120000 index 0000000..b77b8b3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypeSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h new file mode 120000 index 0000000..71b36c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypes.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMacros.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMacros.h new file mode 120000 index 0000000..f1d842d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKMacros.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMacros.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h new file mode 120000 index 0000000..537580d --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKNSJSONSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h new file mode 120000 index 0000000..1391329 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKOperationStateMachine.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h new file mode 120000 index 0000000..2ef3a20 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKPathUtilities.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKSerialization.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKSerialization.h new file mode 120000 index 0000000..b66ce92 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h new file mode 120000 index 0000000..6535c08 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKStringTokenizer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h new file mode 120000 index 0000000..ea62327 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKURLEncodedSerialization.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h new file mode 120000 index 0000000..7902c5b --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_components_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h new file mode 120000 index 0000000..eff8ca5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_extensions_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h new file mode 120000 index 0000000..39088b8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_logger_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing.h new file mode 120000 index 0000000..1404cdc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing.h @@ -0,0 +1 @@ +../../../RestKit/Code/Testing.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKBenchmark.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKBenchmark.h new file mode 120000 index 0000000..e5a9bfd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKBenchmark.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKBenchmark.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKConnectionTestExpectation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKConnectionTestExpectation.h new file mode 120000 index 0000000..6a690f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKConnectionTestExpectation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKConnectionTestExpectation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKMappingTest.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKMappingTest.h new file mode 120000 index 0000000..8bdd3be --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKMappingTest.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKMappingTest.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKPropertyMappingTestExpectation.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKPropertyMappingTestExpectation.h new file mode 120000 index 0000000..13cdab9 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKPropertyMappingTestExpectation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKPropertyMappingTestExpectation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFactory.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFactory.h new file mode 120000 index 0000000..145b1f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFactory.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestFactory.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFixture.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFixture.h new file mode 120000 index 0000000..26226cd --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestFixture.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestFixture.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestHelpers.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestHelpers.h new file mode 120000 index 0000000..44a0b44 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestHelpers.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestHelpers.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestNotificationObserver.h b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestNotificationObserver.h new file mode 120000 index 0000000..d8ed687 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/RestKit/Testing/RKTestNotificationObserver.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Testing/RKTestNotificationObserver.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/SOCKit/SOCKit.h b/Unit-2-Journal/Pods/Headers/Public/SOCKit/SOCKit.h new file mode 120000 index 0000000..72c5afc --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/SOCKit/SOCKit.h @@ -0,0 +1 @@ +../../../SOCKit/SOCKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKEvent.h b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKEvent.h new file mode 120000 index 0000000..e0febb8 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKEvent.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKState.h b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKState.h new file mode 120000 index 0000000..6dbd8d3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKState.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKState.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKStateMachine.h b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKStateMachine.h new file mode 120000 index 0000000..cfbbd7f --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKStateMachine.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKStateMachine.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKTransition.h b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKTransition.h new file mode 120000 index 0000000..d83dc2c --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TKTransition.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKTransition.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TransitionKit.h b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TransitionKit.h new file mode 120000 index 0000000..d5b6768 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/TransitionKit/TransitionKit.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TransitionKit.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h b/Unit-2-Journal/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 120000 index 0000000..d94e2d3 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1 @@ +../../../../../RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POP.h b/Unit-2-Journal/Pods/Headers/Public/pop/POP.h new file mode 120000 index 0000000..dd15660 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POP.h @@ -0,0 +1 @@ +../../../pop/pop/POP.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimatableProperty.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimatableProperty.h new file mode 120000 index 0000000..48fd8c4 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimatableProperty.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimatableProperty.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimation.h new file mode 120000 index 0000000..dfe8a85 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationEvent.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationEvent.h new file mode 120000 index 0000000..5d40492 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationEvent.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationEvent.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationExtras.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationExtras.h new file mode 120000 index 0000000..3a1bc7e --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationExtras.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationExtras.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationTracer.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationTracer.h new file mode 120000 index 0000000..64fff66 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimationTracer.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimationTracer.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimator.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimator.h new file mode 120000 index 0000000..89707ea --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPAnimator.h @@ -0,0 +1 @@ +../../../pop/pop/POPAnimator.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPBasicAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPBasicAnimation.h new file mode 120000 index 0000000..50184f2 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPBasicAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPBasicAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPCustomAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPCustomAnimation.h new file mode 120000 index 0000000..5025bd6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPCustomAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPCustomAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPDecayAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPDecayAnimation.h new file mode 120000 index 0000000..dba2796 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPDecayAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPDecayAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPDefines.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPDefines.h new file mode 120000 index 0000000..4b10036 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPDefines.h @@ -0,0 +1 @@ +../../../pop/pop/POPDefines.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPGeometry.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPGeometry.h new file mode 120000 index 0000000..9b29189 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPGeometry.h @@ -0,0 +1 @@ +../../../pop/pop/POPGeometry.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPLayerExtras.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPLayerExtras.h new file mode 120000 index 0000000..e11f4c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPLayerExtras.h @@ -0,0 +1 @@ +../../../pop/pop/POPLayerExtras.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPPropertyAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPPropertyAnimation.h new file mode 120000 index 0000000..0fae4c5 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPPropertyAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPPropertyAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Headers/Public/pop/POPSpringAnimation.h b/Unit-2-Journal/Pods/Headers/Public/pop/POPSpringAnimation.h new file mode 120000 index 0000000..152f663 --- /dev/null +++ b/Unit-2-Journal/Pods/Headers/Public/pop/POPSpringAnimation.h @@ -0,0 +1 @@ +../../../pop/pop/POPSpringAnimation.h \ No newline at end of file diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h new file mode 100644 index 0000000..7a758e4 --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1,34 @@ +// +// ISO8601DateFormatterValueTransformer.h +// RestKit +// +// Created by Blake Watters on 9/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKValueTransformers.h" +#import "RKISO8601DateFormatter.h" + +/** + The `RKValueTransformers` category extends ISO8601DateFormatter to support the `RKValueTransforming` interface, making it usable with the RestKit value transformation architecture. + */ +@interface RKISO8601DateFormatter (RKValueTransformers) + +/** + Returns an ISO 8601 date formatter configured to strictly parse times into `NSDate` instances with the UTC time zone and `en_US_POSIX` locale. + */ ++ (instancetype)defaultISO8601DateFormatter; + +@end diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m new file mode 100644 index 0000000..fd42686 --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m @@ -0,0 +1,55 @@ +// +// ISO8601DateFormatterValueTransformer.m +// RestKit +// +// Created by Blake Watters on 9/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "ISO8601DateFormatterValueTransformer.h" + +@implementation RKISO8601DateFormatter (RKValueTransformers) + ++ (instancetype)defaultISO8601DateFormatter +{ + RKISO8601DateFormatter *iso8601DateFormatter = [RKISO8601DateFormatter new]; + iso8601DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + iso8601DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + iso8601DateFormatter.includeTime = YES; + iso8601DateFormatter.parsesStrictly = YES; + return iso8601DateFormatter; +} + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSDate class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSDate class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSDate class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSDate class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSDate class]]) { + *outputValue = [self stringFromDate:inputValue]; + } + return YES; +} + +@end diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h new file mode 100644 index 0000000..f4cc12a --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h @@ -0,0 +1,93 @@ +// This is a forked copy of the ISO8601DateFormatter + +/*ISO8601DateFormatter.h + * + *Created by Peter Hosey on 2009-04-11. + *Copyright 2009 Peter Hosey. All rights reserved. + */ + +#import + +/*This class converts dates to and from ISO 8601 strings. A good introduction to ISO 8601: + * + *Parsing can be done strictly, or not. When you parse loosely, leading whitespace is ignored, as is anything after the date. + *The loose parser will return an NSDate for this string: @" \t\r\n\f\t 2006-03-02!!!" + *Leading non-whitespace will not be ignored; the string will be rejected, and nil returned. See the README that came with this addition. + * + *The strict parser will only accept a string if the date is the entire string. The above string would be rejected immediately, solely on these grounds. + *Also, the loose parser provides some extensions that the strict parser doesn't. + *For example, the standard says for "-DDD" (an ordinal date in the implied year) that the logical representation (meaning, hierarchically) would be "--DDD", but because that extra hyphen is "superfluous", it was omitted. + *The loose parser will accept the extra hyphen; the strict parser will not. + *A full list of these extensions is in the README file. + */ + +/*The format to either expect or produce. + *Calendar format is YYYY-MM-DD. + *Ordinal format is YYYY-DDD, where DDD ranges from 1 to 366; for example, 2009-32 is 2009-02-01. + *Week format is YYYY-Www-D, where ww ranges from 1 to 53 (the 'W' is literal) and D ranges from 1 to 7; for example, 2009-W05-07. + */ +enum { + RKISO8601DateFormatCalendar, + RKISO8601DateFormatOrdinal, + RKISO8601DateFormatWeek, +}; +typedef NSUInteger RKISO8601DateFormat; + +@interface RKISO8601DateFormatter: NSFormatter + +/** + The time zone for tge formatter. + + **Default:** `[NSTimeZone defaultTimeZone]` + */ +@property (nonatomic, strong) NSTimeZone *timeZone; + +/** + The locale for the formatter. + + **Default:** `[NSLocale currentLocale]` + */ +@property (nonatomic, strong) NSLocale *locale; + +#pragma mark Parsing + +/** + A Boolean value that determines if the receiver parses strictly. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL parsesStrictly; + +- (NSDateComponents *)dateComponentsFromString:(NSString *)string; +- (NSDate *)dateFromString:(NSString *)string; + +#pragma mark Unparsing + +/** + **Default**: `RKISO8601DateFormatCalendar` + */ +@property (nonatomic, assign) RKISO8601DateFormat format; + +/** + A Boolean value that specifies if time should be included in the formatted strings. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL includeTime; + +/** + The separator character to use between time components. + + **Default**: `':'` + */ +@property (nonatomic, assign) unichar timeSeparator; + +/** + Returns an ISO-8601 string representation of the given date. + + @param date The date to be formatted into a string. + @return An ISO-8601 formatted string representation of the date. + */ +- (NSString *)stringFromDate:(NSDate *)date; + +@end diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m new file mode 100644 index 0000000..2079593 --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m @@ -0,0 +1,912 @@ +// This is a forked copy of the ISO8601DateFormatter + +/*ISO8601DateFormatter.m + * + *Created by Peter Hosey on 2009-04-11. + *Copyright 2009 Peter Hosey. All rights reserved. + */ + +#import +#import "RKISO8601DateFormatter.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitSupport + +unichar RKISO8601DefaultTimeSeparatorCharacter = ':'; + +// Unicode date formats. +#define RK_ISOCALENDAR_DATE_FORMAT @"yyyy-MM-dd" +#define RK_ISOORDINAL_DATE_FORMAT @"yyyy-DDD" +#define RK_ISOTIME_FORMAT @"HH:mm:ss" +#define RK_ISOTIME_WITH_TIMEZONE_FORMAT RK_ISOTIME_FORMAT @"Z" + +// printf formats. +#define RK_ISOTIMEZONE_UTC_FORMAT @"Z" +#define RK_ISOTIMEZONE_OFFSET_FORMAT @"%+.2ld%.2ld" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \ + (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)) +#define NSCalendarUnitYear NSYearCalendarUnit +#define NSCalendarUnitMonth NSMonthCalendarUnit +#define NSCalendarUnitDay NSDayCalendarUnit +#define NSCalendarUnitWeekday NSWeekdayCalendarUnit +#define NSCalendarIdentifierGregorian NSGregorianCalendar +#endif + +#define RK_CALENDAR_UNIT_YEAR NSCalendarUnitYear +#define RK_CALENDAR_UNIT_MONTH NSCalendarUnitMonth +#define RK_CALENDAR_UNIT_DAY NSCalendarUnitDay +#define RK_CALENDAR_UNIT_WEEKDAY NSCalendarUnitWeekday +#define RK_CALENDAR_IDENTIFIER_GREGORIAN NSCalendarIdentifierGregorian + +// Parsing Helpers +static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); +static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); +static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next); +static double read_double(const unsigned char *str, const unsigned char **next); +static BOOL is_leap_year(NSUInteger year); + +@interface RKISO8601DateFormatter(UnparsingPrivate) + +- (NSString *)replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep; +- (NSString *)stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone; +- (NSString *)weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; + +@end + +static NSMutableDictionary *timeZonesByOffset; + +@interface RKISO8601DateFormatter () +@property (nonatomic, strong) NSCalendar *parsingCalendar; +@property (nonatomic, strong) NSCalendar *unparsingCalendar; +@property (nonatomic, strong) NSDateFormatter *unparsingFormatter; +@property (nonatomic, copy) NSString *lastUsedFormatString; +@end + +@implementation RKISO8601DateFormatter + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + timeZonesByOffset = [[NSMutableDictionary alloc] init]; + }); +} + +- (id)init +{ + self = [super init]; + if (self) { + self.timeZone = [NSTimeZone defaultTimeZone]; + self.locale = [NSLocale currentLocale]; + + self.parsingCalendar = [self newCalendar]; + self.unparsingCalendar = [self newCalendar]; + + self.format = RKISO8601DateFormatCalendar; + self.timeSeparator = RKISO8601DefaultTimeSeparatorCharacter; + self.includeTime = NO; + self.parsesStrictly = NO; + } + return self; +} + +- (NSCalendar *)newCalendar +{ + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:RK_CALENDAR_IDENTIFIER_GREGORIAN]; + calendar.firstWeekday = 2; //Monday + calendar.timeZone = self.timeZone; + calendar.locale = self.locale; + return calendar; +} + +- (void)setTimeZone:(NSTimeZone *)timeZone +{ + if (_timeZone != timeZone) { + _timeZone = timeZone; + _unparsingCalendar.timeZone = timeZone; + _unparsingFormatter.timeZone = timeZone; + } +} + +- (void)setLocale:(NSLocale *)locale +{ + if (_locale != locale) { + _locale = locale; + _unparsingCalendar.locale = locale; + _unparsingFormatter.locale = locale; + } +} + +#pragma mark Parsing + +/*Valid ISO 8601 date formats: + * + *YYYYMMDD + *YYYY-MM-DD + *YYYY-MM + *YYYY + *YY //century + * //Implied century: YY is 00-99 + * YYMMDD + * YY-MM-DD + * -YYMM + * -YY-MM + * -YY + * //Implied year + * --MMDD + * --MM-DD + * --MM + * //Implied year and month + * ---DD + * //Ordinal dates: DDD is the number of the day in the year (1-366) + *YYYYDDD + *YYYY-DDD + * YYDDD + * YY-DDD + * -DDD + * //Week-based dates: ww is the number of the week, and d is the number (1-7) of the day in the week + *yyyyWwwd + *yyyy-Www-d + *yyyyWww + *yyyy-Www + *yyWwwd + *yy-Www-d + *yyWww + *yy-Www + * //Year of the implied decade + *-yWwwd + *-y-Www-d + *-yWww + *-y-Www + * //Week and day of implied year + * -Wwwd + * -Www-d + * //Week only of implied year + * -Www + * //Day only of implied week + * -W-d + */ + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string +{ + return [self dateComponentsFromString:string timeZone:NULL]; +} + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone +{ + return [self dateComponentsFromString:string timeZone:outTimeZone range:NULL]; +} + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange +{ + // We don't support ISO-8601 intervals so bail if the string contains a slash delimiter + if ([string rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]].location != NSNotFound) return nil; + + NSDate *now = [NSDate date]; + + NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *nowComponents = [self.parsingCalendar components:(RK_CALENDAR_UNIT_YEAR | RK_CALENDAR_UNIT_MONTH | RK_CALENDAR_UNIT_DAY) fromDate:now]; + + NSUInteger + //Date + year, + month_or_week = 0U, + day = 0U, + //Time + hour = 0U; + NSTimeInterval + minute = 0.0, + second = 0.0; + //Time zone + NSInteger tz_hour = 0; + NSInteger tz_minute = 0; + + enum { + monthAndDate, + week, + dateOnly + } dateSpecification = monthAndDate; + + BOOL strict = self.parsesStrictly; + unichar timeSep = self.timeSeparator; + + if (strict) timeSep = RKISO8601DefaultTimeSeparatorCharacter; + NSAssert(timeSep != '\0', @"Time separator must not be NUL."); + + BOOL isValidDate = ([string length] > 0U); + NSTimeZone *timeZone = nil; + + const unsigned char *ch = (const unsigned char *)[string UTF8String]; + + NSRange range = { 0U, 0U }; + const unsigned char *start_of_date = NULL; + if (strict && isspace(*ch)) { + range.location = NSNotFound; + isValidDate = NO; + } else { + //Skip leading whitespace. + NSUInteger i = 0U; + for(NSUInteger len = strlen((const char *)ch); i < len; ++i) { + if (!isspace(ch[i])) + break; + } + + range.location = i; + ch += i; + start_of_date = ch; + + NSUInteger segment; + NSUInteger num_leading_hyphens = 0U, num_digits = 0U; + + if (*ch == 'T') { + //There is no date here, only a time. Set the date to now; then we'll parse the time. + isValidDate = isdigit(*++ch); + + year = nowComponents.year; + month_or_week = nowComponents.month; + day = nowComponents.day; + } else { + while(*ch == '-') { + ++num_leading_hyphens; + ++ch; + } + + segment = read_segment(ch, &ch, &num_digits); + switch(num_digits) { + case 0: + if (*ch == 'W') { + if ((ch[1] == '-') && isdigit(ch[2]) && ((num_leading_hyphens == 1U) || ((num_leading_hyphens == 2U) && !strict))) { + year = nowComponents.year; + month_or_week = 1U; + ch += 2; + goto parseDayAfterWeek; + } else if (num_leading_hyphens == 1U) { + year = nowComponents.year; + goto parseWeekAndDay; + } else + isValidDate = NO; + } else + isValidDate = NO; + break; + + case 8: //YYYY MM DD + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 100U; + segment /= 100U; + month_or_week = segment % 100U; + year = segment / 100U; + } + break; + + case 6: //YYMMDD (implicit century) + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 100U; + segment /= 100U; + month_or_week = segment % 100U; + year = nowComponents.year; + year -= (year % 100U); + year += segment / 100U; + } + break; + + case 4: + switch(num_leading_hyphens) { + case 0: //YYYY + year = segment; + + if (*ch == '-') ++ch; + + if (!isdigit(*ch)) { + if (*ch == 'W') + goto parseWeekAndDay; + else + month_or_week = day = 1U; + } else { + segment = read_segment(ch, &ch, &num_digits); + switch(num_digits) { + case 4: //MMDD + day = segment % 100U; + month_or_week = segment / 100U; + break; + + case 2: //MM + month_or_week = segment; + + if (*ch == '-') ++ch; + if (!isdigit(*ch)) + day = 1U; + else + day = read_segment(ch, &ch, NULL); + break; + + case 3: //DDD + day = segment % 1000U; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + break; + + default: + isValidDate = NO; + } + } + break; + + case 1: //YYMM + month_or_week = segment % 100U; + year = segment / 100U; + + if (*ch == '-') ++ch; + if (!isdigit(*ch)) + day = 1U; + else + day = read_segment(ch, &ch, NULL); + + break; + + case 2: //MMDD + day = segment % 100U; + month_or_week = segment / 100U; + year = nowComponents.year; + + break; + + default: + isValidDate = NO; + } //switch(num_leading_hyphens) (4 digits) + break; + + case 1: + if (strict) { + //Two digits only - never just one. + if (num_leading_hyphens == 1U) { + if (*ch == '-') ++ch; + if (*++ch == 'W') { + year = nowComponents.year; + year -= (year % 10U); + year += segment; + goto parseWeekAndDay; + } else + isValidDate = NO; + } else + isValidDate = NO; + break; + } + case 2: + switch(num_leading_hyphens) { + case 0: + if (*ch == '-') { + //Implicit century + year = nowComponents.year; + year -= (year % 100U); + year += segment; + + if (*++ch == 'W') + goto parseWeekAndDay; + else if (!isdigit(*ch)) { + goto centuryOnly; + } else { + //Get month and/or date. + segment = read_segment_4digits(ch, &ch, &num_digits); + switch(num_digits) { + case 4: //YY-MMDD + day = segment % 100U; + month_or_week = segment / 100U; + break; + + case 1: //YY-M; YY-M-DD (extension) + if (strict) { + isValidDate = NO; + break; + } + case 2: //YY-MM; YY-MM-DD + month_or_week = segment; + if (*ch == '-') { + if (isdigit(*++ch)) + day = read_segment_2digits(ch, &ch); + else + day = 1U; + } else + day = 1U; + break; + + case 3: //Ordinal date. + day = segment; + dateSpecification = dateOnly; + break; + } + } + } else if (*ch == 'W') { + year = nowComponents.year; + year -= (year % 100U); + year += segment; + + parseWeekAndDay: //*ch should be 'W' here. + if (!isdigit(*++ch)) { + //Not really a week-based date; just a year followed by '-W'. + if (strict) + isValidDate = NO; + else + month_or_week = day = 1U; + } else { + month_or_week = read_segment_2digits(ch, &ch); + if (*ch == '-') ++ch; + parseDayAfterWeek: + day = isdigit(*ch) ? read_segment_2digits(ch, &ch) : 1U; + dateSpecification = week; + } + } else { + //Century only. Assume current year. + centuryOnly: + year = segment * 100U + nowComponents.year % 100U; + month_or_week = day = 1U; + } + break; + + case 1:; //-YY; -YY-MM (implicit century) + NSUInteger current_year = nowComponents.year; + NSUInteger current_century = (current_year % 100U); + year = segment + (current_year - current_century); + if (num_digits == 1U) //implied decade + year += current_century - (current_year % 10U); + + if (*ch == '-') { + ++ch; + month_or_week = read_segment_2digits(ch, &ch); + } + + day = 1U; + break; + + case 2: //--MM; --MM-DD + year = nowComponents.year; + month_or_week = segment; + if (*ch == '-') { + ++ch; + day = read_segment_2digits(ch, &ch); + } + break; + + case 3: //---DD + year = nowComponents.year; + month_or_week = nowComponents.month; + day = segment; + break; + + default: + isValidDate = NO; + } //switch(num_leading_hyphens) (2 digits) + break; + + case 7: //YYYY DDD (ordinal date) + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 1000U; + year = segment / 1000U; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + } + break; + + case 3: //--DDD (ordinal date, implicit year) + //Technically, the standard only allows one hyphen. But it says that two hyphens is the logical implementation, and one was dropped for brevity. So I have chosen to allow the missing hyphen. + if ((num_leading_hyphens < 1U) || ((num_leading_hyphens > 2U) && !strict)) + isValidDate = NO; + else { + day = segment; + year = nowComponents.year; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + } + break; + + default: + isValidDate = NO; + } + } + + if (isValidDate) { + if (isspace(*ch) || (*ch == 'T')) ++ch; + + if (isdigit(*ch)) { + hour = read_segment_2digits(ch, &ch); + if (*ch == timeSep) { + ++ch; + if ((timeSep == ',') || (timeSep == '.')) { + //We can't do fractional minutes when '.' is the segment separator. + //Only allow whole minutes and whole seconds. + minute = read_segment_2digits(ch, &ch); + if (*ch == timeSep) { + ++ch; + second = read_segment_2digits(ch, &ch); + } + } else { + //Allow a fractional minute. + //If we don't get a fraction, look for a seconds segment. + //Otherwise, the fraction of a minute is the seconds. + minute = read_double(ch, &ch); + second = modf(minute, &minute); + if (second > DBL_EPSILON) + second *= 60.0; //Convert fraction (e.g. .5) into seconds (e.g. 30). + else if (*ch == timeSep) { + ++ch; + second = read_double(ch, &ch); + } + } + } + + if (!strict) { + if (isspace(*ch)) ++ch; + } + + switch(*ch) { + case 'Z': + timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + break; + + case '+': + case '-':; + BOOL negative = (*ch == '-'); + if (isdigit(*++ch)) { + //Read hour offset. + segment = *ch - '0'; + if (isdigit(*++ch)) { + segment *= 10U; + segment += *(ch++) - '0'; + } + tz_hour = (NSInteger)segment; + if (negative) tz_hour = -tz_hour; + + //Optional separator. + if (*ch == timeSep) ++ch; + + if (isdigit(*ch)) { + //Read minute offset. + segment = *ch - '0'; + if (isdigit(*++ch)) { + segment *= 10U; + segment += *ch - '0'; + } + tz_minute = segment; + if (negative) tz_minute = -tz_minute; + } + + NSTimeInterval timeZoneOffset = (tz_hour * 3600) + (tz_minute * 60); + NSNumber *offsetNum = [NSNumber numberWithDouble:timeZoneOffset]; + timeZone = [timeZonesByOffset objectForKey:offsetNum]; + if (!timeZone) { + timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timeZoneOffset]; + if (timeZone) + [timeZonesByOffset setObject:timeZone forKey:offsetNum]; + } + } + } + } + } + + if (isValidDate) { + components.year = year; + components.day = day; + components.hour = hour; + components.minute = (NSInteger)minute; + components.second = (NSInteger)second; + + switch(dateSpecification) { + case monthAndDate: + components.month = month_or_week; + break; + + case week:; + //Adapted from . + //This works by converting the week date into an ordinal date, then letting the next case handle it. + NSUInteger prevYear = year - 1U; + NSUInteger YY = prevYear % 100U; + NSUInteger C = prevYear - YY; + NSUInteger G = YY + YY / 4U; + NSUInteger isLeapYear = (((C / 100U) % 4U) * 5U); + NSUInteger Jan1Weekday = (isLeapYear + G) % 7U; + enum { monday, tuesday, wednesday, thursday/*, friday, saturday, sunday*/ }; + components.day = ((8U - Jan1Weekday) + (7U * (Jan1Weekday > thursday))) + (day - 1U) + (7U * (month_or_week - 2)); + + case dateOnly: //An "ordinal date". + break; + } + } + } //if (!(strict && isdigit(ch[0]))) + + if (outRange) { + if (isValidDate) + range.length = ch - start_of_date; + else + range.location = NSNotFound; + + *outRange = range; + } + if (outTimeZone) { + *outTimeZone = timeZone; + } + + return isValidDate ? components : nil; +} + +- (NSDate *)dateFromString:(NSString *)string +{ + return [self dateFromString:string timeZone:NULL]; +} + +- (NSDate *)dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone +{ + return [self dateFromString:string timeZone:outTimeZone range:NULL]; +} + +- (NSDate *)dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange { + NSTimeZone *timeZone = nil; + NSDateComponents *components = [self dateComponentsFromString:string timeZone:&timeZone range:outRange]; + if (! components) return nil; + if (outTimeZone) + *outTimeZone = timeZone; + self.parsingCalendar.timeZone = timeZone ?: self.timeZone; + return [self.parsingCalendar dateFromComponents:components]; +} + +- (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error +{ + NSDate *date = [self dateFromString:string]; + if (outValue) + *outValue = date; + return (date != nil); +} + +#pragma mark Unparsing + +- (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep +{ + if (timeSep != ':') { + NSMutableString *timeFormatMutable = [timeFormat mutableCopy]; + [timeFormatMutable replaceOccurrencesOfString:@":" + withString:[NSString stringWithCharacters:&timeSep length:1U] + options:NSBackwardsSearch | NSLiteralSearch + range:(NSRange){ 0UL, [timeFormat length] }]; + timeFormat = timeFormatMutable; + } + return timeFormat; +} + +- (NSString *)stringFromDate:(NSDate *)date +{ + switch (self.format) { + case RKISO8601DateFormatCalendar: + return [self stringFromDate:date formatString:RK_ISOCALENDAR_DATE_FORMAT]; + case RKISO8601DateFormatWeek: + return [self weekDateStringForDate:date timeZone:self.timeZone]; + case RKISO8601DateFormatOrdinal: + return [self stringFromDate:date formatString:RK_ISOORDINAL_DATE_FORMAT]; + default: + [NSException raise:NSInternalInconsistencyException format:@"self.format was %ld, not calendar (%d), week (%d), or ordinal (%d)", (unsigned long) self.format, RKISO8601DateFormatCalendar, RKISO8601DateFormatWeek, RKISO8601DateFormatOrdinal]; + return nil; + } +} + +- (NSString *)stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat +{ + if (self.includeTime) dateFormat = [dateFormat stringByAppendingFormat:@"'T'%@", [self replaceColonsInString:RK_ISOTIME_FORMAT withTimeSeparator:self.timeSeparator]]; + + if (! [dateFormat isEqualToString:self.lastUsedFormatString]) { + self.unparsingFormatter = nil; + self.lastUsedFormatString = dateFormat; + } + + if (!self.unparsingFormatter) { + self.unparsingFormatter = [[NSDateFormatter alloc] init]; + self.unparsingFormatter.formatterBehavior = NSDateFormatterBehavior10_4; + self.unparsingFormatter.dateFormat = dateFormat; + self.unparsingFormatter.calendar = self.unparsingCalendar; + self.unparsingFormatter.timeZone = self.timeZone; + self.unparsingFormatter.locale = self.locale; + } + + NSString *str = [self.unparsingFormatter stringForObjectValue:date]; + if (self.includeTime) { + NSInteger offset = [self.timeZone secondsFromGMT]; + offset /= 60; //bring down to minutes + if (offset == 0) + str = [str stringByAppendingString:RK_ISOTIMEZONE_UTC_FORMAT]; + else + str = [str stringByAppendingFormat:RK_ISOTIMEZONE_OFFSET_FORMAT, (long) (offset / 60), (long) (offset % 60)]; + } + + return str; +} + +- (NSString *)stringForObjectValue:(id)value +{ + NSParameterAssert([value isKindOfClass:[NSDate class]]); + return [self stringFromDate:(NSDate *)value]; +} + +/*Adapted from: + * Algorithm for Converting Gregorian Dates to ISO 8601 Week Date + * Rick McCarty, 1999 + * http://personal.ecu.edu/mccartyr/ISOwdALG.txt + */ +- (NSString *)weekDateStringForDate:(NSDate *)date +{ + self.unparsingCalendar.timeZone = self.timeZone; + self.unparsingCalendar.locale = self.locale; + NSDateComponents *components = [self.unparsingCalendar components:RK_CALENDAR_UNIT_YEAR | RK_CALENDAR_UNIT_WEEKDAY | RK_CALENDAR_UNIT_DAY fromDate:date]; + + //Determine the ordinal date. + NSDateComponents *startOfYearComponents = [self.unparsingCalendar components:RK_CALENDAR_UNIT_YEAR fromDate:date]; + startOfYearComponents.month = 1; + startOfYearComponents.day = 1; + NSDateComponents *ordinalComponents = [self.unparsingCalendar components:RK_CALENDAR_UNIT_DAY fromDate:[self.unparsingCalendar dateFromComponents:startOfYearComponents] toDate:date options:0]; + ordinalComponents.day += 1; + + enum { + monday, tuesday, wednesday, thursday, friday, saturday, sunday + }; + enum { + january = 1, february, march, + april, may, june, + july, august, september, + october, november, december + }; + + NSInteger year = components.year; + NSInteger week = 0; + //The old unparser added 6 to [calendarDate dayOfWeek], which was zero-based; components.weekday is one-based, so we now add only 5. + NSInteger dayOfWeek = (components.weekday + 5) % 7; + NSInteger dayOfYear = ordinalComponents.day; + + NSInteger prevYear = year - 1; + + BOOL yearIsLeapYear = is_leap_year(year); + BOOL prevYearIsLeapYear = is_leap_year(prevYear); + + NSInteger YY = prevYear % 100; + NSInteger C = prevYear - YY; + NSInteger G = YY + YY / 4; + NSInteger Jan1Weekday = (((((C / 100) % 4) * 5) + G) % 7); + + NSInteger weekday = ((dayOfYear + Jan1Weekday) - 1) % 7; + + if ((dayOfYear <= (7 - Jan1Weekday)) && (Jan1Weekday > thursday)) { + week = 52 + ((Jan1Weekday == friday) || ((Jan1Weekday == saturday) && prevYearIsLeapYear)); + --year; + } else { + NSInteger lengthOfYear = 365 + yearIsLeapYear; + if ((lengthOfYear - dayOfYear) < (thursday - weekday)) { + ++year; + week = 1; + } else { + NSInteger J = dayOfYear + (sunday - weekday) + Jan1Weekday; + week = J / 7 - (Jan1Weekday > thursday); + } + } + + NSString *timeString; + if (self.includeTime) { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + unichar timeSep = self.timeSeparator; + if (!timeSep) timeSep = RKISO8601DefaultTimeSeparatorCharacter; + formatter.dateFormat = [self replaceColonsInString:RK_ISOTIME_WITH_TIMEZONE_FORMAT withTimeSeparator:timeSep]; + + timeString = [formatter stringForObjectValue:date]; + } else + timeString = @""; + + return [NSString stringWithFormat:@"%lu-W%02lu-%02lu%@", (unsigned long)year, (unsigned long)week, ((unsigned long)dayOfWeek) + 1U, timeString]; +} + +@end + +static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { + NSUInteger num_digits = 0U; + NSUInteger value = 0U; + + while(isdigit(*str)) { + value *= 10U; + value += *str - '0'; + ++num_digits; + ++str; + } + + if (next) *next = str; + if (out_num_digits) *out_num_digits = num_digits; + + return value; +} +static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { + NSUInteger num_digits = 0U; + NSUInteger value = 0U; + + if (isdigit(*str)) { + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (next) *next = str; + if (out_num_digits) *out_num_digits = num_digits; + + return value; +} +static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next) { + NSUInteger value = 0U; + + if (isdigit(*str)) + value += *str - '0'; + + if (isdigit(*++str)) { + value *= 10U; + value += *(str++) - '0'; + } + + if (next) *next = str; + + return value; +} + +//strtod doesn't support ',' as a separator. This does. +static double read_double(const unsigned char *str, const unsigned char **next) { + double value = 0.0; + + if (str) { + NSUInteger int_value = 0; + + while(isdigit(*str)) { + int_value *= 10U; + int_value += (*(str++) - '0'); + } + value = int_value; + + if (((*str == ',') || (*str == '.'))) { + ++str; + + register double multiplier, multiplier_multiplier; + multiplier = multiplier_multiplier = 0.1; + + while(isdigit(*str)) { + value += (*(str++) - '0') * multiplier; + multiplier *= multiplier_multiplier; + } + } + } + + if (next) *next = str; + + return value; +} + +static BOOL is_leap_year(NSUInteger year) { + return \ + ((year % 4U) == 0U) + && (((year % 100U) != 0U) + || ((year % 400U) == 0U)); +} diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/LICENSE b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/README.md b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/README.md new file mode 100644 index 0000000..c08cf6d --- /dev/null +++ b/Unit-2-Journal/Pods/ISO8601DateFormatterValueTransformer/README.md @@ -0,0 +1,51 @@ +ISO8601DateFormatterValueTransformer +==================================== + +A small Objective-C library that integrates Peter Hosey's [ISO8601DateFormatter](https://github.com/boredzo/iso-8601-date-formatter) +with [RKValueTransformers](https://github.com/RestKit/RKValueTransformers). + +The implementation is done by adding `RKValueTransforming` conformance to the `ISO8601DateFormatter` via a category. + +## Examples + +### Usage + +Basic usage is identical to all other `RKValueTransforming` classes. + +```objc +#import "ISO8601DateValueTransformer.h" + +RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; + +// Transforming NSDate -> String +NSString *dateString = nil; +NSError *error = nil; +BOOL success = [dateFormatter transformValue:[NSDate date] toValue:&dateString ofClass:[NSDate class] error:&error]; + +// Transforming NSString -> NSDate +NSDate *date = nil; +success = [dateFormatter transformValue:@"2013-09-12T07:24:56-04:00" toValue:&dateString ofClass:[NSDate class] error:&error]; +``` + +### Configuration as Default Date Transformer + +Adding the date formatter to the default value transformer at position 0 ensures that it is used ahead of all other `NSString` <-> `NSDate` value transformers. + +```objc +#import "ISO8601DateValueTransformer.h" + +RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; +[[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +``` + +## Credits + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +## License + +ISO8601DateFormatterValueTransformer is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/Unit-2-Journal/Pods/Manifest.lock b/Unit-2-Journal/Pods/Manifest.lock new file mode 100644 index 0000000..87b4d91 --- /dev/null +++ b/Unit-2-Journal/Pods/Manifest.lock @@ -0,0 +1,69 @@ +PODS: + - AFNetworking (1.3.4) + - Bolts (1.3.0): + - Bolts/AppLinks (= 1.3.0) + - Bolts/Tasks (= 1.3.0) + - Bolts/AppLinks (1.3.0): + - Bolts/Tasks + - Bolts/Tasks (1.3.0) + - FBSDKCoreKit (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/arc (= 4.7.0) + - FBSDKCoreKit/no-arc (= 4.7.0) + - FBSDKCoreKit/arc (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/no-arc (4.7.0): + - Bolts (~> 1.1) + - FBSDKCoreKit/arc + - FBSDKLoginKit (4.7.0): + - FBSDKCoreKit + - FBSDKShareKit (4.7.0): + - FBSDKCoreKit + - FoldingTabBar (1.0.1) + - ISO8601DateFormatterValueTransformer (0.6.1): + - RKValueTransformers (~> 1.1.0) + - Parse (1.9.0): + - Bolts/Tasks (>= 1.3.0) + - pop (1.0.8) + - RestKit/Network (0.24.1): + - AFNetworking (~> 1.3.0) + - RestKit/ObjectMapping + - RestKit/Support + - SOCKit + - RestKit/ObjectMapping (0.24.1): + - ISO8601DateFormatterValueTransformer (~> 0.6.0) + - RestKit/Support + - RKValueTransformers (~> 1.1.0) + - RestKit/Support (0.24.1): + - TransitionKit (~> 2.1.0) + - RestKit/Testing (0.24.1): + - RestKit/Network + - RKValueTransformers (1.1.2) + - SOCKit (1.1) + - TransitionKit (2.1.1) + +DEPENDENCIES: + - FBSDKCoreKit (~> 4.7) + - FBSDKLoginKit (~> 4.7) + - FBSDKShareKit (~> 4.7) + - FoldingTabBar (~> 1.0.1) + - Parse + - pop (~> 1.0) + - RestKit/Testing (~> 0.24.0) + +SPEC CHECKSUMS: + AFNetworking: cf8e418e16f0c9c7e5c3150d019a3c679d015018 + Bolts: 805a4a87413e49d4a0c2b7d469084cbc46b09342 + FBSDKCoreKit: eb580bfc2040ad44f4c0b4f4d0befb1d35bce59c + FBSDKLoginKit: 01bce8dd3f3a26a023b0ba4ffdde7ef5062889fe + FBSDKShareKit: 1f927bb05e4d36a99d5d5bf2f4b1ff294ce3e15c + FoldingTabBar: 3e04c49dbe2b02c529561a4182bf017b928d04d2 + ISO8601DateFormatterValueTransformer: 52da467d6ec899d6aedda8e48280ac92e8ee97e6 + Parse: 712efbc476d4f47b0f96b70db7e53101575753aa + pop: bb773ae2c791ca2629de13b347e7a8b450fa6a57 + RestKit: 1987b5efef289c6b27bd980714d6ca48d3871b78 + RKValueTransformers: 66ac5e4f077fdbe3496e792d89eeff4c3eb67701 + SOCKit: c7376ac262bea9115b8f749358f762522a47d392 + TransitionKit: 3a14b6acc7cf2d1dd3e454e24dbad1cfab9a1ef1 + +COCOAPODS: 0.39.0 diff --git a/Unit-2-Journal/Pods/Parse/LICENSE b/Unit-2-Journal/Pods/Parse/LICENSE new file mode 100644 index 0000000..d98b0e0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Parse iOS/OSX SDK software + +Copyright (c) 2015-present, Parse, LLC. 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 Parse 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. diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h new file mode 100644 index 0000000..cff7a3e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFACL; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFDefaultACLController : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +// TODO: (nlutsenko, richardross) Make it not terrible aka don't have singletons ++ (instancetype)defaultController; ++ (void)clearDefaultController; + +///-------------------------------------- +/// @name Default ACL +///-------------------------------------- + +/*! + Get the default ACL managed by this controller. + + @return A task that returns the ACL encapsulated by this controller. + */ +- (BFTask *)getDefaultACLAsync; + +/*! + Set the new default default ACL to be encapsulated in this controller. + + @param acl The new ACL. Will be copied. + @param accessForCurrentUser Whether or not we should add special access for the current user on this ACL. + + @return A task that returns the new (copied) ACL now encapsulated in this controller. + */ +- (BFTask *)setDefaultACLAsync:(PFACL *)acl withCurrentUserAccess:(BOOL)accessForCurrentUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m new file mode 100644 index 0000000..82bd638 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDefaultACLController.h" + +#import + +#import "PFACLPrivate.h" +#import "PFAsyncTaskQueue.h" +#import "PFCoreManager.h" +#import "PFCurrentUserController.h" +#import "Parse_Private.h" + +@implementation PFDefaultACLController { + PFAsyncTaskQueue *_taskQueue; + + PFACL *_defaultACL; + BOOL _useCurrentUser; + + PFUser *_lastCurrentUser; + PFACL *_defaultACLWithCurrentUser; +} + +static PFDefaultACLController *defaultController_; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)defaultController { + if (!defaultController_) { + defaultController_ = [[self alloc] init]; + } + return defaultController_; +} + ++ (void)clearDefaultController { + defaultController_ = nil; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _taskQueue = [[PFAsyncTaskQueue alloc] init]; + + return self; +} + +///-------------------------------------- +#pragma mark - ACL +///-------------------------------------- + +- (BFTask PF_GENERIC(PFACL *)*)getDefaultACLAsync { + return [_taskQueue enqueue:^id(BFTask *task) { + if (!_defaultACL || !_useCurrentUser) { + return _defaultACL; + } + + PFCurrentUserController *currentUserController = [Parse _currentManager].coreManager.currentUserController; + return [[currentUserController getCurrentObjectAsync] continueWithBlock:^id(BFTask *task) { + PFUser *currentUser = task.result; + if (!currentUser) { + return _defaultACL; + } + + if (currentUser != _lastCurrentUser) { + _defaultACLWithCurrentUser = [_defaultACL createUnsharedCopy]; + [_defaultACLWithCurrentUser setShared:YES]; + [_defaultACLWithCurrentUser setReadAccess:YES forUser:currentUser]; + [_defaultACLWithCurrentUser setWriteAccess:YES forUser:currentUser]; + _lastCurrentUser = currentUser; + } + return _defaultACLWithCurrentUser; + }]; + }]; +} + +- (BFTask PF_GENERIC(PFACL *)*)setDefaultACLAsync:(PFACL *)acl withCurrentUserAccess:(BOOL)accessForCurrentUser { + return [_taskQueue enqueue:^id(BFTask *task) { + _defaultACLWithCurrentUser = nil; + _lastCurrentUser = nil; + + _defaultACL = [acl createUnsharedCopy]; + [_defaultACL setShared:YES]; + + _useCurrentUser = accessForCurrentUser; + + return _defaultACL; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/PFACLPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/PFACLPrivate.h new file mode 100644 index 0000000..6a641d6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/PFACLPrivate.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFACL.h" + +@class PFUser; + +@interface PFACL (Private) + +// Internal commands + +/* + Gets the encoded format for an ACL. + */ +- (NSDictionary *)encodeIntoDictionary; + +/* + Creates a new ACL object from an existing dictionary. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +/*! + Creates an ACL from its encoded format. + */ ++ (instancetype)ACLWithDictionary:(NSDictionary *)dictionary; + +- (void)setShared:(BOOL)shared; +- (BOOL)isShared; +- (instancetype)createUnsharedCopy; +- (BOOL)hasUnresolvedUser; + ++ (instancetype)defaultACL; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.h new file mode 100644 index 0000000..90e06af --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +NS_ASSUME_NONNULL_BEGIN + +@class PFMutableACLState; + +typedef void (^PFACLStateMutationBlock)(PFMutableACLState *); + +@interface PFACLState : PFBaseState + +@property (nonatomic, copy, readonly) NSDictionary *permissions; +@property (nonatomic, assign, readonly, getter=isShared) BOOL shared; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithState:(PFACLState *)otherState NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithState:(PFACLState *)otherState mutatingBlock:(PFACLStateMutationBlock)mutatingBlock; + ++ (instancetype)stateWithState:(PFACLState *)otherState; ++ (instancetype)stateWithState:(PFACLState *)otherState mutatingBlock:(PFACLStateMutationBlock)mutatingBlock; + +///-------------------------------------- +/// @name Mutating +///-------------------------------------- + +- (instancetype)copyByMutatingWithBlock:(PFACLStateMutationBlock)mutatingBlock NS_RETURNS_RETAINED; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.m new file mode 100644 index 0000000..a80649e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState.m @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFACLState_Private.h" + +#import "PFMutableACLState.h" + +@implementation PFACLState + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + return @{ + @"permissions": [PFPropertyAttributes attributes], + @"shared": [PFPropertyAttributes attributes], + }; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _permissions = [NSDictionary dictionary]; + _shared = NO; + + return self; +} + +- (instancetype)initWithState:(PFACLState *)otherState { + return [super initWithState:otherState]; +} + +- (instancetype)initWithState:(PFACLState *)otherState mutatingBlock:(PFACLStateMutationBlock)mutatingBlock { + self = [self initWithState:otherState]; + if (!self) return nil; + + // Make permissions mutable for the duration of the block. + _permissions = [_permissions mutableCopy]; + + mutatingBlock((PFMutableACLState *)self); + + _permissions = [_permissions copy]; + + return self; +} + ++ (instancetype)stateWithState:(PFACLState *)otherState { + return [super stateWithState:otherState]; +} + ++ (instancetype)stateWithState:(PFACLState *)otherState mutatingBlock:(PFACLStateMutationBlock)mutatingBlock { + return [[self alloc] initWithState:otherState mutatingBlock:mutatingBlock]; +} + +///-------------------------------------- +#pragma mark - Copying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[PFACLState allocWithZone:zone] initWithState:self]; +} + +- (instancetype)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableACLState allocWithZone:zone] initWithState:self]; +} + +///-------------------------------------- +#pragma mark - Mutating +///-------------------------------------- + +- (instancetype)copyByMutatingWithBlock:(PFACLStateMutationBlock)mutationsBlock { + return [[PFACLState alloc] initWithState:self mutatingBlock:mutationsBlock]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState_Private.h new file mode 100644 index 0000000..a3ed153 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFACLState_Private.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFACLState.h" + +@interface PFACLState () { +@protected + NSDictionary *_permissions; + BOOL _shared; +} + +@property (nonatomic, copy, readwrite) NSDictionary *permissions; +@property (nonatomic, assign, readwrite, getter=isShared) BOOL shared; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.h new file mode 100644 index 0000000..d2bda0c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFACLState.h" + +@interface PFMutableACLState : PFACLState + +@property (nonatomic, copy, readwrite) NSMutableDictionary *permissions; +@property (nonatomic, assign, readwrite, getter=isShared) BOOL shared; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.m new file mode 100644 index 0000000..5361b8d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ACL/State/PFMutableACLState.m @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableACLState.h" + +#import "PFACLState_Private.h" + +@implementation PFMutableACLState + +@dynamic permissions; +@dynamic shared; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _permissions = [NSMutableDictionary dictionary]; + + return self; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.h new file mode 100644 index 0000000..0681ec4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +@interface PFAnalyticsController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Track Event +///-------------------------------------- + +/*! + @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 payload The Remote Notification payload. + @param sessionToken Current user session token. + + @returns `BFTask` with result set to `@YES`. + */ +- (BFTask *)trackAppOpenedEventAsyncWithRemoteNotificationPayload:(NSDictionary *)payload + sessionToken:(NSString *)sessionToken; + +/*! + @abstract Tracks the occurrence of a custom event with additional dimensions. + + @param name Event name. + @param dimensions `NSDictionary` of information by which to segment this event. + @param sessionToken Current user session token. + + @returns `BFTask` with result set to `@YES`. + */ +- (BFTask *)trackEventAsyncWithName:(NSString *)name + dimensions:(NSDictionary *)dimensions + sessionToken:(NSString *)sessionToken; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.m new file mode 100644 index 0000000..b77eba6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Controller/PFAnalyticsController.m @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAnalyticsController.h" + +#import "BFTask+Private.h" +#import "PFAnalyticsUtilities.h" +#import "PFAssert.h" +#import "PFEventuallyQueue.h" +#import "PFRESTAnalyticsCommand.h" + +@interface PFAnalyticsController () + +@property (nonatomic, weak, readonly) PFEventuallyQueue *eventuallyQueue; + +@end + +@implementation PFAnalyticsController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Track Event +///-------------------------------------- + +- (BFTask *)trackAppOpenedEventAsyncWithRemoteNotificationPayload:(NSDictionary *)payload + sessionToken:(NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + // If the Remote Notification payload had a message sent along with it, make + // sure to send that along so the server can identify "app opened from push" + // instead. + id alert = payload[@"aps"][@"alert"]; + NSString *pushDigest = (alert ? [PFAnalyticsUtilities md5DigestFromPushPayload:alert] : nil); + + PFRESTCommand *command = [PFRESTAnalyticsCommand trackAppOpenedEventCommandWithPushHash:pushDigest + sessionToken:sessionToken]; + return [self.eventuallyQueue enqueueCommandInBackground:command]; + }] continueWithSuccessResult:@YES]; +} + +- (BFTask *)trackEventAsyncWithName:(NSString *)name + dimensions:(NSDictionary *)dimensions + sessionToken:(NSString *)sessionToken { + PFParameterAssert([[name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length], + @"A name for the custom event must be provided."); + + if (dimensions) { + [dimensions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + PFParameterAssert([key isKindOfClass:[NSString class]] && [obj isKindOfClass:[NSString class]], + @"trackEvent dimensions expect keys and values of type NSString."); + }]; + } + + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + NSDictionary *encodedDimensions = [[PFNoObjectEncoder objectEncoder] encodeObject:dimensions]; + PFRESTCommand *command = [PFRESTAnalyticsCommand trackEventCommandWithEventName:name + dimensions:encodedDimensions + sessionToken:sessionToken]; + return [self.eventuallyQueue enqueueCommandInBackground:command]; + }] continueWithSuccessResult:@YES]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFEventuallyQueue *)eventuallyQueue { + return self.dataSource.eventuallyQueue; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/PFAnalytics_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/PFAnalytics_Private.h new file mode 100644 index 0000000..d001798 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/PFAnalytics_Private.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +/*! + Predefined events - AppOpened, CrashReport + Coming soon - Log, ... + */ +extern NSString *const PFAnalyticsEventAppOpened; +extern NSString *const PFAnalyticsEventCrashReport; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h new file mode 100644 index 0000000..69f581f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFAnalyticsUtilities : NSObject + +/*! + Serializes and hexdigests an alert payload into a "push_hash" identifier + for use in Analytics. + Limitedly flexible - the payload is the value under the "alert" key in the + "aps" hash of a remote notification, so we can reasonably assume that the + complexity of its structure is limited to that accepted by Apple (in its + "The Notification Payload" docs) + + @param payload `alert` value from a push notification. + + @returns md5 identifier. + */ ++ (NSString *)md5DigestFromPushPayload:(id)payload; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m new file mode 100644 index 0000000..9107d18 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAnalyticsUtilities.h" + +#import "PFHash.h" + +@implementation PFAnalyticsUtilities + ++ (NSString *)md5DigestFromPushPayload:(id)payload { + if (!payload || payload == [NSNull null]) { + payload = @""; + } else if ([payload isKindOfClass:[NSDictionary class]]) { + NSDictionary *dict = payload; + NSArray *keys = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *components = [NSMutableArray arrayWithCapacity:[dict count] * 2]; + [keys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) { + [components addObject:key]; + + // alert[@"loc-args"] can be an NSArray + id value = [dict objectForKey:key]; + if ([value isKindOfClass:[NSArray class]]) { + value = [value componentsJoinedByString:@""]; + } + [components addObject:value]; + }]; + payload = [components componentsJoinedByString:@""]; + } + return PFMD5HashFromString([payload description]); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.h new file mode 100644 index 0000000..0d01c82 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.h @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInternalUtils.h" + +@interface BFExecutor (Background) + ++ (instancetype)defaultPriorityBackgroundExecutor; + +@end + +@interface BFTask (Private) + +- (instancetype)continueAsyncWithBlock:(BFContinuationBlock)block; +- (instancetype)continueAsyncWithSuccessBlock:(BFContinuationBlock)block; + +- (instancetype)continueWithResult:(id)result; +- (instancetype)continueWithSuccessResult:(id)result; + +- (instancetype)continueWithMainThreadResultBlock:(PFIdResultBlock)resultBlock + executeIfCancelled:(BOOL)executeIfCancelled; +- (instancetype)continueWithMainThreadBooleanResultBlock:(PFBooleanResultBlock)resultBlock + executeIfCancelled:(BOOL)executeIfCancelled; + +/*! + Adds a continuation to the task that will run the given block on the main + thread sometime after this task has finished. If the task was cancelled, + the block will never be called. If the task had an exception, the exception + will be throw on the main thread instead of running the block. Otherwise, + the block will be given the result and error of this task. + @returns A new task that will be finished once the block has run. + */ +- (BFTask *)thenCallBackOnMainThreadAsync:(void(^)(id result, NSError *error))block; + +/*! + Identical to thenCallBackOnMainThreadAsync:, except that the result of a successful + task will be converted to a BOOL using the boolValue method, and that will + be passed to the block instead of the original result. + */ +- (BFTask *)thenCallBackOnMainThreadWithBoolValueAsync:(void(^)(BOOL result, NSError *error))block; + +/*! + Same as `waitForResult:error withMainThreadWarning:YES` + */ +- (id)waitForResult:(NSError **)error; + +/*! + Waits until this operation is completed, then returns its value. + This method is inefficient and consumes a thread resource while its running. + + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + @param warningEnabled `BOOL` value that + + @return Returns a `self.result` if task completed. `nil` - if cancelled. + */ +- (id)waitForResult:(NSError **)error withMainThreadWarning:(BOOL)warningEnabled; + +@end + +extern void forceLoadCategory_BFTask_Private(); diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.m new file mode 100644 index 0000000..5ed4959 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/BFTask+Private.m @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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+Private.h" + +#import +#import + +#import "PFLogging.h" + +@implementation BFExecutor (Background) + ++ (instancetype)defaultPriorityBackgroundExecutor { + static BFExecutor *executor; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + executor = [BFExecutor executorWithDispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; + }); + return executor; +} + +@end + +@implementation BFTask (Private) + +- (instancetype)continueAsyncWithBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:block]; +} + +- (instancetype)continueAsyncWithSuccessBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withSuccessBlock:block]; +} + +- (instancetype)continueWithResult:(id)result { + return [self continueWithBlock:^id(BFTask *task) { + return result; + }]; +} + +- (instancetype)continueWithSuccessResult:(id)result { + return [self continueWithSuccessBlock:^id(BFTask *task) { + return result; + }]; +} + +- (instancetype)continueWithMainThreadResultBlock:(PFIdResultBlock)resultBlock + executeIfCancelled:(BOOL)executeIfCancelled { + if (!resultBlock) { + return self; + } + return [self continueWithExecutor:[BFExecutor mainThreadExecutor] + withBlock:^id(BFTask *task) { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + + @try { + if (self.exception) { + //TODO: (nlutsenko) Add more context, by passing a `_cmd` from the caller method + PFLogException(self.exception); + @throw self.exception; + } + + if (!self.cancelled || executeIfCancelled) { + resultBlock(self.result, self.error); + } + } @finally { + tcs.result = nil; + } + + return tcs.task; + }]; +} + +- (instancetype)continueWithMainThreadBooleanResultBlock:(PFBooleanResultBlock)resultBlock + executeIfCancelled:(BOOL)executeIfCancelled { + return [self continueWithMainThreadResultBlock:^(id object, NSError *error) { + resultBlock([object boolValue], error); + } executeIfCancelled:executeIfCancelled]; +} + +- (BFTask *)thenCallBackOnMainThreadAsync:(void(^)(id result, NSError *error))block { + return [self continueWithMainThreadResultBlock:block executeIfCancelled:NO]; +} + +- (BFTask *)thenCallBackOnMainThreadWithBoolValueAsync:(void(^)(BOOL result, NSError *error))block { + if (!block) { + return self; + } + return [self thenCallBackOnMainThreadAsync:^(id blockResult, NSError *blockError) { + block([blockResult boolValue], blockError); + }]; +} + +- (id)waitForResult:(NSError **)error { + return [self waitForResult:error withMainThreadWarning:YES]; +} + +- (id)waitForResult:(NSError **)error withMainThreadWarning:(BOOL)warningEnabled { + if (warningEnabled) { + [self waitUntilFinished]; + } else { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [self continueWithBlock:^id(BFTask *task) { + dispatch_semaphore_signal(semaphore); + return nil; + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + } + if (self.cancelled) { + return nil; + } else if (self.exception) { + @throw self.exception; + } + if (self.error && error) { + *error = self.error; + } + return self.result; +} + +@end + +void forceLoadCategory_BFTask_Private() { + NSString *string = nil; + [string description]; +} diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.h new file mode 100644 index 0000000..8532572 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@protocol PFCommandRunning; + +@interface PFCloudCodeController : NSObject + +@property (nonatomic, strong, readonly) id commandRunner; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommandRunner:(id)commandRunner NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner; + +///-------------------------------------- +/// @name Cloud Functions +///-------------------------------------- + +/*! + Calls a Cloud Code function and returns a result of it's execution. + + @param functionName Function name to call. + @param parameters Parameters to pass. (can't be nil). + @param sessionToken Session token to use. + + @returns `BFTask` with a result set to a result of Cloud Function. + */ +- (BFTask *)callCloudCodeFunctionAsync:(NSString *)functionName + withParameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.m new file mode 100644 index 0000000..212e47a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/CloudCode/PFCloudCodeController.m @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCloudCodeController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFDecoder.h" +#import "PFEncoder.h" +#import "PFInternalUtils.h" +#import "PFRESTCloudCommand.h" + +@implementation PFCloudCodeController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner { + self = [super init]; + if (!self) return nil; + + _commandRunner = commandRunner; + + return self; +} + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner { + return [[self alloc] initWithCommandRunner:commandRunner]; +} + +///-------------------------------------- +#pragma mark - Cloud Functions +///-------------------------------------- + +- (BFTask *)callCloudCodeFunctionAsync:(NSString *)functionName + withParameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + @weakify(self); + return [[[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + NSDictionary *encodedParameters = [[PFNoObjectEncoder objectEncoder] encodeObject:parameters]; + PFRESTCloudCommand *command = [PFRESTCloudCommand commandForFunction:functionName + withParameters:encodedParameters + sessionToken:sessionToken]; + return [self.commandRunner runCommandAsync:command withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return ((PFCommandResult *)(task.result)).result[@"result"]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [[PFDecoder objectDecoder] decodeObject:task.result]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.h new file mode 100644 index 0000000..c07f754 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.h @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +@class BFCancellationToken; +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFCommandResult; +@class PFRESTCommand; +@protocol PFNetworkCommand; + +typedef NS_OPTIONS(NSUInteger, PFCommandRunningOptions) { + PFCommandRunningOptionRetryIfFailed = 1 << 0, +}; + +extern NSTimeInterval const PFCommandRunningDefaultRetryDelay; + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFCommandRunning + +@property (nonatomic, weak, readonly) id dataSource; + +@property (nonatomic, copy, readonly) NSString *applicationId; +@property (nonatomic, copy, readonly) NSString *clientKey; + +@property (nonatomic, assign) NSTimeInterval initialRetryDelay; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource + applicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey; ++ (instancetype)commandRunnerWithDataSource:(id)dataSource + applicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey; + +///-------------------------------------- +/// @name Data Commands +///-------------------------------------- + +/*! + Run command. + + @param command Command to run. + @param options Options to use to run command. + + @returns `BFTask` with result set to `PFCommandResult`. + */ +- (BFTask *)runCommandAsync:(PFRESTCommand *)command + withOptions:(PFCommandRunningOptions)options; + +/*! + Run command. + + @param command Command to run. + @param options Options to use to run command. + @param cancellationToken Operation to use as a cancellation token. + + @returns `BFTask` with result set to `PFCommandResult`. + */ +- (BFTask *)runCommandAsync:(PFRESTCommand *)command + withOptions:(PFCommandRunningOptions)options + cancellationToken:(nullable BFCancellationToken *)cancellationToken; + +///-------------------------------------- +/// @name File Commands +///-------------------------------------- + +- (BFTask *)runFileUploadCommandAsync:(PFRESTCommand *)command + withContentType:(NSString *)contentType + contentSourceFilePath:(NSString *)sourceFilePath + options:(PFCommandRunningOptions)options + cancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock; + +- (BFTask *)runFileDownloadCommandAsyncWithFileURL:(NSURL *)url + targetFilePath:(NSString *)filePath + cancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.m new file mode 100644 index 0000000..6b0c49f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunning.m @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandRunning.h" + +NSTimeInterval const PFCommandRunningDefaultRetryDelay = 1.0; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h new file mode 100644 index 0000000..7531fde --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +///-------------------------------------- +/// @name Running +///-------------------------------------- + +extern uint8_t const PFCommandRunningDefaultMaxAttemptsCount; + +///-------------------------------------- +/// @name Headers +///-------------------------------------- + +extern NSString *const PFCommandHeaderNameApplicationId; +extern NSString *const PFCommandHeaderNameClientKey; +extern NSString *const PFCommandHeaderNameClientVersion; +extern NSString *const PFCommandHeaderNameInstallationId; +extern NSString *const PFCommandHeaderNameAppBuildVersion; +extern NSString *const PFCommandHeaderNameAppDisplayVersion; +extern NSString *const PFCommandHeaderNameOSVersion; +extern NSString *const PFCommandHeaderNameSessionToken; + +///-------------------------------------- +/// @name HTTP Method Override +///-------------------------------------- + +extern NSString *const PFCommandParameterNameMethodOverride; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.m new file mode 100644 index 0000000..3ea747f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.m @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandRunningConstants.h" + +uint8_t const PFCommandRunningDefaultMaxAttemptsCount = 5; + +NSString *const PFCommandHeaderNameApplicationId = @"X-Parse-Application-Id"; +NSString *const PFCommandHeaderNameClientKey = @"X-Parse-Client-Key"; +NSString *const PFCommandHeaderNameClientVersion = @"X-Parse-Client-Version"; +NSString *const PFCommandHeaderNameInstallationId = @"X-Parse-Installation-Id"; +NSString *const PFCommandHeaderNameAppBuildVersion = @"X-Parse-App-Build-Version"; +NSString *const PFCommandHeaderNameAppDisplayVersion = @"X-Parse-App-Display-Version"; +NSString *const PFCommandHeaderNameOSVersion = @"X-Parse-OS-Version"; +NSString *const PFCommandHeaderNameSessionToken = @"X-Parse-Session-Token"; + +NSString *const PFCommandParameterNameMethodOverride = @"_method"; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h new file mode 100644 index 0000000..6583f5b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +@class PFRESTCommand; + +@interface PFCommandURLRequestConstructor : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)constructorWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Data +///-------------------------------------- + +- (NSURLRequest *)dataURLRequestForCommand:(PFRESTCommand *)command; + +///-------------------------------------- +/// @name File Upload +///-------------------------------------- + +- (NSURLRequest *)fileUploadURLRequestForCommand:(PFRESTCommand *)command + withContentType:(NSString *)contentType + contentSourceFilePath:(NSString *)contentFilePath; + +///-------------------------------------- +/// @name Headers +///-------------------------------------- + ++ (NSDictionary *)defaultURLRequestHeadersForApplicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey + bundle:(NSBundle *)bundle; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.m new file mode 100644 index 0000000..b489704 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.m @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandURLRequestConstructor.h" + +#import "PFAssert.h" +#import "PFCommandRunningConstants.h" +#import "PFDevice.h" +#import "PFHTTPRequest.h" +#import "PFHTTPURLRequestConstructor.h" +#import "PFInstallationIdentifierStore.h" +#import "PFInternalUtils.h" +#import "PFRESTCommand.h" +#import "PFURLConstructor.h" +#import "Parse_Private.h" + +@implementation PFCommandURLRequestConstructor + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)constructorWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Data +///-------------------------------------- + +- (NSURLRequest *)dataURLRequestForCommand:(PFRESTCommand *)command { + NSURL *url = [PFURLConstructor URLFromAbsoluteString:[PFInternalUtils parseServerURLString] + path:[NSString stringWithFormat:@"/1/%@", command.httpPath] + query:nil]; + NSDictionary *headers = [self _URLRequestHeadersForCommand:command]; + + NSString *requestMethod = command.httpMethod; + NSDictionary *requestParameters = nil; + if (command.parameters) { + NSDictionary *parameters = nil; + + // The request URI may be too long to include parameters in the URI. + // To avoid this problem we send the parameters in a POST request json-encoded body + // and add a custom parameter that overrides the method in a request. + if ([requestMethod isEqualToString:PFHTTPRequestMethodGET] || + [requestMethod isEqualToString:PFHTTPRequestMethodHEAD] || + [requestMethod isEqualToString:PFHTTPRequestMethodDELETE]) { + NSMutableDictionary *mutableParameters = [command.parameters mutableCopy]; + mutableParameters[PFCommandParameterNameMethodOverride] = command.httpMethod; + + requestMethod = PFHTTPRequestMethodPOST; + parameters = [mutableParameters copy]; + } else { + parameters = command.parameters; + } + requestParameters = [[PFPointerObjectEncoder objectEncoder] encodeObject:parameters]; + } + + return [PFHTTPURLRequestConstructor urlRequestWithURL:url + httpMethod:requestMethod + httpHeaders:headers + parameters:requestParameters]; +} + +///-------------------------------------- +#pragma mark - File +///-------------------------------------- + +- (NSURLRequest *)fileUploadURLRequestForCommand:(PFRESTCommand *)command + withContentType:(NSString *)contentType + contentSourceFilePath:(NSString *)contentFilePath { + NSMutableURLRequest *request = [[self dataURLRequestForCommand:command] mutableCopy]; + + if (contentType) { + [request setValue:contentType forHTTPHeaderField:PFHTTPRequestHeaderNameContentType]; + } + + //TODO (nlutsenko): Check for error here. + NSNumber *fileSize = [PFInternalUtils fileSizeOfFileAtPath:contentFilePath error:nil]; + [request setValue:[fileSize stringValue] forHTTPHeaderField:PFHTTPRequestHeaderNameContentLength]; + + return request; +} + +///-------------------------------------- +#pragma mark - Headers +///-------------------------------------- + ++ (NSDictionary *)defaultURLRequestHeadersForApplicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey + bundle:(NSBundle *)bundle { +#if TARGET_OS_IPHONE + NSString *versionPrefix = @"i"; +#else + NSString *versionPrefix = @"osx"; +#endif + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + + mutableHeaders[PFCommandHeaderNameApplicationId] = applicationId; + mutableHeaders[PFCommandHeaderNameClientKey] = clientKey; + + mutableHeaders[PFCommandHeaderNameClientVersion] = [versionPrefix stringByAppendingString:PARSE_VERSION]; + mutableHeaders[PFCommandHeaderNameOSVersion] = [PFDevice currentDevice].operatingSystemFullVersion; + + // Bundle Version and Display Version can be null, when running tests + NSString *bundleVersion = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (bundleVersion) { + mutableHeaders[PFCommandHeaderNameAppBuildVersion] = bundleVersion; + } + NSString *displayVersion = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if (displayVersion) { + mutableHeaders[PFCommandHeaderNameAppDisplayVersion] = displayVersion; + } + + return [mutableHeaders copy]; +} + +- (NSDictionary *)_URLRequestHeadersForCommand:(PFRESTCommand *)command { + NSMutableDictionary *headers = [NSMutableDictionary dictionary]; + [headers addEntriesFromDictionary:command.additionalRequestHeaders]; + PFInstallationIdentifierStore *installationIdentifierStore = self.dataSource.installationIdentifierStore; + headers[PFCommandHeaderNameInstallationId] = installationIdentifierStore.installationIdentifier; + if (command.sessionToken) { + headers[PFCommandHeaderNameSessionToken] = command.sessionToken; + } + return [headers copy]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h new file mode 100644 index 0000000..7f75dfd --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandRunning.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionCommandRunner : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m new file mode 100644 index 0000000..d504980 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m @@ -0,0 +1,286 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionCommandRunner.h" +#import "PFURLSessionCommandRunner_Private.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunningConstants.h" +#import "PFCommandURLRequestConstructor.h" +#import "PFConstants.h" +#import "PFDevice.h" +#import "PFEncoder.h" +#import "PFHTTPRequest.h" +#import "PFHTTPURLRequestConstructor.h" +#import "PFInstallationIdentifierStore.h" +#import "PFInternalUtils.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFRESTCommand.h" +#import "PFURLConstructor.h" +#import "PFURLSession.h" + +@interface PFURLSessionCommandRunner () + +@property (nonatomic, strong) NSNotificationCenter *notificationCenter; + +@end + +@implementation PFURLSessionCommandRunner + +@synthesize applicationId = _applicationId; +@synthesize clientKey = _clientKey; +@synthesize initialRetryDelay = _initialRetryDelay; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource + applicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey { + NSURLSessionConfiguration *configuration = [[self class] _urlSessionConfigurationForApplicationId:applicationId + clientKey:clientKey]; + PFURLSession *session = [PFURLSession sessionWithConfiguration:configuration delegate:self]; + PFCommandURLRequestConstructor *constructor = [PFCommandURLRequestConstructor constructorWithDataSource:dataSource]; + self = [self initWithDataSource:dataSource + session:session + requestConstructor:constructor + notificationCenter:[NSNotificationCenter defaultCenter]]; + if (!self) return nil; + + _applicationId = [applicationId copy]; + _clientKey = [clientKey copy]; + + return self; +} + +- (instancetype)initWithDataSource:(id)dataSource + session:(PFURLSession *)session + requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor + notificationCenter:(NSNotificationCenter *)notificationCenter { + self = [super init]; + if (!self) return nil; + + _initialRetryDelay = PFCommandRunningDefaultRetryDelay; + + _requestConstructor = requestConstructor; + _session = session; + _notificationCenter = notificationCenter; + + return self; +} + ++ (instancetype)commandRunnerWithDataSource:(id)dataSource + applicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey { + return [[self alloc] initWithDataSource:dataSource applicationId:applicationId clientKey:clientKey]; +} + +///-------------------------------------- +#pragma mark - Dealloc +///-------------------------------------- + +- (void)dealloc { + // This is required to call, since session will continue to be present in memory and running otherwise. + [_session invalidateAndCancel]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (id)dataSource { + return _requestConstructor.dataSource; +} + +///-------------------------------------- +#pragma mark - Data Commands +///-------------------------------------- + +- (BFTask PF_GENERIC(PFCommandResult *)*)runCommandAsync:(PFRESTCommand *)command withOptions:(PFCommandRunningOptions)options { + return [self runCommandAsync:command withOptions:options cancellationToken:nil]; +} + +- (BFTask PF_GENERIC(PFCommandResult *)*)runCommandAsync:(PFRESTCommand *)command + withOptions:(PFCommandRunningOptions)options + cancellationToken:(BFCancellationToken *)cancellationToken { + return [self _performCommandRunningBlock:^id { + [command resolveLocalIds]; + NSURLRequest *request = [self.requestConstructor dataURLRequestForCommand:command]; + return [_session performDataURLRequestAsync:request forCommand:command cancellationToken:cancellationToken]; + } withOptions:options cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - File Commands +///-------------------------------------- + +- (BFTask PF_GENERIC(PFCommandResult *)*)runFileUploadCommandAsync:(PFRESTCommand *)command + withContentType:(NSString *)contentType + contentSourceFilePath:(NSString *)sourceFilePath + options:(PFCommandRunningOptions)options + cancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock { + @weakify(self); + return [self _performCommandRunningBlock:^id { + @strongify(self); + + [command resolveLocalIds]; + NSURLRequest *request = [self.requestConstructor fileUploadURLRequestForCommand:command + withContentType:contentType + contentSourceFilePath:sourceFilePath]; + return [_session performFileUploadURLRequestAsync:request + forCommand:command + withContentSourceFilePath:sourceFilePath + cancellationToken:cancellationToken + progressBlock:progressBlock]; + + } withOptions:options cancellationToken:cancellationToken]; +} + +- (BFTask PF_GENERIC(PFCommandResult *)*)runFileDownloadCommandAsyncWithFileURL:(NSURL *)url + targetFilePath:(NSString *)filePath + cancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock { + return [self _performCommandRunningBlock:^id { + NSURLRequest *request = [NSURLRequest requestWithURL:url]; + return [_session performFileDownloadURLRequestAsync:request + toFileAtPath:filePath + withCancellationToken:cancellationToken + progressBlock:progressBlock]; + } withOptions:PFCommandRunningOptionRetryIfFailed + cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Retrying +///-------------------------------------- + +- (BFTask *)_performCommandRunningBlock:(nonnull id (^)())block + withOptions:(PFCommandRunningOptions)options + cancellationToken:(BFCancellationToken *)cancellationToken { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + if (!(options & PFCommandRunningOptionRetryIfFailed)) { + return block(); + } + + NSTimeInterval delay = self.initialRetryDelay; // Delay (secs) of next retry attempt + + // Set the initial delay to something between 1 and 2 seconds. We want it to be + // random so that clients that fail simultaneously don't retry on simultaneous + // intervals. + delay += self.initialRetryDelay * ((double)(arc4random() & 0x0FFFF) / (double)0x0FFFF); + return [self _performCommandRunningBlock:block + withCancellationToken:cancellationToken + delay:delay + forAttempts:PFCommandRunningDefaultMaxAttemptsCount]; +} + +- (BFTask *)_performCommandRunningBlock:(nonnull id (^)())block + withCancellationToken:(BFCancellationToken *)cancellationToken + delay:(NSTimeInterval)delay + forAttempts:(NSUInteger)attempts { + @weakify(self); + return [block() continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (task.cancelled) { + return task; + } + + if ([[task.error userInfo][@"temporary"] boolValue] && attempts > 1) { + PFLogError(PFLoggingTagCommon, + @"Network connection failed. Making attempt %lu after sleeping for %f seconds.", + (unsigned long)(PFCommandRunningDefaultMaxAttemptsCount - attempts + 1), (double)delay); + + return [[BFTask taskWithDelay:(int)(delay * 1000)] continueWithBlock:^id(BFTask *task) { + return [self _performCommandRunningBlock:block + withCancellationToken:cancellationToken + delay:delay * 2.0 + forAttempts:attempts - 1]; + } cancellationToken:cancellationToken]; + } + return task; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - NSURLSessionConfiguration +///-------------------------------------- + ++ (NSURLSessionConfiguration *)_urlSessionConfigurationForApplicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey { + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + + // No cookies, they are bad for you. + configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever; + configuration.HTTPShouldSetCookies = NO; + + // Completely disable caching of responses for security reasons. + configuration.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:[NSURLCache sharedURLCache].memoryCapacity + diskCapacity:0 + diskPath:nil]; + + NSBundle *bundle = [NSBundle mainBundle]; + NSDictionary *headers = [PFCommandURLRequestConstructor defaultURLRequestHeadersForApplicationId:applicationId + clientKey:clientKey + bundle:bundle]; + configuration.HTTPAdditionalHeaders = headers; + + return configuration; +} + +///-------------------------------------- +#pragma mark - PFURLSessionDelegate +///-------------------------------------- + +- (void)urlSession:(PFURLSession *)session willPerformURLRequest:(NSURLRequest *)request { + [[BFExecutor defaultPriorityBackgroundExecutor] execute:^{ + NSDictionary *userInfo = ([PFLogger sharedLogger].logLevel == PFLogLevelDebug ? + @{ PFNetworkNotificationURLRequestUserInfoKey : request } : nil); + [self.notificationCenter postNotificationName:PFNetworkWillSendURLRequestNotification + object:self + userInfo:userInfo]; + }]; +} + +- (void)urlSession:(PFURLSession *)session +didPerformURLRequest:(NSURLRequest *)request + withURLResponse:(nullable NSURLResponse *)response + responseString:(nullable NSString *)responseString { + [[BFExecutor defaultPriorityBackgroundExecutor] execute:^{ + NSMutableDictionary *userInfo = nil; + if ([PFLogger sharedLogger].logLevel == PFLogLevelDebug) { + userInfo = [NSMutableDictionary dictionaryWithObject:request + forKey:PFNetworkNotificationURLRequestUserInfoKey]; + if (response) { + userInfo[PFNetworkNotificationURLResponseUserInfoKey] = response; + } + if (responseString) { + userInfo[PFNetworkNotificationURLResponseBodyUserInfoKey] = responseString; + } + } + [self.notificationCenter postNotificationName:PFNetworkDidReceiveURLResponseNotification + object:self + userInfo:userInfo]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h new file mode 100644 index 0000000..e10c6f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionCommandRunner.h" + +@class PFCommandURLRequestConstructor; +@class PFURLSession; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionCommandRunner () + +@property (nonatomic, strong, readonly) PFURLSession *session; +@property (nonatomic, strong, readonly) PFCommandURLRequestConstructor *requestConstructor; + +- (instancetype)initWithDataSource:(id)dataSource + session:(PFURLSession *)session + requestConstructor:(PFCommandURLRequestConstructor *)requestConstructor + notificationCenter:(NSNotificationCenter *)notificationCenter NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h new file mode 100644 index 0000000..ff53d22 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFCancellationToken; + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFRESTCommand; + +NS_ASSUME_NONNULL_BEGIN + +@class PFURLSession; + +@protocol PFURLSessionDelegate + +- (void)urlSession:(PFURLSession *)session willPerformURLRequest:(NSURLRequest *)request; + +- (void)urlSession:(PFURLSession *)session didPerformURLRequest:(NSURLRequest *)request withURLResponse:(nullable NSURLResponse *)response responseString:(nullable NSString *)string; + +@end + +@interface PFURLSession : NSObject + +@property (nonatomic, weak, readonly) id delegate; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration + delegate:(id)delegate NS_DESIGNATED_INITIALIZER; + ++ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration + delegate:(id)delegate; + +///-------------------------------------- +/// @name Teardown +///-------------------------------------- + +- (void)invalidateAndCancel; + +///-------------------------------------- +/// @name Network Requests +///-------------------------------------- + +- (BFTask *)performDataURLRequestAsync:(NSURLRequest *)request + forCommand:(PFRESTCommand *)command + cancellationToken:(nullable BFCancellationToken *)cancellationToken; + +- (BFTask *)performFileUploadURLRequestAsync:(NSURLRequest *)request + forCommand:(PFRESTCommand *)command + withContentSourceFilePath:(NSString *)sourceFilePath + cancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock; + +- (BFTask *)performFileDownloadURLRequestAsync:(NSURLRequest *)request + toFileAtPath:(NSString *)filePath + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m new file mode 100644 index 0000000..9934f47 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSession.h" +#import "PFURLSession_Private.h" + +#import + +#import "BFTask+Private.h" +#import "PFCommandResult.h" +#import "PFMacros.h" +#import "PFAssert.h" +#import "PFURLSessionJSONDataTaskDelegate.h" +#import "PFURLSessionUploadTaskDelegate.h" +#import "PFURLSessionFileDownloadTaskDelegate.h" + +typedef void (^PFURLSessionTaskCompletionHandler)(NSData *data, NSURLResponse *response, NSError *error); + +@interface PFURLSession () { + dispatch_queue_t _sessionTaskQueue; + NSURLSession *_urlSession; + NSMutableDictionary *_delegatesDictionary; + dispatch_queue_t _delegatesAccessQueue; +} + +@end + +@implementation PFURLSession + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithConfiguration:(NSURLSessionConfiguration *)configuration + delegate:(id)delegate { + // NOTE: cast to id suppresses warning about designated initializer. + return [(id)self initWithURLSession:[NSURLSession sessionWithConfiguration:configuration + delegate:self + delegateQueue:nil] + delegate:delegate]; +} + +- (instancetype)initWithURLSession:(NSURLSession *)session + delegate:(id)delegate { + self = [super init]; + if (!self) return nil; + + _delegate = delegate; + _urlSession = session; + + _sessionTaskQueue = dispatch_queue_create("com.parse.urlSession.tasks", DISPATCH_QUEUE_SERIAL); + + _delegatesDictionary = [NSMutableDictionary dictionary]; + _delegatesAccessQueue = dispatch_queue_create("com.parse.urlSession.delegates", DISPATCH_QUEUE_CONCURRENT); + + return self; +} + ++ (instancetype)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration + delegate:(id)delegate { + return [[self alloc] initWithConfiguration:configuration delegate:delegate]; +} + ++ (instancetype)sessionWithURLSession:(nonnull NSURLSession *)session + delegate:(id)delegate { + return [[self alloc] initWithURLSession:session delegate:delegate]; +} + +///-------------------------------------- +#pragma mark - Teardown +///-------------------------------------- + +- (void)invalidateAndCancel { + [_urlSession invalidateAndCancel]; +} + +///-------------------------------------- +#pragma mark - Network Requests +///-------------------------------------- + +- (BFTask *)performDataURLRequestAsync:(NSURLRequest *)request + forCommand:(PFRESTCommand *)command + cancellationToken:(BFCancellationToken *)cancellationToken { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + __block NSURLSessionDataTask *task = nil; + dispatch_sync(_sessionTaskQueue, ^{ + task = [_urlSession dataTaskWithRequest:request]; + }); + PFURLSessionDataTaskDelegate *delegate = [PFURLSessionJSONDataTaskDelegate taskDelegateForDataTask:task + withCancellationToken:cancellationToken]; + return [self _performDataTask:task withDelegate:delegate]; + }]; +} + +- (BFTask *)performFileUploadURLRequestAsync:(NSURLRequest *)request + forCommand:(PFRESTCommand *)command + withContentSourceFilePath:(NSString *)sourceFilePath + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + __block NSURLSessionDataTask *task = nil; + dispatch_sync(_sessionTaskQueue, ^{ + task = [_urlSession uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:sourceFilePath]]; + }); + PFURLSessionUploadTaskDelegate *delegate = [PFURLSessionUploadTaskDelegate taskDelegateForDataTask:task + withCancellationToken:cancellationToken + uploadProgressBlock:progressBlock]; + return [self _performDataTask:task withDelegate:delegate]; + }]; +} + +- (BFTask *)performFileDownloadURLRequestAsync:(NSURLRequest *)request + toFileAtPath:(NSString *)filePath + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + progressBlock:(nullable PFProgressBlock)progressBlock { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + __block NSURLSessionDataTask *task = nil; + dispatch_sync(_sessionTaskQueue, ^{ + task = [_urlSession dataTaskWithRequest:request]; + }); + PFURLSessionFileDownloadTaskDelegate *delegate = [PFURLSessionFileDownloadTaskDelegate taskDelegateForDataTask:task + withCancellationToken:cancellationToken + targetFilePath:filePath + progressBlock:progressBlock]; + return [self _performDataTask:task withDelegate:delegate]; + }]; +} + +- (BFTask *)_performDataTask:(NSURLSessionDataTask *)dataTask withDelegate:(PFURLSessionDataTaskDelegate *)delegate { + [self.delegate urlSession:self willPerformURLRequest:dataTask.originalRequest]; + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + @strongify(self); + NSNumber *taskIdentifier = @(dataTask.taskIdentifier); + [self setDelegate:delegate forDataTask:dataTask]; + + BFTask *resultTask = [delegate.resultTask continueWithBlock:^id(BFTask *task) { + @strongify(self); + [self.delegate urlSession:self + didPerformURLRequest:dataTask.originalRequest + withURLResponse:delegate.response + responseString:delegate.responseString]; + + [self _removeDelegateForTaskWithIdentifier:taskIdentifier]; + return task; + }]; + [dataTask resume]; + + return resultTask; + }]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (PFURLSessionDataTaskDelegate *)_taskDelegateForDataTask:(NSURLSessionDataTask *)task { + __block PFURLSessionDataTaskDelegate *delegate = nil; + dispatch_sync(_delegatesAccessQueue, ^{ + delegate = _delegatesDictionary[@(task.taskIdentifier)]; + }); + return delegate; +} + +- (void)setDelegate:(PFURLSessionDataTaskDelegate *)delegate forDataTask:(NSURLSessionDataTask *)task { + dispatch_barrier_async(_delegatesAccessQueue, ^{ + _delegatesDictionary[@(task.taskIdentifier)] = delegate; + }); +} + +- (void)_removeDelegateForTaskWithIdentifier:(NSNumber *)identifier { + dispatch_barrier_async(_delegatesAccessQueue, ^{ + [_delegatesDictionary removeObjectForKey:identifier]; + }); +} + +///-------------------------------------- +#pragma mark - NSURLSessionTaskDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionDataTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForDataTask:task]; + [delegate URLSession:session + task:task + didSendBodyData:bytesSent + totalBytesSent:totalBytesSent +totalBytesExpectedToSend:totalBytesExpectedToSend]; +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionDataTask *)task didCompleteWithError:(NSError *)error { + PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForDataTask:task]; + [delegate URLSession:session task:task didCompleteWithError:error]; +} + +///-------------------------------------- +#pragma mark - NSURLSessionDataDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForDataTask:dataTask]; + [delegate URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler]; +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForDataTask:dataTask]; + [delegate URLSession:session dataTask:dataTask didReceiveData:data]; +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + completionHandler(nil); // Prevent any caching for security reasons +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h new file mode 100644 index 0000000..1f047ac --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSession.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSession () + +- (instancetype)initWithURLSession:(NSURLSession *)session + delegate:(id)delegate NS_DESIGNATED_INITIALIZER; + ++ (instancetype)sessionWithURLSession:(NSURLSession *)session + delegate:(id)delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h new file mode 100644 index 0000000..a1f8ca9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFCancellationToken; + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionDataTaskDelegate : NSObject + +@property (nonatomic, strong, readonly) NSURLSessionDataTask *dataTask; +@property (nonatomic, strong, readonly) BFTask *resultTask; + +@property (nonatomic, strong, readonly) NSHTTPURLResponse *response; +@property (nullable, nonatomic, copy, readonly) NSString *responseString; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken NS_DESIGNATED_INITIALIZER; + ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m new file mode 100644 index 0000000..f81e9d6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionDataTaskDelegate.h" +#import "PFURLSessionDataTaskDelegate_Private.h" + +#import +#import + +#import "PFAssert.h" +#import "PFMacros.h" + +@interface PFURLSessionDataTaskDelegate () { + BFTaskCompletionSource *_taskCompletionSource; +} + +@end + +@implementation PFURLSessionDataTaskDelegate + +@synthesize dataOutputStream = _dataOutputStream; +@synthesize downloadedBytes = _downloadedBytes; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(BFCancellationToken *)cancellationToken { + self = [super init]; + if (!self) return nil; + + _taskCompletionSource = [BFTaskCompletionSource taskCompletionSource]; + + _dataTask = dataTask; + @weakify(self); + [cancellationToken registerCancellationObserverWithBlock:^{ + @strongify(self); + [self _cancel]; + }]; + + return self; +} + ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken { + return [[self alloc] initForDataTask:dataTask withCancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (BFTask *)resultTask { + return _taskCompletionSource.task; +} + +- (NSOutputStream *)dataOutputStream { + if (!_dataOutputStream) { + _dataOutputStream = [NSOutputStream outputStreamToMemory]; + } + return _dataOutputStream; +} + +///-------------------------------------- +#pragma mark - Task +///-------------------------------------- + +- (void)_taskDidFinish { + [self _closeDataOutputStream]; + if (self.error) { + [_taskCompletionSource trySetError:self.error]; + } else { + [_taskCompletionSource trySetResult:self.result]; + } +} + +- (void)_taskDidCancel { + [self _closeDataOutputStream]; + [_taskCompletionSource trySetCancelled]; +} + +- (void)_cancel { + [self.dataTask cancel]; +} + +///-------------------------------------- +#pragma mark - Stream +///-------------------------------------- + +- (void)_openDataOutputStream { + [self.dataOutputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [self.dataOutputStream open]; +} + +- (void)_writeDataOutputStreamData:(NSData *)data { + NSInteger length = [data length]; + while (YES) { + NSInteger bytesWritten = 0; + if ([self.dataOutputStream hasSpaceAvailable]) { + const uint8_t *dataBuffer = (uint8_t *)[data bytes]; + + NSInteger numberOfBytesWritten = 0; + while (bytesWritten < length) { + numberOfBytesWritten = [self.dataOutputStream write:&dataBuffer[bytesWritten] + maxLength:(length - bytesWritten)]; + if (numberOfBytesWritten == -1) { + break; + } + + bytesWritten += numberOfBytesWritten; + } + break; + } + + if (self.dataOutputStream.streamError) { + [self.dataTask cancel]; + self.error = self.dataOutputStream.streamError; + // Don't finish the delegate here, as we will finish when NSURLSessionTask calls back about cancellation. + return; + } + } + _downloadedBytes += length; +} + +- (void)_closeDataOutputStream { + [self.dataOutputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [self.dataOutputStream close]; +} + +///-------------------------------------- +#pragma mark - NSURLSessionTaskDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + // No-op, we don't care about progress here. +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) { + [self _taskDidCancel]; + } else { + self.error = self.error ?: error; + [self _taskDidFinish]; + } +} + +///-------------------------------------- +#pragma mark - NSURLSessionDataDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + _response = (NSHTTPURLResponse *)response; + [self _openDataOutputStream]; + + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + [self _writeDataOutputStreamData:data]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h new file mode 100644 index 0000000..030d4f0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionDataTaskDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionDataTaskDelegate () + +@property (nonatomic, strong, readonly) dispatch_queue_t dataQueue; + +/*! + @abstract Defaults to to-memory output stream if not overwritten. + */ +@property (nonatomic, strong, readonly) NSOutputStream *dataOutputStream; +@property (nonatomic, assign, readonly) uint64_t downloadedBytes; + +@property (nullable, nonatomic, strong) id result; +@property (nullable, nonatomic, strong) NSError *error; + +@property (nullable, nonatomic, copy, readwrite) NSString *responseString; + +- (void)_taskDidFinish NS_REQUIRES_SUPER; +- (void)_taskDidCancel NS_REQUIRES_SUPER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h new file mode 100644 index 0000000..918e1b5 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionDataTaskDelegate.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionFileDownloadTaskDelegate : PFURLSessionDataTaskDelegate + +@property (nonatomic, copy, readonly) NSString *targetFilePath; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + targetFilePath:(NSString *)targetFilePath + progressBlock:(nullable PFProgressBlock)progressBlock; ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + targetFilePath:(NSString *)targetFilePath + progressBlock:(nullable PFProgressBlock)progressBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m new file mode 100644 index 0000000..d770267 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionFileDownloadTaskDelegate.h" + +#import "PFErrorUtilities.h" +#import "PFHash.h" +#import "PFURLSessionDataTaskDelegate_Private.h" + +@interface PFURLSessionFileDownloadTaskDelegate () { + NSOutputStream *_fileDataOutputStream; + PFProgressBlock _progressBlock; +} + +@end + +@implementation PFURLSessionFileDownloadTaskDelegate + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(BFCancellationToken *)cancellationToken + targetFilePath:(NSString *)targetFilePath + progressBlock:(PFProgressBlock)progressBlock { + self = [super initForDataTask:dataTask withCancellationToken:cancellationToken]; + if (!self) return nil; + + _targetFilePath = targetFilePath; + _fileDataOutputStream = [NSOutputStream outputStreamToFileAtPath:_targetFilePath append:NO]; + _progressBlock = progressBlock; + + return self; +} + ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(BFCancellationToken *)cancellationToken + targetFilePath:(NSString *)targetFilePath + progressBlock:(PFProgressBlock)progressBlock { + return [[self alloc] initForDataTask:dataTask + withCancellationToken:cancellationToken + targetFilePath:targetFilePath + progressBlock:progressBlock]; +} + +///-------------------------------------- +#pragma mark - Progress +///-------------------------------------- + +- (void)_reportProgress { + if (!_progressBlock) { + return; + } + + int progress = (int)(self.downloadedBytes / (CGFloat)self.response.expectedContentLength * 100); + _progressBlock(progress); +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSOutputStream *)dataOutputStream { + return _fileDataOutputStream; +} + +///-------------------------------------- +#pragma mark - Task +///-------------------------------------- + +- (void)_taskDidFinish { + if (self.error) { + // TODO: (nlutsenko) Unify this with code from PFURLSessionJSONDataTaskDelegate + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + errorDictionary[@"code"] = @(kPFErrorConnectionFailed); + errorDictionary[@"error"] = [self.error localizedDescription]; + errorDictionary[@"originalError"] = self.error; + errorDictionary[NSUnderlyingErrorKey] = self.error; + errorDictionary[@"temporary"] = @(self.response.statusCode >= 500 || self.response.statusCode < 400); + self.error = [PFErrorUtilities errorFromResult:errorDictionary]; + } + [super _taskDidFinish]; +} + +///-------------------------------------- +#pragma mark - NSURLSessionDataDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + [super URLSession:session dataTask:dataTask didReceiveData:data]; + [self _reportProgress]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h new file mode 100644 index 0000000..66a06d1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionDataTaskDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionJSONDataTaskDelegate : PFURLSessionDataTaskDelegate + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m new file mode 100644 index 0000000..f10eac3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionJSONDataTaskDelegate.h" + +#import +#import +#import + +#import "PFCommandResult.h" +#import "PFConstants.h" +#import "PFErrorUtilities.h" +#import "PFMacros.h" +#import "PFURLSessionDataTaskDelegate_Private.h" + +@interface PFURLSessionJSONDataTaskDelegate () + +@end + +@implementation PFURLSessionJSONDataTaskDelegate + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (void)_taskDidFinish { + NSData *data = [self.dataOutputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + + id result = nil; + + NSError *jsonError = nil; + if (data) { + self.responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + result = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&jsonError]; + + if (jsonError && !self.error) { + self.error = jsonError; + [super _taskDidFinish]; + return; + } + } + + if (self.error) { + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + errorDictionary[@"code"] = @(kPFErrorConnectionFailed); + errorDictionary[@"originalError"] = self.error; + errorDictionary[NSUnderlyingErrorKey] = self.error; + errorDictionary[@"temporary"] = @(self.response.statusCode >= 500 || self.response.statusCode < 400); + + NSString *description = [self.error localizedDescription] ?: [self.error localizedFailureReason]; + if (description) { + errorDictionary[@"error"] = description; + } + + self.error = [PFErrorUtilities errorFromResult:errorDictionary]; + [super _taskDidFinish]; + return; + } + + if (self.response.statusCode >= 200) { + if (self.response.statusCode < 400) { + PFCommandResult *commandResult = [PFCommandResult commandResultWithResult:result + resultString:self.responseString + httpResponse:self.response]; + self.result = commandResult; + } else if ([result isKindOfClass:[NSDictionary class]]) { + NSDictionary *resultDictionary = (NSDictionary *)result; + if (resultDictionary[@"error"]) { + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionaryWithDictionary:resultDictionary]; + errorDictionary[@"temporary"] = @(self.response.statusCode >= 500 || self.response.statusCode < 400); + self.error = [PFErrorUtilities errorFromResult:errorDictionary]; + } + } + } + + if (!self.result && !self.error) { + self.error = [PFErrorUtilities errorWithCode:kPFErrorInternalServer message:self.responseString]; + } + [super _taskDidFinish]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h new file mode 100644 index 0000000..d08225f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionJSONDataTaskDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLSessionUploadTaskDelegate : PFURLSessionJSONDataTaskDelegate + +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + uploadProgressBlock:(nullable PFProgressBlock)progressBlock; ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + uploadProgressBlock:(nullable PFProgressBlock)progressBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m new file mode 100644 index 0000000..8cf9698 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLSessionUploadTaskDelegate.h" + +@implementation PFURLSessionUploadTaskDelegate { + __nullable PFProgressBlock _progressBlock; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + uploadProgressBlock:(nullable PFProgressBlock)progressBlock { + self = [self initForDataTask:dataTask withCancellationToken:cancellationToken]; + if (!self) return nil; + + _progressBlock = [progressBlock copy]; + + return self; +} + ++ (instancetype)taskDelegateForDataTask:(NSURLSessionDataTask *)dataTask + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + uploadProgressBlock:(nullable PFProgressBlock)progressBlock { + return [[self alloc] initForDataTask:dataTask + withCancellationToken:cancellationToken + uploadProgressBlock:progressBlock]; +} + +///-------------------------------------- +#pragma mark - NSURLSessionTaskDelegate +///-------------------------------------- + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent +totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + int progress = (int)round(totalBytesSent / (CGFloat)totalBytesExpectedToSend * 100); + dispatch_async(dispatch_get_main_queue(), ^{ + if (_progressBlock) { + _progressBlock(progress); + } + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.h new file mode 100644 index 0000000..585b141 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const PFRESTAnalyticsEventNameAppOpened; +extern NSString *const PFRESTAnalyticsEventNameCrashReport; + +@interface PFRESTAnalyticsCommand : PFRESTCommand + ++ (instancetype)trackAppOpenedEventCommandWithPushHash:(nullable NSString *)pushHash + sessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)trackEventCommandWithEventName:(NSString *)eventName + dimensions:(nullable NSDictionary *)dimensions + sessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)trackCrashReportCommandWithBreakpadDumpParameters:(NSDictionary *)parameters + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.m new file mode 100644 index 0000000..6badd35 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTAnalyticsCommand.m @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTAnalyticsCommand.h" + +#import "PFHTTPRequest.h" + +/** + * Predefined events - AppOpened, CrashReport + * Coming soon - Log, ... + */ +NSString *const PFRESTAnalyticsEventNameAppOpened = @"AppOpened"; +NSString *const PFRESTAnalyticsEventNameCrashReport = @"_CrashReport"; + +@implementation PFRESTAnalyticsCommand + ++ (instancetype)trackAppOpenedEventCommandWithPushHash:(NSString *)pushHash + sessionToken:(NSString *)sessionToken { + NSDictionary *parameters = (pushHash ? @{ @"push_hash" : pushHash } : nil); + return [self _trackEventCommandWithEventName:PFRESTAnalyticsEventNameAppOpened + parameters:parameters + sessionToken:sessionToken]; +} + ++ (instancetype)trackEventCommandWithEventName:(NSString *)eventName + dimensions:(NSDictionary *)dimensions + sessionToken:(NSString *)sessionToken { + NSDictionary *parameters = (dimensions ? @{ @"dimensions" : dimensions } : nil); + return [self _trackEventCommandWithEventName:eventName parameters:parameters sessionToken:sessionToken]; +} + ++ (instancetype)trackCrashReportCommandWithBreakpadDumpParameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + return [self _trackEventCommandWithEventName:PFRESTAnalyticsEventNameCrashReport + parameters:@{ @"breakpadDump" : parameters } + sessionToken:sessionToken]; +} + ++ (instancetype)_trackEventCommandWithEventName:(NSString *)eventName + parameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + NSString *httpPath = [NSString stringWithFormat:@"events/%@", eventName]; + + NSMutableDictionary *dictionary = (parameters ? [parameters mutableCopy] : [NSMutableDictionary dictionary]); + if (!dictionary[@"at"]) { + dictionary[@"at"] = [NSDate date]; + } + + return [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodPOST + parameters:dictionary + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.h new file mode 100644 index 0000000..b15bf7a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTCloudCommand : PFRESTCommand + ++ (instancetype)commandForFunction:(NSString *)function + withParameters:(nullable NSDictionary *)parameters + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.m new file mode 100644 index 0000000..5bd85a9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCloudCommand.m @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCloudCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" + +@implementation PFRESTCloudCommand + ++ (instancetype)commandForFunction:(NSString *)function + withParameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + NSString *path = [NSString stringWithFormat:@"functions/%@", function]; + return [self commandWithHTTPPath:path + httpMethod:PFHTTPRequestMethodPOST + parameters:parameters + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.h new file mode 100644 index 0000000..0e6ad3e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFNetworkCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTCommand : NSObject + +@property (nonatomic, copy, readonly) NSString *httpPath; +@property (nonatomic, copy, readonly) NSString *httpMethod; + +@property (nullable, nonatomic, copy, readonly) NSDictionary *parameters; +@property (nullable, nonatomic, copy) NSDictionary *additionalRequestHeaders; + +@property (nonatomic, copy, readonly) NSString *cacheKey; + +@property (nullable, nonatomic, copy) NSString *localId; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + ++ (instancetype)commandWithHTTPPath:(NSString *)path + httpMethod:(NSString *)httpMethod + parameters:(nullable NSDictionary *)parameters + sessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)commandWithHTTPPath:(NSString *)path + httpMethod:(NSString *)httpMethod + parameters:(nullable NSDictionary *)parameters + operationSetUUID:(nullable NSString *)operationSetIdentifier + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.m new file mode 100644 index 0000000..b9460fa --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand.m @@ -0,0 +1,230 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" +#import "PFRESTCommand_Private.h" + +#import "PFAssert.h" +#import "PFCoreManager.h" +#import "PFFieldOperation.h" +#import "PFHTTPRequest.h" +#import "PFHash.h" +#import "PFInternalUtils.h" +#import "PFObjectLocalIdStore.h" +#import "PFObjectPrivate.h" +#import "Parse_Private.h" + +static NSString *const PFRESTCommandHTTPPathEncodingKey = @"httpPath"; +static NSString *const PFRESTCommandHTTPMethodEncodingKey = @"httpMethod"; +static NSString *const PFRESTCommandParametersEncodingKey = @"parameters"; +static NSString *const PFRESTCommandSessionTokenEncodingKey = @"sessionToken"; +static NSString *const PFRESTCommandLocalIdEncodingKey = @"localId"; + +// Increment this when you change the format of cache values. +static const int PFRESTCommandCacheKeyVersion = 1; + +@implementation PFRESTCommand + +@synthesize sessionToken = _sessionToken; +@synthesize operationSetUUID = _operationSetUUID; +@synthesize localId = _localId; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)commandWithHTTPPath:(NSString *)path + httpMethod:(NSString *)httpMethod + parameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + return [self commandWithHTTPPath:path + httpMethod:httpMethod + parameters:parameters + operationSetUUID:nil + sessionToken:sessionToken]; +} + ++ (instancetype)commandWithHTTPPath:(NSString *)path + httpMethod:(NSString *)httpMethod + parameters:(NSDictionary *)parameters + operationSetUUID:(NSString *)operationSetIdentifier + sessionToken:(NSString *)sessionToken { + PFRESTCommand *command = [[self alloc] init]; + command.httpPath = path; + command.httpMethod = httpMethod; + command.parameters = parameters; + command.operationSetUUID = operationSetIdentifier; + command.sessionToken = sessionToken; + return command; +} + +///-------------------------------------- +#pragma mark - CacheKey +///-------------------------------------- + +- (NSString *)cacheKey { + if (_cacheKey) { + return _cacheKey; + } + + NSMutableDictionary *cacheParameters = [NSMutableDictionary dictionaryWithCapacity:2]; + if (self.parameters) { + cacheParameters[PFRESTCommandParametersEncodingKey] = self.parameters; + } + if (self.sessionToken) { + cacheParameters[PFRESTCommandSessionTokenEncodingKey] = self.sessionToken; + } + + NSString *parametersCacheKey = [PFInternalUtils cacheKeyForObject:cacheParameters]; + + _cacheKey = [NSString stringWithFormat:@"PFRESTCommand.%i.%@.%@.%ld.%@", + PFRESTCommandCacheKeyVersion, self.httpMethod, PFMD5HashFromString(self.httpPath), + // We use MD5 instead of native hash because it collides too much. + (long)PARSE_API_VERSION, PFMD5HashFromString(parametersCacheKey)]; + return _cacheKey; +} + +///-------------------------------------- +#pragma mark - PFNetworkCommand +///-------------------------------------- + +#pragma mark Encoding/Decoding + ++ (instancetype)commandFromDictionaryRepresentation:(NSDictionary *)dictionary { + if (![self isValidDictionaryRepresentation:dictionary]) { + return nil; + } + + PFRESTCommand *command = [self commandWithHTTPPath:dictionary[PFRESTCommandHTTPPathEncodingKey] + httpMethod:dictionary[PFRESTCommandHTTPMethodEncodingKey] + parameters:dictionary[PFRESTCommandParametersEncodingKey] + sessionToken:dictionary[PFRESTCommandSessionTokenEncodingKey]]; + command.localId = dictionary[PFRESTCommandLocalIdEncodingKey]; + return command; +} + +- (NSDictionary *)dictionaryRepresentation { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + if (self.httpPath) { + dictionary[PFRESTCommandHTTPPathEncodingKey] = self.httpPath; + } + if (self.httpMethod) { + dictionary[PFRESTCommandHTTPMethodEncodingKey] = self.httpMethod; + } + if (self.parameters) { + NSDictionary *parameters = [[PFPointerOrLocalIdObjectEncoder objectEncoder] encodeObject:self.parameters]; + dictionary[PFRESTCommandParametersEncodingKey] = parameters; + } + if (self.sessionToken) { + dictionary[PFRESTCommandSessionTokenEncodingKey] = self.sessionToken; + } + if (self.localId) { + dictionary[PFRESTCommandLocalIdEncodingKey] = self.localId; + } + return [dictionary copy]; +} + ++ (BOOL)isValidDictionaryRepresentation:(NSDictionary *)dictionary { + return dictionary[PFRESTCommandHTTPPathEncodingKey] != nil; +} + +#pragma mark Local Identifiers + +/*! + If this was the second save on a new object while offline, then its objectId + wasn't yet set when the command was created, so it would have been considered a + "create". But if the first save succeeded, then there is an objectId now, and it + will be mapped to the localId for this command's result. If so, change the + "create" operation to an "update", and add the objectId to the command. + */ +- (void)maybeChangeServerOperation { + if (self.localId) { + NSString *objectId = [[Parse _currentManager].coreManager.objectLocalIdStore objectIdForLocalId:self.localId]; + if (objectId) { + self.localId = nil; + + NSArray *components = [self.httpPath pathComponents]; + if ([components count] == 2) { + self.httpPath = [NSString pathWithComponents:[components arrayByAddingObject:objectId]]; + } + + if ([self.httpPath hasPrefix:@"classes"] && + [self.httpMethod isEqualToString:PFHTTPRequestMethodPOST]) { + self.httpMethod = PFHTTPRequestMethodPUT; + } + } + + PFConsistencyAssert(![self.httpMethod isEqualToString:PFHTTPRequestMethodDELETE] || objectId, + @"Attempt to delete non-existent object."); + } +} + ++ (BOOL)forEachLocalIdIn:(id)object doBlock:(BOOL(^)(PFObject *pointer))block { + __block BOOL modified = NO; + + // If this is a Pointer with a local id, try to resolve it. + if ([object isKindOfClass:[PFObject class]] && !((PFObject *)object).objectId) { + return block(object); + } + + if ([object isKindOfClass:[NSDictionary class]]) { + [object enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + if ([[self class] forEachLocalIdIn:obj doBlock:block]) { + modified = YES; + } + }]; + } else if ([object isKindOfClass:[NSArray class]]) { + for (id value in object) { + if ([[self class] forEachLocalIdIn:value doBlock:block]) { + modified = YES; + } + } + } else if ([object isKindOfClass:[PFAddOperation class]]) { + for (id value in ((PFAddOperation *)object).objects) { + if ([[self class] forEachLocalIdIn:value doBlock:block]) { + modified = YES; + } + } + } else if ([object isKindOfClass:[PFAddUniqueOperation class]]) { + for (id value in ((PFAddUniqueOperation *)object).objects) { + if ([[self class] forEachLocalIdIn:value doBlock:block]) { + modified = YES; + } + } + } else if ([object isKindOfClass:[PFRemoveOperation class]]) { + for (id value in ((PFRemoveOperation *)object).objects) { + if ([[self class] forEachLocalIdIn:value doBlock:block]) { + modified = YES; + } + } + } + + return modified; +} + +- (void)forEachLocalId:(BOOL(^)(PFObject *pointer))block { + NSDictionary *data = [[PFDecoder objectDecoder] decodeObject:self.parameters]; + if (!data) { + return; + } + + if ([[self class] forEachLocalIdIn:data doBlock:block]) { + self.parameters = [[PFPointerOrLocalIdObjectEncoder objectEncoder] encodeObject:data]; + } +} + +- (void)resolveLocalIds { + [self forEachLocalId:^(PFObject *pointer) { + [pointer resolveLocalId]; + return YES; + }]; + [self maybeChangeServerOperation]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand_Private.h new file mode 100644 index 0000000..f3d1e4e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTCommand_Private.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +@interface PFRESTCommand () + +@property (nonatomic, copy, readwrite) NSString *sessionToken; + +@property (nonatomic, copy, readwrite) NSString *httpPath; +@property (nonatomic, copy, readwrite) NSString *httpMethod; + +@property (nonatomic, copy, readwrite) NSDictionary *parameters; + +@property (nonatomic, copy, readwrite) NSString *cacheKey; + +@property (nonatomic, copy, readwrite) NSString *operationSetUUID; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.h new file mode 100644 index 0000000..7b52307 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTConfigCommand : PFRESTCommand + ++ (instancetype)configFetchCommandWithSessionToken:(nullable NSString *)sessionToken; ++ (instancetype)configUpdateCommandWithConfigParameters:(NSDictionary *)parameters + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.m new file mode 100644 index 0000000..6709990 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTConfigCommand.m @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTConfigCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" + +@implementation PFRESTConfigCommand + ++ (instancetype)configFetchCommandWithSessionToken:(NSString *)sessionToken { + return [self commandWithHTTPPath:@"config" + httpMethod:PFHTTPRequestMethodGET + parameters:nil + sessionToken:sessionToken]; +} + ++ (instancetype)configUpdateCommandWithConfigParameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + NSDictionary *commandParameters = @{ @"params" : parameters }; + return [self commandWithHTTPPath:@"config" + httpMethod:PFHTTPRequestMethodPUT + parameters:commandParameters + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.h new file mode 100644 index 0000000..770b258 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTFileCommand : PFRESTCommand + ++ (instancetype)uploadCommandForFileWithName:(NSString *)fileName + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.m new file mode 100644 index 0000000..1de7cc9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTFileCommand.m @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTFileCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" + +@implementation PFRESTFileCommand + ++ (instancetype)uploadCommandForFileWithName:(NSString *)fileName + sessionToken:(NSString *)sessionToken { + NSMutableString *httpPath = [@"files/" mutableCopy]; + if (fileName) { + [httpPath appendString:fileName]; + } + return [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodPOST + parameters:nil + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.h new file mode 100644 index 0000000..8b28e34 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +extern NSUInteger const PFRESTObjectBatchCommandSubcommandsLimit; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTObjectBatchCommand : PFRESTCommand + ++ (instancetype)batchCommandWithCommands:(NSArray *)commands sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.m new file mode 100644 index 0000000..7aa407f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectBatchCommand.m @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTObjectBatchCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" + +NSUInteger const PFRESTObjectBatchCommandSubcommandsLimit = 50; + +@implementation PFRESTObjectBatchCommand + ++ (nonnull instancetype)batchCommandWithCommands:(NSArray *)commands + sessionToken:(NSString *)sessionToken { + PFParameterAssert([commands count] <= PFRESTObjectBatchCommandSubcommandsLimit, + @"Max of %d commands are allowed in a single batch command", + (int)PFRESTObjectBatchCommandSubcommandsLimit); + + NSMutableArray *requests = [NSMutableArray arrayWithCapacity:[commands count]]; + for (PFRESTCommand *command in commands) { + NSMutableDictionary *requestDictionary = [@{ @"method" : command.httpMethod, + @"path" : [NSString stringWithFormat:@"/1/%@", command.httpPath] + } mutableCopy]; + if (command.parameters) { + requestDictionary[@"body"] = command.parameters; + } + + [requests addObject:requestDictionary]; + } + return [self commandWithHTTPPath:@"batch" + httpMethod:PFHTTPRequestMethodPOST + parameters:@{ @"requests" : requests } + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.h new file mode 100644 index 0000000..67a8ff4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@class PFObjectState; + +@interface PFRESTObjectCommand : PFRESTCommand + ++ (instancetype)fetchObjectCommandForObjectState:(PFObjectState *)state + withSessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)createObjectCommandForObjectState:(PFObjectState *)state + changes:(nullable NSDictionary *)changes + operationSetUUID:(nullable NSString *)operationSetIdentifier + sessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)updateObjectCommandForObjectState:(PFObjectState *)state + changes:(nullable NSDictionary *)changes + operationSetUUID:(nullable NSString *)operationSetIdentifier + sessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)deleteObjectCommandForObjectState:(PFObjectState *)state + withSessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.m new file mode 100644 index 0000000..964273e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTObjectCommand.m @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTObjectCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" +#import "PFObjectState.h" + +@implementation PFRESTObjectCommand + ++ (instancetype)fetchObjectCommandForObjectState:(PFObjectState *)state + withSessionToken:(NSString *)sessionToken { + PFParameterAssert(state.objectId.length, @"objectId should be non nil"); + PFParameterAssert(state.parseClassName.length, @"Class name should be non nil"); + + NSString *httpPath = [NSString stringWithFormat:@"classes/%@/%@", state.parseClassName, state.objectId]; + PFRESTObjectCommand *command = [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodGET + parameters:nil + sessionToken:sessionToken]; + return command; +} + ++ (instancetype)createObjectCommandForObjectState:(PFObjectState *)state + changes:(NSDictionary *)changes + operationSetUUID:(NSString *)operationSetIdentifier + sessionToken:(NSString *)sessionToken { + PFParameterAssert(state.parseClassName.length, @"Class name should be non nil"); + + NSString *httpPath = [NSString stringWithFormat:@"classes/%@", state.parseClassName]; + PFRESTObjectCommand *command = [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodPOST + parameters:changes + operationSetUUID:operationSetIdentifier + sessionToken:sessionToken]; + return command; +} + ++ (instancetype)updateObjectCommandForObjectState:(PFObjectState *)state + changes:(NSDictionary *)changes + operationSetUUID:(NSString *)operationSetIdentifier + sessionToken:(NSString *)sessionToken { + PFParameterAssert(state.parseClassName.length, @"Class name should be non nil"); + PFParameterAssert(state.objectId.length, @"objectId should be non nil"); + + NSString *httpPath = [NSString stringWithFormat:@"classes/%@/%@", state.parseClassName, state.objectId]; + PFRESTObjectCommand *command = [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodPUT + parameters:changes + operationSetUUID:operationSetIdentifier + sessionToken:sessionToken]; + return command; +} + ++ (instancetype)deleteObjectCommandForObjectState:(PFObjectState *)state + withSessionToken:(NSString *)sessionToken { + PFParameterAssert(state.parseClassName.length, @"Class name should be non nil"); + + NSMutableString *httpPath = [NSMutableString stringWithFormat:@"classes/%@", state.parseClassName]; + if (state.objectId) { + [httpPath appendFormat:@"/%@", state.objectId]; + } + PFRESTObjectCommand *command = [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodDELETE + parameters:nil + sessionToken:sessionToken]; + return command; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.h new file mode 100644 index 0000000..d58965d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +#import + +@class PFPushState; + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFRESTPushCommand : PFRESTCommand + ++ (instancetype)sendPushCommandWithPushState:(PFPushState *)state + sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.m new file mode 100644 index 0000000..2f7601e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTPushCommand.m @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTPushCommand.h" + +#import "PFAssert.h" +#import "PFDateFormatter.h" +#import "PFHTTPRequest.h" +#import "PFInternalUtils.h" +#import "PFPushState.h" +#import "PFQueryState.h" +#import "PFRESTQueryCommand.h" + +@implementation PFRESTPushCommand + ++ (instancetype)sendPushCommandWithPushState:(PFPushState *)state + sessionToken:(NSString *)sessionToken { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + + if (state.queryState) { + NSDictionary *queryParameters = [PFRESTQueryCommand findCommandParametersForQueryState:state.queryState]; + parameters[@"where"] = queryParameters[@"where"]; + } else { + if (state.channels) { + parameters[@"channels"] = [state.channels allObjects]; + } + } + + // If there are no conditions set, then push to everyone by specifying empty query conditions. + if ([parameters count] == 0) { + parameters[@"where"] = @{}; + } + + if (state.expirationDate) { + parameters[@"expiration_time"] = [[PFDateFormatter sharedFormatter] preciseStringFromDate:state.expirationDate]; + } else if (state.expirationTimeInterval) { + parameters[@"expiration_interval"] = state.expirationTimeInterval; + } + + // TODO (nlutsenko): Probably we need an assert here, as there is no reason to send push without message + if (state.payload) { + parameters[@"data"] = state.payload; + } + + return [self commandWithHTTPPath:@"push" + httpMethod:PFHTTPRequestMethodPOST + parameters:parameters + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.h new file mode 100644 index 0000000..a77a66f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +@class PFQueryState; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTQueryCommand : PFRESTCommand + +///-------------------------------------- +/// @name Find +///-------------------------------------- + ++ (instancetype)findCommandForQueryState:(PFQueryState *)queryState withSessionToken:(nullable NSString *)sessionToken; + ++ (instancetype)findCommandForClassWithName:(NSString *)className + order:(nullable NSString *)order + conditions:(nullable NSDictionary *)conditions + selectedKeys:(nullable NSSet *)selectedKeys + includedKeys:(nullable NSSet *)includedKeys + limit:(NSInteger)limit + skip:(NSInteger)skip + extraOptions:(nullable NSDictionary *)extraOptions + tracingEnabled:(BOOL)trace + sessionToken:(nullable NSString *)sessionToken; + +///-------------------------------------- +/// @name Count +///-------------------------------------- + ++ (instancetype)countCommandFromFindCommand:(PFRESTQueryCommand *)findCommand; + +///-------------------------------------- +/// @name Parameters +///-------------------------------------- + ++ (NSDictionary *)findCommandParametersForQueryState:(PFQueryState *)queryState; ++ (NSDictionary *)findCommandParametersWithOrder:(nullable NSString *)order + conditions:(nullable NSDictionary *)conditions + selectedKeys:(nullable NSSet *)selectedKeys + includedKeys:(nullable NSSet *)includedKeys + limit:(NSInteger)limit + skip:(NSInteger)skip + extraOptions:(nullable NSDictionary *)extraOptions + tracingEnabled:(BOOL)trace; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.m new file mode 100644 index 0000000..bf90f49 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTQueryCommand.m @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTQueryCommand.h" + +#import "PFAssert.h" +#import "PFEncoder.h" +#import "PFHTTPRequest.h" +#import "PFQueryPrivate.h" +#import "PFQueryState.h" + +@implementation PFRESTQueryCommand + +///-------------------------------------- +#pragma mark - Find +///-------------------------------------- + ++ (instancetype)findCommandForQueryState:(PFQueryState *)queryState withSessionToken:(NSString *)sessionToken { + NSDictionary *parameters = [self findCommandParametersForQueryState:queryState]; + return [self _findCommandForClassWithName:queryState.parseClassName + parameters:parameters + sessionToken:sessionToken]; +} + ++ (instancetype)findCommandForClassWithName:(NSString *)className + order:(NSString *)order + conditions:(NSDictionary *)conditions + selectedKeys:(NSSet *)selectedKeys + includedKeys:(NSSet *)includedKeys + limit:(NSInteger)limit + skip:(NSInteger)skip + extraOptions:(NSDictionary *)extraOptions + tracingEnabled:(BOOL)trace + sessionToken:(NSString *)sessionToken { + NSDictionary *parameters = [self findCommandParametersWithOrder:order + conditions:conditions + selectedKeys:selectedKeys + includedKeys:includedKeys + limit:limit + skip:skip + extraOptions:extraOptions + tracingEnabled:trace]; + return [self _findCommandForClassWithName:className + parameters:parameters + sessionToken:sessionToken]; +} + ++ (instancetype)_findCommandForClassWithName:(NSString *)className + parameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken { + NSString *httpPath = [NSString stringWithFormat:@"classes/%@", className]; + PFRESTQueryCommand *command = [self commandWithHTTPPath:httpPath + httpMethod:PFHTTPRequestMethodGET + parameters:parameters + sessionToken:sessionToken]; + return command; +} + +///-------------------------------------- +#pragma mark - Count +///-------------------------------------- + ++ (instancetype)countCommandFromFindCommand:(PFRESTQueryCommand *)findCommand { + NSMutableDictionary *parameters = [findCommand.parameters mutableCopy]; + parameters[@"count"] = @"1"; + parameters[@"limit"] = @"0"; // Set the limit to 0, as we are not interested in results at all. + [parameters removeObjectForKey:@"skip"]; + + return [self commandWithHTTPPath:findCommand.httpPath + httpMethod:findCommand.httpMethod + parameters:[parameters copy] + sessionToken:findCommand.sessionToken]; +} + +///-------------------------------------- +#pragma mark - Parameters +///-------------------------------------- + ++ (NSDictionary *)findCommandParametersForQueryState:(PFQueryState *)queryState { + return [self findCommandParametersWithOrder:queryState.sortOrderString + conditions:queryState.conditions + selectedKeys:queryState.selectedKeys + includedKeys:queryState.includedKeys + limit:queryState.limit + skip:queryState.skip + extraOptions:queryState.extraOptions + tracingEnabled:queryState.trace]; +} + ++ (NSDictionary *)findCommandParametersWithOrder:(NSString *)order + conditions:(NSDictionary *)conditions + selectedKeys:(NSSet *)selectedKeys + includedKeys:(NSSet *)includedKeys + limit:(NSInteger)limit + skip:(NSInteger)skip + extraOptions:(NSDictionary *)extraOptions + tracingEnabled:(BOOL)trace { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + + if ([order length]) { + parameters[@"order"] = order; + } + if (selectedKeys != nil) { + parameters[@"keys"] = [[selectedKeys allObjects] componentsJoinedByString:@","]; + } + if ([includedKeys count] > 0) { + parameters[@"include"] = [[includedKeys allObjects] componentsJoinedByString:@","]; + } + if (limit >= 0) { + parameters[@"limit"] = [NSString stringWithFormat:@"%d", (int)limit]; + } + if (skip > 0) { + parameters[@"skip"] = [NSString stringWithFormat:@"%d", (int)skip]; + } + if (trace) { + // TODO: (nlutsenko) Double check that tracing still works. Maybe create test for it. + parameters[@"trace"] = @"1"; + } + [extraOptions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + parameters[key] = obj; + }]; + + if ([conditions count] > 0) { + NSMutableDictionary *whereData = [[NSMutableDictionary alloc] init]; + [conditions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([key isEqualToString:@"$or"]) { + NSArray *array = (NSArray *)obj; + NSMutableArray *newArray = [NSMutableArray array]; + for (PFQuery *subquery in array) { + // TODO: (nlutsenko) Move this validation into PFQuery/PFQueryState. + PFParameterAssert(subquery.state.limit < 0, @"OR queries do not support sub queries with limits"); + PFParameterAssert(subquery.state.skip == 0, @"OR queries do not support sub queries with skip"); + PFParameterAssert(subquery.state.sortKeys.count == 0, @"OR queries do not support sub queries with order"); + PFParameterAssert(subquery.state.includedKeys.count == 0, @"OR queries do not support sub-queries with includes"); + PFParameterAssert(subquery.state.selectedKeys == nil, @"OR queries do not support sub-queries with selectKeys"); + + NSDictionary *queryDict = [self findCommandParametersWithOrder:subquery.state.sortOrderString + conditions:subquery.state.conditions + selectedKeys:subquery.state.selectedKeys + includedKeys:subquery.state.includedKeys + limit:subquery.state.limit + skip:subquery.state.skip + extraOptions:nil + tracingEnabled:NO]; + + queryDict = queryDict[@"where"]; + if ([queryDict count] > 0) { + [newArray addObject:queryDict]; + } else { + [newArray addObject:[NSDictionary dictionary]]; + } + } + whereData[key] = newArray; + } else { + id object = [self _encodeSubqueryIfNeeded:obj]; + whereData[key] = [[PFPointerObjectEncoder objectEncoder] encodeObject:object]; + } + }]; + + parameters[@"where"] = whereData; + } + + return parameters; +} + ++ (id)_encodeSubqueryIfNeeded:(id)object { + if (![object isKindOfClass:[NSDictionary class]]) { + return object; + } + + NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithCapacity:[object count]]; + [object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([obj isKindOfClass:[PFQuery class]]) { + PFQuery *subquery = (PFQuery *)obj; + NSMutableDictionary *subqueryParameters = [[self findCommandParametersWithOrder:subquery.state.sortOrderString + conditions:subquery.state.conditions + selectedKeys:subquery.state.selectedKeys + includedKeys:subquery.state.includedKeys + limit:subquery.state.limit + skip:subquery.state.skip + extraOptions:subquery.state.extraOptions + tracingEnabled:NO] mutableCopy]; + subqueryParameters[@"className"] = subquery.parseClassName; + obj = subqueryParameters; + } else if ([obj isKindOfClass:[NSDictionary class]]) { + obj = [self _encodeSubqueryIfNeeded:obj]; + } + + parameters[key] = obj; + }]; + return parameters; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.h new file mode 100644 index 0000000..d777b04 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTSessionCommand : PFRESTCommand + ++ (instancetype)getCurrentSessionCommandWithSessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.m new file mode 100644 index 0000000..c38bd1c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTSessionCommand.m @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTSessionCommand.h" + +#import "PFHTTPRequest.h" + +@implementation PFRESTSessionCommand + ++ (instancetype)getCurrentSessionCommandWithSessionToken:(nullable NSString *)sessionToken { + return [self commandWithHTTPPath:@"sessions/me" + httpMethod:PFHTTPRequestMethodGET + parameters:nil + sessionToken:sessionToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.h new file mode 100644 index 0000000..93c81db --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTCommand.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFRESTUserCommand : PFRESTCommand + +@property (nonatomic, assign, readonly) BOOL revocableSessionEnabled; + +///-------------------------------------- +/// @name Log In +///-------------------------------------- + ++ (instancetype)logInUserCommandWithUsername:(NSString *)username + password:(NSString *)password + revocableSession:(BOOL)revocableSessionEnabled; ++ (instancetype)serviceLoginUserCommandWithAuthenticationType:(NSString *)authenticationType + authenticationData:(NSDictionary *)authenticationData + revocableSession:(BOOL)revocableSessionEnabled; ++ (instancetype)serviceLoginUserCommandWithParameters:(NSDictionary *)parameters + revocableSession:(BOOL)revocableSessionEnabled + sessionToken:(nullable NSString *)sessionToken; + +///-------------------------------------- +/// @name Sign Up +///-------------------------------------- + ++ (instancetype)signUpUserCommandWithParameters:(NSDictionary *)parameters + revocableSession:(BOOL)revocableSessionEnabled + sessionToken:(nullable NSString *)sessionToken; + +///-------------------------------------- +/// @name Current User +///-------------------------------------- + ++ (instancetype)getCurrentUserCommandWithSessionToken:(NSString *)sessionToken; ++ (instancetype)upgradeToRevocableSessionCommandWithSessionToken:(NSString *)sessionToken; ++ (instancetype)logOutUserCommandWithSessionToken:(NSString *)sessionToken; + +///-------------------------------------- +/// @name Password Rest +///-------------------------------------- + ++ (instancetype)resetPasswordCommandForUserWithEmail:(NSString *)email; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.m new file mode 100644 index 0000000..190a5d5 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Commands/PFRESTUserCommand.m @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRESTUserCommand.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" + +static NSString *const PFRESTUserCommandRevocableSessionHeader = @"X-Parse-Revocable-Session"; +static NSString *const PFRESTUserCommandRevocableSessionHeaderEnabledValue = @"1"; + +@interface PFRESTUserCommand () + +@property (nonatomic, assign, readwrite) BOOL revocableSessionEnabled; + +@end + +@implementation PFRESTUserCommand + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)_commandWithHTTPPath:(NSString *)path + httpMethod:(NSString *)httpMethod + parameters:(NSDictionary *)parameters + sessionToken:(NSString *)sessionToken + revocableSession:(BOOL)revocableSessionEnabled { + PFRESTUserCommand *command = [self commandWithHTTPPath:path + httpMethod:httpMethod + parameters:parameters + sessionToken:sessionToken]; + if (revocableSessionEnabled) { + command.additionalRequestHeaders = @{ PFRESTUserCommandRevocableSessionHeader : + PFRESTUserCommandRevocableSessionHeaderEnabledValue}; + } + command.revocableSessionEnabled = revocableSessionEnabled; + return command; +} + +///-------------------------------------- +#pragma mark - Log In +///-------------------------------------- + ++ (instancetype)logInUserCommandWithUsername:(NSString *)username + password:(NSString *)password + revocableSession:(BOOL)revocableSessionEnabled { + NSDictionary *parameters = @{ @"username" : username, + @"password" : password }; + return [self _commandWithHTTPPath:@"login" + httpMethod:PFHTTPRequestMethodGET + parameters:parameters + sessionToken:nil + revocableSession:revocableSessionEnabled]; +} + ++ (instancetype)serviceLoginUserCommandWithAuthenticationType:(NSString *)authenticationType + authenticationData:(NSDictionary *)authenticationData + revocableSession:(BOOL)revocableSessionEnabled { + NSDictionary *parameters = @{ @"authData" : @{ authenticationType : authenticationData } }; + return [self serviceLoginUserCommandWithParameters:parameters + revocableSession:revocableSessionEnabled + sessionToken:nil]; +} + ++ (instancetype)serviceLoginUserCommandWithParameters:(NSDictionary *)parameters + revocableSession:(BOOL)revocableSessionEnabled + sessionToken:(NSString *)sessionToken { + return [self _commandWithHTTPPath:@"users" + httpMethod:PFHTTPRequestMethodPOST + parameters:parameters + sessionToken:sessionToken + revocableSession:revocableSessionEnabled]; +} + +///-------------------------------------- +#pragma mark - Sign Up +///-------------------------------------- + ++ (instancetype)signUpUserCommandWithParameters:(NSDictionary *)parameters + revocableSession:(BOOL)revocableSessionEnabled + sessionToken:(NSString *)sessionToken { + return [self _commandWithHTTPPath:@"users" + httpMethod:PFHTTPRequestMethodPOST + parameters:parameters + sessionToken:sessionToken + revocableSession:revocableSessionEnabled]; +} + +///-------------------------------------- +#pragma mark - Current User +///-------------------------------------- + ++ (instancetype)getCurrentUserCommandWithSessionToken:(NSString *)sessionToken { + return [self commandWithHTTPPath:@"users/me" + httpMethod:PFHTTPRequestMethodGET + parameters:nil + sessionToken:sessionToken]; +} + ++ (instancetype)upgradeToRevocableSessionCommandWithSessionToken:(NSString *)sessionToken { + return [self commandWithHTTPPath:@"upgradeToRevocableSession" + httpMethod:PFHTTPRequestMethodPOST + parameters:nil + sessionToken:sessionToken]; +} + ++ (instancetype)logOutUserCommandWithSessionToken:(NSString *)sessionToken { + return [self commandWithHTTPPath:@"logout" + httpMethod:PFHTTPRequestMethodPOST + parameters:nil + sessionToken:sessionToken]; +} + +///-------------------------------------- +#pragma mark - Additional User Commands +///-------------------------------------- + ++ (instancetype)resetPasswordCommandForUserWithEmail:(NSString *)email { + return [self commandWithHTTPPath:@"requestPasswordReset" + httpMethod:PFHTTPRequestMethodPOST + parameters:@{ @"email" : email } + sessionToken:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.h new file mode 100644 index 0000000..1333849 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFConfig; +@class PFCurrentConfigController; +@class PFFileManager; +@protocol PFCommandRunning; + +@interface PFConfigController : NSObject + +@property (nonatomic, strong, readonly) PFFileManager *fileManager; +@property (nonatomic, strong, readonly) id commandRunner; + +@property (nonatomic, strong, readonly) PFCurrentConfigController *currentConfigController; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(PFFileManager *)fileManager + commandRunner:(id)commandRunner NS_DESIGNATED_INITIALIZER; + +///-------------------------------------- +/// @name Fetch +///-------------------------------------- + +/*! + Fetches current config from network async. + + @param sessionToken Current user session token. + + @returns `BFTask` with result set to `PFConfig`. + */ +- (BFTask *)fetchConfigAsyncWithSessionToken:(NSString *)sessionToken; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.m new file mode 100644 index 0000000..ec26b5b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFConfigController.m @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFConfigController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFConfig_Private.h" +#import "PFCurrentConfigController.h" +#import "PFDecoder.h" +#import "PFRESTConfigCommand.h" + +@interface PFConfigController () +{ + dispatch_queue_t _dataAccessQueue; + dispatch_queue_t _networkQueue; + BFExecutor *_networkExecutor; +} + +@end + +@implementation PFConfigController + +@synthesize currentConfigController = _currentConfigController; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithFileManager:(PFFileManager *)fileManager + commandRunner:(id)commandRunner { + self = [super init]; + if (!self) return nil; + + _fileManager = fileManager; + _commandRunner = commandRunner; + + _dataAccessQueue = dispatch_queue_create("com.parse.config.access", DISPATCH_QUEUE_SERIAL); + + _networkQueue = dispatch_queue_create("com.parse.config.network", DISPATCH_QUEUE_SERIAL); + _networkExecutor = [BFExecutor executorWithDispatchQueue:_networkQueue]; + + return self; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BFTask *)fetchConfigAsyncWithSessionToken:(NSString *)sessionToken { + @weakify(self); + return [BFTask taskFromExecutor:_networkExecutor withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTConfigCommand configFetchCommandWithSessionToken:sessionToken]; + return [[[self.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed] + continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + NSDictionary *fetchedConfig = [[PFDecoder objectDecoder] decodeObject:result.result]; + return [[PFConfig alloc] initWithFetchedConfig:fetchedConfig]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // Roll-forward the config. + return [[self.currentConfigController setCurrentConfigAsync:task.result] continueWithResult:task.result]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFCurrentConfigController *)currentConfigController { + __block PFCurrentConfigController *controller = nil; + dispatch_sync(_dataAccessQueue, ^{ + if (!_currentConfigController) { + _currentConfigController = [[PFCurrentConfigController alloc] initWithFileManager:self.fileManager]; + } + controller = _currentConfigController; + }); + return controller; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.h new file mode 100644 index 0000000..0c947c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFConfig; +@class PFFileManager; + +@interface PFCurrentConfigController : NSObject + +@property (nonatomic, strong, readonly) PFFileManager *fileManager; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(PFFileManager *)fileManager NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithFileManager:(PFFileManager *)fileManager; + +///-------------------------------------- +/// @name Accessors +///-------------------------------------- + +- (BFTask *)getCurrentConfigAsync; +- (BFTask *)setCurrentConfigAsync:(PFConfig *)config; + +- (BFTask *)clearCurrentConfigAsync; +- (BFTask *)clearMemoryCachedCurrentConfigAsync; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.m new file mode 100644 index 0000000..1378520 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/Controller/PFCurrentConfigController.m @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCurrentConfigController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFConfig_Private.h" +#import "PFDecoder.h" +#import "PFFileManager.h" +#import "PFJSONSerialization.h" + +static NSString *const PFConfigCurrentConfigFileName_ = @"config"; + +@interface PFCurrentConfigController () { + dispatch_queue_t _dataQueue; + BFExecutor *_dataExecutor; + PFConfig *_currentConfig; +} + +@property (nonatomic, copy, readonly) NSString *configFilePath; + +@end + +@implementation PFCurrentConfigController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithFileManager:(PFFileManager *)fileManager { + self = [super init]; + if (!self) return nil; + + _dataQueue = dispatch_queue_create("com.parse.config.current", DISPATCH_QUEUE_SERIAL); + _dataExecutor = [BFExecutor executorWithDispatchQueue:_dataQueue]; + + _fileManager = fileManager; + + return self; +} + ++ (instancetype)controllerWithFileManager:(PFFileManager *)fileManager { + return [[self alloc] initWithFileManager:fileManager]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (BFTask *)getCurrentConfigAsync { + return [BFTask taskFromExecutor:_dataExecutor withBlock:^id{ + if (!_currentConfig) { + NSDictionary *dictionary = [PFJSONSerialization JSONObjectFromFileAtPath:self.configFilePath]; + if (dictionary) { + NSDictionary *decodedDictionary = [[PFDecoder objectDecoder] decodeObject:dictionary]; + _currentConfig = [[PFConfig alloc] initWithFetchedConfig:decodedDictionary]; + } else { + _currentConfig = [[PFConfig alloc] init]; + } + } + return _currentConfig; + }]; +} + +- (BFTask *)setCurrentConfigAsync:(PFConfig *)config { + @weakify(self); + return [BFTask taskFromExecutor:_dataExecutor withBlock:^id{ + @strongify(self); + _currentConfig = config; + + NSDictionary *configParameters = @{ PFConfigParametersRESTKey : (config.parametersDictionary ?: @{}) }; + id encodedObject = [[PFPointerObjectEncoder objectEncoder] encodeObject:configParameters]; + NSData *jsonData = [PFJSONSerialization dataFromJSONObject:encodedObject]; + return [PFFileManager writeDataAsync:jsonData toFile:self.configFilePath]; + }]; +} + +- (BFTask *)clearCurrentConfigAsync { + @weakify(self); + return [BFTask taskFromExecutor:_dataExecutor withBlock:^id{ + @strongify(self); + _currentConfig = nil; + return [PFFileManager removeItemAtPathAsync:self.configFilePath]; + }]; +} + +- (BFTask *)clearMemoryCachedCurrentConfigAsync { + return [BFTask taskFromExecutor:_dataExecutor withBlock:^id{ + _currentConfig = nil; + return nil; + }]; +} + +- (NSString *)configFilePath { + return [self.fileManager parseDataItemPathForPathComponent:PFConfigCurrentConfigFileName_]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/PFConfig_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/PFConfig_Private.h new file mode 100644 index 0000000..8ea452f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Config/PFConfig_Private.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern NSString *const PFConfigParametersRESTKey; + +@interface PFConfig (Private) + +@property (atomic, copy, readonly) NSDictionary *parametersDictionary; + +- (instancetype)initWithFetchedConfig:(NSDictionary *)config; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.h new file mode 100644 index 0000000..519353d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.h @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEncoder.h" + +@class PFDecoder; +@class PFObject; + +///-------------------------------------- +#pragma mark - PFFieldOperation +///-------------------------------------- + +/*! + A PFFieldOperation represents a modification to a value in a PFObject. + For example, setting, deleting, or incrementing a value are all different + kinds of PFFieldOperations. PFFieldOperations themselves can be considered + to be immutable. + */ +@interface PFFieldOperation : NSObject + +/*! + Converts the PFFieldOperation to a data structure (typically an NSDictionary) + that can be converted to JSON and sent to Parse as part of a save operation. + + @param objectEncoder encoder that will be used to encode the object. + @returns An object to be jsonified. + */ +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder; + +/*! + Returns a field operation that is composed of a previous operation followed by + this operation. This will not mutate either operation. However, it may return + self if the current operation is not affected by previous changes. For example: + [{increment by 2} mergeWithPrevious:{set to 5}] -> {set to 7} + [{set to 5} mergeWithPrevious:{increment by 2}] -> {set to 5} + [{add "foo"} mergeWithPrevious:{delete}] -> {set to ["foo"]} + [{delete} mergeWithPrevious:{add "foo"}] -> {delete} + + @param previous The most recent operation on the field, or nil if none. + @returns A new PFFieldOperation or self. + */ +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous; + +/*! + Returns a new estimated value based on a previous value and this operation. This + value is not intended to be sent to Parse, but it used locally on the client to + inspect the most likely current value for a field. + + The key and object are used solely for PFRelation to be able to construct objects + that refer back to its parent. + + @param oldValue The previous value for the field. + @param key The key that this value is for. + + @returns The new value for the field. + */ +- (id)applyToValue:(id)oldValue forKey:(NSString *)key; + +@end + +///-------------------------------------- +#pragma mark - Independent Operations +///-------------------------------------- + +/*! + An operation where a field is set to a given value regardless of + its previous value. + */ +@interface PFSetOperation : PFFieldOperation + +@property (nonatomic, strong, readonly) id value; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithValue:(id)value NS_DESIGNATED_INITIALIZER; ++ (instancetype)setWithValue:(id)value; + +@end + +/*! + An operation where a field is deleted from the object. + */ +@interface PFDeleteOperation : PFFieldOperation + ++ (instancetype)operation; + +@end + +///-------------------------------------- +#pragma mark - Numeric Operations +///-------------------------------------- + +/*! + An operation that increases a numeric field's value by a given amount. + */ +@interface PFIncrementOperation : PFFieldOperation + +@property (nonatomic, strong, readonly) NSNumber *amount; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithAmount:(NSNumber *)amount NS_DESIGNATED_INITIALIZER; ++ (instancetype)incrementWithAmount:(NSNumber *)amount; + +@end + +///-------------------------------------- +#pragma mark - Array Operations +///-------------------------------------- + +/*! + An operation that adds a new element to an array field. + */ +@interface PFAddOperation : PFFieldOperation + +@property (nonatomic, strong, readonly) NSArray *objects; + ++ (instancetype)addWithObjects:(NSArray *)array; + +@end + +/*! + An operation that adds a new element to an array field, + only if it wasn't already present. + */ +@interface PFAddUniqueOperation : PFFieldOperation + +@property (nonatomic, strong, readonly) NSArray *objects; + ++ (instancetype)addUniqueWithObjects:(NSArray *)array; + +@end + +/*! + An operation that removes every instance of an element from + an array field. + */ +@interface PFRemoveOperation : PFFieldOperation + +@property (nonatomic, strong, readonly) NSArray *objects; + ++ (instancetype)removeWithObjects:(NSArray *)array; + +@end + +///-------------------------------------- +#pragma mark - Relation Operations +///-------------------------------------- + +/*! + An operation where a PFRelation's value is modified. + */ +@interface PFRelationOperation : PFFieldOperation + +@property (nonatomic, copy) NSString *targetClass; +@property (nonatomic, strong) NSMutableSet *relationsToAdd; +@property (nonatomic, strong) NSMutableSet *relationsToRemove; + ++ (instancetype)addRelationToObjects:(NSArray *)targets; ++ (instancetype)removeRelationToObjects:(NSArray *)targets; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.m new file mode 100644 index 0000000..780347f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperation.m @@ -0,0 +1,552 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFieldOperation.h" + +#import "PFAssert.h" +#import "PFDecoder.h" +#import "PFInternalUtils.h" +#import "PFObject.h" +#import "PFOfflineStore.h" +#import "PFRelation.h" +#import "PFRelationPrivate.h" + +///-------------------------------------- +#pragma mark - PFFieldOperation +///-------------------------------------- + +// PFFieldOperation and its subclasses encapsulate operations that can be done on a field. +@implementation PFFieldOperation + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + PFConsistencyAssert(NO, @"Operation is invalid."); + return nil; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + PFConsistencyAssert(NO, @"Operation is invalid."); + return nil; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + PFConsistencyAssert(NO, @"Operation is invalid."); + return nil; +} + +@end + +///-------------------------------------- +#pragma mark - Independent Operations +///-------------------------------------- + +@implementation PFSetOperation + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithValue:(id)value { + self = [super init]; + if (!self) return nil; + + PFParameterAssert(value, @"Cannot set a nil value in a PFObject."); + _value = value; + + return self; +} + ++ (id)setWithValue:(id)newValue { + return [[self alloc] initWithValue:newValue]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"set to %@", self.value]; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + return [objectEncoder encodeObject:self.value]; +} + +- (PFSetOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + return self; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + return self.value; +} + +@end + +@implementation PFDeleteOperation + ++ (instancetype)operation { + return [[self alloc] init]; +} + +- (NSString *)description { + return @"delete"; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + return @{ @"__op" : @"Delete" }; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + return self; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + return nil; +} + +@end + +///-------------------------------------- +#pragma mark - Numeric Operations +///-------------------------------------- + +@implementation PFIncrementOperation + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithAmount:(NSNumber *)amount { + self = [super init]; + if (!self) return nil; + + _amount = amount; + + return self; +} + ++ (instancetype)incrementWithAmount:(NSNumber *)newAmount { + return [[self alloc] initWithAmount:newAmount]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"increment by %@", self.amount]; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + return @{ @"__op" : @"Increment", + @"amount" : self.amount }; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + if (!previous) { + return self; + } else if ([previous isKindOfClass:[PFDeleteOperation class]]) { + return [PFSetOperation setWithValue:self.amount]; + } else if ([previous isKindOfClass:[PFSetOperation class]]) { + id oldValue = ((PFSetOperation *)previous).value; + PFParameterAssert([oldValue isKindOfClass:[NSNumber class]], @"You cannot increment a non-number."); + return [PFSetOperation setWithValue:[PFInternalUtils addNumber:self.amount withNumber:oldValue]]; + } else if ([previous isKindOfClass:[PFIncrementOperation class]]) { + NSNumber *newAmount = [PFInternalUtils addNumber:self.amount + withNumber:((PFIncrementOperation *)previous).amount]; + return [PFIncrementOperation incrementWithAmount:newAmount]; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + if (!oldValue) { + return self.amount; + } + + PFParameterAssert([oldValue isKindOfClass:[NSNumber class]], @"You cannot increment a non-number."); + return [PFInternalUtils addNumber:self.amount withNumber:oldValue]; +} + +@end + +///-------------------------------------- +#pragma mark - Array Operations +///-------------------------------------- + +@implementation PFAddOperation + +- (instancetype)initWithObjects:(NSArray *)array { + self = [super init]; + if (!self) return nil; + + _objects = array; + + return self; +} + ++ (instancetype)addWithObjects:(NSArray *)objects { + return [(PFAddOperation *)[self alloc] initWithObjects:objects]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"add %@", self.objects]; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableArray *encodedObjects = [objectEncoder encodeObject:self.objects]; + return @{ @"__op" : @"Add", + @"objects" : encodedObjects }; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + if (!previous) { + return self; + } else if ([previous isKindOfClass:[PFDeleteOperation class]]) { + return [PFSetOperation setWithValue:self.objects]; + } else if ([previous isKindOfClass:[PFSetOperation class]]) { + if ([((PFSetOperation *)previous).value isKindOfClass:[NSArray class]]) { + NSArray *oldArray = (NSArray *)(((PFSetOperation *)previous).value); + NSArray *newArray = [oldArray arrayByAddingObjectsFromArray:self.objects]; + return [PFSetOperation setWithValue:newArray]; + } else { + [NSException raise:NSInternalInconsistencyException format:@"You can't add an item to a non-array."]; + return nil; + } + } else if ([previous isKindOfClass:[PFAddOperation class]]) { + NSMutableArray *newObjects = [((PFAddOperation *)previous).objects mutableCopy]; + [newObjects addObjectsFromArray:self.objects]; + return [[self class] addWithObjects:newObjects]; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + if (!oldValue) { + return [self.objects mutableCopy]; + } else if ([oldValue isKindOfClass:[NSArray class]]) { + return [((NSArray *)oldValue)arrayByAddingObjectsFromArray:self.objects]; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +@end + +@implementation PFAddUniqueOperation + +- (instancetype)initWithObjects:(NSArray *)array { + self = [super init]; + if (!self) return nil; + + _objects = [[NSSet setWithArray:array] allObjects]; + + return self; +} + ++ (instancetype)addUniqueWithObjects:(NSArray *)objects { + return [(PFAddUniqueOperation *)[self alloc] initWithObjects:objects]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"addToSet %@", self.objects]; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableArray *encodedObjects = [objectEncoder encodeObject:self.objects]; + return @{ @"__op" : @"AddUnique", + @"objects" : encodedObjects }; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + if (!previous) { + return self; + } else if ([previous isKindOfClass:[PFDeleteOperation class]]) { + return [PFSetOperation setWithValue:self.objects]; + } else if ([previous isKindOfClass:[PFSetOperation class]]) { + if ([((PFSetOperation *)previous).value isKindOfClass:[NSArray class]]) { + NSArray *oldArray = (((PFSetOperation *)previous).value); + return [PFSetOperation setWithValue:[self applyToValue:oldArray forKey:nil]]; + } else { + [NSException raise:NSInternalInconsistencyException format:@"You can't add an item to a non-array."]; + return nil; + } + } else if ([previous isKindOfClass:[PFAddUniqueOperation class]]) { + NSArray *previousObjects = ((PFAddUniqueOperation *)previous).objects; + return [[self class] addUniqueWithObjects:[self applyToValue:previousObjects forKey:nil]]; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + if (!oldValue) { + return [self.objects mutableCopy]; + } else if ([oldValue isKindOfClass:[NSArray class]]) { + NSMutableArray *newValue = [oldValue mutableCopy]; + for (id objectToAdd in self.objects) { + if ([objectToAdd isKindOfClass:[PFObject class]] && [objectToAdd objectId]) { + // Check uniqueness by objectId instead of equality. If the PFObject + // already exists in the array, replace it with the newer one. + NSUInteger index = [newValue indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return [obj isKindOfClass:[PFObject class]] && + [[obj objectId] isEqualToString:[objectToAdd objectId]]; + }]; + if (index == NSNotFound) { + [newValue addObject:objectToAdd]; + } else { + [newValue replaceObjectAtIndex:index withObject:objectToAdd]; + } + } else if (![newValue containsObject:objectToAdd]) { + [newValue addObject:objectToAdd]; + } + } + return newValue; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +@end + +@implementation PFRemoveOperation + +- (instancetype)initWithObjects:(NSArray *)array { + self = [super init]; + + _objects = array; + + return self; +} + ++ (id)removeWithObjects:(NSArray *)objects { + return [(PFRemoveOperation *)[self alloc] initWithObjects:objects]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"remove %@", self.objects]; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableArray *encodedObjects = [objectEncoder encodeObject:self.objects]; + return @{ @"__op" : @"Remove", + @"objects" : encodedObjects }; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + if (!previous) { + return self; + } else if ([previous isKindOfClass:[PFDeleteOperation class]]) { + [NSException raise:NSInternalInconsistencyException format:@"You can't remove items from a deleted array."]; + return nil; + } else if ([previous isKindOfClass:[PFSetOperation class]]) { + if ([((PFSetOperation *)previous).value isKindOfClass:[NSArray class]]) { + NSArray *oldArray = ((PFSetOperation *)previous).value; + return [PFSetOperation setWithValue:[self applyToValue:oldArray forKey:nil]]; + } else { + [NSException raise:NSInternalInconsistencyException format:@"You can't add an item to a non-array."]; + return nil; + } + } else if ([previous isKindOfClass:[PFRemoveOperation class]]) { + NSArray *newObjects = [((PFRemoveOperation *)previous).objects arrayByAddingObjectsFromArray:self.objects]; + return [PFRemoveOperation removeWithObjects:newObjects]; + } + + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + if (!oldValue) { + return [self.objects mutableCopy]; + } else if ([oldValue isKindOfClass:[NSArray class]]) { + NSMutableArray *newValue = [((NSArray *)oldValue)mutableCopy]; + [newValue removeObjectsInArray:self.objects]; + + // Remove the removed objects from objectsToBeRemoved -- the items + // remaining should be ones that weren't removed by object equality. + NSMutableArray *objectsToBeRemoved = [self.objects mutableCopy]; + [objectsToBeRemoved removeObjectsInArray:newValue]; + for (id objectToRemove in objectsToBeRemoved) { + if ([objectToRemove isKindOfClass:[PFObject class]] && [objectToRemove objectId]) { + NSIndexSet *indexes = [newValue indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return ([obj isKindOfClass:[PFObject class]] && + [[obj objectId] isEqualToString:[objectToRemove objectId]]); + }]; + if ([indexes count] != 0) { + [newValue removeObjectsAtIndexes:indexes]; + } + } + } + return newValue; + } + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; +} + +@end + +///-------------------------------------- +#pragma mark - Relation Operations +///-------------------------------------- + +@implementation PFRelationOperation +@synthesize targetClass; + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _relationsToAdd = [NSMutableSet set]; + _relationsToRemove = [NSMutableSet set]; + + return self; +} + ++ (instancetype)addRelationToObjects:(NSArray *)targets { + PFRelationOperation *op = [[self alloc] init]; + if (targets.count > 0) { + op.targetClass = [[targets firstObject] parseClassName]; + } + + for (PFObject *target in targets) { + PFParameterAssert([target.parseClassName isEqualToString:op.targetClass], + @"All objects in a relation must be of the same class."); + [op.relationsToAdd addObject:target]; + } + + return op; +} + ++ (instancetype)removeRelationToObjects:(NSArray *)targets { + PFRelationOperation *operation = [[self alloc] init]; + if (targets.count > 0) { + operation.targetClass = [[targets objectAtIndex:0] parseClassName]; + } + + for (PFObject *target in targets) { + PFParameterAssert([target.parseClassName isEqualToString:operation.targetClass], + @"All objects in a relation must be of the same class."); + [operation.relationsToRemove addObject:target]; + } + + return operation; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"PFRelationOperation<%@> add:%@ remove:%@", + self.targetClass, + self.relationsToAdd, + self.relationsToRemove]; +} + +- (NSArray *)_convertToArrayInSet:(NSSet *)set withObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:set.count]; + for (PFObject *object in set) { + id encodedDict = [objectEncoder encodeObject:object]; + [array addObject:encodedDict]; + } + return array; +} + +- (id)encodeWithObjectEncoder:(PFEncoder *)objectEncoder { + NSDictionary *addDict = nil; + NSDictionary *removeDict = nil; + if (self.relationsToAdd.count > 0) { + NSArray *array = [self _convertToArrayInSet:self.relationsToAdd withObjectEncoder:objectEncoder]; + addDict = @{ @"__op" : @"AddRelation", + @"objects" : array }; + } + if (self.relationsToRemove.count > 0) { + NSArray *array = [self _convertToArrayInSet:self.relationsToRemove withObjectEncoder:objectEncoder]; + removeDict = @{ @"__op" : @"RemoveRelation", + @"objects" : array }; + } + + if (addDict && removeDict) { + return @{ @"__op" : @"Batch", + @"ops" : @[ addDict, removeDict ] }; + } + + if (addDict) { + return addDict; + } + + if (removeDict) { + return removeDict; + } + + [NSException raise:NSInternalInconsistencyException format:@"A PFRelationOperation was created without any data."]; + return nil; +} + +- (PFFieldOperation *)mergeWithPrevious:(PFFieldOperation *)previous { + if (!previous) { + return self; + } + + PFConsistencyAssert(![previous isKindOfClass:[PFDeleteOperation class]], @"You can't modify a relation after deleting it"); + PFConsistencyAssert([previous isKindOfClass:[PFRelationOperation class]], @"Operation is invalid after previous operation"); + + PFRelationOperation *previousOperation = (PFRelationOperation *)previous; + + PFParameterAssert(!previousOperation.targetClass || [previousOperation.targetClass isEqualToString:self.targetClass], + @"Related object object must be of class %@, but %@ was passed in", + previousOperation.targetClass, self.targetClass); + + //TODO: (nlutsenko) This logic seems to be messed up. We should return a new operation here, also merging logic seems funky. + NSSet *newRelationsToAdd = [self.relationsToAdd copy]; + NSSet *newRelationsToRemove = [self.relationsToRemove copy]; + [self.relationsToAdd removeAllObjects]; + [self.relationsToRemove removeAllObjects]; + + for (NSString *objectId in previousOperation.relationsToAdd) { + [self.relationsToRemove removeObject:objectId]; + [self.relationsToAdd addObject:objectId]; + } + for (NSString *objectId in previousOperation.relationsToRemove) { + [self.relationsToRemove removeObject:objectId]; + [self.relationsToRemove addObject:objectId]; + } + + for (NSString *objectId in newRelationsToAdd) { + [self.relationsToRemove removeObject:objectId]; + [self.relationsToAdd addObject:objectId]; + } + for (NSString *objectId in newRelationsToRemove) { + [self.relationsToRemove removeObject:objectId]; + [self.relationsToRemove addObject:objectId]; + } + return self; +} + +- (id)applyToValue:(id)oldValue forKey:(NSString *)key { + PFRelation *relation = nil; + if (!oldValue) { + relation = [PFRelation relationWithTargetClass:self.targetClass]; + } else if ([oldValue isKindOfClass:[PFRelation class]]) { + relation = oldValue; + if (self.targetClass) { + if (relation.targetClass) { + PFParameterAssert([relation.targetClass isEqualToString:targetClass], + @"Related object object must be of class %@, but %@ was passed in", + relation.targetClass, self.targetClass); + } else { + relation.targetClass = self.targetClass; + } + } + } else { + [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."]; + return nil; + } + + for (PFObject *object in self.relationsToAdd) { + [relation _addKnownObject:object]; + } + for (PFObject *object in self.relationsToRemove) { + [relation _removeKnownObject:object]; + } + + return relation; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.h new file mode 100644 index 0000000..831418a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFDecoder; +@class PFFieldOperation; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFFieldOperationDecoder : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + ++ (instancetype)defaultDecoder; + +///-------------------------------------- +/// @name Decoding +///-------------------------------------- + +/*! + Converts a parsed JSON object into a PFFieldOperation. + + @param encoded An NSDictionary containing an __op field. + @returns An NSObject that conforms to PFFieldOperation. + */ +- (PFFieldOperation *)decode:(NSDictionary *)encoded withDecoder:(PFDecoder *)decoder; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.m new file mode 100644 index 0000000..1c5a303 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/FieldOperation/PFFieldOperationDecoder.m @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFieldOperationDecoder.h" + +#import "PFAssert.h" +#import "PFDecoder.h" +#import "PFFieldOperation.h" + +@interface PFFieldOperationDecoder () { + NSMutableDictionary *_operationDecoders; +} + +@end + +typedef PFFieldOperation * (^PFFieldOperationDecodingBlock_)(NSDictionary *encoded, PFDecoder *decoder); + +@implementation PFFieldOperationDecoder + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _operationDecoders = [NSMutableDictionary dictionary]; + [self _registerDefaultOperationDecoders]; + + return self; +} + ++ (instancetype)defaultDecoder { + static PFFieldOperationDecoder *decoder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + decoder = [[self alloc] init]; + }); + return decoder; +} + +///-------------------------------------- +#pragma mark - Setup +///-------------------------------------- + +- (void)_registerDecoderForOperationWithName:(NSString *)name block:(PFFieldOperationDecodingBlock_)block { + _operationDecoders[name] = [block copy]; +} + +- (void)_registerDefaultOperationDecoders { + @weakify(self); + [self _registerDecoderForOperationWithName:@"Batch" block:^(NSDictionary *encoded, PFDecoder *decoder) { + @strongify(self); + PFFieldOperation *op = nil; + NSArray *ops = encoded[@"ops"]; + for (id maybeEncodedNextOp in ops) { + PFFieldOperation *nextOp = nil; + if ([maybeEncodedNextOp isKindOfClass:[PFFieldOperation class]]) { + nextOp = maybeEncodedNextOp; + } else { + nextOp = [self decode:maybeEncodedNextOp withDecoder:decoder]; + } + op = [nextOp mergeWithPrevious:op]; + } + return op; + }]; + + [self _registerDecoderForOperationWithName:@"Delete" block:^(NSDictionary *encoded, PFDecoder *decoder) { + // Deleting has no state, so it can be a singleton. + static PFDeleteOperation *deleteOperation = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + deleteOperation = [[PFDeleteOperation alloc] init]; + }); + return deleteOperation; + }]; + + [self _registerDecoderForOperationWithName:@"Increment" block:^(NSDictionary *encoded, PFDecoder *decoder) { + return [PFIncrementOperation incrementWithAmount:encoded[@"amount"]]; + }]; + + [self _registerDecoderForOperationWithName:@"Add" block:^(NSDictionary *encoded, PFDecoder *decoder) { + NSArray *objects = [decoder decodeObject:encoded[@"objects"]]; + return [PFAddOperation addWithObjects:objects]; + }]; + + [self _registerDecoderForOperationWithName:@"AddUnique" block:^(NSDictionary *encoded, PFDecoder *decoder) { + NSArray *objects = [decoder decodeObject:encoded[@"objects"]]; + return [PFAddUniqueOperation addUniqueWithObjects:objects]; + }]; + + [self _registerDecoderForOperationWithName:@"Remove" block:^(NSDictionary *encoded, PFDecoder *decoder) { + NSArray *objects = [decoder decodeObject:encoded[@"objects"]]; + return [PFRemoveOperation removeWithObjects:objects]; + }]; + + [self _registerDecoderForOperationWithName:@"AddRelation" block:^(NSDictionary *encoded, PFDecoder *decoder) { + NSArray *objects = [decoder decodeObject:encoded[@"objects"]]; + return [PFRelationOperation addRelationToObjects:objects]; + }]; + + [self _registerDecoderForOperationWithName:@"RemoveRelation" block:^(NSDictionary *encoded, PFDecoder *decoder) { + NSArray *objects = [decoder decodeObject:encoded[@"objects"]]; + return [PFRelationOperation removeRelationToObjects:objects]; + }]; +} + +///-------------------------------------- +#pragma mark - Decoding +///-------------------------------------- + +- (PFFieldOperation *)decode:(NSDictionary *)encoded withDecoder:(PFDecoder *)decoder { + NSString *operationName = encoded[@"__op"]; + PFFieldOperationDecodingBlock_ block = _operationDecoders[operationName]; + PFConsistencyAssert(block, @"Unable to decode operation of type %@.", operationName); + return block(encoded, decoder); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.h new file mode 100644 index 0000000..dd12a2c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" +#import "PFMacros.h" + +@class BFCancellationToken; +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFFileState; +@class PFFileStagingController; + +@interface PFFileController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +@property (nonatomic, strong, readonly) PFFileStagingController *fileStagingController; + +@property (nonatomic, copy, readonly) NSString *cacheFilesDirectoryPath; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithDataSource:(id)dataSource; + + +///-------------------------------------- +/// @name Download +///-------------------------------------- + +/*! + Downloads a file asynchronously with a given state. + + @param fileState File state to download the file for. + @param cancellationToken Cancellation token. + @param progressBlock Progress block to call (optional). + + @returns `BFTask` with a result set to `nil`. + */ +- (BFTask *)downloadFileAsyncWithState:(PFFileState *)fileState + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock; + +/*! + Downloads a file asynchronously with a given state and yields a stream to the live download of that file. + + @param fileState File state to download the file for. + @param cancellationToken Cancellation token. + @param progressBlock Progress block to call (optional). + + @return `BFTask` with a result set to live `NSInputStream` of the file. + */ +- (BFTask *)downloadFileStreamAsyncWithState:(PFFileState *)fileState + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock; + +///-------------------------------------- +/// @name Upload +///-------------------------------------- + +/*! + Uploads a file asynchronously from file path for a given file state. + + @param fileState File state to upload the file for. + @param sourceFilePath Source file path. + @param sessionToken Session token to use. + @param cancellationToken Cancellation token. + @param progressBlock Progress block to call (optional). + + @returns `BFTask` with a result set to `PFFileState` of uploaded file. + */ +- (BFTask *)uploadFileAsyncWithState:(PFFileState *)fileState + sourceFilePath:(NSString *)sourceFilePath + sessionToken:(NSString *)sessionToken + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock; + +///-------------------------------------- +/// @name Cache +///-------------------------------------- + +- (BFTask *)clearFileCacheAsync; + +- (NSString *)cachedFilePathForFileState:(PFFileState *)fileState; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.m new file mode 100644 index 0000000..d9b2a51 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileController.m @@ -0,0 +1,269 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileController.h" + +#import +#import + +#import "BFTask+Private.h" +#import "PFFileDataStream.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFFileManager.h" +#import "PFFileStagingController.h" +#import "PFFileState.h" +#import "PFHash.h" +#import "PFMacros.h" +#import "PFRESTFileCommand.h" + +static NSString *const PFFileControllerCacheDirectoryName_ = @"PFFileCache"; + +@interface PFFileController () { + NSMutableDictionary *_downloadTasks; // { "urlString" : BFTask } + NSMutableDictionary *_downloadProgressBlocks; // { "urlString" : [ block1, block2 ] } + dispatch_queue_t _downloadDataAccessQueue; + dispatch_queue_t _fileStagingControllerAccessQueue; +} + +@end + +@implementation PFFileController + +@synthesize fileStagingController = _fileStagingController; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + _downloadTasks = [NSMutableDictionary dictionary]; + _downloadProgressBlocks = [NSMutableDictionary dictionary]; + _downloadDataAccessQueue = dispatch_queue_create("com.parse.fileController.download", DISPATCH_QUEUE_SERIAL); + _fileStagingControllerAccessQueue = dispatch_queue_create("com.parse.filestaging.controller.access", DISPATCH_QUEUE_SERIAL); + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Properties +///-------------------------------------- + +- (PFFileStagingController *)fileStagingController { + __block PFFileStagingController *result = nil; + dispatch_sync(_fileStagingControllerAccessQueue, ^{ + if (!_fileStagingController) { + _fileStagingController = [PFFileStagingController controllerWithDataSource:self.dataSource]; + } + result = _fileStagingController; + }); + return result; +} + +///-------------------------------------- +#pragma mark - Download +///-------------------------------------- + +- (BFTask *)downloadFileAsyncWithState:(PFFileState *)fileState + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + [self _addFileDownloadProgressBlock:progressBlock forFileWithState:fileState]; + + BFTask *resultTask = [self _fileDownloadResultTaskForFileWithState:fileState]; + if (!resultTask) { + NSURL *url = [NSURL URLWithString:fileState.secureURLString]; + NSString *temporaryPath = [self _temporaryFileDownloadPathForFileState:fileState]; + + PFProgressBlock unifyingProgressBlock = [self _fileDownloadUnifyingProgressBlockForFileState:fileState]; + resultTask = [self.dataSource.commandRunner runFileDownloadCommandAsyncWithFileURL:url + targetFilePath:temporaryPath + cancellationToken:cancellationToken + progressBlock:unifyingProgressBlock]; + resultTask = [[resultTask continueWithSuccessBlock:^id(BFTask *task) { + return [[PFFileManager moveItemAsyncAtPath:temporaryPath + toPath:[self cachedFilePathForFileState:fileState]] continueWithBlock:^id(BFTask *task) { + // Ignore the error if file exists. + if (task.error && task.error.code == NSFileWriteFileExistsError) { + return nil; + } + return task; + }]; + }] continueWithBlock:^id(BFTask *task) { + dispatch_barrier_async(_downloadDataAccessQueue, ^{ + [_downloadTasks removeObjectForKey:fileState.secureURLString]; + [_downloadProgressBlocks removeObjectForKey:fileState.secureURLString]; + }); + return task; + }]; + dispatch_barrier_async(_downloadDataAccessQueue, ^{ + _downloadTasks[fileState.secureURLString] = resultTask; + }); + } + return resultTask; + }]; +} + +- (BFTask *)downloadFileStreamAsyncWithState:(PFFileState *)fileState + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource]; + NSString *filePath = [self _temporaryFileDownloadPathForFileState:fileState]; + PFFileDataStream *stream = [[PFFileDataStream alloc] initWithFileAtPath:filePath]; + [[self downloadFileAsyncWithState:fileState + cancellationToken:cancellationToken + progressBlock:^(int percentDone) { + [taskCompletionSource trySetResult:stream]; + + if (progressBlock) { + progressBlock(percentDone); + } + }] continueWithBlock:^id(BFTask *task) { + [stream stopBlocking]; + return task; + }]; + return taskCompletionSource.task; + }]; +} + +- (BFTask *)_fileDownloadResultTaskForFileWithState:(PFFileState *)state { + __block BFTask *resultTask = nil; + dispatch_sync(_downloadDataAccessQueue, ^{ + resultTask = _downloadTasks[state.secureURLString]; + }); + return resultTask; +} + +- (PFProgressBlock)_fileDownloadUnifyingProgressBlockForFileState:(PFFileState *)fileState { + return ^(int progress) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + __block NSArray *blocks = nil; + dispatch_sync(_downloadDataAccessQueue, ^{ + blocks = [_downloadProgressBlocks[fileState.secureURLString] copy]; + }); + if (blocks.count != 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + for (PFProgressBlock block in blocks) { + block(progress); + } + }); + } + }); + }; +} + +- (void)_addFileDownloadProgressBlock:(PFProgressBlock)block forFileWithState:(PFFileState *)state { + if (!block) { + return; + } + + dispatch_barrier_async(_downloadDataAccessQueue, ^{ + NSMutableArray *progressBlocks = _downloadProgressBlocks[state.secureURLString]; + if (!progressBlocks) { + progressBlocks = [NSMutableArray arrayWithObject:block]; + _downloadProgressBlocks[state.secureURLString] = progressBlocks; + } else { + [progressBlocks addObject:block]; + } + }); +} + +- (NSString *)_temporaryFileDownloadPathForFileState:(PFFileState *)fileState { + return [NSTemporaryDirectory() stringByAppendingPathComponent:PFMD5HashFromString(fileState.secureURLString)]; +} + +///-------------------------------------- +#pragma mark - Upload +///-------------------------------------- + +- (BFTask *)uploadFileAsyncWithState:(PFFileState *)fileState + sourceFilePath:(NSString *)sourceFilePath + sessionToken:(NSString *)sessionToken + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock { + PFRESTFileCommand *command = [PFRESTFileCommand uploadCommandForFileWithName:fileState.name + sessionToken:sessionToken]; + + @weakify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + return [[[self.dataSource.commandRunner runFileUploadCommandAsync:command + withContentType:fileState.mimeType + contentSourceFilePath:sourceFilePath + options:PFCommandRunningOptionRetryIfFailed + cancellationToken:cancellationToken + progressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + PFFileState *fileState = [[PFFileState alloc] initWithName:result.result[@"name"] + urlString:result.result[@"url"] + mimeType:nil]; + return fileState; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + + NSString *finalPath = [self cachedFilePathForFileState:task.result]; + NSError *error = nil; + [[NSFileManager defaultManager] moveItemAtPath:sourceFilePath + toPath:finalPath + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return task; + }]; +} + +///-------------------------------------- +#pragma mark - Cache +///-------------------------------------- + +- (NSString *)cachedFilePathForFileState:(PFFileState *)fileState { + if (!fileState.secureURLString) { + return nil; + } + + NSString *filename = [fileState.secureURLString lastPathComponent]; + NSString *path = [self.cacheFilesDirectoryPath stringByAppendingPathComponent:filename]; + return path; +} + +- (NSString *)cacheFilesDirectoryPath { + NSString *path = [self.dataSource.fileManager parseCacheItemPathForPathComponent:PFFileControllerCacheDirectoryName_]; + [[PFFileManager createDirectoryIfNeededAsyncAtPath:path] waitForResult:nil withMainThreadWarning:NO]; + return path; +} + +- (BFTask *)clearFileCacheAsync { + NSString *path = [self cacheFilesDirectoryPath]; + return [PFFileManager removeDirectoryContentsAsyncAtPath:path]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.h new file mode 100644 index 0000000..15ee8d7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.h @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFFileManagerProvider; + +@interface PFFileStagingController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +@property (nonatomic, copy, readonly) NSString *stagedFilesDirectoryPath; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Staging +///-------------------------------------- + +/*! + Moves a file from the specified path to the staging directory based off of the name and unique ID passed in. + + @param filePath The source path to stage + @param name The name of the file to stage + @param uniqueId A unique ID for this file to be used when differentiating between files with the same name. + + @return A task, which yields the path of the staged file on disk. + */ +- (BFTask *)stageFileAsyncAtPath:(NSString *)filePath name:(NSString *)name uniqueId:(uint64_t)uniqueId; + +/*! + Creates a file from the specified data and places it into the staging directory based off of the name and unique + ID passed in. + + @param fileData The data to stage + @param name The name of the file to stage + @param uniqueId The unique ID for this file to be used when differentiating between files with the same name. + + @return A task, which yields the path of the staged file on disk. + */ +- (BFTask *)stageFileAsyncWithData:(NSData *)fileData name:(NSString *)name uniqueId:(uint64_t)uniqueId; + +/*! + Get the staged directory path for a file with the specified name and unique ID. + + @param name The name of the staged file + @param uniqueId The unique ID of the staged file + + @return The path in the staged directory folder which contains the contents of the requested file. + */ +- (NSString *)stagedFilePathForFileWithName:(NSString *)name uniqueId:(uint64_t)uniqueId; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.m new file mode 100644 index 0000000..fb13749 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/Controller/PFFileStagingController.m @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileStagingController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFAsyncTaskQueue.h" +#import "PFDataProvider.h" +#import "PFFileManager.h" +#import "PFLogging.h" + +static NSString *const PFFileStagingControllerDirectoryName_ = @"PFFileStaging"; + +@implementation PFFileStagingController { + PFAsyncTaskQueue *_taskQueue; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + _taskQueue = [PFAsyncTaskQueue taskQueue]; + + [self _clearStagedFilesAsync]; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Properties +///-------------------------------------- + +- (NSString *)stagedFilesDirectoryPath { + NSString *folderPath = [self.dataSource.fileManager parseLocalSandboxDataDirectoryPath]; + return [folderPath stringByAppendingPathComponent:PFFileStagingControllerDirectoryName_]; +} + +///-------------------------------------- +#pragma mark - Staging +///-------------------------------------- + +- (BFTask *)stageFileAsyncAtPath:(NSString *)filePath name:(NSString *)name uniqueId:(uint64_t)uniqueId { + return [_taskQueue enqueue:^id(BFTask *task) { + return [[PFFileManager createDirectoryIfNeededAsyncAtPath:[self stagedFilesDirectoryPath]] continueWithBlock:^id(BFTask *task) { + NSString *destinationPath = [self stagedFilePathForFileWithName:name uniqueId:uniqueId]; + return [[PFFileManager copyItemAsyncAtPath:filePath toPath:destinationPath] continueWithSuccessResult:destinationPath]; + }]; + }]; +} + +- (BFTask *)stageFileAsyncWithData:(NSData *)fileData name:(NSString *)name uniqueId:(uint64_t)uniqueId { + return [_taskQueue enqueue:^id(BFTask *task) { + return [[PFFileManager createDirectoryIfNeededAsyncAtPath:[self stagedFilesDirectoryPath]] continueWithBlock:^id(BFTask *task) { + NSString *destinationPath = [self stagedFilePathForFileWithName:name uniqueId:uniqueId]; + return [[PFFileManager writeDataAsync:fileData toFile:destinationPath] continueWithSuccessResult:destinationPath]; + }]; + }]; +} + +- (NSString *)stagedFilePathForFileWithName:(NSString *)name uniqueId:(uint64_t)uniqueId { + NSString *fileName = [NSString stringWithFormat:@"%llX_%@", uniqueId, name]; + return [[self stagedFilesDirectoryPath] stringByAppendingPathComponent:fileName]; +} + +///-------------------------------------- +#pragma mark - Clearing +///-------------------------------------- + +- (BFTask *)_clearStagedFilesAsync { + return [_taskQueue enqueue:^id(BFTask *task) { + NSString *stagedFilesDirectoryPath = [self stagedFilesDirectoryPath]; + return [PFFileManager removeItemAtPathAsync:stagedFilesDirectoryPath]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.h new file mode 100644 index 0000000..fa86bc6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + PFFileDataStream is an NSStream proxy which won't read the last byte of a file until the downlaod has finished. + + When downloading a file stream via `-[PFFile getDataDownloadStreamInBackground]`, we need to be able to read and write + to the same file on disk concurrently. + + NSInputStream closes itself as soon as it hits EOF, so this class wraps an underlying NSInputStream and stops the + stream from closing until after writing has finished. + */ +@interface PFFileDataStream : NSProxy + +- (instancetype)initWithFileAtPath:(NSString *)path; + +- (void)stopBlocking; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.m new file mode 100644 index 0000000..ac03501 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/FileDataStream/PFFileDataStream.m @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileDataStream.h" + +#import +#import + +@interface PFFileDataStream() { + NSString *_path; + NSInputStream *_inputStream; + + int _fd; + BOOL _finished; + + __weak id _delegate; +} + +@end + +@implementation PFFileDataStream + +- (instancetype)initWithFileAtPath:(NSString *)path { + _finished = NO; + + _path = path; + _inputStream = [NSInputStream inputStreamWithFileAtPath:path]; + _inputStream.delegate = self; + + return self; +} + +- (void)stopBlocking { + _finished = YES; + + [self stream:_inputStream handleEvent:NSStreamEventHasBytesAvailable]; +} + +///-------------------------------------- +#pragma mark - NSProxy methods +///-------------------------------------- + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [_inputStream methodSignatureForSelector:sel]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:_inputStream]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + Method implementation = class_getInstanceMethod([self class], aSelector); + return implementation ? YES : [_inputStream respondsToSelector:aSelector]; +} + +///-------------------------------------- +#pragma mark - NSInputStream methods +///-------------------------------------- + +- (void)setDelegate:(id)delegate { + _delegate = delegate; +} + +- (id)delegate { + return _delegate; +} + +- (void)open { + _fd = open([_path UTF8String], O_RDONLY | O_NONBLOCK); + [_inputStream open]; +} + +- (void)close { + [_inputStream close]; + close(_fd); +} + +- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len { + if (!_finished) { + off_t currentOffset = [[_inputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; + off_t fileSize = lseek(_fd, 0, SEEK_END); + + len = (NSUInteger)MIN(len, ((fileSize - currentOffset) - 1)); + } + + // Reading 0 bytes from an NSInputStream causes this strange undocumented behavior: it marks the stream as 'at end', + // regardless of whether more bytes are available or not. lolwut? + if (len == 0) { + return 0; + } + + return [_inputStream read:buffer maxLength:len]; +} + +///-------------------------------------- +#pragma mark - NSStreamDelegate +///-------------------------------------- + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { + id delegate = _delegate; + if ([delegate respondsToSelector:@selector(stream:handleEvent:)]) { + [delegate stream:(NSInputStream *)self handleEvent:eventCode]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/PFFile_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/PFFile_Private.h new file mode 100644 index 0000000..43fe6cc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/PFFile_Private.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFFile (Private) + +@property (nonatomic, strong, readonly) PFFileState *state; + ++ (instancetype)fileWithName:(nullable NSString *)name url:(nullable NSString *)url; + +- (nullable NSString *)_cachedFilePath; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.h new file mode 100644 index 0000000..8088ae9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFFileState : PFBaseState + +@property (nonatomic, copy, readonly) NSString *name; +@property (nullable, nonatomic, copy, readonly) NSString *urlString; +@property (nullable, nonatomic, copy, readonly) NSString *secureURLString; + +@property (nullable, nonatomic, copy, readonly) NSString *mimeType; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithState:(PFFileState *)state; +- (instancetype)initWithName:(nullable NSString *)name + urlString:(nullable NSString *)urlString + mimeType:(nullable NSString *)mimeType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.m new file mode 100644 index 0000000..3a0e4e8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState.m @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileState.h" +#import "PFFileState_Private.h" + +#import "PFMutableFileState.h" +#import "PFPropertyInfo.h" + +static NSString *const _PFFileStateSecureDomain = @"files.parsetfss.com"; + +@interface PFFileState () + +@property (nonatomic, copy, readwrite) NSString *secureURLString; + +@end + +@implementation PFFileState + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + return @{ + @"name" : [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"urlString" : [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"mimeType" : [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + }; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithState:(PFFileState *)state { + return [super initWithState:state]; +} + +- (instancetype)initWithName:(NSString *)name urlString:(NSString *)urlString mimeType:(NSString *)mimeType { + self = [super init]; + if (!self) return nil; + + _name = (name ? [name copy] : @"file"); + _urlString = [urlString copy]; + _mimeType = [mimeType copy]; + + return self; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setUrlString:(NSString *)urlString { + if (self.urlString != urlString) { + _urlString = [urlString copy]; + _secureURLString = nil; // Invalidate variable cache + } +} + +- (NSString *)secureURLString { + if (_secureURLString) { + return _secureURLString; + } + + if (!self.urlString) { + return nil; + } + + NSURLComponents *components = [NSURLComponents componentsWithString:self.urlString]; + if (!components) { + return self.urlString; + } + + NSString *scheme = [components scheme]; + if (![scheme isEqualToString:@"http"]) { + return self.urlString; + } + + if ([[components host] isEqualToString:_PFFileStateSecureDomain]) { + components.scheme = @"https"; + } + _secureURLString = [[components URL] absoluteString]; + return _secureURLString; +} + +///-------------------------------------- +#pragma mark - Mutable Copying +///-------------------------------------- + +- (id)copyWithZone:(NSZone *)zone { + return [[PFFileState allocWithZone:zone] initWithState:self]; +} + +- (instancetype)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableFileState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState_Private.h new file mode 100644 index 0000000..5114fef --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFFileState_Private.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFFileState () + +@property (nonatomic, copy, readwrite) NSString *name; +@property (nullable, nonatomic, copy, readwrite) NSString *urlString; +@property (nullable, nonatomic, copy, readwrite) NSString *mimeType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.h new file mode 100644 index 0000000..1d33fa8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFMutableFileState : PFFileState + +@property (nonatomic, copy, readwrite) NSString *name; +@property (nullable, nonatomic, copy, readwrite) NSString *urlString; +@property (nullable, nonatomic, copy, readwrite) NSString *mimeType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.m new file mode 100644 index 0000000..53db52c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/File/State/PFMutableFileState.m @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableFileState.h" + +@implementation PFMutableFileState + +@dynamic name; +@dynamic urlString; +@dynamic mimeType; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPRequest.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPRequest.h new file mode 100644 index 0000000..e6394e4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPRequest.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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. + */ + +#ifndef Parse_PFHTTPRequest_h +#define Parse_PFHTTPRequest_h + +#import + +static NSString *const PFHTTPRequestMethodGET = @"GET"; +static NSString *const PFHTTPRequestMethodHEAD = @"HEAD"; +static NSString *const PFHTTPRequestMethodDELETE = @"DELETE"; +static NSString *const PFHTTPRequestMethodPOST = @"POST"; +static NSString *const PFHTTPRequestMethodPUT = @"PUT"; + +static NSString *const PFHTTPRequestHeaderNameContentType = @"Content-Type"; +static NSString *const PFHTTPRequestHeaderNameContentLength = @"Content-Length"; + +#endif diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h new file mode 100644 index 0000000..b3bfb70 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFHTTPURLRequestConstructor : NSObject + ++ (NSMutableURLRequest *)urlRequestWithURL:(NSURL *)url + httpMethod:(NSString *)httpMethod + httpHeaders:(NSDictionary *)httpHeaders + parameters:(NSDictionary *)parameters; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m new file mode 100644 index 0000000..e948c3d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFHTTPURLRequestConstructor.h" + +#import "PFAssert.h" +#import "PFHTTPRequest.h" +#import "PFURLConstructor.h" + +static NSString *const PFHTTPURLRequestContentTypeJSON = @"application/json; charset=utf8"; + +@implementation PFHTTPURLRequestConstructor + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + ++ (NSMutableURLRequest *)urlRequestWithURL:(NSURL *)url + httpMethod:(NSString *)httpMethod + httpHeaders:(NSDictionary *)httpHeaders + parameters:(NSDictionary *)parameters { + NSParameterAssert(url != nil); + NSParameterAssert(httpMethod != nil); + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + + request.HTTPMethod = httpMethod; + request.allHTTPHeaderFields = httpHeaders; + + if (parameters != nil) { + PFConsistencyAssert([httpMethod isEqualToString:PFHTTPRequestMethodPOST] || + [httpMethod isEqualToString:PFHTTPRequestMethodPUT], + @"Can't create %@ request with json body.", httpMethod); + + [request setValue:PFHTTPURLRequestContentTypeJSON forHTTPHeaderField:PFHTTPRequestHeaderNameContentType]; + + NSError *error = nil; + [request setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters + options:(NSJSONWritingOptions)0 + error:&error]]; + PFConsistencyAssert(error == nil, @"Failed to serialize JSON with error = %@", error); + } + return request; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.h new file mode 100644 index 0000000..19f7e26 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFURLConstructor : NSObject + ++ (NSURL *)URLFromAbsoluteString:(NSString *)string + path:(nullable NSString *)path + query:(nullable NSString *)query; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.m new file mode 100644 index 0000000..7e0dd24 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/HTTPRequest/PFURLConstructor.m @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFURLConstructor.h" + +#import "PFAssert.h" + +@implementation PFURLConstructor + +///-------------------------------------- +#pragma mark - Basic +///-------------------------------------- + ++ (NSURL *)URLFromAbsoluteString:(NSString *)string + path:(nullable NSString *)path + query:(nullable NSString *)query { + NSURLComponents *components = [NSURLComponents componentsWithString:string]; + if (components.path) { + components.path = path; + } + if (query) { + components.query = query; + } + return components.URL; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.h new file mode 100644 index 0000000..29ef544 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern NSString *const PFInstallationKeyParseVersion; +extern NSString *const PFInstallationKeyDeviceType; +extern NSString *const PFInstallationKeyInstallationId; +extern NSString *const PFInstallationKeyDeviceToken; +extern NSString *const PFInstallationKeyAppName; +extern NSString *const PFInstallationKeyAppVersion; +extern NSString *const PFInstallationKeyAppIdentifier; +extern NSString *const PFInstallationKeyTimeZone; +extern NSString *const PFInstallationKeyLocaleIdentifier; +extern NSString *const PFInstallationKeyBadge; +extern NSString *const PFInstallationKeyChannels; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.m new file mode 100644 index 0000000..19f2565 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Constants/PFInstallationConstants.m @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInstallationConstants.h" + +NSString *const PFInstallationKeyParseVersion = @"parseVersion"; +NSString *const PFInstallationKeyDeviceType = @"deviceType"; +NSString *const PFInstallationKeyInstallationId = @"installationId"; +NSString *const PFInstallationKeyDeviceToken = @"deviceToken"; +NSString *const PFInstallationKeyAppName = @"appName"; +NSString *const PFInstallationKeyAppVersion = @"appVersion"; +NSString *const PFInstallationKeyAppIdentifier = @"appIdentifier"; +NSString *const PFInstallationKeyTimeZone = @"timeZone"; +NSString *const PFInstallationKeyLocaleIdentifier = @"localeIdentifier"; +NSString *const PFInstallationKeyBadge = @"badge"; +NSString *const PFInstallationKeyChannels = @"channels"; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.h new file mode 100644 index 0000000..75573b9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFObjectControlling.h" + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFInstallationController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.m new file mode 100644 index 0000000..66d09cc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/Controller/PFInstallationController.m @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInstallationController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCurrentInstallationController.h" +#import "PFInstallationPrivate.h" +#import "PFObjectController.h" +#import "PFObjectPrivate.h" + +@implementation PFInstallationController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BFTask *)fetchObjectAsync:(PFInstallation *)object withSessionToken:(nullable NSString *)sessionToken { + @weakify(self); + return [[[self.objectController fetchObjectAsync:object + withSessionToken:sessionToken] continueWithBlock:^id(BFTask *task) { + @strongify(self); + + // Do not attempt to resave an object if LDS is enabled, since changing objectId is not allowed. + if (self.currentInstallationController.storageType == PFCurrentObjectStorageTypeOfflineStore) { + return task; + } + + if (task.faulted && task.error.code == kPFErrorObjectNotFound) { + @synchronized (object.lock) { + // Retry the fetch as a save operation because this Installation was deleted on the server. + // We always want [currentInstallation fetch] to succeed. + object.objectId = nil; + [object _markAllFieldsDirty]; + return [[object saveAsync:nil] continueWithSuccessResult:object]; + } + } + return task; + }] continueWithBlock:^id(BFTask *task) { + @strongify(self); + // Roll-forward the previous task. + return [[self.currentInstallationController saveCurrentObjectAsync:object] continueWithResult:task]; + }]; +} + +- (BFTask *)processFetchResultAsync:(NSDictionary *)result forObject:(PFInstallation *)object { + @weakify(self); + return [[self.objectController processFetchResultAsync:result forObject:object] continueWithBlock:^id(BFTask *task) { + @strongify(self); + // Roll-forward the previous task. + return [[self.currentInstallationController saveCurrentObjectAsync:object] continueWithResult:task]; + }]; +} + +///-------------------------------------- +#pragma mark - Delete +///-------------------------------------- + +- (BFTask *)deleteObjectAsync:(PFObject *)object withSessionToken:(nullable NSString *)sessionToken { + PFConsistencyAssert(NO, @"Installations cannot be deleted."); + return nil; +} + +- (BFTask *)processDeleteResultAsync:(nullable NSDictionary *)result forObject:(PFObject *)object { + PFConsistencyAssert(NO, @"Installations cannot be deleted."); + return nil; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (id)objectController { + return self.dataSource.objectController; +} + +- (PFCurrentInstallationController *)currentInstallationController { + return self.dataSource.currentInstallationController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h new file mode 100644 index 0000000..b51f996 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFCurrentObjectControlling.h" +#import "PFDataProvider.h" +#import "PFMacros.h" + +extern NSString *const PFCurrentInstallationFileName; +extern NSString *const PFCurrentInstallationPinName; + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFInstallation; + +PF_WATCH_UNAVAILABLE @interface PFCurrentInstallationController : NSObject + +@property (nonatomic, weak, readonly) id commonDataSource; +@property (nonatomic, weak, readonly) id coreDataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithStorageType:(PFCurrentObjectStorageType)dataStorageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; + ++ (instancetype)controllerWithStorageType:(PFCurrentObjectStorageType)dataStorageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; + +///-------------------------------------- +/// @name Installation +///-------------------------------------- + +@property (nonatomic, strong, readonly) PFInstallation *memoryCachedCurrentInstallation; + +- (BFTask *)clearCurrentInstallationAsync; +- (BFTask *)clearMemoryCachedCurrentInstallationAsync; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m new file mode 100644 index 0000000..f716106 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m @@ -0,0 +1,289 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCurrentInstallationController.h" + +#import "BFTask+Private.h" +#import "PFAsyncTaskQueue.h" +#import "PFFileManager.h" +#import "PFInstallationIdentifierStore.h" +#import "PFInstallationPrivate.h" +#import "PFMacros.h" +#import "PFObjectFilePersistenceController.h" +#import "PFObjectPrivate.h" +#import "PFPushPrivate.h" +#import "PFQuery.h" + +NSString *const PFCurrentInstallationFileName = @"currentInstallation"; +NSString *const PFCurrentInstallationPinName = @"_currentInstallation"; + +@interface PFCurrentInstallationController () { + dispatch_queue_t _dataQueue; + PFAsyncTaskQueue *_dataTaskQueue; +} + +@property (nonatomic, strong, readonly) PFFileManager *fileManager; +@property (nonatomic, strong, readonly) PFInstallationIdentifierStore *installationIdentifierStore; + +@property (nonatomic, strong) PFInstallation *currentInstallation; +@property (nonatomic, assign) BOOL currentInstallationMatchesDisk; + +@end + +@implementation PFCurrentInstallationController + +@synthesize storageType = _storageType; + +@synthesize currentInstallation = _currentInstallation; +@synthesize currentInstallationMatchesDisk = _currentInstallationMatchesDisk; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithStorageType:(PFCurrentObjectStorageType)storageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + self = [super init]; + if (!self) return nil; + + _dataQueue = dispatch_queue_create("com.parse.installation.current", DISPATCH_QUEUE_CONCURRENT); + _dataTaskQueue = [[PFAsyncTaskQueue alloc] init]; + + _storageType = storageType; + _commonDataSource = commonDataSource; + _coreDataSource = coreDataSource; + + return self; +} + ++ (instancetype)controllerWithStorageType:(PFCurrentObjectStorageType)storageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + return [[self alloc] initWithStorageType:storageType + commonDataSource:commonDataSource + coreDataSource:coreDataSource]; +} + +///-------------------------------------- +#pragma mark - PFCurrentObjectControlling +///-------------------------------------- + +- (BFTask *)getCurrentObjectAsync { + @weakify(self); + return [_dataTaskQueue enqueue:^BFTask *(BFTask *unused) { + return [[[BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id { + @strongify(self); + if (self.currentInstallation) { + return self.currentInstallation; + } + + if (!self.currentInstallationMatchesDisk) { + return [[self _loadCurrentInstallationFromDiskAsync] continueWithBlock:^id(BFTask *task) { + PFInstallation *installation = task.result; + if (installation) { + // If there is no objectId, but there is some data + // it means that the data wasn't yet saved to the server + // so we should mark everything as dirty + if (!installation.objectId && [[installation allKeys] count]) { + [installation _markAllFieldsDirty]; + } + } + return task; + }]; + } + return nil; + }] continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (task.faulted) { + return task; + } + + PFInstallation *installation = task.result; + NSString *installationId = self.installationIdentifierStore.installationIdentifier; + installationId = [installationId lowercaseString]; + if (!installation || ![installationId isEqualToString:installation.installationId]) { + // If there's no installation object, or the object's installation + // ID doesn't match this device's installation ID, create a new + // installation. Try to keep track of the previously stored device + // token: if there was an installation already stored just re-use + // its device token, otherwise try loading from the keychain (where + // old SDKs stored the token). Discard the old installation. + NSString *oldDeviceToken = nil; + if (installation) { + oldDeviceToken = installation.deviceToken; + } else { + oldDeviceToken = [[PFPush pushInternalUtilClass] getDeviceTokenFromKeychain]; + } + + installation = [PFInstallation object]; + installation.deviceType = kPFDeviceType; + installation.installationId = installationId; + if (oldDeviceToken) { + installation.deviceToken = oldDeviceToken; + } + } + + return installation; + }] continueWithBlock:^id(BFTask *task) { + dispatch_barrier_sync(_dataQueue, ^{ + _currentInstallation = task.result; + _currentInstallationMatchesDisk = !task.faulted; + }); + return task; + }]; + }]; +} + +- (BFTask *)saveCurrentObjectAsync:(PFInstallation *)installation { + @weakify(self); + return [_dataTaskQueue enqueue:^BFTask *(BFTask *unused) { + @strongify(self); + + if (installation != self.currentInstallation) { + return nil; + } + return [[self _saveCurrentInstallationToDiskAsync:installation] continueWithBlock:^id(BFTask *task) { + self.currentInstallationMatchesDisk = (!task.faulted && !task.cancelled); + return nil; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Installation +///-------------------------------------- + +- (PFInstallation *)memoryCachedCurrentInstallation { + return self.currentInstallation; +} + +- (BFTask *)clearCurrentInstallationAsync { + @weakify(self); + return [_dataTaskQueue enqueue:^BFTask *(BFTask *unused) { + @strongify(self); + + dispatch_barrier_sync(_dataQueue, ^{ + _currentInstallation = nil; + _currentInstallationMatchesDisk = NO; + }); + + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:2]; + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + BFTask *unpinTask = [PFObject unpinAllObjectsInBackgroundWithName:PFCurrentInstallationPinName]; + [tasks addObject:unpinTask]; + } + + NSString *path = [self.fileManager parseDataItemPathForPathComponent:PFCurrentInstallationFileName]; + BFTask *fileTask = [PFFileManager removeItemAtPathAsync:path]; + [tasks addObject:fileTask]; + + return [BFTask taskForCompletionOfAllTasks:tasks]; + }]; +} + +- (BFTask *)clearMemoryCachedCurrentInstallationAsync { + return [_dataTaskQueue enqueue:^BFTask *(BFTask *unused) { + self.currentInstallation = nil; + self.currentInstallationMatchesDisk = NO; + + return nil; + }]; +} + +///-------------------------------------- +#pragma mark - Data Storage +///-------------------------------------- + +- (BFTask *)_loadCurrentInstallationFromDiskAsync { + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + // Try loading from OfflineStore + PFQuery *query = [[[PFQuery queryWithClassName:[PFInstallation parseClassName]] + fromPinWithName:PFCurrentInstallationPinName] ignoreACLs]; + + return [[query findObjectsInBackground] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *results = task.result; + if ([results count] == 1) { + return [BFTask taskWithResult:[results firstObject]]; + } else if ([results count] != 0) { + return [[PFObject unpinAllObjectsInBackgroundWithName:PFCurrentInstallationPinName] + continueWithSuccessResult:nil]; + } + + // Backward compatibility if we previously have non-LDS currentInstallation. + return [PFObject _migrateObjectInBackgroundFromFile:PFCurrentInstallationFileName + toPin:PFCurrentInstallationPinName]; + }]; + } + + PFObjectFilePersistenceController *controller = self.objectFilePersistenceController; + return [controller loadPersistentObjectAsyncForKey:PFCurrentInstallationFileName]; +} + +- (BFTask *)_saveCurrentInstallationToDiskAsync:(PFInstallation *)installation { + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + BFTask *task = [PFObject unpinAllObjectsInBackgroundWithName:PFCurrentInstallationPinName]; + return [task continueWithBlock:^id(BFTask *task) { + // Make sure to not pin children of PFInstallation automatically, as it can create problems + // if any of the children are of Installation class. + return [installation _pinInBackgroundWithName:PFCurrentInstallationPinName includeChildren:NO]; + }]; + } + + PFObjectFilePersistenceController *controller = self.objectFilePersistenceController; + return [controller persistObjectAsync:installation forKey:PFCurrentInstallationFileName]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFFileManager *)fileManager { + return self.commonDataSource.fileManager; +} + +- (PFObjectFilePersistenceController *)objectFilePersistenceController { + return self.coreDataSource.objectFilePersistenceController; +} + +- (PFInstallationIdentifierStore *)installationIdentifierStore { + return self.commonDataSource.installationIdentifierStore; +} + +- (PFInstallation *)currentInstallation { + __block PFInstallation *installation = nil; + dispatch_sync(_dataQueue, ^{ + installation = _currentInstallation; + }); + return installation; +} + +- (void)setCurrentInstallation:(PFInstallation *)currentInstallation { + dispatch_barrier_sync(_dataQueue, ^{ + if (_currentInstallation != currentInstallation) { + _currentInstallation = currentInstallation; + } + }); +} + +- (BOOL)currentInstallationMatchesDisk { + __block BOOL matches = NO; + dispatch_sync(_dataQueue, ^{ + matches = _currentInstallationMatchesDisk; + }); + return matches; +} + +- (void)setCurrentInstallationMatchesDisk:(BOOL)currentInstallationMatchesDisk { + dispatch_barrier_sync(_dataQueue, ^{ + _currentInstallationMatchesDisk = currentInstallationMatchesDisk; + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h new file mode 100644 index 0000000..3e7becb --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFFileManager; + +@interface PFInstallationIdentifierStore : NSObject + +/*! + Returns a cached installationId or creates a new one, saves it to disk and returns it. + + @returns `NSString` representation of current installationId. + */ +@property (nonatomic, copy, readonly) NSString *installationIdentifier; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(PFFileManager *)fileManager NS_DESIGNATED_INITIALIZER; + +///-------------------------------------- +/// @name Clear +///-------------------------------------- + +/*! + Clears installation identifier on disk and in-memory. + */ +- (void)clearInstallationIdentifier; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m new file mode 100644 index 0000000..af7fac5 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInstallationIdentifierStore.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFFileManager.h" +#import "PFInternalUtils.h" +#import "PFMacros.h" +#import "PFMultiProcessFileLockController.h" +#import "Parse_Private.h" + +static NSString *const PFInstallationIdentifierFileName = @"installationId"; + +@interface PFInstallationIdentifierStore () { + dispatch_queue_t _synchronizationQueue; + PFFileManager *_fileManager; +} + +@property (nonatomic, copy, readwrite) NSString *installationIdentifier; +@property (nonatomic, copy, readonly) NSString *installationIdentifierFilePath; + +@end + +@implementation PFInstallationIdentifierStore + +@synthesize installationIdentifier = _installationIdentifier; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithFileManager:(PFFileManager *)fileManager { + self = [super init]; + if (!self) return nil; + + _synchronizationQueue = dispatch_queue_create("com.parse.installationIdentifier", DISPATCH_QUEUE_SERIAL); + PFMarkDispatchQueue(_synchronizationQueue); + + _fileManager = fileManager; + + return self; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSString *)installationIdentifier { + __block NSString *identifier = nil; + dispatch_sync(_synchronizationQueue, ^{ + if (!_installationIdentifier) { + [self _loadInstallationIdentifier]; + } + + identifier = _installationIdentifier; + }); + return identifier; +} + +- (void)setInstallationIdentifier:(NSString *)installationIdentifier { + PFAssertIsOnDispatchQueue(_synchronizationQueue); + if (_installationIdentifier != installationIdentifier) { + _installationIdentifier = [installationIdentifier copy]; + } +} + +- (void)clearInstallationIdentifier { + dispatch_sync(_synchronizationQueue, ^{ + NSString *filePath = self.installationIdentifierFilePath; + [[PFFileManager removeItemAtPathAsync:filePath] waitForResult:nil withMainThreadWarning:NO]; + + self.installationIdentifier = nil; + }); +} + +///-------------------------------------- +#pragma mark - Disk Operations +///-------------------------------------- + +- (void)_loadInstallationIdentifier { + PFAssertIsOnDispatchQueue(_synchronizationQueue); + + NSString *filePath = self.installationIdentifierFilePath; + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:filePath]; + + NSString *identifier = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + if (!identifier) { + identifier = [[[NSUUID UUID] UUIDString] lowercaseString]; + [[PFFileManager writeStringAsync:identifier toFile:filePath] waitForResult:nil withMainThreadWarning:NO]; + } + self.installationIdentifier = identifier; + + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:filePath]; +} + +- (void)_clearCachedInstallationIdentifier { + dispatch_sync(_synchronizationQueue, ^{ + self.installationIdentifier = nil; + }); +} + +- (NSString *)installationIdentifierFilePath { + return [_fileManager parseDataItemPathForPathComponent:PFInstallationIdentifierFileName]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h new file mode 100644 index 0000000..f84b36b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInstallationIdentifierStore.h" + +@interface PFInstallationIdentifierStore (Private) + +/*! + Clears in-memory cached installation identifier, if any. + */ +- (void)_clearCachedInstallationIdentifier; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/PFInstallationPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/PFInstallationPrivate.h new file mode 100644 index 0000000..0e24f86 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Installation/PFInstallationPrivate.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFInstallation (Private) + +- (void)_clearDeviceToken; +- (void)_markAllFieldsDirty; + +@end + +@interface PFInstallation () + +// Private read-write declarations of publicly-readonly fields. +@property (nonatomic, copy, readwrite) NSString *deviceType; +@property (nonatomic, copy, readwrite) NSString *installationId; +@property (nonatomic, copy, readwrite) NSString *timeZone; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.h new file mode 100644 index 0000000..e2518de --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFKeyValueCache : NSObject + +@property (nonatomic, copy, readonly) NSString *cacheDirectoryPath; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCacheDirectoryPath:(NSString *)path; + +///-------------------------------------- +/// @name Setting +///-------------------------------------- + +- (void)setObject:(NSString *)object forKey:(NSString *)key; +- (void)setObject:(NSString *)object forKeyedSubscript:(NSString *)key; + +///-------------------------------------- +/// @name Getting +///-------------------------------------- + +- (NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)age; + +///-------------------------------------- +/// @name Removing +///-------------------------------------- + +- (void)removeObjectForKey:(NSString *)key; +- (void)removeAllObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.m new file mode 100644 index 0000000..f2ee85f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache.m @@ -0,0 +1,336 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFKeyValueCache_Private.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFConstants.h" +#import "PFFileManager.h" +#import "PFInternalUtils.h" +#import "PFLogging.h" + +static const NSUInteger PFKeyValueCacheDefaultDiskCacheSize = 10 << 20; +static const NSUInteger PFKeyValueCacheDefaultDiskCacheRecords = 1000; +static const NSUInteger PFKeyValueCacheDefaultMemoryCacheRecordSize = 1 << 20; +static const NSTimeInterval PFKeyValueCacheDiskCacheTimeResolution = 1; // HFS+ stores only second level accuracy. + +static NSString *const PFKeyValueCacheDiskCachePathKey = @"path"; + +@interface PFKeyValueCacheEntry () + +// We need to generate a setter that's atomic to safely clear the value. +@property (nullable, atomic, readwrite, copy) NSString *value; + +@end + +@implementation PFKeyValueCacheEntry + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithValue:(NSString *)value { + return [self initWithValue:value creationTime:[NSDate date]]; +} + +- (instancetype)initWithValue:(NSString *)value creationTime:(NSDate *)creationTime { + self = [super init]; + if (!self) return nil; + + _value = [value copy]; + _creationTime = creationTime; + + return self; +} + ++ (instancetype)cacheEntryWithValue:(NSString *)value { + return [[self alloc] initWithValue:value]; +} + ++ (instancetype)cacheEntryWithValue:(NSString *)value creationTime:(NSDate *)creationTime { + return [[self alloc] initWithValue:value creationTime:creationTime]; +} + +@end + +@implementation PFKeyValueCache { + NSURL *_cacheDirectoryURL; + dispatch_queue_t _diskCacheQueue; + + NSDate *_lastDiskCacheModDate; + NSUInteger _lastDiskCacheSize; + NSMutableArray *_lastDiskCacheAttributes; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCacheDirectoryPath:(NSString *)path { + return [self initWithCacheDirectoryURL:[NSURL fileURLWithPath:path] + fileManager:[NSFileManager defaultManager] + memoryCache:[[NSCache alloc] init]]; +} + +- (instancetype)initWithCacheDirectoryURL:(NSURL *)url + fileManager:(NSFileManager *)fileManager + memoryCache:(NSCache *)cache { + self = [super init]; + if (!self) return nil; + + _cacheDirectoryURL = url; + _fileManager = fileManager; + _memoryCache = cache; + + _diskCacheQueue = dispatch_queue_create("com.parse.keyvaluecache.disk", DISPATCH_QUEUE_SERIAL); + + _maxDiskCacheBytes = PFKeyValueCacheDefaultDiskCacheSize; + _maxDiskCacheRecords = PFKeyValueCacheDefaultDiskCacheRecords; + _maxMemoryCacheBytesPerRecord = PFKeyValueCacheDefaultMemoryCacheRecordSize; + + return self; +} + +///-------------------------------------- +#pragma mark - Property Accessors +///-------------------------------------- + +- (NSString *)cacheDirectoryPath { + [_fileManager createDirectoryAtURL:_cacheDirectoryURL withIntermediateDirectories:YES attributes:nil error:NULL]; + return _cacheDirectoryURL.path; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (void)setObject:(NSString *)object forKeyedSubscript:(NSString *)key { + [self setObject:object forKey:key]; +} + +- (void)setObject:(NSString *)value forKey:(NSString *)key { + NSUInteger keyBytes = [key maximumLengthOfBytesUsingEncoding:[key fastestEncoding]]; + NSUInteger valueBytes = [value maximumLengthOfBytesUsingEncoding:[value fastestEncoding]]; + + if ((keyBytes + valueBytes) < self.maxMemoryCacheBytesPerRecord) { + [self.memoryCache setObject:[PFKeyValueCacheEntry cacheEntryWithValue:value] forKey:key]; + } else { + [self.memoryCache removeObjectForKey:key]; + } + + dispatch_async(_diskCacheQueue, ^{ + [self _createDiskCacheEntry:value atURL:[self _cacheURLForKey:key]]; + [self _compactDiskCache]; + }); +} + +- (NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)maxAge { + NSURL *cacheURL = [self _cacheURLForKey:key]; + PFKeyValueCacheEntry *cacheEntry = [self.memoryCache objectForKey:key]; + + if (cacheEntry) { + if ([[NSDate date] timeIntervalSinceDate:cacheEntry.creationTime] > maxAge) { + // We know the cache to be too old in both copies. + // Save space, remove this key from disk, and it's value from the memory cache. + [self removeObjectForKey:key]; + return nil; + } + + dispatch_async(_diskCacheQueue, ^{ + [self _updateModificationDateAtURL:cacheURL]; + }); + + return cacheEntry.value; + } + + // Wait for all outstanding disk operations before continuing, as another thread could be in the process of + // Writing a value to disk right now. + __block NSString *value = nil; + dispatch_sync(_diskCacheQueue, ^{ + NSDate *modificationDate = [self _modificationDateOfCacheEntryAtURL:cacheURL]; + if ([[NSDate date] timeIntervalSinceDate:modificationDate] > maxAge) { + [self removeObjectForKey:key]; + return; + } + + // Cache misses here (e.g. creationDate and value are both nil) should still be put into the memory cache. + value = [self _diskCacheEntryForURL:cacheURL]; + [self.memoryCache setObject:[PFKeyValueCacheEntry cacheEntryWithValue:value creationTime:modificationDate] + forKey:key]; + }); + + return value; +} + +- (void)removeObjectForKey:(NSString *)key { + [self.memoryCache removeObjectForKey:key]; + + dispatch_async(_diskCacheQueue, ^{ + [self.fileManager removeItemAtURL:[self _cacheURLForKey:key] error:NULL]; + }); +} + +- (void)removeAllObjects { + [self.memoryCache removeAllObjects]; + + dispatch_sync(_diskCacheQueue, ^{ + // Directory will be automatically recreated the next time 'cacheDir' is accessed. + [self.fileManager removeItemAtURL:_cacheDirectoryURL error:NULL]; + }); +} + +- (void)waitForOutstandingOperations { + dispatch_sync(_diskCacheQueue, ^{ + // Wait, do nothing + }); +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (NSURL *)_cacheURLForKey:(NSString *)key { + return [_cacheDirectoryURL URLByAppendingPathComponent:key]; +} + +- (void)_updateModificationDateAtURL:(NSURL *)url { + [self.fileManager setAttributes:@{ NSFileModificationDate: [NSDate date] } ofItemAtPath:url.path error:NULL]; +} + +- (NSDate *)_modificationDateOfCacheEntryAtURL:(NSURL *)url { + return [self.fileManager attributesOfItemAtPath:url.path error:NULL][NSFileModificationDate]; +} + +///-------------------------------------- +#pragma mark - Disk Cache +///-------------------------------------- + +- (NSString *)_diskCacheEntryForURL:(NSURL *)url { + NSData *bytes = [self.fileManager contentsAtPath:[url path]]; + if (!bytes) { + return nil; + } + + [self _updateModificationDateAtURL:url]; + return [[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding]; +} + +- (void)_createDiskCacheEntry:(NSString *)value atURL:(NSURL *)url { + NSString *path = [url path]; + NSData *bytes = [value dataUsingEncoding:NSUTF8StringEncoding]; + NSDate *creationDate = [NSDate date]; + + BOOL isDirty = [self _isDiskCacheDirty]; + + [_fileManager createDirectoryAtURL:_cacheDirectoryURL withIntermediateDirectories:YES attributes:nil error:NULL]; + [self.fileManager createFileAtPath:path + contents:bytes + attributes:@{ NSFileCreationDate: creationDate, NSFileModificationDate: creationDate }]; + + if (!isDirty) { + _lastDiskCacheModDate = creationDate; + _lastDiskCacheSize += bytes.length; + + [self _addToDiskCacheDictionary:path + modificationDate:creationDate + size:bytes.length]; + } else { + [self _invalidateDiskCache]; + } +} + +- (BOOL)_isDiskCacheDirty { + if (!_lastDiskCacheModDate) { + return YES; + } + + NSDate *modificationDate = [self _modificationDateOfCacheEntryAtURL:_cacheDirectoryURL]; + NSTimeInterval knownInterval = [_lastDiskCacheModDate timeIntervalSinceReferenceDate]; + NSTimeInterval actualInterval = [modificationDate timeIntervalSinceReferenceDate]; + + // NOTE: Most file systems (HFS) can only store up to 1 second of precision, whereas NSDate is super high resolution + // Yes, this is actually really bad to have hard coded, as this does give some window where we can get unwanted + // entries in the cache. However, that chance of another process touching this directory is greatly outweighed by + // the performance gained by using this technique. Plus, in the case of concurrent modification, we will never over- + // agressively remove something from the cache, we just might go a little bit over our limit. + return (actualInterval - knownInterval) >= PFKeyValueCacheDiskCacheTimeResolution; +} + +- (void)_invalidateDiskCache { + _lastDiskCacheModDate = nil; + _lastDiskCacheSize = 0; + _lastDiskCacheAttributes = nil; +} + +- (void)_recreateDiskCache { + NSDictionary *cacheDirectoryAttributes = [self.fileManager attributesOfItemAtPath:_cacheDirectoryURL.path error:NULL]; + + _lastDiskCacheModDate = cacheDirectoryAttributes[NSFileModificationDate]; + _lastDiskCacheSize = 0; + _lastDiskCacheAttributes = [[NSMutableArray alloc] init]; + + NSDirectoryEnumerator *enumerator = [self.fileManager enumeratorAtPath:[_cacheDirectoryURL path]]; + NSString *path = nil; + + while ((path = [enumerator nextObject]) != nil) { + [enumerator skipDescendants]; + + NSDictionary *attributes = enumerator.fileAttributes; + NSUInteger size = [attributes[NSFileSize] unsignedIntegerValue]; + + _lastDiskCacheSize += size; + + // NOTE: Do not use -copy here, as fileAttributes are lazily-loaded, we would run into issues with a lot of + // syscalls all at once here. + [self _addToDiskCacheDictionary:path + modificationDate:attributes[NSFileModificationDate] + size:size]; + } +} + +- (void)_addToDiskCacheDictionary:(NSString *)path modificationDate:(NSDate *)modificationDate size:(NSUInteger)size { + NSDictionary *entry = @{ + PFKeyValueCacheDiskCachePathKey: path, + NSFileModificationDate: modificationDate, + NSFileSize: @(size) + }; + + NSInteger insertionIndex = [_lastDiskCacheAttributes indexOfObject:entry + inSortedRange:NSMakeRange(0, _lastDiskCacheAttributes.count) + options:NSBinarySearchingInsertionIndex + usingComparator:^NSComparisonResult(id obj1, id obj2) { + return [obj1[NSFileModificationDate] compare:obj2[NSFileModificationDate]]; + }]; + + [_lastDiskCacheAttributes insertObject:entry atIndex:insertionIndex]; +} + +- (void)_compactDiskCache { + if ([self _isDiskCacheDirty]) { + [self _recreateDiskCache]; + } + + while (_lastDiskCacheAttributes.count > _maxDiskCacheRecords || _lastDiskCacheSize > _maxDiskCacheBytes) { + NSDictionary *attributes = [_lastDiskCacheAttributes firstObject]; + NSString *toRemove = attributes[PFKeyValueCacheDiskCachePathKey]; + NSNumber *fileSize = attributes[NSFileSize]; + + [self.fileManager removeItemAtURL:[self _cacheURLForKey:toRemove] error:NULL]; + _lastDiskCacheSize -= [fileSize unsignedIntegerValue]; + + [_lastDiskCacheAttributes removeObjectAtIndex:0]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h new file mode 100644 index 0000000..6c45b6d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFKeyValueCache.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFKeyValueCache () + +///-------------------------------------- +/// @name Properties +///-------------------------------------- + +@property (nullable, nonatomic, strong, readwrite) NSFileManager *fileManager; +@property (nullable, nonatomic, strong, readwrite) NSCache *memoryCache; + +@property (nonatomic, assign) NSUInteger maxDiskCacheBytes; +@property (nonatomic, assign) NSUInteger maxDiskCacheRecords; +@property (nonatomic, assign) NSUInteger maxMemoryCacheBytesPerRecord; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithCacheDirectoryURL:(nullable NSURL *)url + fileManager:(nullable NSFileManager *)fileManager + memoryCache:(nullable NSCache *)cache NS_DESIGNATED_INITIALIZER; + +///-------------------------------------- +/// @name Waiting +///-------------------------------------- + +- (void)waitForOutstandingOperations; + +@end + +@interface PFKeyValueCacheEntry : NSObject + +///-------------------------------------- +/// @name Properties +///-------------------------------------- + +@property (atomic, copy, readonly) NSString *value; +@property (atomic, strong, readonly) NSDate *creationTime; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + ++ (instancetype)cacheEntryWithValue:(NSString *)value; ++ (instancetype)cacheEntryWithValue:(NSString *)value creationTime:(NSDate *)creationTime; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithValue:(NSString *)value; +- (instancetype)initWithValue:(NSString *)value + creationTime:(NSDate *)creationTime NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h new file mode 100644 index 0000000..ff8bfa2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; +@class PFOfflineStore; +@class PFQueryState; +@class PFSQLiteDatabase; +@class PFUser; + +typedef BFTask PF_GENERIC(NSNumber *)* (^PFConstraintMatcherBlock)(PFObject *object, PFSQLiteDatabase *database); + +typedef NS_OPTIONS(uint8_t, PFOfflineQueryOption) { + PFOfflineQueryOptionOrder = 1 << 0, + PFOfflineQueryOptionLimit = 1 << 1, + PFOfflineQueryOptionSkip = 1 << 2, +}; + +@interface PFOfflineQueryLogic : NSObject + +/*! + Initialize an `PFOfflineQueryLogic` instance with `PFOfflineStore` instance. + `PFOfflineStore` is needed for subQuery, inQuery and fetch. + */ +- (instancetype)initWithOfflineStore:(PFOfflineStore *)offlineStore; + +/*! + @returns YES iff the object is visible based on its read ACL and the given user objectId. + */ ++ (BOOL)userHasReadAccess:(PFUser *)user ofObject:(PFObject *)object; + +/*! + @returns YES iff the object is visible based on its read ACL and the given user objectId. + */ ++ (BOOL)userHasWriteAccess:(PFUser *)user ofObject:(PFObject *)object; + +/*! + Returns a PFConstraintMatcherBlock that returns true iff the object matches the given + query's constraints. This takes in a PFSQLiteDatabase connection because SQLite is finicky + about nesting connections, so we want to reuse them whenever possible. + */ +- (PFConstraintMatcherBlock)createMatcherForQueryState:(PFQueryState *)queryState user:(PFUser *)user; + +/*! + Sort given array with given `PFQuery` constraint. + + @returns sorted result. + */ +- (NSArray *)resultsByApplyingOptions:(PFOfflineQueryOption)options + ofQueryState:(PFQueryState *)queryState + toResults:(NSArray *)results; + +/*! + Make sure all of the objects included by the given query get fetched. + */ +- (BFTask *)fetchIncludesAsyncForResults:(NSArray *)results + ofQueryState:(PFQueryState *)queryState + inDatabase:(PFSQLiteDatabase *)database; + +/*! + Make sure all of the objects included by the given query get fetched. + */ +- (BFTask *)fetchIncludesForObjectAsync:(PFObject *)object + queryState:(PFQueryState *)queryState + database:(PFSQLiteDatabase *)database; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m new file mode 100644 index 0000000..63168ce --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m @@ -0,0 +1,918 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFOfflineQueryLogic.h" + +#import + +#import "PFACL.h" +#import "PFAssert.h" +#import "PFConstants.h" +#import "PFDateFormatter.h" +#import "PFDecoder.h" +#import "PFEncoder.h" +#import "PFErrorUtilities.h" +#import "PFGeoPoint.h" +#import "PFOfflineStore.h" +#import "PFQueryPrivate.h" +#import "PFRelation.h" +#import "PFRelationPrivate.h" + +typedef BOOL (^PFComparatorDeciderBlock)(id value, id constraint); +typedef BOOL (^PFSubQueryMatcherBlock)(id object, NSArray *results); + +/*! + A query to be used in $inQuery, $notInQuery, $select and $dontSelect + */ +@interface PFSubQueryMatcher : NSObject + +@property (nonatomic, strong, readonly) PFQuery *subQuery; +@property (nonatomic, strong) BFTask *subQueryResults; +@property (nonatomic, strong, readonly) PFOfflineStore *offlineStore; + +@end + +@implementation PFSubQueryMatcher + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithSubQuery:(PFQuery *)query offlineStore:(PFOfflineStore *)offlineStore { + if ((self = [super init]) != nil) { + _subQuery = query; + _offlineStore = offlineStore; + } + + return self; +} + +///-------------------------------------- +#pragma mark - SubQuery Matcher Creator +///-------------------------------------- + +- (PFConstraintMatcherBlock)createMatcherWithSubQueryMatcherBlock:(PFSubQueryMatcherBlock)block user:(PFUser *)user { + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + if (self.subQueryResults == nil) { + self.subQueryResults = [self.offlineStore findAsyncForQueryState:self.subQuery.state + user:user + pin:nil + isCount:NO + database:database]; + } + return [self.subQueryResults continueWithSuccessBlock:^id(BFTask *task) { + return @(block(object, task.result)); + }]; + }; +} + +@end + +@interface PFOfflineQueryLogic () + +@property (nonatomic, weak) PFOfflineStore *offlineStore; + +@end + +@implementation PFOfflineQueryLogic + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithOfflineStore:(PFOfflineStore *)offlineStore { + if ((self = [super init]) != nil) { + _offlineStore = offlineStore; + } + return self; +} + +///-------------------------------------- +#pragma mark - Value Getter +///-------------------------------------- + +- (id)valueForContainer:(id)container + key:(NSString *)key { + return [self valueForContainer:container key:key depth:0]; +} + +- (id)valueForContainer:(id)container + key:(NSString *)key + depth:(int)depth { + if ([key rangeOfString:@"."].location != NSNotFound) { + NSArray *parts = [key componentsSeparatedByString:@"."]; + + NSString *firstKey = [parts firstObject]; + NSString *rest = nil; + if ([parts count] > 1) { + NSRange range = NSMakeRange(1, [parts count] - 1); + rest = [[parts subarrayWithRange:range] componentsJoinedByString:@"."]; + } + id value = [self valueForContainer:container key:firstKey depth:depth + 1]; + // Only NSDictionary can be dotted into for getting values, so we should reject + // anything like ParseObjects and arrays. + if (!(value == nil || [value isKindOfClass:[NSDictionary class]])) { + if (depth > 0) { + id restFormat = [[PFPointerObjectEncoder objectEncoder] encodeObject:value]; + if ([restFormat isKindOfClass:[NSDictionary class]]) { + return [self valueForContainer:restFormat key:rest depth:depth + 1]; + } + } + [NSException raise:NSInvalidArgumentException format:@"Key %@ is invalid", key]; + } + return [self valueForContainer:value key:rest depth:depth + 1]; + } + + if ([container isKindOfClass:[PFObject class]]) { + PFObject *object = (PFObject *)container; + + // The object needs to have been fetched already if we are going to sort by one of its field. + PFParameterAssert(object.isDataAvailable, @"Bad key %@", key); + + // Handle special keys for PFObject. + if ([key isEqualToString:@"objectId"]) { + return object.objectId; + } else if ([key isEqualToString:@"createdAt"] || [key isEqualToString:@"_created_at"]) { + return object.createdAt; + } else if ([key isEqualToString:@"updatedAt"] || [key isEqualToString:@"_updated_at"]) { + return object.updatedAt; + } else { + return object[key]; + } + } else if ([container isKindOfClass:[NSDictionary class]]) { + return ((NSDictionary *)container)[key]; + } else if (container == nil) { + return nil; + } else { + [NSException raise:NSInvalidArgumentException format:@"Bad key %@", key]; + // Shouldn't reach here. + return nil; + } +} + +///-------------------------------------- +#pragma mark - Matcher With Decider +///-------------------------------------- + +/*! + Returns YES if decider returns YES for any value in the given array. + */ ++ (BOOL)matchesArray:(NSArray *)array + constraint:(id)constraint + withDecider:(PFComparatorDeciderBlock)decider { + for (id value in array) { + if (decider(value, constraint)) { + return YES; + } + } + return NO; +} + +/*! + Returns YES if decider returns YES for any value in the given array. + */ ++ (BOOL)matchesValue:(id)value + constraint:(id)constraint + withDecider:(PFComparatorDeciderBlock)decider { + if ([value isKindOfClass:[NSArray class]]) { + return [self matchesArray:value constraint:constraint withDecider:decider]; + } else { + return decider(value, constraint); + } +} + +///-------------------------------------- +#pragma mark - Matcher +///-------------------------------------- + +/*! + Implements simple equality constraints. This emulates Mongo's behavior where "equals" can mean array containment. + */ ++ (BOOL)matchesValue:(id)value + equalTo:(id)constraint { + return [self matchesValue:value constraint:constraint withDecider:^BOOL (id value, id constraint) { + // Do custom matching for dates to make sure we have proper precision. + if ([value isKindOfClass:[NSDate class]] && + [constraint isKindOfClass:[NSDate class]]) { + PFDateFormatter *dateFormatter = [PFDateFormatter sharedFormatter]; + NSString *valueString = [dateFormatter preciseStringFromDate:value]; + NSString *constraintString = [dateFormatter preciseStringFromDate:constraint]; + return [valueString isEqual:constraintString]; + } + + if ([value isKindOfClass:[PFRelation class]]) { + return [value isEqual:constraint] || [value _hasKnownObject:constraint]; + } + + return [value isEqual:constraint]; + }]; +} + +/*! + Matches $ne constraints. + */ ++ (BOOL)matchesValue:(id)value + notEqualTo:(id)constraint { + return ![self matchesValue:value equalTo:constraint]; +} + +/*! + Matches $lt constraints. + */ ++ (BOOL)matchesValue:(id)value + lessThan:(id)constraint { + return [self matchesValue:value constraint:constraint withDecider:^BOOL (id value, id constraint) { + if (value == nil || value == [NSNull null]) { + return NO; + } + NSComparisonResult comparisonResult = [value compare:constraint]; + return comparisonResult == NSOrderedAscending; + }]; +} + +/*! + Matches $lte constraints. + */ ++ (BOOL)matchesValue:(id)value + lessThanOrEqualTo:(id)constraint { + return [self matchesValue:value constraint:constraint withDecider:^BOOL (id value, id constraint) { + if (value == nil || value == [NSNull null]) { + return NO; + } + NSComparisonResult comparisonResult = [value compare:constraint]; + return (comparisonResult == NSOrderedAscending) || (comparisonResult == NSOrderedSame); + }]; +} + +/*! + Matches $gt constraints. + */ ++ (BOOL)matchesValue:(id)value + greaterThan:(id)constraint { + return [self matchesValue:value constraint:constraint withDecider:^BOOL (id value, id constraint) { + if (value == nil || value == [NSNull null]) { + return NO; + } + NSComparisonResult comparisonResult = [value compare:constraint]; + return comparisonResult == NSOrderedDescending; + }]; +} + +/*! + Matches $gte constraints. + */ ++ (BOOL)matchesValue:(id)value +greaterThanOrEqualTo:(id)constraint { + return [self matchesValue:value constraint:constraint withDecider:^BOOL (id value, id constraint) { + if (value == nil || value == [NSNull null]) { + return NO; + } + NSComparisonResult comparisonResult = [value compare:constraint]; + return (comparisonResult == NSOrderedDescending) || (comparisonResult == NSOrderedSame); + }]; +} + +/*! + Matches $in constraints. + $in returns YES if the intersection of value and constraint is not an empty set. + */ ++ (BOOL)matchesValue:(id)value + containedIn:(id)constraint { + if (constraint == nil || constraint == [NSNull null]) { + return NO; + } + + PFParameterAssert([constraint isKindOfClass:[NSArray class]], @"Constraint type not supported for $in queries"); + + for (id requiredItem in (NSArray *)constraint) { + if ([self matchesValue:value equalTo:requiredItem]) { + return YES; + } + } + return NO; +} + +/*! + Matches $nin constraints. + */ ++ (BOOL)matchesValue:(id)value + notContainedIn:(id)constraint { + return ![self matchesValue:value containedIn:constraint]; +} + +/*! + Matches $all constraints. + */ ++ (BOOL)matchesValue:(id)value containsAllObjectsInArray:(id)constraints { + PFParameterAssert([constraints isKindOfClass:[NSArray class]], @"Constraint type not supported for $all queries"); + PFParameterAssert([value isKindOfClass:[NSArray class]], @"Value type not supported for $all queries"); + + for (id requiredItem in (NSArray *)constraints) { + if (![self matchesValue:value equalTo:requiredItem]) { + return NO; + } + } + return YES; +} + +/*! + Matches $regex constraints. + */ ++ (BOOL)matchesValue:(id)value + regex:(id)constraint + withOptions:(NSString *)options { + if (value == nil || value == [NSNull null]) { + return NO; + } + + if (options == nil) { + options = @""; + } + + PFParameterAssert([options rangeOfString:@"^[imxs]*$" options:NSRegularExpressionSearch].location != NSNotFound, + @"Invalid regex options %@", options); + + NSRegularExpressionOptions flags = 0; + if ([options rangeOfString:@"i"].location != NSNotFound) { + flags = flags | NSRegularExpressionCaseInsensitive; + } + if ([options rangeOfString:@"m"].location != NSNotFound) { + flags = flags | NSRegularExpressionAnchorsMatchLines; + } + if ([options rangeOfString:@"x"].location != NSNotFound) { + flags = flags | NSRegularExpressionAllowCommentsAndWhitespace; + } + if ([options rangeOfString:@"s"].location != NSNotFound) { + flags = flags | NSRegularExpressionDotMatchesLineSeparators; + } + + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:constraint + options:flags + error:&error]; + NSArray *matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + return matches.count > 0; +} + +/*! + Matches $exists constraints. + */ ++ (BOOL)matchesValue:(id)value + exists:(id)constraint { + if (constraint != nil && [constraint boolValue]) { + return value != nil && value != [NSNull null]; + } + + return value == nil || value == [NSNull null]; +} + +/*! + Matches $nearSphere constraints. + */ ++ (BOOL)matchesValue:(id)value + nearSphere:(id)constraint + maxDistance:(NSNumber *)maxDistance { + if (value == nil || value == [NSNull null]) { + return NO; + } + if (maxDistance == nil) { + return YES; + } + PFGeoPoint *point1 = constraint; + PFGeoPoint *point2 = value; + return [point1 distanceInRadiansTo:point2] <= [maxDistance doubleValue]; +} + +/*! + Matches $within constraints. + */ ++ (BOOL)matchesValue:(id)value + within:(id)constraint { + NSDictionary *constraintDictionary = (NSDictionary *)constraint; + NSArray *box = constraintDictionary[PFQueryOptionKeyBox]; + PFGeoPoint *southWest = box[0]; + PFGeoPoint *northEast = box[1]; + PFGeoPoint *target = (PFGeoPoint *)value; + + PFParameterAssert(northEast.longitude >= southWest.longitude, + @"whereWithinGeoBox queries cannot cross the International Date Line."); + PFParameterAssert(northEast.latitude >= southWest.latitude, + @"The southwest corner of a geo box must be south of the northeast corner."); + PFParameterAssert((northEast.longitude - southWest.longitude) <= 180, + @"Geo box queries larger than 180 degrees in longitude are not supported." + @"Please check point order."); + + return (target.latitude >= southWest.latitude && + target.latitude <= northEast.latitude && + target.longitude >= southWest.longitude && + target.longitude <= northEast.longitude); +} + +/*! + Returns YES iff the given value matches the given operator and constraint. + Raise NSInvalidArgumentException if the operator is not one this function can handle + */ ++ (BOOL)matchesValue:(id)value + constraint:(id)constraint + operator:(NSString *)operator + allKeyConstraints:(NSDictionary *)allKeyConstraints { + if ([operator isEqualToString:PFQueryKeyNotEqualTo]) { + return [self matchesValue:value notEqualTo:constraint]; + } else if ([operator isEqualToString:PFQueryKeyLessThan]) { + return [self matchesValue:value lessThan:constraint]; + } else if ([operator isEqualToString:PFQueryKeyLessThanEqualTo]) { + return [self matchesValue:value lessThanOrEqualTo:constraint]; + } else if ([operator isEqualToString:PFQueryKeyGreaterThan]) { + return [self matchesValue:value greaterThan:constraint]; + } else if ([operator isEqualToString:PFQueryKeyGreaterThanOrEqualTo]) { + return [self matchesValue:value greaterThanOrEqualTo:constraint]; + } else if ([operator isEqualToString:PFQueryKeyContainedIn]) { + return [self matchesValue:value containedIn:constraint]; + } else if ([operator isEqualToString:PFQueryKeyNotContainedIn]) { + return [self matchesValue:value notContainedIn:constraint]; + } else if ([operator isEqualToString:PFQueryKeyContainsAll]) { + return [self matchesValue:value containsAllObjectsInArray:constraint]; + } else if ([operator isEqualToString:PFQueryKeyRegex]) { + return [self matchesValue:value regex:constraint withOptions:allKeyConstraints[PFQueryOptionKeyRegexOptions]]; + } else if ([operator isEqualToString:PFQueryOptionKeyRegexOptions]) { + // No need to do anything. This is handled by $regex. + return YES; + } else if ([operator isEqualToString:PFQueryKeyExists]) { + return [self matchesValue:value exists:constraint]; + } else if ([operator isEqualToString:PFQueryKeyNearSphere]) { + return [self matchesValue:value + nearSphere:constraint + maxDistance:allKeyConstraints[PFQueryOptionKeyMaxDistance]]; + } else if ([operator isEqualToString:PFQueryOptionKeyMaxDistance]) { + // No need to do anything. This is handled by $nearSphere. + return YES; + } else if ([operator isEqualToString:PFQueryKeyWithin]) { + return [self matchesValue:value within:constraint]; + } + + [NSException raise:NSInvalidArgumentException + format:@"The offline store does not yet support %@ operator.", operator]; + // Shouldn't reach here + return YES; +} + +/*! + Creates a matcher that handles $inQuery constraints. + */ +- (PFConstraintMatcherBlock)createMatcherForKey:(NSString *)key + inQuery:(id)constraints + user:(PFUser *)user { + PFQuery *query = (PFQuery *)constraints; + PFSubQueryMatcher *subQueryMatcher = [[PFSubQueryMatcher alloc] initWithSubQuery:query + offlineStore:self.offlineStore]; + return [subQueryMatcher createMatcherWithSubQueryMatcherBlock:^BOOL(id object, NSArray *results) { + id value = [self valueForContainer:object key:key]; + return [[self class] matchesValue:value containedIn:results]; + } user:user]; +} + +/*! + Creates a matcher that handles $notInQuery constraints. + */ +- (PFConstraintMatcherBlock)createMatcherForKey:(NSString *)key + notInQuery:(id)constraints + user:(PFUser *)user { + PFConstraintMatcherBlock inQueryMatcher = [self createMatcherForKey:key inQuery:constraints user:user]; + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + return [inQueryMatcher(object, database) continueWithSuccessBlock:^id(BFTask *task) { + return @(![task.result boolValue]); + }]; + }; +} + +/*! + Creates a matcher that handles $select constraints. + */ +- (PFConstraintMatcherBlock)createMatcherForKey:(NSString *)key + select:(id)constraints + user:(PFUser *)user { + NSDictionary *constraintDictionary = (NSDictionary *)constraints; + PFQuery *query = (PFQuery *)constraintDictionary[PFQueryKeyQuery]; + NSString *resultKey = (NSString *)constraintDictionary[PFQueryKeyKey]; + PFSubQueryMatcher *subQueryMatcher = [[PFSubQueryMatcher alloc] initWithSubQuery:query + offlineStore:self.offlineStore]; + return [subQueryMatcher createMatcherWithSubQueryMatcherBlock:^BOOL(id object, NSArray *results) { + id value = [self valueForContainer:object key:key]; + for (id result in results) { + id resultValue = [self valueForContainer:result key:resultKey]; + if ([[self class] matchesValue:resultValue equalTo:value]) { + return YES; + } + } + return NO; + } user:user]; +} + +/*! + Creates a matcher that handles $dontSelect constraints. + */ +- (PFConstraintMatcherBlock)createMatcherForKey:(NSString *)key + dontSelect:(id)constraints + user:(PFUser *)user { + PFConstraintMatcherBlock selectMatcher = [self createMatcherForKey:key select:constraints user:user]; + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + return [selectMatcher(object, database) continueWithSuccessBlock:^id(BFTask *task) { + return @(![task.result boolValue]); + }]; + }; +} + +/*! + Creates a matcher for a particular constraint operator. + */ +- (PFConstraintMatcherBlock)createMatcherWithOperator:(NSString *)operator + constraints:(id)constraint + key:(NSString *)key + allKeyConstraints:(NSDictionary *)allKeyConstraints + user:(PFUser *)user { + if ([operator isEqualToString:PFQueryKeyInQuery]) { + return [self createMatcherForKey:key inQuery:constraint user:user]; + } else if ([operator isEqualToString:PFQueryKeyNotInQuery]) { + return [self createMatcherForKey:key notInQuery:constraint user:user]; + } else if ([operator isEqualToString:PFQueryKeySelect]) { + return [self createMatcherForKey:key select:constraint user:user]; + } else if ([operator isEqualToString:PFQueryKeyDontSelect]) { + return [self createMatcherForKey:key dontSelect:constraint user:user]; + } else { + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + id value = [self valueForContainer:object key:key]; + BOOL matchesValue = [[self class] matchesValue:value + constraint:constraint + operator:operator + allKeyConstraints:allKeyConstraints]; + return [BFTask taskWithResult:@(matchesValue)]; + }; + } +} + +/*! + Handles $or queries. + */ +- (PFConstraintMatcherBlock)createOrMatcherForQueries:(NSArray *)queries user:(PFUser *)user { + NSMutableArray *matchers = [NSMutableArray array]; + for (PFQuery *query in queries) { + PFConstraintMatcherBlock matcher = [self createMatcherWithQueryConstraints:query.state.conditions user:user]; + [matchers addObject:matcher]; + } + + // Now OR together the constraints for each query. + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + BFTask *task = [BFTask taskWithResult:@NO]; + for (PFConstraintMatcherBlock matcher in matchers) { + task = [task continueWithSuccessBlock:^id(BFTask *task) { + if ([task.result boolValue]) { + return task; + } + return matcher(object, database); + }]; + } + return task; + }; +} + +/*! + Returns a PFConstraintMatcherBlock that return true iff the object matches queryConstraints. This + takes in a SQLiteDatabase connection because SQLite is finicky about nesting connections, so we + want to reuse them whenever possible. + */ +- (PFConstraintMatcherBlock)createMatcherWithQueryConstraints:(NSDictionary *)queryConstraints user:(PFUser *)user { + NSMutableArray *matchers = [[NSMutableArray alloc] init]; + [queryConstraints enumerateKeysAndObjectsUsingBlock:^(id key, id queryConstraintValue, BOOL *stop) { + if ([key isEqualToString:PFQueryKeyOr]) { + // A set of queries to be OR-ed together + PFConstraintMatcherBlock matcher = [self createOrMatcherForQueries:queryConstraintValue user:user]; + [matchers addObject:matcher]; + } else if ([key isEqualToString:PFQueryKeyRelatedTo]) { + PFConstraintMatcherBlock matcher = ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + PFObject *parent = queryConstraintValue[PFQueryKeyObject]; + NSString *relationKey = queryConstraintValue[PFQueryKeyKey]; + PFRelation *relation = parent[relationKey]; + + return [BFTask taskWithResult:@([relation _hasKnownObject:object])]; + }; + [matchers addObject:matcher]; + } else if ([queryConstraintValue isKindOfClass:[NSDictionary class]]) { + // If it's a set of constraints that should be AND-ed together + NSDictionary *keyConstraints = (NSDictionary *)queryConstraintValue; + [keyConstraints enumerateKeysAndObjectsUsingBlock:^(id operator, id keyConstraintValue, BOOL *stop) { + PFConstraintMatcherBlock matcher = [self createMatcherWithOperator:operator + constraints:keyConstraintValue + key:key + allKeyConstraints:keyConstraints + user:user]; + [matchers addObject:matcher]; + }]; + } else { + // It's not a set of constraints, so it's just a value to compare against. + PFConstraintMatcherBlock matcher = ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + id objectValue = [self valueForContainer:object key:key]; + BOOL matches = [[self class] matchesValue:objectValue equalTo:queryConstraintValue]; + return [BFTask taskWithResult:@(matches)]; + }; + [matchers addObject:matcher]; + } + }]; + + // Now AND together the constraints for each key + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + BFTask *task = [BFTask taskWithResult:@YES]; + for (PFConstraintMatcherBlock matcher in matchers) { + task = [task continueWithSuccessBlock:^id(BFTask *task) { + if (![task.result boolValue]) { + return task; + } + @try { + return matcher(object, database); + } @catch (NSException *exception) { + // Promote to error to keep the same behavior as online. + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorInvalidQuery + message:exception.reason + shouldLog:NO]; + return [BFTask taskWithError:error]; + } + }]; + } + return task; + }; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BFTask *)fetchIncludeAsync:(NSString *)include + container:(id)container + database:(PFSQLiteDatabase *)database { + if (container == nil) { + return [BFTask taskWithResult:nil]; + } + + if ([container isKindOfClass:[NSArray class]]) { + NSArray *array = (NSArray *)container; + // We do the fetches in series because it makes it easier to fail on the first error. + BFTask *task = [BFTask taskWithResult:nil]; + for (id item in array) { + task = [task continueWithSuccessBlock:^id(BFTask *task) { + return [self fetchIncludeAsync:include container:item database:database]; + }]; + } + return task; + } + + // If we've reached the end of include, then actually do the fetch. + if (include == nil) { + if ([container isKindOfClass:[PFObject class]]) { + PFObject *object = (PFObject *)container; + return [self.offlineStore fetchObjectLocallyAsync:object database:database]; + } else if (container == [NSNull null]) { + // Accept NSNull value in included field. We swallow it silently instead of + // throwing an exception. + return nil; + } + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorInvalidNestedKey + message:@"include is invalid for non-ParseObjects"]; + return [BFTask taskWithError:error]; + } + + // Descend into the container and try again + NSArray *parts = [include componentsSeparatedByString:@"."]; + + NSString *key = [parts firstObject]; + NSString *rest = nil; + if ([parts count] > 1) { + NSRange range = NSMakeRange(1, [parts count] - 1); + rest = [[parts subarrayWithRange:range] componentsJoinedByString:@"."]; + } + + return [[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) { + if ([container isKindOfClass:[PFObject class]]) { + BFTask *fetchTask = [self fetchIncludeAsync:nil container:container database:database]; + return [fetchTask continueWithSuccessBlock:^id(BFTask *task) { + return ((PFObject *)container)[key]; + }]; + } else if ([container isKindOfClass:[NSDictionary class]]) { + return ((NSDictionary *)container)[key]; + } else if (container == [NSNull null]) { + // Accept NSNull value in included field. We swallow it silently instead of + // throwing an exception. + return nil; + } + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"include is invalid" + userInfo:nil]; + return [BFTask taskWithException:exception]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [self fetchIncludeAsync:rest container:task.result database:database]; + }]; +} + +///-------------------------------------- +#pragma mark - User Access +///-------------------------------------- + ++ (BOOL)userHasReadAccess:(PFUser *)user ofObject:(PFObject *)object { + if (user == object) { + return YES; + } + + PFACL *acl = [object ACL]; + if (acl == nil) { + return YES; + } + if ([acl getPublicReadAccess]) { + return YES; + } + if (user != nil && [acl getReadAccessForUser:user]) { + return YES; + } + + // TODO (hallucinogen): Implement roles + return NO; +} + ++ (BOOL)userHasWriteAccess:(PFUser *)user ofObject:(PFObject *)object { + if (user == object) { + return YES; + } + + PFACL *acl = [object ACL]; + if (acl == nil) { + return YES; + } + if ([acl getPublicWriteAccess]) { + return YES; + } + if (user != nil && [acl getWriteAccessForUser:user]) { + return YES; + } + + // TODO (hallucinogen): Implement roles + return NO; +} + +///-------------------------------------- +#pragma mark - Internal Public Methods +///-------------------------------------- + +- (PFConstraintMatcherBlock)createMatcherForQueryState:(PFQueryState *)queryState user:(PFUser *)user { + PFConstraintMatcherBlock constraintMatcher = [self createMatcherWithQueryConstraints:queryState.conditions + user:user]; + // Capture ignoreACLs before the block since it might be modified between matchings. + BOOL shouldIgnoreACLs = queryState.shouldIgnoreACLs; + + return ^BFTask *(PFObject *object, PFSQLiteDatabase *database) { + // TODO (hallucinogen): revisit this whether we should check query and object parseClassname equality + if (!shouldIgnoreACLs && ![[self class] userHasReadAccess:user ofObject:object]) { + return [BFTask taskWithResult:@NO]; + } + return constraintMatcher(object, database); + }; +} + +///-------------------------------------- +#pragma mark - Query Options +///-------------------------------------- + +- (NSArray *)resultsByApplyingOptions:(PFOfflineQueryOption)options + ofQueryState:(PFQueryState *)queryState + toResults:(NSArray *)results { + // No results or empty options. + if (results.count == 0 || options == 0) { + return results; + } + + NSMutableArray *mutableResults = [results mutableCopy]; + if (options & PFOfflineQueryOptionOrder) { + [self _sortResults:mutableResults ofQueryState:queryState]; + } + if (options & PFOfflineQueryOptionSkip) { + NSInteger skip = queryState.skip; + if (skip > 0) { + skip = MIN(skip, results.count); + [mutableResults removeObjectsInRange:NSMakeRange(0, skip)]; + } + } + if (options & PFOfflineQueryOptionLimit) { + NSInteger limit = queryState.limit; + if (limit >= 0 && mutableResults.count > limit) { + [mutableResults removeObjectsInRange:NSMakeRange(limit, mutableResults.count - limit)]; + } + } + + return [mutableResults copy]; +} + +- (void)_sortResults:(NSMutableArray *)results ofQueryState:(PFQueryState *)queryState { + NSArray *keys = queryState.sortKeys; + [keys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString *key = (NSString *)obj; + if ([key rangeOfString:@"^-?[A-Za-z][A-Za-z0-9_]*$" options:NSRegularExpressionSearch].location == NSNotFound) { + PFConsistencyAssert([@"_created_at" isEqualToString:key] || [@"_updated_at" isEqualToString:key], + @"Invalid key name: %@", key); + } + }]; + + __block NSString *nearSphereKey = nil; + __block PFGeoPoint *nearSphereValue = nil; + [queryState.conditions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([obj isKindOfClass:[NSDictionary class]]) { + NSDictionary *keyConstraints = (NSDictionary *)obj; + if (keyConstraints[PFQueryKeyNearSphere]) { + nearSphereKey = [key copy]; + nearSphereValue = keyConstraints[PFQueryKeyNearSphere]; + } + } + }]; + + // If there's nothing to sort based on, then don't do anything. + if (keys.count == 0 && nearSphereKey == nil) { + return; + } + + [results sortUsingComparator:^NSComparisonResult(id lhs, id rhs) { + if (nearSphereKey != nil) { + PFGeoPoint *lhsPoint = [self valueForContainer:lhs key:nearSphereKey]; + PFGeoPoint *rhsPoint = [self valueForContainer:rhs key:nearSphereKey]; + + double lhsDistance = [lhsPoint distanceInRadiansTo:nearSphereValue]; + double rhsDistance = [rhsPoint distanceInRadiansTo:nearSphereValue]; + if (lhsDistance != rhsDistance) { + return (lhsDistance - rhsDistance < 0) ? NSOrderedAscending : NSOrderedDescending; + } + } + + for (int i = 0; i < keys.count; ++i) { + NSString *key = keys[i]; + BOOL descending = NO; + if ([key hasPrefix:@"-"]) { + descending = YES; + key = [key substringFromIndex:1]; + } + + id lhsValue = [self valueForContainer:lhs key:key]; + id rhsValue = [self valueForContainer:rhs key:key]; + + NSComparisonResult result = NSOrderedSame; + if (lhsValue != nil && rhsValue == nil) { + result = NSOrderedAscending; + } else if (lhsValue == nil && rhsValue != nil) { + result = NSOrderedDescending; + } else if (lhsValue == nil && rhsValue == nil) { + result = NSOrderedSame; + } else { + result = [lhsValue compare:rhsValue]; + } + + if (result != 0) { + return descending ? -result : result; + } + + } + + return NSOrderedSame; + }]; +} + +- (BFTask *)fetchIncludesAsyncForResults:(NSArray *)results + ofQueryState:(PFQueryState *)queryState + inDatabase:(PFSQLiteDatabase *)database { + BFTask *fetchTask = [BFTask taskWithResult:nil]; + for (PFObject *object in results) { + @weakify(self); + fetchTask = [fetchTask continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + return [self fetchIncludesForObjectAsync:object + queryState:queryState + database:database]; + }]; + } + return fetchTask; +} + +- (BFTask *)fetchIncludesForObjectAsync:(PFObject *)object + queryState:(PFQueryState *)queryState + database:(PFSQLiteDatabase *)database { + NSSet *includes = queryState.includedKeys; + // We do the fetches in series because it makes it easier to fail on first error. + BFTask *task = [BFTask taskWithResult:nil]; + for (NSString *include in includes) { + // We do the fetches in series because it makes it easier to fail on the first error. + task = [task continueWithSuccessBlock:^id(BFTask *task) { + return [self fetchIncludeAsync:include container:object database:database]; + }]; + } + return task; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h new file mode 100644 index 0000000..b8f1c69 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFFileManager; +@class PFObject; +@class PFPin; +@class PFQueryState; +@class PFSQLiteDatabase; +@class PFUser; + +typedef NS_OPTIONS(uint8_t, PFOfflineStoreOptions) +{ + PFOfflineStoreOptionAlwaysFetchFromSQLite = 1 << 0, +}; + +//TODO: (nlutsenko) Bring this header up to standard with @name, method comments, etc... +@interface PFOfflineStore : NSObject + +@property (nonatomic, assign, readonly) PFOfflineStoreOptions options; +@property (nonatomic, strong, readonly) PFFileManager *fileManager; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(PFFileManager *)fileManager + options:(PFOfflineStoreOptions)options NS_DESIGNATED_INITIALIZER; + +///-------------------------------------- +/// @name Fetch +///-------------------------------------- + +- (BFTask *)fetchObjectLocallyAsync:(PFObject *)object; + +/*! + Gets the data for the given object from the offline database. Returns a task that will be + completed if data for the object was available. If the object is not in the cache, the task + will be faulted, with a CACHE_MISS error. + + @param object The object to fetch. + @param database A database connection to use. + */ +- (BFTask *)fetchObjectLocallyAsync:(PFObject *)object database:(PFSQLiteDatabase *)database; + +///-------------------------------------- +/// @name Save +///-------------------------------------- + +//TODO: (nlutsenko) Remove `includChildren` method, replace with PFLocalStore that wraps OfflineStore + Pin. +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object includeChildren:(BOOL)includeChildren; +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object withChildren:(NSArray *)children; + +/*! + Stores an object (and optionally, every object it points to recursively) in the local database. + If any of the objects have not been fetched from Parse, they will not be stored. However, if + they have changed data, the data will be retained. To get the objects back later, you can use a + ParseQuery with a cache policy that uses the local cache, or you can create an unfetched + pointer with ParseObject.createWithoutData() and then call fetchFromLocalDatastore() on it. + If you modify the object after saving it locally, such as by fetching it or saving it, + those changes will automatically be applied to the cache. + + @param object The root of the objects to save. + @param children If non-empty - these children will be saved to LDS as well. + @param database A database connection to use. + */ +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object + withChildren:(NSArray *)children + database:(PFSQLiteDatabase *)database; + +///-------------------------------------- +/// @name Find +///-------------------------------------- + +/*! + Runs a PFQueryState against the store's contents. + + @returns The objects that match the query's constraint. + */ +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin; + +/*! + Runs a PFQueryState against the store's contents. + + @returns The count of objects that match the query's constraint. + */ +- (BFTask *)countAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin; + +/*! + Runs a PFQueryState against the store's contents. + + @returns The objects that match the query's constraint. + */ +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin + isCount:(BOOL)isCount; + +/*! + Runs a PFQueryState against the store's contents. May cause any instances of the object to get fetched from + offline database. (TODO (hallucinogen): should we consider objects in memory but not in Offline Store?) + + @param queryState The query. + @param user The user making the query. + @param pin (Optional) The pin we're querying across. If null, all pins. + @param isCount YES if we're doing count. + @param database The PFSQLiteDatabase + + @returns The objects that match the query's constraint. + */ +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin + isCount:(BOOL)isCount + database:(PFSQLiteDatabase *)database; + +///-------------------------------------- +/// @name Update Internal State +///-------------------------------------- + +/*! + Takes an object that has been fetched from the database before and updates it with whatever + data is in memory. This will only be used when data comes back from the server after a fetch + or a save. + */ +- (BFTask *)updateDataForObjectAsync:(PFObject *)object; + +///-------------------------------------- +/// @name Delete +///-------------------------------------- + +/*! + Deletes the given object from Offline Store's pins + */ +- (BFTask *)deleteDataForObjectAsync:(PFObject *)object; + +///-------------------------------------- +/// @name Unpin +///-------------------------------------- + +- (BFTask *)unpinObjectAsync:(PFObject *)object; + +///-------------------------------------- +/// @name Internal Helper Methods +///-------------------------------------- + +/*! + Gets the UUID for the given object, if it has one. Otherwise, creates a new UUID for the object + and adds a new row to the database for the object with no data. + */ +- (BFTask *)getOrCreateUUIDAsyncForObject:(PFObject *)object + database:(PFSQLiteDatabase *)database; + +/*! + This should only be called from `PFObject.objectWithoutDataWithClassName`. + + @returns an object from OfflineStore cache. If nil is returned the object is not found in the cache. + */ +- (PFObject *)getOrCreateObjectWithoutDataWithClassName:(NSString *)className + objectId:(NSString *)objectId; + +/*! + When an object is finished saving, it gets an objectId. Then it should call this method to + clean up the bookeeping around ids. + */ +- (void)updateObjectIdForObject:(PFObject *)object + oldObjectId:(NSString *)oldObjectId + newObjectId:(NSString *)newObjectId; + +///-------------------------------------- +/// @name Unit Test Helper Methods +///-------------------------------------- + +/*! + Used in unit testing only. Clears all in-memory caches so that data must be retrieved from disk. + */ +- (void)simulateReboot; + +/*! + Used in unit testing only. Clears the database on disk. + */ +- (void)clearDatabase; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m new file mode 100644 index 0000000..d90e373 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m @@ -0,0 +1,1067 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFOfflineStore.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFDecoder.h" +#import "PFEncoder.h" +#import "PFErrorUtilities.h" +#import "PFFileManager.h" +#import "PFJSONSerialization.h" +#import "PFObjectPrivate.h" +#import "PFOfflineQueryLogic.h" +#import "PFPin.h" +#import "PFQueryPrivate.h" +#import "PFSQLiteDatabase.h" +#import "PFSQLiteDatabaseController.h" +#import "PFSQLiteDatabaseResult.h" +#import "PFUser.h" +#import "PFWeakValue.h" +#import "Parse_Private.h" + +typedef BFTask *(^PFOfflineStoreDatabaseExecutionBlock)(PFSQLiteDatabase *database); + +NSString *const PFOfflineStoreDatabaseName = @"ParseOfflineStore"; + +NSString *const PFOfflineStoreTableOfObjects = @"ParseObjects"; +NSString *const PFOfflineStoreKeyOfClassName = @"className"; +NSString *const PFOfflineStoreKeyOfIsDeletingEventually = @"isDeletingEventually"; +NSString *const PFOfflineStoreKeyOfJSON = @"json"; +NSString *const PFOfflineStoreKeyOfObjectId = @"objectId"; +NSString *const PFOfflineStoreKeyOfUUID = @"uuid"; + +NSString *const PFOfflineStoreTableOfDependencies = @"Dependencies"; +NSString *const PFOfflineStoreKeyOfKey = @"key"; + +int const PFOfflineStoreMaximumSQLVariablesCount = 999; + +@interface PFOfflineStore () + +@property (nonatomic, assign, readwrite) PFOfflineStoreOptions options; + +@property (nonatomic, strong, readonly) NSObject *lock; + +/*! + In-memory map of (className, objectId) to ParseObject. This is used so that we can + always return the same instance for a given object. Objects in this map may or may + not be in the database. + */ +@property (nonatomic, strong, readonly) NSMapTable *classNameAndObjectIdToObjectMap; + +/*! + In-memory set of ParseObjects that have been fetched from local database already. + If the object is in the map, a fetch of it has been started. If the value is a + finished task, then the fetch was completed. + */ +@property (nonatomic, strong, readonly) NSMapTable *fetchedObjects; + +/*! + In-memory map of ParseObject to UUID. This is used so that we can always return + the same instance for a given object. Objects in this map may or may not be in the + database. + */ +@property (nonatomic, strong, readonly) NSMapTable *objectToUUIDMap; + +/*! + In-memory map of UUID to ParseObject. This is used so we can always return + the same instance for a given object. The only objects in this map are ones that + are in database. + */ +@property (nonatomic, strong, readonly) NSMapTable *UUIDToObjectMap; + +@property (nonatomic, strong, readonly) PFOfflineQueryLogic *offlineQueryLogic; + +@property (nonatomic, strong, readonly) PFSQLiteDatabaseController *databaseController; + +@end + +@implementation PFOfflineStore + +@synthesize offlineQueryLogic = _offlineQueryLogic; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithFileManager:(PFFileManager *)fileManager options:(PFOfflineStoreOptions)options { + self = [super init]; + if (!self) return nil; + + _options = options; + _fileManager = fileManager; + _databaseController = [PFSQLiteDatabaseController controllerWithFileManager:_fileManager]; + _lock = [[NSObject alloc] init]; + _classNameAndObjectIdToObjectMap = [NSMapTable strongToWeakObjectsMapTable]; + _fetchedObjects = [NSMapTable weakToStrongObjectsMapTable]; + // This is a bit different from what we have in Android. The reason is because the object is quickly + // retained by the OS and we depend on this MapTable to fetch the `uuidTask` of the object. + _objectToUUIDMap = [NSMapTable weakToStrongObjectsMapTable]; + _UUIDToObjectMap = [NSMapTable strongToWeakObjectsMapTable]; + + [[self class] _initializeTablesInBackgroundWithDatabaseController:_databaseController]; + + return self; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BFTask *)fetchObjectLocallyAsync:(PFObject *)object { + __block BFTask *fetchTask = nil; + return [[self _performDatabaseOperationAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + // We need this to return the result of `fetchObjectLocallyAsync` instead of returning the + // result of `[database closeAsync]` + fetchTask = [self fetchObjectLocallyAsync:object database:database]; + return fetchTask; + }] continueWithBlock:^id(BFTask *task) { + return fetchTask; + }]; +} + +- (BFTask *)fetchObjectLocallyAsync:(PFObject *)object database:(PFSQLiteDatabase *)database { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + BFTask *uuidTask = nil; + + @synchronized (self.lock) { + BFTask *fetchTask = [self.fetchedObjects objectForKey:object]; + if (fetchTask && !(self.options & PFOfflineStoreOptionAlwaysFetchFromSQLite)) { + // The object has been fetched from offline store, so any data that's in there + // is already reflected in the in-memory version. There's nothing more to do. + return [fetchTask continueWithBlock:^id(BFTask *task) { + return [BFTask taskWithResult:[task.result weakObject]]; + }]; + } + + // Put a placeholder so that anyone else who attempts to fetch this object will just + // wait for this call to finish doing it. + [self.fetchedObjects setObject:[tcs.task continueWithBlock:^id(BFTask *task) { + return [BFTask taskWithResult:[PFWeakValue valueWithWeakObject:task.result]]; + }] forKey:object]; + uuidTask = [self.objectToUUIDMap objectForKey:object]; + } + NSString *className = [object parseClassName]; + NSString *objectId = [object objectId]; + + // If this gets set, then it will contain data from offline store that need to be merged + // into existing object in memory + BFTask *jsonStringTask = [BFTask taskWithResult:nil]; + __block NSString *uuid = nil; + + if (objectId == nil) { + // This object has never been saved to Parse + if (uuidTask == nil) { + // This object was not pulled from the datastore or previously saved to it. + // There's nothing that can be fetched from it. This isn't an error, because it's + // really convenient to try to fetch objects from offline store just to make sure + // they're up-to-date, and we shouldn't force developers to specially handle this case. + } else { + // This object is a new ParseObject that is known to the datastore, but hasn't been + // fetched. The only way this could happen is if the object had previously been stored + // in the offline store, then the object was removed from memory (maybe by rebooting), + // and then an object with a pointer to it was fetched, so we only created the pointer. + // We need to pull the data out of the database using UUID. + + jsonStringTask = [[uuidTask continueWithSuccessBlock:^id(BFTask *task) { + uuid = task.result; + NSString *query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = ?;", + PFOfflineStoreKeyOfJSON, PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID]; + return [database executeQueryAsync:query + withArgumentsInArray:[NSArray arrayWithObjects:uuid, nil]]; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFSQLiteDatabaseResult *result = task.result; + if (![result next]) { + [result close]; + [NSException raise:NSInternalInconsistencyException + format:@"Attempted to find non-existent uuid %@.", uuid]; + } + NSString *jsonString = [result stringForColumnIndex:0]; + [result close]; + + return jsonString; + }]; + } + } else { + if (uuidTask && !(self.options & PFOfflineStoreOptionAlwaysFetchFromSQLite)) { + // This object is an existing ParseObject, and we must've already pulled its data + // out of the offline store, or else we wouldn't know its UUID. This should never happen. + NSString *message = @"Object must have already been fetched but isn't marked as fetched."; + [tcs setException:[NSException exceptionWithName:NSInternalInconsistencyException + reason:message + userInfo:nil]]; + + @synchronized (self.lock) { + [self.fetchedObjects removeObjectForKey:object]; + } + return tcs.task; + } + + // We've got a pointer to an existing ParseObject, but we've never pulled its data out of + // the offline store. Since fetching from the server forces a fetch from the offline + // store, that means this is a pointer. We need to try to find any existing entry for this + // object in the database. + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@ FROM %@ WHERE %@ = ? AND %@ = ?;", + PFOfflineStoreKeyOfJSON, PFOfflineStoreKeyOfUUID, + PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfClassName, + PFOfflineStoreKeyOfObjectId]; + NSArray *args = @[ className, objectId ]; + jsonStringTask = [[database executeQueryAsync:query + withArgumentsInArray:args] continueWithSuccessBlock:^id(BFTask *task) { + PFSQLiteDatabaseResult *result = task.result; + if (![result next]) { + NSString *errorMessage = @"This object is not available in the offline cache."; + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCacheMiss + message:errorMessage + shouldLog:NO]; + [result close]; + return [BFTask taskWithError:error]; + } + + NSString *jsonString = [result stringForColumnIndex:0]; + NSString *newUUID = [result stringForColumnIndex:1]; + [result close]; + + @synchronized (self.lock) { + // It's okay to put this object into the uuid map. No one will try to fetch it, + // because it's already in the fetchedObjects map. And no one will try to save it + // without fetching it first, so everything should be fine. + [self.objectToUUIDMap setObject:[BFTask taskWithResult:newUUID] forKey:object]; + [self.UUIDToObjectMap setObject:object forKey:newUUID]; + } + return jsonString; + }]; + } + + return [[jsonStringTask continueWithSuccessBlock:^id(BFTask *task) { + NSString *jsonString = task.result; + if (jsonString == nil) { + // This means we tried to fetch from the database that was never actually saved + // locally. This probably means that its parent object was saved locally and we + // just created a pointer to this object. This should be considered cache miss. + + NSString *errorMessage = @"Attempted to fetch and object offline which was never " + @"saved to the offline cache"; + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCacheMiss + message:errorMessage + shouldLog:NO]; + return [BFTask taskWithError:error]; + } + id parsedJson = [PFJSONSerialization JSONObjectFromString:jsonString]; + NSMutableDictionary *offlineObjects = [[NSMutableDictionary alloc] init]; + [PFInternalUtils traverseObject:parsedJson usingBlock:^id(id object) { + // Omit root and PFObject + if ([object isKindOfClass:[NSDictionary class]] && + [((NSDictionary *)object)[@"__type"] isEqualToString:@"OfflineObject"] && + object != parsedJson) { + NSString *uuid = ((NSDictionary *)object)[@"uuid"]; + offlineObjects[uuid] = [self _getPointerAsyncWithUUID:uuid database:database]; + } + return object; + }]; + + NSArray *objectValues = [offlineObjects allValues]; + return [[BFTask taskForCompletionOfAllTasks:objectValues] continueWithSuccessBlock:^id(BFTask *task) { + PFDecoder *decoder = [PFOfflineDecoder decoderWithOfflineObjects:offlineObjects]; + [object mergeFromRESTDictionary:parsedJson withDecoder:decoder]; + return [BFTask taskWithResult:nil]; + }]; + }] continueWithBlock:^id(BFTask *task) { + if (task.isCancelled) { + [tcs cancel]; + } else if (task.error != nil) { + [tcs setError:task.error]; + } else if (task.exception != nil) { + [tcs setException:task.exception]; + } else { + [tcs setResult:object]; + } + return tcs.task; + }]; +} + +///-------------------------------------- +#pragma mark - Save +///-------------------------------------- + +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object includeChildren:(BOOL)includeChildren { + //TODO: (nlutsenko) Remove this method, replace with LocalStore implementation that wraps OfflineStore + Pin. + return [self _performDatabaseTransactionAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + return [self saveObjectLocallyAsync:object includeChildren:includeChildren database:database]; + }]; +} + +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object withChildren:(NSArray *)children { + return [self _performDatabaseTransactionAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + return [self saveObjectLocallyAsync:object withChildren:children database:database]; + }]; +} + +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object + includeChildren:(BOOL)includeChildren + database:(PFSQLiteDatabase *)database { + //TODO: (nlutsenko) Remove this method, replace with LocalStore implementation that wraps OfflineStore + Pin. + NSMutableArray *children = nil; + if (includeChildren) { + children = [NSMutableArray array]; + [PFInternalUtils traverseObject:object usingBlock:^id(id traversedObject) { + if ([traversedObject isKindOfClass:[PFObject class]]) { + [children addObject:traversedObject]; + } + return traversedObject; + }]; + } + return [self saveObjectLocallyAsync:object withChildren:children database:database]; +} + +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object + withChildren:(NSArray *)children + database:(PFSQLiteDatabase *)database { + //TODO (nlutsenko): Add assert that checks whether all children are actually children of an object. + NSMutableArray *objectsInTree = nil; + if (children == nil) { + objectsInTree = [NSMutableArray arrayWithObject:object]; + } else { + objectsInTree = [children mutableCopy]; + if (![objectsInTree containsObject:object]) { + [objectsInTree addObject:object]; + } + } + + // Call saveObjectLocallyAsync for each of them individually + NSMutableArray *tasks = [[NSMutableArray alloc] init]; + for (PFObject *objInTree in objectsInTree) { + [tasks addObject:[self fetchObjectLocallyAsync:objInTree database:database]]; + } + + return [[[[[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *task) { + return [self.objectToUUIDMap objectForKey:object]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSString *uuid = task.result; + if (uuid == nil) { + // The root object was never stored in offline store, so nothing unpin. + return [BFTask taskWithResult:nil]; + } + + // Delete all objects locally corresponding to the key we're trying to use in case it was + // used before (overwrite) + return [self _unpinKeyAsync:uuid database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [self getOrCreateUUIDAsyncForObject:object database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSString *uuid = task.result; + + NSMutableArray *tasks = [[NSMutableArray alloc] init]; + for (PFObject *object in objectsInTree) { + [tasks addObject:[self saveObjectLocallyAsync:object key:uuid database:database]]; + } + + return [BFTask taskForCompletionOfAllTasks:tasks]; + }]; +} + +- (BFTask *)saveObjectLocallyAsync:(PFObject *)object + key:(NSString *)key + database:(PFSQLiteDatabase *)database { + if ([object objectId] != nil && ![object isDataAvailable] && + ![object _hasChanges] && ![object _hasOutstandingOperations]) { + return [BFTask taskWithResult:nil]; + } + + __block NSString *uuid = nil; + __block id encoded = nil; + return [[[[BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + // Make sure we have UUID for the object to be saved. + return [self getOrCreateUUIDAsyncForObject:object database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + uuid = task.result; + + // Encode the object, and wait for the UUIDs in its pointers to get encoded. + PFOfflineObjectEncoder *encoder = [PFOfflineObjectEncoder objectEncoderWithOfflineStore:self database:database]; + // We don't care about operationSetUUIDs here + NSArray *operationSetUUIDs = nil; + encoded = [object RESTDictionaryWithObjectEncoder:encoder operationSetUUIDs:&operationSetUUIDs]; + return [encoder encodeFinished]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // Time to actually save the object + NSString *className = [object parseClassName]; + NSString *objectId = [object objectId]; + NSString *encodedString = [PFJSONSerialization stringFromJSONObject:encoded]; + NSString *updateFields = nil; + NSArray *queryParams = nil; + + if (objectId != nil) { + updateFields = [NSString stringWithFormat:@"%@ = ?, %@ = ?, %@ = ?", + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfJSON, + PFOfflineStoreKeyOfObjectId]; + queryParams = @[className, encodedString, objectId, uuid]; + } else { + updateFields = [NSString stringWithFormat:@"%@ = ?, %@ = ?", + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfJSON]; + queryParams = @[className, encodedString, uuid]; + } + + NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@ = ?", + PFOfflineStoreTableOfObjects, updateFields, + PFOfflineStoreKeyOfUUID]; + return [database executeSQLAsync:sql withArgumentsInArray:queryParams]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSString *sql = [NSString stringWithFormat:@"INSERT OR IGNORE INTO %@(%@, %@) VALUES (?, ?)", + PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfKey, + PFOfflineStoreKeyOfUUID]; + return [database executeSQLAsync:sql withArgumentsInArray:@[key, uuid]]; + }]; +} + +///-------------------------------------- +#pragma mark - Find +///-------------------------------------- + +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin { + return [self findAsyncForQueryState:queryState user:user pin:pin isCount:NO]; +} + +- (BFTask *)countAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin { + return [[self findAsyncForQueryState:queryState + user:user + pin:pin + isCount:YES] continueWithSuccessBlock:^id(BFTask *task) { + if (!task.cancelled && !task.error && !task.exception) { + NSArray *result = task.result; + return @(result.count); + } + return task; + }]; +} + +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin + isCount:(BOOL)isCount { + __block BFTask *resultTask = nil; + return [[self _performDatabaseOperationAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + resultTask = [self findAsyncForQueryState:queryState user:user pin:pin isCount:isCount database:database]; + return resultTask; + }] continueWithBlock:^id(BFTask *ignored) { + // We need this to return the result of `findQuery` instead of returning the + // result of `[database closeAsync]` + return resultTask; + }]; +} + +- (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState + user:(PFUser *)user + pin:(PFPin *)pin + isCount:(BOOL)isCount + database:(PFSQLiteDatabase *)database { + __block NSMutableArray *mutableResults = [NSMutableArray array]; + BFTask *queryTask = nil; + BOOL includeIsDeletingEventually = queryState.shouldIncludeDeletingEventually; + + if (pin == nil) { + NSString *isDeletingEventuallyQuery = @""; + if (!includeIsDeletingEventually) { + isDeletingEventuallyQuery = [NSString stringWithFormat:@"AND %@ = 0", + PFOfflineStoreKeyOfIsDeletingEventually]; + } + NSString *queryString = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = ? %@;", + PFOfflineStoreKeyOfUUID, PFOfflineStoreTableOfObjects, + PFOfflineStoreKeyOfClassName, isDeletingEventuallyQuery]; + queryTask = [database executeQueryAsync:queryString withArgumentsInArray:@[ queryState.parseClassName ]]; + } else { + BFTask *uuidTask = [self.objectToUUIDMap objectForKey:pin]; + if (uuidTask == nil) { + // Pin was never saved locally, therefore there won't be any results. + return [BFTask taskWithResult:mutableResults]; + } + + queryTask = [uuidTask continueWithSuccessBlock:^id(BFTask *task) { + NSString *uuid = task.result; + NSString *isDeletingEventuallyQuery = @""; + if (!includeIsDeletingEventually) { + isDeletingEventuallyQuery = [NSString stringWithFormat:@"AND %@ = 0", + PFOfflineStoreKeyOfIsDeletingEventually]; + } + NSString *queryString = [NSString stringWithFormat:@"SELECT A.%@ FROM %@ A " + @"INNER JOIN %@ B ON A.%@ = B.%@ WHERE %@ = ? AND %@ = ? %@;", + PFOfflineStoreKeyOfUUID, PFOfflineStoreTableOfObjects, + PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfUUID, + PFOfflineStoreKeyOfUUID, PFOfflineStoreKeyOfClassName, + PFOfflineStoreKeyOfKey, isDeletingEventuallyQuery]; + + return [database executeQueryAsync:queryString + withArgumentsInArray:@[ queryState.parseClassName, uuid ]]; + }]; + } + + @weakify(self); + return [[queryTask continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFSQLiteDatabaseResult *result = task.result; + + PFConstraintMatcherBlock matcherBlock = [self.offlineQueryLogic createMatcherForQueryState:queryState + user:user]; + + BFTask *checkAllObjectsTask = [BFTask taskWithResult:nil]; + while ([result next]) { + NSString *uuid = [result stringForColumnIndex:0]; + __block PFObject *object = nil; + + checkAllObjectsTask = [[[[checkAllObjectsTask continueWithSuccessBlock:^id(BFTask *task) { + return [self _getPointerAsyncWithUUID:uuid database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + object = task.result; + return [self fetchObjectLocallyAsync:object database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + if (!object.isDataAvailable) { + return [BFTask taskWithResult:@NO]; + } + return matcherBlock(object, database); + }] continueWithSuccessBlock:^id(BFTask *task) { + if ([task.result boolValue]) { + [mutableResults addObject:object]; + } + return [BFTask taskWithResult:nil]; + }]; + } + [result close]; + + return checkAllObjectsTask; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + + // Sort, Apply Skip and Limit + + PFOfflineQueryOption queryOptions = 0; + if (!isCount) { + queryOptions = PFOfflineQueryOptionOrder | PFOfflineQueryOptionSkip | PFOfflineQueryOptionLimit; + } + NSArray *results = [self.offlineQueryLogic resultsByApplyingOptions:queryOptions + ofQueryState:queryState + toResults:mutableResults]; + + // Fetch includes + BFTask *fetchIncludesTask = [self.offlineQueryLogic fetchIncludesAsyncForResults:results + ofQueryState:queryState + inDatabase:database]; + + return [fetchIncludesTask continueWithSuccessBlock:^id(BFTask *task) { + return results; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Update +///-------------------------------------- + +- (BFTask *)updateDataForObjectAsync:(PFObject *)object { + BFTask *fetchTask = nil; + + @synchronized (self.lock) { + fetchTask = [self.fetchedObjects objectForKey:object]; + if (!fetchTask) { + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"An object cannot be updated if it wasn't fetched" + userInfo:nil]; + return [BFTask taskWithException:exception]; + } + } + return [fetchTask continueWithBlock:^id(BFTask *task) { + if (task.error != nil) { + // Catch CACHE_MISS errors and ignore them. + if (task.error.code == kPFErrorCacheMiss) { + return [BFTask taskWithResult:nil]; + } + return [BFTask taskWithResult:[task.result weakObject]]; + } + + return [self _performDatabaseTransactionAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + return [self _updateDataForObjectAsync:object inDatabase:database]; + }]; + }]; +} + +- (BFTask *)_updateDataForObjectAsync:(PFObject *)object inDatabase:(PFSQLiteDatabase *)database { + BFTask *uuidTask = nil; + @synchronized (self.lock) { + uuidTask = [self.objectToUUIDMap objectForKey:object]; + if (!uuidTask) { + // It was fetched, but it has no UUID. That must mean it isn't actually in the database. + return [BFTask taskWithResult:nil]; + } + } + + __block NSString *uuid = nil; + __block NSDictionary *dataDictionary = nil; + return [[uuidTask continueWithSuccessBlock:^id(BFTask *task) { + uuid = task.result; + + PFOfflineObjectEncoder *encoder = [PFOfflineObjectEncoder objectEncoderWithOfflineStore:self + database:database]; + NSArray *operationSetUUIDs = nil; + dataDictionary = [object RESTDictionaryWithObjectEncoder:encoder operationSetUUIDs:&operationSetUUIDs]; + return [encoder encodeFinished]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // Put it in database + NSString *className = object.parseClassName; + NSString *objectId = object.objectId; + NSString *encodedDataDictionary = [PFJSONSerialization stringFromJSONObject:dataDictionary]; + NSNumber *deletingEventually = dataDictionary[PFOfflineStoreKeyOfIsDeletingEventually]; + + NSString *updateParams = nil; + NSArray *updateArguments = nil; + if (objectId != nil) { + updateParams = [NSString stringWithFormat:@"%@ = ?, %@ = ?, %@ = ?, %@ = ?", + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfJSON, + PFOfflineStoreKeyOfIsDeletingEventually, PFOfflineStoreKeyOfObjectId]; + updateArguments = @[ className, encodedDataDictionary, deletingEventually, objectId, uuid ]; + } else { + updateParams = [NSString stringWithFormat:@"%@ = ?, %@ = ?, %@ = ?", + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfJSON, + PFOfflineStoreKeyOfIsDeletingEventually]; + updateArguments = @[ className, encodedDataDictionary, deletingEventually, uuid ]; + } + + NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@ = ?", + PFOfflineStoreTableOfObjects, updateParams, PFOfflineStoreKeyOfUUID]; + + return [database executeSQLAsync:sql withArgumentsInArray:updateArguments]; + }]; +} + +///-------------------------------------- +#pragma mark - Delete +///-------------------------------------- + +- (BFTask *)deleteDataForObjectAsync:(PFObject *)object { + return [self _performDatabaseTransactionAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + return [self deleteDataForObjectAsync:object database:database]; + }]; +} + +- (BFTask *)deleteDataForObjectAsync:(PFObject *)object database:(PFSQLiteDatabase *)database { + __block NSString *uuid = nil; + + // Make sure the object has a UUID. + BFTask *uuidTask = nil; + @synchronized (self.lock) { + uuidTask = [self.objectToUUIDMap objectForKey:object]; + if (!uuidTask) { + // It was fetched, but it has no UUID. That must mean it isn't actually in the database. + return [BFTask taskWithResult:nil]; + } + } + + uuidTask = [uuidTask continueWithSuccessBlock:^id(BFTask *task) { + uuid = task.result; + return task; + }]; + + // If the object was the root of a pin, unpin it. + BFTask *unpinTask = [[uuidTask continueWithSuccessBlock:^id(BFTask *task) { + // Find all the roots for this object. + NSString *sql = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = ?", + PFOfflineStoreKeyOfKey, PFOfflineStoreTableOfDependencies, + PFOfflineStoreKeyOfUUID]; + return [database executeQueryAsync:sql withArgumentsInArray:@[ uuid ]]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // Try to unpin this object from the pin label if it's a root of the PFPin. + PFSQLiteDatabaseResult *result = task.result; + NSMutableArray *tasks = [NSMutableArray array]; + + while (result.next) { + NSString *objectUUID = [result stringForColumnIndex:0]; + + BFTask *getPointerTask = [self _getPointerAsyncWithUUID:objectUUID database:database]; + BFTask *objectUnpinTask = [[getPointerTask continueWithSuccessBlock:^id(BFTask *task) { + PFPin *pin = task.result; + return [self fetchObjectLocallyAsync:pin database:database]; + }] continueWithBlock:^id(BFTask *task) { + PFPin *pin = task.result; + + NSMutableArray *modified = pin.objects; + if (modified == nil || ![modified containsObject:object]) { + return task; + } + + [modified removeObject:object]; + if (modified.count == 0) { + return [self _unpinKeyAsync:objectUUID database:database]; + } + pin.objects = modified; + + return [self saveObjectLocallyAsync:pin includeChildren:YES database:database]; + }]; + [tasks addObject:objectUnpinTask]; + } + [result close]; + + return [BFTask taskForCompletionOfAllTasks:tasks]; + }]; + + return [[[unpinTask continueWithSuccessBlock:^id(BFTask *task) { + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?", + PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfUUID]; + return [database executeSQLAsync:sql withArgumentsInArray:@[ uuid ]]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?", + PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID]; + return [database executeSQLAsync:sql withArgumentsInArray:@[ uuid ]]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // Delete the object from memory cache. + // (or else `PFObject.objectWithoutDataWithClassName` will return a valid object) + @synchronized (self.lock) { + // TODO (hallucinogen): we should probably clean up UUIDToObjectMap and objectToUUIDMap + // but getting the uuid requires a task and things might get a little funky... + if (object.objectId != nil) { + NSString *key = [self _generateKeyForClassName:object.parseClassName objectId:object.objectId]; + [self.classNameAndObjectIdToObjectMap removeObjectForKey:key]; + } + [self.fetchedObjects removeObjectForKey:object]; + } + return task; + }]; +} + +///-------------------------------------- +#pragma mark - Unpin +///-------------------------------------- + +- (BFTask *)unpinObjectAsync:(PFObject *)object { + BFTask *uuidTask = [self.objectToUUIDMap objectForKey:object]; + return [uuidTask continueWithBlock:^id(BFTask *task) { + NSString *uuid = task.result; + if (!uuid) { + // The root object was never stored in the offline store, so nothing to unpin. + return [BFTask taskWithResult:nil]; + } + return [self _unpinKeyAsync:uuid]; + }]; +} + +- (BFTask *)_unpinKeyAsync:(NSString *)key { + return [self _performDatabaseTransactionAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + return [self _unpinKeyAsync:key database:database]; + }]; +} + +- (BFTask *)_unpinKeyAsync:(NSString *)key database:(PFSQLiteDatabase *)database { + NSMutableArray *uuidsToDelete = [NSMutableArray array]; + // Fetch all uuids from Dependencies for key=? grouped by uuid having a count of 1 + NSString *query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = ? AND %@ IN " + @"(SELECT %@ FROM %@ GROUP BY %@ HAVING COUNT(%@) = 1);", + PFOfflineStoreKeyOfUUID, PFOfflineStoreTableOfDependencies, + PFOfflineStoreKeyOfKey, PFOfflineStoreKeyOfUUID, PFOfflineStoreKeyOfUUID, + PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfUUID, + PFOfflineStoreKeyOfUUID]; + return [[[[database executeQueryAsync:query + withArgumentsInArray:@[ key ]] continueWithSuccessBlock:^id(BFTask *task) { + // DELETE FROM Objects + PFSQLiteDatabaseResult *result = task.result; + while (result.next) { + [uuidsToDelete addObject:[result stringForColumnIndex:0]]; + } + [result close]; + + return [self _deleteObjectsWithUUIDs:uuidsToDelete database:database]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // DELETE FROM Dependencies + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?", + PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfKey]; + return [database executeSQLAsync:sql withArgumentsInArray:@[ key ]]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @synchronized (self.lock) { + // Remove uuids from memory + for (NSString *uuid in uuidsToDelete) { + PFObject *object = [self.UUIDToObjectMap objectForKey:uuid]; + if (object != nil) { + [self.objectToUUIDMap removeObjectForKey:object]; + [self.UUIDToObjectMap removeObjectForKey:uuid]; + } + } + } + return [BFTask taskWithResult:nil]; + }]; +} + +- (BFTask *)_deleteObjectsWithUUIDs:(NSArray *)uuids database:(PFSQLiteDatabase *)database { + if (uuids.count <= 0) { + return [BFTask taskWithResult:nil]; + } + + if (uuids.count > PFOfflineStoreMaximumSQLVariablesCount) { + NSRange range = NSMakeRange(0, PFOfflineStoreMaximumSQLVariablesCount); + return [[self _deleteObjectsWithUUIDs:[uuids subarrayWithRange:range] + database:database] continueWithSuccessBlock:^id(BFTask *task) { + unsigned long includedCount = uuids.count - PFOfflineStoreMaximumSQLVariablesCount; + NSRange range = NSMakeRange(PFOfflineStoreMaximumSQLVariablesCount, includedCount); + return [self _deleteObjectsWithUUIDs:[uuids subarrayWithRange:range] database:database]; + }]; + } + + NSMutableArray *placeholders = [NSMutableArray array]; + for (int i = 0; i < uuids.count; ++i) { + [placeholders addObject:@"?"]; + } + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ IN (%@);", + PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID, + [placeholders componentsJoinedByString:@","]]; + return [database executeSQLAsync:sql withArgumentsInArray:uuids]; +} + +///-------------------------------------- +#pragma mark - Internal Helper Methods +///-------------------------------------- + +- (BFTask *)getOrCreateUUIDAsyncForObject:(PFObject *)object + database:(PFSQLiteDatabase *)database { + NSString *newUUID = [[NSUUID UUID] UUIDString]; + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + + @synchronized (self.lock) { + BFTask *uuidTask = [self.objectToUUIDMap objectForKey:object]; + if (uuidTask != nil) { + // Return existing task. + return uuidTask; + } + + // The object doesn't have UUID yet, so we're gonna have to make one + [self.objectToUUIDMap setObject:tcs.task forKey:object]; + [self.UUIDToObjectMap setObject:object forKey:newUUID]; + + __weak id weakObject = object; + [self.fetchedObjects setObject:[tcs.task continueWithSuccessBlock:^id(BFTask *task) { + return [PFWeakValue valueWithWeakObject:weakObject]; + }] forKey:object]; + } + + // We need to put a placeholder row in the database so that later on the save can be just + // an update. This could be a pointer to an object that itself never gets saved offline, + // in which case the consumer will just have to deal with that. + NSString *query = [NSString stringWithFormat:@"INSERT INTO %@(%@, %@) VALUES(?, ?);", + PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID, PFOfflineStoreKeyOfClassName]; + [[database executeSQLAsync:query + withArgumentsInArray:@[ newUUID, [object parseClassName]]] continueWithSuccessBlock:^id(BFTask *task) { + [tcs setResult:newUUID]; + return [BFTask taskWithResult:nil]; + }]; + + return tcs.task; +} + +/*! + Gets an unfetched pointer to an object in the database, based on its uuid. The object may or may + not be in memory, but it must be in database. If it is already in memory, the instance will be + returned. Since this is only for creating pointers to objects that are referenced by other objects + in the datastore, it's a fair assumption. + + @param uuid The UUID of the object to retrieve. + @param database The database instance to retrieve from. + @returns The object with that UUID. + */ +- (BFTask *)_getPointerAsyncWithUUID:(NSString *)uuid + database:(PFSQLiteDatabase *)database { + @synchronized (self.lock) { + PFObject *existing = [self.UUIDToObjectMap objectForKey:uuid]; + if (existing != nil) { + return [BFTask taskWithResult:existing]; + } + } + + // We only want the pointer, but we have to look in the database to know if there's something + // with this classname and object id already. + NSString *query = [NSString stringWithFormat:@"SELECT %@, %@ FROM %@ WHERE %@ = ?;", + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfObjectId, + PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID]; + return [[database executeQueryAsync:query + withArgumentsInArray:@[ uuid ]] continueWithSuccessBlock:^id(BFTask *task) { + PFSQLiteDatabaseResult *result = task.result; + if (![result next]) { + [result close]; + [NSException raise:NSInternalInconsistencyException + format:@"Attempted to find non-existent uuid %@", uuid]; + } + + @synchronized (self.lock) { + PFObject *existing = [self.UUIDToObjectMap objectForKey:uuid]; + if (existing != nil) { + [result close]; + return existing; + } + + NSString *className = [result stringForColumnIndex:0]; + NSString *objectId = [result stringForColumnIndex:1]; + [result close]; + + PFObject *pointer = [PFObject objectWithoutDataWithClassName:className objectId:objectId]; + + // If it doesn't have objectId, we don't really need the UUID, and this simplifies some + // other logic elsewhere if we only update the map for new objects. + if (objectId == nil) { + [self.UUIDToObjectMap setObject:pointer forKey:uuid]; + [self.objectToUUIDMap setObject:[BFTask taskWithResult:uuid] forKey:pointer]; + } + return pointer; + } + }]; +} + +- (PFObject *)getOrCreateObjectWithoutDataWithClassName:(NSString *)className + objectId:(NSString *)objectId { + PFParameterAssert(objectId, @"objectId cannot be nil."); + + PFObject *object = nil; + @synchronized (self.lock) { + NSString *key = [self _generateKeyForClassName:className objectId:objectId]; + object = [self.classNameAndObjectIdToObjectMap objectForKey:key]; + if (!object) { + object = [PFObject objectWithClassName:className objectId:objectId completeData:NO]; + [self updateObjectIdForObject:object oldObjectId:nil newObjectId:objectId]; + } + } + return object; +} + +- (void)updateObjectIdForObject:(PFObject *)object + oldObjectId:(NSString *)oldObjectId + newObjectId:(NSString *)newObjectId { + if (oldObjectId != nil) { + PFConsistencyAssert([oldObjectId isEqualToString:newObjectId], @"objectIds cannot be changed in offline mode."); + return; + } + + NSString *className = object.parseClassName; + NSString *key = [self _generateKeyForClassName:className objectId:newObjectId]; + + @synchronized (self.lock) { + // See if there's already an entry for new objectId. + PFObject *existing = [self.classNameAndObjectIdToObjectMap objectForKey:key]; + PFConsistencyAssert(existing == nil || existing == object, + @"Attempted to change an objectId to one that's already known to the OfflineStore."); + + // Okay, all clear to add the new reference. + [self.classNameAndObjectIdToObjectMap setObject:object forKey:key]; + } +} + +- (NSString *)_generateKeyForClassName:(NSString *)className + objectId:(NSString *)objectId { + return [NSString stringWithFormat:@"%@:%@", className, objectId]; +} + +// TODO (hallucinogen): is this the right way to store the schema? ++ (NSString *)PFOfflineStoreParseObjectsTableSchema { + return [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (" + @"%@ TEXT PRIMARY KEY, " + @"%@ TEXT NOT NULL, " + @"%@ TEXT, " + @"%@ TEXT, " + @"%@ INTEGER DEFAULT 0, " + @"UNIQUE(%@, %@));", PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID, + PFOfflineStoreKeyOfClassName, PFOfflineStoreKeyOfObjectId, PFOfflineStoreKeyOfJSON, + PFOfflineStoreKeyOfIsDeletingEventually, PFOfflineStoreKeyOfClassName, + PFOfflineStoreKeyOfObjectId]; +} + ++ (NSString *)PFOfflineStoreDependenciesTableSchema { + return [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (" + @"%@ TEXT NOT NULL, " + @"%@ TEXT NOT NULL, " + @"PRIMARY KEY(%@, %@));", PFOfflineStoreTableOfDependencies, PFOfflineStoreKeyOfKey, + PFOfflineStoreKeyOfUUID, PFOfflineStoreKeyOfKey, PFOfflineStoreKeyOfUUID]; +} + ++ (BFTask *)_initializeTablesInBackgroundWithDatabaseController:(PFSQLiteDatabaseController *)databaseController { + return [[databaseController openDatabaseWithNameAsync:PFOfflineStoreDatabaseName] continueWithBlock:^id(BFTask *task) { + PFSQLiteDatabase *database = task.result; + return [[[[[database beginTransactionAsync] continueWithSuccessBlock:^id(BFTask *task) { + return [database executeSQLAsync:[self PFOfflineStoreParseObjectsTableSchema] withArgumentsInArray:nil]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [database executeSQLAsync:[self PFOfflineStoreDependenciesTableSchema] withArgumentsInArray:nil]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [database commitAsync]; + }] continueWithBlock:^id(BFTask *task) { + return [database closeAsync]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Database Helpers +///-------------------------------------- + +- (BFTask *)_performDatabaseTransactionAsyncWithBlock:(PFOfflineStoreDatabaseExecutionBlock)block { + return [self _performDatabaseOperationAsyncWithBlock:^BFTask *(PFSQLiteDatabase *database) { + BFTask *task = [database beginTransactionAsync]; + task = [task continueWithSuccessBlock:^id(BFTask *task) { + return block(database); + }]; + return [task continueWithSuccessBlock:^id(BFTask *task) { + return [database commitAsync]; + }]; + }]; +} + +- (BFTask *)_performDatabaseOperationAsyncWithBlock:(PFOfflineStoreDatabaseExecutionBlock)block { + return [[self.databaseController openDatabaseWithNameAsync:PFOfflineStoreDatabaseName] continueWithBlock:^id(BFTask *task) { + PFSQLiteDatabase *database = task.result; + return [block(database) continueWithBlock:^id(BFTask *task) { + return [database closeAsync]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFOfflineQueryLogic *)offlineQueryLogic { + @synchronized (self.lock) { + if (!_offlineQueryLogic) { + _offlineQueryLogic = [[PFOfflineQueryLogic alloc] initWithOfflineStore:self]; + } + return _offlineQueryLogic; + } +} + +///-------------------------------------- +#pragma mark - Unit Test helper +///-------------------------------------- + +- (void)simulateReboot { + @synchronized (self.lock) { + [self.UUIDToObjectMap removeAllObjects]; + [self.objectToUUIDMap removeAllObjects]; + [self.classNameAndObjectIdToObjectMap removeAllObjects]; + [self.fetchedObjects removeAllObjects]; + } +} + +- (void)clearDatabase { + // Delete DB file + NSString *filePath = [self.fileManager parseDataItemPathForPathComponent:PFOfflineStoreDatabaseName]; + [[PFFileManager removeItemAtPathAsync:filePath] waitForResult:nil withMainThreadWarning:NO]; + + // Reinitialize tables + [PFOfflineStore _initializeTablesInBackgroundWithDatabaseController:self.databaseController]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.h new file mode 100644 index 0000000..745baf6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern NSString *const PFPinKeyName; +extern NSString *const PFPinKeyObjects; + +/*! + PFPin represent internal pin implementation of PFObject's `pin`. + */ +@interface PFPin : PFObject + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, strong) NSMutableArray *objects; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithName:(NSString *)name; ++ (instancetype)pinWithName:(NSString *)name; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.m new file mode 100644 index 0000000..3519b47 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/Pin/PFPin.m @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPin.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFObject+Subclass.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFQueryPrivate.h" +#import "Parse_Private.h" + +NSString *const PFPinKeyName = @"_name"; +NSString *const PFPinKeyObjects = @"_objects"; + +@implementation PFPin + +///-------------------------------------- +#pragma mark - PFSubclassing +///-------------------------------------- + ++ (NSString *)parseClassName { + return @"_Pin"; +} + +// Validates a class name. We override this to only allow the pin class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[self parseClassName]], + @"Cannot initialize a PFPin with a custom class name."); +} + +- (BOOL)needsDefaultACL { + return NO; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithName:(NSString *)name { + self = [super init]; + if (!self) return nil; + + // Use property accessor, as there is no ivar here for `name`. + self.name = name; + + return self; +} + ++ (instancetype)pinWithName:(NSString *)name { + return [[self alloc] initWithName:name]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSString *)name { + return self[PFPinKeyName]; +} + +- (void)setName:(NSString *)name { + self[PFPinKeyName] = [name copy]; +} + +- (NSMutableArray *)objects { + return self[PFPinKeyObjects]; +} + +- (void)setObjects:(NSMutableArray *)objects { + self[PFPinKeyObjects] = [objects mutableCopy]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h new file mode 100644 index 0000000..fc37993 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFFileManager; +@class PFSQLiteDatabaseResult; + +/*! + Argument count given in executeSQLAsync or executeQueryAsync is invalid. + */ +extern int const PFSQLiteDatabaseInvalidArgumenCountErrorCode; + +/*! + Method `executeSQL` cannot execute SELECT. Use `executeQuery` instead. + */ +extern int const PFSQLiteDatabaseInvalidSQL; + +/*! + Database is opened already. + */ +extern int const PFSQLiteDatabaseDatabaseAlreadyOpened; + +/*! + Database is closed already. + */ +extern int const PFSQLiteDatabaseDatabaseAlreadyClosed; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSQLiteDatabase : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithPath:(NSString *)path; + +///-------------------------------------- +/// @name Database Creation +///-------------------------------------- + ++ (instancetype)databaseWithPath:(NSString *)path; + +///-------------------------------------- +/// @name Connection +///-------------------------------------- + +/*! + @returns A `BFTask` that resolves to `YES` if the database is open. + */ +- (BFTask *)isOpenAsync; + +/*! + Opens database. Database is one time use. Open > Close > Open is forbidden. + */ +- (BFTask *)openAsync; + +/*! + Closes the database connection. + */ +- (BFTask *)closeAsync; + +///-------------------------------------- +/// @name Transaction +///-------------------------------------- + +/*! + Begins a database transaction in EXCLUSIVE mode. + */ +- (BFTask *)beginTransactionAsync; + +/*! + Commits running transaction. + */ +- (BFTask *)commitAsync; + +/*! + Rollbacks running transaction. + */ +- (BFTask *)rollbackAsync; + +///-------------------------------------- +/// @name Query Methods +///-------------------------------------- + +/*! + Runs a single SQL statement which return result (SELECT). + */ +- (BFTask *)executeQueryAsync:(NSString *)sql withArgumentsInArray:(nullable NSArray *)args; + +/*! + Runs a single SQL statement, while caching the resulting statement for future use. + */ +- (BFTask *)executeCachedQueryAsync:(NSString *)sql withArgumentsInArray:(nullable NSArray *)args; + +/*! + Runs a single SQL statement which doesn't return result (UPDATE/INSERT/DELETE). + */ +- (BFTask *)executeSQLAsync:(NSString *)sql withArgumentsInArray:(nullable NSArray *)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m new file mode 100644 index 0000000..9c46fa3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m @@ -0,0 +1,339 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSQLiteDatabase.h" +#import "PFSQLiteDatabase_Private.h" + +#import + +#import +#import + +#import "BFTask+Private.h" +#import "PFFileManager.h" +#import "PFInternalUtils.h" +#import "PFMacros.h" +#import "PFMultiProcessFileLockController.h" +#import "PFSQLiteDatabaseResult.h" +#import "PFSQLiteStatement.h" +#import "Parse_Private.h" + +NSString *const PFSQLiteDatabaseBeginExclusiveOperationCommand = @"BEGIN EXCLUSIVE"; +NSString *const PFSQLiteDatabaseCommitOperationCommand = @"COMMIT"; +NSString *const PFSQLiteDatabaseRollbackOperationCommand = @"ROLLBACK"; + +NSString *const PFSQLiteDatabaseErrorSQLiteDomain = @"SQLite"; +NSString *const PFSQLiteDatabaseErrorPFSQLiteDatabaseDomain = @"PFSQLiteDatabase"; + +int const PFSQLiteDatabaseInvalidArgumenCountErrorCode = 1; +int const PFSQLiteDatabaseInvalidSQL = 2; +int const PFSQLiteDatabaseDatabaseAlreadyOpened = 3; +int const PFSQLiteDatabaseDatabaseAlreadyClosed = 4; + +@interface PFSQLiteDatabase () { + BFTaskCompletionSource *_databaseClosedTaskCompletionSource; + dispatch_queue_t _databaseQueue; + BFExecutor *_databaseExecutor; + NSMutableDictionary *_cachedStatements; +} + +/*! + Database instance + */ +@property (nonatomic, assign) sqlite3 *database; + +/*! + Database path + */ +@property (nonatomic, copy) NSString *databasePath; + +@end + +@implementation PFSQLiteDatabase + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithPath:(NSString *)path { + self = [super init]; + if (!self) return nil; + + _databaseClosedTaskCompletionSource = [[BFTaskCompletionSource alloc] init]; + _databasePath = [path copy]; + _databaseQueue = dispatch_queue_create("com.parse.sqlite.db.queue", DISPATCH_QUEUE_SERIAL); + _databaseExecutor = [BFExecutor executorWithDispatchQueue:_databaseQueue]; + _cachedStatements = [[NSMutableDictionary alloc] init]; + + return self; +} + ++ (instancetype)databaseWithPath:(NSString *)path { + return [[self alloc] initWithPath:path]; +} + +///-------------------------------------- +#pragma mark - Connection +///-------------------------------------- + +- (BFTask *)isOpenAsync { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + return @(self.database != nil); + }]; +} + +- (BFTask *)openAsync { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + if (self.database) { + NSError *error = [self _errorWithErrorCode:PFSQLiteDatabaseDatabaseAlreadyOpened + errorMessage:@"Database is opened already." + domain:PFSQLiteDatabaseErrorPFSQLiteDatabaseDomain]; + return [BFTask taskWithError:error]; + } + + // Check if this database have already been opened before. + if (_databaseClosedTaskCompletionSource.task.completed) { + NSError *error = [self _errorWithErrorCode:PFSQLiteDatabaseDatabaseAlreadyClosed + errorMessage:@"Closed database cannot be reopen." + domain:PFSQLiteDatabaseErrorPFSQLiteDatabaseDomain]; + return [BFTask taskWithError:error]; + } + + // Lock the file to avoid multi-process access. + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:self.databasePath]; + + sqlite3 *db; + int resultCode = sqlite3_open([self.databasePath UTF8String], &db); + if (resultCode != SQLITE_OK) { + return [BFTask taskWithError:[self _errorWithErrorCode:resultCode]]; + } + + self.database = db; + return [BFTask taskWithResult:nil]; + }]; +} + +- (BFTask *)closeAsync { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + if (!self.database) { + NSError *error = [self _errorWithErrorCode:PFSQLiteDatabaseDatabaseAlreadyClosed + errorMessage:@"Database is closed already." + domain:PFSQLiteDatabaseErrorPFSQLiteDatabaseDomain]; + return [BFTask taskWithError:error]; + } + + [self _clearCachedStatements]; + int resultCode = sqlite3_close(self.database); + + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:self.databasePath]; + + if (resultCode == SQLITE_OK) { + + self.database = nil; + [_databaseClosedTaskCompletionSource setResult:nil]; + } else { + // Returns error + [_databaseClosedTaskCompletionSource setError:[self _errorWithErrorCode:resultCode]]; + } + return _databaseClosedTaskCompletionSource.task; + }]; +} + +///-------------------------------------- +#pragma mark - Transaction +///-------------------------------------- + +- (BFTask *)beginTransactionAsync { + return [self executeSQLAsync:PFSQLiteDatabaseBeginExclusiveOperationCommand + withArgumentsInArray:nil]; +} + +- (BFTask *)commitAsync { + return [self executeSQLAsync:PFSQLiteDatabaseCommitOperationCommand + withArgumentsInArray:nil]; +} + +- (BFTask *)rollbackAsync { + return [self executeSQLAsync:PFSQLiteDatabaseRollbackOperationCommand + withArgumentsInArray:nil]; +} + +///-------------------------------------- +#pragma mark - Query Methods +///-------------------------------------- + +- (BFTask *)_executeQueryAsync:(NSString *)sql withArgumentsInArray:(NSArray *)args cachingEnabled:(BOOL)enableCaching { + int resultCode = 0; + PFSQLiteStatement *statement = enableCaching ? [self _cachedStatementForQuery:sql] : nil; + if (!statement) { + sqlite3_stmt *sqliteStatement = nil; + resultCode = sqlite3_prepare_v2(self.database, [sql UTF8String], -1, &sqliteStatement, 0); + if (resultCode != SQLITE_OK) { + sqlite3_finalize(sqliteStatement); + return [BFTask taskWithError:[self _errorWithErrorCode:resultCode]]; + } + statement = [[PFSQLiteStatement alloc] initWithStatement:sqliteStatement]; + + if (enableCaching) { + [self _cacheStatement:statement forQuery:sql]; + } + } else { + [statement reset]; + } + + // Make parameter + int queryCount = sqlite3_bind_parameter_count([statement sqliteStatement]); + int argumentCount = (int)[args count]; + if (queryCount != argumentCount) { + if (!enableCaching) { + [statement close]; + } + + NSError *error = [self _errorWithErrorCode:PFSQLiteDatabaseInvalidArgumenCountErrorCode + errorMessage:@"Statement arguments count doesn't match " + @"given arguments count." + domain:NSStringFromClass([self class])]; + return [BFTask taskWithError:error]; + } + + for (int idx = 0; idx < queryCount; ++idx) { + [self _bindObject:args[idx] toColumn:(idx + 1) inStatement:statement]; + } + + PFSQLiteDatabaseResult *result = [[PFSQLiteDatabaseResult alloc] initWithStatement:statement]; + return [BFTask taskWithResult:result]; +} + +- (BFTask *)executeCachedQueryAsync:(NSString *)sql withArgumentsInArray:(NSArray *)args { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + return [self _executeQueryAsync:sql withArgumentsInArray:args cachingEnabled:YES]; + }]; +} + +- (BFTask *)executeQueryAsync:(NSString *)sql withArgumentsInArray:(NSArray *)args { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + return [self _executeQueryAsync:sql withArgumentsInArray:args cachingEnabled:NO]; + }]; +} + +- (BFTask *)executeSQLAsync:(NSString *)sql withArgumentsInArray:(NSArray *)args { + return [BFTask taskFromExecutor:_databaseExecutor withBlock:^id { + return [[self _executeQueryAsync:sql + withArgumentsInArray:args + cachingEnabled:NO] continueWithExecutor:[BFExecutor immediateExecutor] withSuccessBlock:^id(BFTask *task) { + PFSQLiteDatabaseResult *databaseResult = task.result; + int sqliteResultCode = [databaseResult step]; + [databaseResult close]; + + switch (sqliteResultCode) { + case SQLITE_DONE: { + return [BFTask taskWithResult:nil]; + } + case SQLITE_ROW: { + NSError *error = [self _errorWithErrorCode:PFSQLiteDatabaseInvalidSQL + errorMessage:@"Cannot SELECT on executeSQLAsync." + @"Please use executeQueryAsync." + domain:NSStringFromClass([self class])]; + return [BFTask taskWithError:error]; + } + default: { + return [BFTask taskWithError:[self _errorWithErrorCode:sqliteResultCode]]; + } + } + }]; + }]; +} + +/*! + bindObject will bind any object supported by PFSQLiteDatabase to query statement. + Note: sqlite3 query index binding is one-based, while querying result is zero-based. + */ +- (void)_bindObject:(id)obj toColumn:(int)idx inStatement:(PFSQLiteStatement *)statement { + if ((!obj) || ((NSNull *)obj == [NSNull null])) { + sqlite3_bind_null([statement sqliteStatement], idx); + } else if ([obj isKindOfClass:[NSData class]]) { + const void *bytes = [obj bytes]; + if (!bytes) { + // It's an empty NSData object, aka [NSData data]. + // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob. + bytes = ""; + } + sqlite3_bind_blob([statement sqliteStatement], idx, bytes, (int)[obj length], SQLITE_TRANSIENT); + } else if ([obj isKindOfClass:[NSDate class]]) { + sqlite3_bind_double([statement sqliteStatement], idx, [obj timeIntervalSince1970]); + } else if ([obj isKindOfClass:[NSNumber class]]) { + if (CFNumberIsFloatType((__bridge CFNumberRef)obj)) { + sqlite3_bind_double([statement sqliteStatement], idx, [obj doubleValue]); + } else { + sqlite3_bind_int64([statement sqliteStatement], idx, [obj longLongValue]); + } + } else { + sqlite3_bind_text([statement sqliteStatement], idx, [[obj description] UTF8String], -1, SQLITE_TRANSIENT); + } +} + +///-------------------------------------- +#pragma mark - Cached Statements +///-------------------------------------- + +- (void)_clearCachedStatements { + for (PFSQLiteStatement *statement in [_cachedStatements allValues]) { + [statement close]; + } + + [_cachedStatements removeAllObjects]; +} + +- (PFSQLiteStatement *)_cachedStatementForQuery:(NSString *)query { + return _cachedStatements[query]; +} + +- (void)_cacheStatement:(PFSQLiteStatement *)statement forQuery:(NSString *)query { + _cachedStatements[query] = statement; +} + +///-------------------------------------- +#pragma mark - Errors +///-------------------------------------- + +/*! + Generates SQLite error. The details of the error code can be seen in: www.sqlite.org/c3ref/errcode.html + */ +- (NSError *)_errorWithErrorCode:(int)errorCode { + return [self _errorWithErrorCode:errorCode + errorMessage:[NSString stringWithUTF8String:sqlite3_errmsg(self.database)]]; +} + +- (NSError *)_errorWithErrorCode:(int)errorCode errorMessage:(NSString *)errorMessage { + return [self _errorWithErrorCode:errorCode + errorMessage:errorMessage + domain:PFSQLiteDatabaseErrorSQLiteDomain]; +} + +/*! + Generates SQLite/PFSQLiteDatabase error. + */ +- (NSError *)_errorWithErrorCode:(int)errorCode + errorMessage:(NSString *)errorMessage + domain:(NSString *)domain { + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + result[@"code"] = @(errorCode); + result[@"error"] = errorMessage; + return [[NSError alloc] initWithDomain:domain code:errorCode userInfo:result]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (BFTask *)databaseClosedTask { + return _databaseClosedTaskCompletionSource.task; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h new file mode 100644 index 0000000..d1a0f8c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFFileManager; +@class PFSQLiteDatabase; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSQLiteDatabaseController : NSObject + +@property (nonatomic, strong, readonly) PFFileManager *fileManager; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(PFFileManager *)fileManager NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithFileManager:(PFFileManager *)fileManager; + +///-------------------------------------- +/// @name Opening +///-------------------------------------- + +/*! + @abstract Asynchronously opens a database connection to the database with the name specified. + @note Only one database can be actively open at a time. + + @param name The name of the database to open. + + @return A task, which yields a `PFSQLiteDatabase`, with the open database. + When the database is closed, a new database connection can be opened. + */ +- (BFTask *)openDatabaseWithNameAsync:(NSString *)name; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.m new file mode 100644 index 0000000..d971ea4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.m @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSQLiteDatabaseController.h" + +#import +#import + +#import "PFAssert.h" +#import "PFAsyncTaskQueue.h" +#import "PFFileManager.h" +#import "PFSQLiteDatabase_Private.h" + +@implementation PFSQLiteDatabaseController { + PFAsyncTaskQueue *_openDatabaseQueue; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithFileManager:(PFFileManager *)fileManager { + self = [super init]; + if (!self) return nil; + + _fileManager = fileManager; + _openDatabaseQueue = [[PFAsyncTaskQueue alloc] init]; + + return self; +} + ++ (instancetype)controllerWithFileManager:(PFFileManager *)fileManager { + return [[self alloc] initWithFileManager:fileManager]; +} + +///-------------------------------------- +#pragma mark - Opening +///-------------------------------------- + +// TODO: (richardross) Implement connection pooling using NSCache or similar mechanism. +- (BFTask *)openDatabaseWithNameAsync:(NSString *)name { + BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource]; + [_openDatabaseQueue enqueue:^id(BFTask *task) { + NSString *databasePath = [self.fileManager parseDataItemPathForPathComponent:name]; + PFSQLiteDatabase *sqliteDatabase = [PFSQLiteDatabase databaseWithPath:databasePath]; + [[sqliteDatabase openAsync] continueWithBlock:^id(BFTask *task) { + if (task.faulted) { + NSError *error = task.error; + if (error) { + [taskCompletionSource trySetError:error]; + } else { + [taskCompletionSource trySetException:task.exception]; + } + } else if (task.cancelled) { + [taskCompletionSource trySetCancelled]; + } else { + [taskCompletionSource trySetResult:sqliteDatabase]; + } + + return nil; + }]; + + return sqliteDatabase.databaseClosedTask; + }]; + + return taskCompletionSource.task; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h new file mode 100644 index 0000000..d63d36f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFSQLiteStatement; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSQLiteDatabaseResult : NSObject + +- (instancetype)initWithStatement:(PFSQLiteStatement *)statement; + +/*! + Move current result to next row. Returns true if next result exists. False if current result + is the end of result set. + */ +- (BOOL)next; + +/*! + Move the current result to next row, and returns the raw SQLite return code for the cursor. + Useful for detecting end of cursor vs. error. + */ +- (int)step; + +/*! + Closes the database result. + */ +- (BOOL)close; + +///-------------------------------------- +/// @name Get Column Value +///-------------------------------------- + +- (int)intForColumn:(NSString *)columnName; +- (int)intForColumnIndex:(int)columnIndex; + +- (long)longForColumn:(NSString *)columnName; +- (long)longForColumnIndex:(int)columnIndex; + +- (BOOL)boolForColumn:(NSString *)columnName; +- (BOOL)boolForColumnIndex:(int)columnIndex; + +- (double)doubleForColumn:(NSString *)columnName; +- (double)doubleForColumnIndex:(int)columnIndex; + +- (nullable NSString *)stringForColumn:(NSString *)columnName; +- (nullable NSString *)stringForColumnIndex:(int)columnIndex; + +- (nullable NSDate *)dateForColumn:(NSString *)columnName; +- (nullable NSDate *)dateForColumnIndex:(int)columnIndex; + +- (nullable NSData *)dataForColumn:(NSString *)columnName; +- (nullable NSData *)dataForColumnIndex:(int)columnIndex; + +- (nullable id)objectForColumn:(NSString *)columnName; +- (nullable id)objectForColumnIndex:(int)columnIndex; + +- (BOOL)columnIsNull:(NSString *)columnName; +- (BOOL)columnIndexIsNull:(int)columnIndex; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m new file mode 100644 index 0000000..cdbeb0e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSQLiteDatabaseResult.h" + +#import + +#import "PFSQLiteStatement.h" + +@interface PFSQLiteDatabaseResult () + +@property (nonatomic, copy, readonly) NSDictionary *columnNameToIndexMap; +@property (nonatomic, strong, readonly) PFSQLiteStatement *statement; + +@end + +@implementation PFSQLiteDatabaseResult + +@synthesize columnNameToIndexMap = _columnNameToIndexMap; + +- (instancetype)initWithStatement:(PFSQLiteStatement *)stmt { + if ((self = [super init])) { + _statement = stmt; + } + return self; +} + +- (BOOL)next { + return [self step] == SQLITE_ROW; +} + +- (int)step { + return sqlite3_step([self.statement sqliteStatement]); +} + +- (BOOL)close { + return [self.statement close]; +} + +- (int)intForColumn:(NSString *)columnName { + return [self intForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (int)intForColumnIndex:(int)columnIndex { + return sqlite3_column_int([self.statement sqliteStatement], columnIndex); +} + +- (long)longForColumn:(NSString *)columnName { + return [self longForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (long)longForColumnIndex:(int)columnIndex { + return (long)sqlite3_column_int64([self.statement sqliteStatement], columnIndex); +} + +- (BOOL)boolForColumn:(NSString *)columnName { + return [self boolForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (BOOL)boolForColumnIndex:(int)columnIndex { + return ([self intForColumnIndex:columnIndex] != 0); +} + +- (double)doubleForColumn:(NSString *)columnName { + return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (double)doubleForColumnIndex:(int)columnIndex { + return sqlite3_column_double([self.statement sqliteStatement], columnIndex); +} + +- (NSString *)stringForColumn:(NSString *)columnName { + return [self stringForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSString *)stringForColumnIndex:(int)columnIndex { + if ([self columnIndexIsNull:columnIndex]) { + return nil; + } + + const char *str = (const char *)sqlite3_column_text([self.statement sqliteStatement], columnIndex); + if (!str) { + return nil; + } + return [NSString stringWithUTF8String:str]; +} + +- (NSDate *)dateForColumn:(NSString *)columnName { + return [self dateForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSDate *)dateForColumnIndex:(int)columnIndex { + // TODO: (nlutsenko) probably use formatter + return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIndex]]; +} + +- (NSData *)dataForColumn:(NSString *)columnName { + return [self dataForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (NSData *)dataForColumnIndex:(int)columnIndex { + if ([self columnIndexIsNull:columnIndex]) { + return nil; + } + + int size = sqlite3_column_bytes([self.statement sqliteStatement], columnIndex); + const char *buffer = sqlite3_column_blob([self.statement sqliteStatement], columnIndex); + if (buffer == nil) { + return nil; + } + return [NSData dataWithBytes:buffer length:size]; +} + +- (id)objectForColumn:(NSString *)columnName { + return [self objectForColumnIndex:[self columnIndexForName:columnName]]; +} + +- (id)objectForColumnIndex:(int)columnIndex { + int columnType = sqlite3_column_type([self.statement sqliteStatement], columnIndex); + switch (columnType) { + case SQLITE_INTEGER: + return @([self longForColumnIndex:columnIndex]); + case SQLITE_FLOAT: + return @([self doubleForColumnIndex:columnIndex]); + case SQLITE_BLOB: + return [self dataForColumnIndex:columnIndex]; + default: + return [self stringForColumnIndex:columnIndex]; + } +} + +- (BOOL)columnIsNull:(NSString *)columnName { + return [self columnIndexIsNull:[self columnIndexForName:columnName]]; +} + +- (BOOL)columnIndexIsNull:(int)columnIndex { + return (sqlite3_column_type([self.statement sqliteStatement], columnIndex) == SQLITE_NULL); +} + +- (int)columnIndexForName:(NSString *)columnName { + NSNumber *index = self.columnNameToIndexMap[[columnName lowercaseString]]; + if (index) { + return [index intValue]; + } + // not found + return -1; +} + +- (NSDictionary *)columnNameToIndexMap { + if (!_columnNameToIndexMap) { + int columnCount = sqlite3_column_count([self.statement sqliteStatement]); + NSMutableDictionary *mutableColumnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:columnCount]; + for (int i = 0; i < columnCount; ++i) { + NSString *key = [NSString stringWithUTF8String:sqlite3_column_name([self.statement sqliteStatement], i)]; + mutableColumnNameToIndexMap[[key lowercaseString]] = @(i); + } + _columnNameToIndexMap = mutableColumnNameToIndexMap; + } + return _columnNameToIndexMap; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h new file mode 100644 index 0000000..5db0366 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSQLiteDatabase.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSQLiteDatabase () + +@property (nonatomic, strong, readonly) BFTask *databaseClosedTask; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h new file mode 100644 index 0000000..04e181c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + PFSQLiteStatement is sqlite3_stmt wrapper class. + */ +typedef struct sqlite3_stmt sqlite3_stmt; + +@interface PFSQLiteStatement : NSObject + +@property (atomic, assign, readonly) sqlite3_stmt *sqliteStatement; + +- (instancetype)initWithStatement:(sqlite3_stmt *)stmt; + +- (BOOL)close; +- (BOOL)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m new file mode 100644 index 0000000..03f31b6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSQLiteStatement.h" + +#import + +@implementation PFSQLiteStatement + +- (instancetype)initWithStatement:(sqlite3_stmt *)stmt { + self = [super init]; + if (!stmt || !self) return nil; + + _sqliteStatement = stmt; + + return self; +} + +- (void)dealloc { + [self close]; +} + +- (BOOL)close { + if (!_sqliteStatement) { + return YES; + } + + int resultCode = sqlite3_finalize(_sqliteStatement); + _sqliteStatement = nil; + + return (resultCode == SQLITE_OK || resultCode == SQLITE_DONE); +} + +- (BOOL)reset { + if (!_sqliteStatement) { + return YES; + } + + int resultCode = sqlite3_reset(_sqliteStatement); + return (resultCode == SQLITE_OK || resultCode == SQLITE_DONE); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h new file mode 100644 index 0000000..da1ad89 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +//TODO: (nlutsenko) Add unit tests for this class. +@interface PFMultiProcessFileLock : NSObject + +@property (nonatomic, copy, readonly) NSString *filePath; +@property (nonatomic, copy, readonly) NSString *lockFilePath; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initForFileWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER; ++ (instancetype)lockForFileWithPath:(NSString *)path; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m new file mode 100644 index 0000000..2c02cea --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMultiProcessFileLock.h" + +#import "PFAssert.h" +#import "PFMacros.h" + +static const NSTimeInterval PFMultiProcessLockAttemptsDelay = 0.001; + +@interface PFMultiProcessFileLock () { + dispatch_queue_t _synchronizationQueue; + int _fileDescriptor; +} + +@property (nonatomic, copy, readwrite) NSString *filePath; +@property (nonatomic, copy, readwrite) NSString *lockFilePath; + +@end + +@implementation PFMultiProcessFileLock + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initForFileWithPath:(NSString *)path { + self = [super init]; + if (!self) return nil; + + _filePath = [path copy]; + _lockFilePath = [path stringByAppendingPathExtension:@"pflock"]; + + NSString *queueName = [NSString stringWithFormat:@"com.parse.multiprocess.%@", + [[path lastPathComponent] stringByDeletingPathExtension]]; + _synchronizationQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL); + + return self; +} + ++ (instancetype)lockForFileWithPath:(NSString *)path { + return [[self alloc] initForFileWithPath:path]; +} + +- (void)dealloc { + [self unlock]; +} + +///-------------------------------------- +#pragma mark - NSLocking +///-------------------------------------- + +- (void)lock { + dispatch_sync(_synchronizationQueue, ^{ + // Greater than zero means that the lock was already succesfully acquired. + if (_fileDescriptor > 0) { + return; + } + + BOOL locked = NO; + while (!locked) @autoreleasepool { + locked = [self _tryLock]; + if (!locked) { + [NSThread sleepForTimeInterval:PFMultiProcessLockAttemptsDelay]; + } + } + }); +} + +- (void)unlock { + dispatch_sync(_synchronizationQueue, ^{ + // Only descriptor that is greater than zero is going to be open. + if (_fileDescriptor <= 0) { + return; + } + + close(_fileDescriptor); + _fileDescriptor = 0; + }); +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (BOOL)_tryLock { + const char *filePath = [self.lockFilePath fileSystemRepresentation]; + + // Atomically create a lock file if it doesn't exist and acquire the lock. + _fileDescriptor = open(filePath, (O_RDWR | O_CREAT | O_EXLOCK), + ((S_IRUSR | S_IWUSR | S_IXUSR) | (S_IRGRP | S_IWGRP | S_IXGRP) | (S_IROTH | S_IWOTH | S_IXOTH))); + return (_fileDescriptor > 0); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h new file mode 100644 index 0000000..098b01a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +//TODO: (nlutsenko) Add unit tests for this class. +@interface PFMultiProcessFileLockController : NSObject + +//TODO: (nlutsenko) Re-consider using singleton here. ++ (instancetype)sharedController; + +/*! + Increments the content access counter by 1. + If the count was 0 - this will try to acquire the file lock first. + + @param filePath Path to a file to lock access to. + */ +- (void)beginLockedContentAccessForFileAtPath:(NSString *)filePath; + +/*! + Decrements the content access counter by 1. + If the count reaches 0 - the lock is going to be released. + + @param filePath Path to a file to lock access to. + */ +- (void)endLockedContentAccessForFileAtPath:(NSString *)filePath; + +- (NSUInteger)lockedContentAccessCountForFileAtPath:(NSString *)filePath; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.m new file mode 100644 index 0000000..be10da9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.m @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMultiProcessFileLockController.h" + +#import "PFMultiProcessFileLock.h" + +@interface PFMultiProcessFileLockController () { + dispatch_queue_t _synchronizationQueue; + NSMutableDictionary *_locksDictionary; + NSMutableDictionary *_contentAccessDictionary; +} + +@end + +@implementation PFMultiProcessFileLockController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _synchronizationQueue = dispatch_queue_create("com.parse.multiprocesslock.controller", DISPATCH_QUEUE_CONCURRENT); + + _locksDictionary = [NSMutableDictionary dictionary]; + _contentAccessDictionary = [NSMutableDictionary dictionary]; + + return self; +} + ++ (instancetype)sharedController { + static PFMultiProcessFileLockController *controller; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + controller = [[self alloc] init]; + }); + return controller; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (void)beginLockedContentAccessForFileAtPath:(NSString *)filePath { + dispatch_barrier_sync(_synchronizationQueue, ^{ + PFMultiProcessFileLock *fileLock = _locksDictionary[filePath]; + if (!fileLock) { + fileLock = [PFMultiProcessFileLock lockForFileWithPath:filePath]; + _locksDictionary[filePath] = fileLock; + } + + [fileLock lock]; + + NSUInteger contentAccess = [_contentAccessDictionary[filePath] unsignedIntegerValue]; + _contentAccessDictionary[filePath] = @(contentAccess + 1); + }); +} + +- (void)endLockedContentAccessForFileAtPath:(NSString *)filePath { + dispatch_barrier_sync(_synchronizationQueue, ^{ + PFMultiProcessFileLock *fileLock = _locksDictionary[filePath]; + [fileLock unlock]; + + if (fileLock && [_contentAccessDictionary[filePath] unsignedIntegerValue] == 0) { + [_locksDictionary removeObjectForKey:filePath]; + [_contentAccessDictionary removeObjectForKey:filePath]; + } + }); +} + +- (NSUInteger)lockedContentAccessCountForFileAtPath:(NSString *)filePath { + __block NSUInteger value = 0; + dispatch_sync(_synchronizationQueue, ^{ + value = [_contentAccessDictionary[filePath] unsignedIntegerValue]; + }); + return value; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.h new file mode 100644 index 0000000..a513f6d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" +#import "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFObjectBatchController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Fetch +///-------------------------------------- + +- (BFTask *)fetchObjectsAsync:(nullable NSArray *)objects withSessionToken:(nullable NSString *)sessionToken; + +///-------------------------------------- +/// @name Delete +///-------------------------------------- + +- (BFTask *)deleteObjectsAsync:(nullable NSArray *)objects withSessionToken:(nullable NSString *)sessionToken; + +///-------------------------------------- +/// @name Utilities +///-------------------------------------- + ++ (nullable NSArray *)uniqueObjectsArrayFromArray:(nullable NSArray *)objects omitObjectsWithData:(BOOL)omitFetched; ++ (NSArray *)uniqueObjectsArrayFromArray:(NSArray *)objects usingFilter:(BOOL (^)(PFObject *object))filter; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.m new file mode 100644 index 0000000..5ad34ca --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/BatchController/PFObjectBatchController.m @@ -0,0 +1,229 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectBatchController.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFErrorUtilities.h" +#import "PFMacros.h" +#import "PFObjectController.h" +#import "PFObjectPrivate.h" +#import "PFQueryPrivate.h" +#import "PFRESTQueryCommand.h" +#import "PFRESTObjectCommand.h" +#import "PFRESTObjectBatchCommand.h" + +@implementation PFObjectBatchController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BFTask *)fetchObjectsAsync:(NSArray *)objects withSessionToken:(NSString *)sessionToken { + if (objects.count == 0) { + return [BFTask taskWithResult:objects]; + } + + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [self _fetchCommandForObjects:objects withSessionToken:sessionToken]; + return [self.dataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFCommandResult *result = task.result; + return [self _processFetchResultAsync:result.result forObjects:objects]; + }]; +} + +- (PFRESTCommand *)_fetchCommandForObjects:(NSArray *)objects withSessionToken:(NSString *)sessionToken { + NSArray *objectIds = [objects valueForKey:@keypath(PFObject, objectId)]; + PFQuery *query = [PFQuery queryWithClassName:[objects.firstObject parseClassName]]; + [query whereKey:@keypath(PFObject, objectId) containedIn:objectIds]; + query.limit = objectIds.count; + return [PFRESTQueryCommand findCommandForQueryState:query.state withSessionToken:sessionToken]; +} + +- (BFTask *)_processFetchResultAsync:(NSDictionary *)result forObjects:(NSArray *)objects { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSArray *results = result[@"results"]; // TODO: (nlutsenko) Move this logic into command itself? + NSArray *objectIds = [results valueForKey:@keypath(PFObject, objectId)]; + NSDictionary *objectResults = [NSDictionary dictionaryWithObjects:results forKeys:objectIds]; + + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:objects.count]; + for (PFObject *object in objects) { + PFObjectController *controller = [[object class] objectController]; + NSDictionary *objectResult = objectResults[object.objectId]; + + BFTask *task = nil; + if (objectResult) { + task = [controller processFetchResultAsync:objectResult forObject:object]; + } else { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorObjectNotFound + message:@"Object not found on the server."]; + task = [BFTask taskWithError:error]; + } + [tasks addObject:task]; + } + return [BFTask taskForCompletionOfAllTasks:tasks]; + }]; +} + +///-------------------------------------- +#pragma mark - Delete +///-------------------------------------- + +- (BFTask *)deleteObjectsAsync:(NSArray *)objects withSessionToken:(NSString *)sessionToken { + if (objects.count == 0) { + return [BFTask taskWithResult:objects]; + } + + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + NSArray *objectBatches = [PFInternalUtils arrayBySplittingArray:objects + withMaximumComponentsPerSegment:PFRESTObjectBatchCommandSubcommandsLimit]; + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:objectBatches.count]; + for (NSArray *batch in objectBatches) { + PFRESTCommand *command = [self _deleteCommandForObjects:batch withSessionToken:sessionToken]; + BFTask *task = [[self.dataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + return [self _processDeleteResultsAsync:[result result] forObjects:batch]; + }]; + [tasks addObject:task]; + } + return [[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *task) { + NSError *taskError = task.error; + if (taskError && [taskError.domain isEqualToString:BFTaskErrorDomain]) { + NSArray *taskErrors = taskError.userInfo[@"errors"]; + NSMutableArray *errors = [NSMutableArray array]; + for (NSError *error in taskErrors) { + if ([error.domain isEqualToString:BFTaskErrorDomain]) { + [errors addObjectsFromArray:error.userInfo[@"errors"]]; + } else { + [errors addObject:error]; + } + } + return [BFTask taskWithError:[NSError errorWithDomain:BFTaskErrorDomain + code:kBFMultipleErrorsError + userInfo:@{ @"errors" : errors }]]; + } + return task; + }]; + }] continueWithSuccessResult:objects]; +} + +- (PFRESTCommand *)_deleteCommandForObjects:(NSArray *)objects withSessionToken:(NSString *)sessionToken { + NSMutableArray *commands = [NSMutableArray arrayWithCapacity:objects.count]; + for (PFObject *object in objects) { + PFRESTCommand *deleteCommand = [PFRESTObjectCommand deleteObjectCommandForObjectState:object._state + withSessionToken:sessionToken]; + [commands addObject:deleteCommand]; + } + return [PFRESTObjectBatchCommand batchCommandWithCommands:commands sessionToken:sessionToken]; +} + +- (BFTask *)_processDeleteResultsAsync:(NSArray *)results forObjects:(NSArray *)objects { + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:results.count]; + [results enumerateObjectsUsingBlock:^(NSDictionary *result, NSUInteger idx, BOOL *stop) { + PFObject *object = objects[idx]; + NSDictionary *errorResult = result[@"error"]; + NSDictionary *successResult = result[@"success"]; + + id controller = [[object class] objectController]; + BFTask *task = [controller processDeleteResultAsync:successResult forObject:object]; + if (errorResult) { + task = [task continueWithBlock:^id(BFTask *task) { + return [BFTask taskWithError:[PFErrorUtilities errorFromResult:errorResult]]; + }]; + } + [tasks addObject:task]; + }]; + return [BFTask taskForCompletionOfAllTasks:tasks]; +} + +///-------------------------------------- +#pragma mark - Utilities +///-------------------------------------- + +//TODO: (nlutsenko) Convert to use `uniqueObjectsArrayFromArray:usingFilter:` ++ (NSArray *)uniqueObjectsArrayFromArray:(NSArray *)objects omitObjectsWithData:(BOOL)omitFetched { + if (objects.count == 0) { + return objects; + } + + NSMutableSet *set = [NSMutableSet setWithCapacity:[objects count]]; + NSString *className = [objects.firstObject parseClassName]; + for (PFObject *object in objects) { + @synchronized (object.lock) { + if (omitFetched && [object isDataAvailable]) { + continue; + } + + //TODO: (nlutsenko) Convert to using errors instead of assertions. + PFParameterAssert([className isEqualToString:object.parseClassName], + @"All object should be in the same class."); + PFParameterAssert(object.objectId != nil, + @"All objects must exist on the server."); + + [set addObject:object]; + } + } + return [set allObjects]; +} + ++ (NSArray *)uniqueObjectsArrayFromArray:(NSArray *)objects usingFilter:(BOOL (^)(PFObject *object))filter { + if (objects.count == 0) { + return objects; + } + + NSMutableDictionary *uniqueObjects = [NSMutableDictionary dictionary]; + for (PFObject *object in objects) { + if (!filter(object)) { + continue; + } + + // Use stringWithFormat: in case objectId or parseClassName are nil. + NSString *objectIdentifier = [NSString stringWithFormat:@"%@%@", object.parseClassName, object.objectId]; + if (!uniqueObjects[objectIdentifier]) { + uniqueObjects[objectIdentifier] = object; + } + } + return [uniqueObjects allValues]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.h new file mode 100644 index 0000000..371acc1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFDecoder; +@class PFEncoder; +@class PFObject; + +NS_ASSUME_NONNULL_BEGIN + +/*! + Handles encoding/decoding of `PFObject`s into a /2 JSON format. + /2 format is only used for persisting `currentUser`, `currentInstallation` to disk when LDS is not enabled. + */ +@interface PFObjectFileCoder : NSObject + +///-------------------------------------- +/// @name Encode +///-------------------------------------- + ++ (NSData *)dataFromObject:(PFObject *)object usingEncoder:(PFEncoder *)encoder; + +///-------------------------------------- +/// @name Decode +///-------------------------------------- + ++ (PFObject *)objectFromData:(NSData *)data usingDecoder:(PFDecoder *)decoder; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.m new file mode 100644 index 0000000..75bc197 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCoder.m @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectFileCoder.h" + +#import "PFJSONSerialization.h" +#import "PFObjectFileCodingLogic.h" +#import "PFObjectPrivate.h" +#import "PFObjectState.h" + +@implementation PFObjectFileCoder + +///-------------------------------------- +#pragma mark - Encode +///-------------------------------------- + ++ (NSData *)dataFromObject:(PFObject *)object usingEncoder:(PFEncoder *)encoder { + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + result[@"classname"] = object._state.parseClassName; + result[@"data"] = [object._state dictionaryRepresentationWithObjectEncoder:encoder]; + return [PFJSONSerialization dataFromJSONObject:result]; +} + +///-------------------------------------- +#pragma mark - Decode +///-------------------------------------- + ++ (PFObject *)objectFromData:(NSData *)data usingDecoder:(PFDecoder *)decoder { + NSDictionary *dictionary = [PFJSONSerialization JSONObjectFromData:data]; + NSString *className = dictionary[@"classname"] ?: dictionary[@"className"]; + NSString *objectId = dictionary[@"data"][@"objectId"] ?: dictionary[@"id"]; + + PFObject *object = [PFObject objectWithoutDataWithClassName:className objectId:objectId]; + [[[object class] objectFileCodingLogic] updateObject:object fromDictionary:dictionary usingDecoder:decoder]; + return object; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h new file mode 100644 index 0000000..c9ce66c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFDecoder; +@class PFObject; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFObjectFileCodingLogic : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + ++ (instancetype)codingLogic; + +///-------------------------------------- +/// @name Logic +///-------------------------------------- + +- (void)updateObject:(PFObject *)object fromDictionary:(NSDictionary *)dictionary usingDecoder:(PFDecoder *)decoder; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m new file mode 100644 index 0000000..f5955f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectFileCodingLogic.h" + +#import "PFMutableObjectState.h" +#import "PFObjectPrivate.h" + +@implementation PFObjectFileCodingLogic + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)codingLogic { + return [[self alloc] init]; +} + +///-------------------------------------- +#pragma mark - Logic +///-------------------------------------- + +- (void)updateObject:(PFObject *)object fromDictionary:(NSDictionary *)dictionary usingDecoder:(PFDecoder *)decoder { + PFMutableObjectState *state = [object._state mutableCopy]; + NSString *newObjectId = dictionary[@"id"]; + if (newObjectId) { + state.objectId = newObjectId; + } + NSString *createdAtString = dictionary[@"created_at"]; + if (createdAtString) { + [state setCreatedAtFromString:createdAtString]; + } + NSString *updatedAtString = dictionary[@"updated_at"]; + if (updatedAtString) { + [state setUpdatedAtFromString:updatedAtString]; + } + object._state = state; + + NSDictionary *newPointers = dictionary[@"pointers"]; + NSMutableDictionary *pointersDictionary = [NSMutableDictionary dictionaryWithCapacity:newPointers.count]; + [newPointers enumerateKeysAndObjectsUsingBlock:^(id key, NSArray *pointerArray, BOOL *stop) { + PFObject *pointer = [PFObject objectWithoutDataWithClassName:[pointerArray firstObject] + objectId:[pointerArray lastObject]]; + pointersDictionary[key] = pointer; + }]; + + NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary[@"data"]]; + [dataDictionary addEntriesFromDictionary:pointersDictionary]; + [object _mergeAfterFetchWithResult:dataDictionary decoder:decoder completeData:YES]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.h new file mode 100644 index 0000000..524078c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +// REST Key magic strings +extern NSString *const PFObjectCompleteRESTKey; +extern NSString *const PFObjectOperationsRESTKey; +extern NSString *const PFObjectTypeRESTKey; +extern NSString *const PFObjectObjectIdRESTKey; +extern NSString *const PFObjectUpdatedAtRESTKey; +extern NSString *const PFObjectCreatedAtRESTKey; +extern NSString *const PFObjectIsDeletingEventuallyRESTKey; +extern NSString *const PFObjectClassNameRESTKey; +extern NSString *const PFObjectACLRESTKey; + +extern NSString *const PFObjectDefaultPin; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.m new file mode 100644 index 0000000..76047ec --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Constants/PFObjectConstants.m @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectConstants.h" + +NSString *const PFObjectCompleteRESTKey = @"__complete"; +NSString *const PFObjectOperationsRESTKey = @"__operations"; +NSString *const PFObjectTypeRESTKey = @"__type"; +NSString *const PFObjectObjectIdRESTKey = @"objectId"; +NSString *const PFObjectUpdatedAtRESTKey = @"updatedAt"; +NSString *const PFObjectCreatedAtRESTKey = @"createdAt"; +NSString *const PFObjectIsDeletingEventuallyRESTKey = @"isDeletingEventually"; +NSString *const PFObjectClassNameRESTKey = @"className"; +NSString *const PFObjectACLRESTKey = @"ACL"; + +NSString *const PFObjectDefaultPin = @"_default"; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h new file mode 100644 index 0000000..27dd6dd --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFOfflineObjectController : PFObjectController + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m new file mode 100644 index 0000000..e9cefc3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFOfflineObjectController.h" + +#import "BFTask+Private.h" +#import "PFMacros.h" +#import "PFObjectController_Private.h" +#import "PFObjectPrivate.h" +#import "PFObjectState.h" +#import "PFOfflineStore.h" + +@interface PFOfflineObjectController () + +@property (nonatomic, strong, readonly) PFOfflineStore *offlineStore; + +@end + +@implementation PFOfflineObjectController + +@dynamic dataSource; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource { + return [super initWithDataSource:dataSource]; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [super controllerWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - PFObjectController +///-------------------------------------- + +- (BFTask *)processFetchResultAsync:(NSDictionary *)result forObject:(PFObject *)object { + return [[[[self.offlineStore fetchObjectLocallyAsync:object] continueWithBlock:^id(BFTask *task) { + // Catch CacheMiss error and ignore it. + if ([task.error.domain isEqualToString:PFParseErrorDomain] && + task.error.code == kPFErrorCacheMiss) { + return nil; + } + return task; + }] continueWithBlock:^id(BFTask *task) { + return [super processFetchResultAsync:result forObject:object]; + }] continueWithBlock:^id(BFTask *task) { + return [[self.offlineStore updateDataForObjectAsync:object] continueWithBlock:^id(BFTask *task) { + // Catch CACHE_MISS and ignore it. + if ([task.error.domain isEqualToString:PFParseErrorDomain] && + task.error.code == kPFErrorCacheMiss) { + return [BFTask taskWithResult:nil]; + } + return task; + }]; + }]; +} + +- (BFTask *)processDeleteResultAsync:(nullable NSDictionary *)result forObject:(PFObject *)object { + @weakify(self); + return [[super processDeleteResultAsync:result forObject:object] continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (object._state.deleted) { + return [self.offlineStore deleteDataForObjectAsync:object]; + } + return [self.offlineStore updateDataForObjectAsync:object]; + }]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFOfflineStore *)offlineStore { + return self.dataSource.offlineStore; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.h new file mode 100644 index 0000000..44a8ac6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" +#import "PFObjectControlling.h" + + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFObjectController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.m new file mode 100644 index 0000000..ec5d45b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController.m @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectController.h" +#import "PFObjectController_Private.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFErrorUtilities.h" +#import "PFMacros.h" +#import "PFObjectPrivate.h" +#import "PFObjectState.h" +#import "PFRESTObjectCommand.h" +#import "PFTaskQueue.h" + +@implementation PFObjectController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - PFObjectControlling +///-------------------------------------- + +#pragma mark Fetch + +- (BFTask *)fetchObjectAsync:(PFObject *)object withSessionToken:(NSString *)sessionToken { + @weakify(self); + return [[[[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + return [object _validateFetchAsync]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFRESTCommand *command = [PFRESTObjectCommand fetchObjectCommandForObjectState:[object._state copy] + withSessionToken:sessionToken]; + return [self _runFetchCommand:command forObject:object]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFCommandResult *result = task.result; + return [self processFetchResultAsync:result.result forObject:object]; + }] continueWithSuccessResult:object]; +} + +- (BFTask *)_runFetchCommand:(PFRESTCommand *)command forObject:(PFObject *)object { + return [self.dataSource.commandRunner runCommandAsync:command withOptions:PFCommandRunningOptionRetryIfFailed]; +} + +- (BFTask *)processFetchResultAsync:(NSDictionary *)result forObject:(PFObject *)object { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSDictionary *fetchedObjects = [object _collectFetchedObjects]; + @synchronized (object.lock) { + PFKnownParseObjectDecoder *decoder = [PFKnownParseObjectDecoder decoderWithFetchedObjects:fetchedObjects]; + [object _mergeAfterFetchWithResult:result decoder:decoder completeData:YES]; + } + return nil; + }]; +} + +#pragma mark Delete + +- (BFTask *)deleteObjectAsync:(PFObject *)object withSessionToken:(nullable NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + return [object _validateDeleteAsync]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFObjectState *state = [object._state copy]; + if (!state.objectId) { + return nil; + } + + PFRESTCommand *command = [PFRESTObjectCommand deleteObjectCommandForObjectState:state + withSessionToken:sessionToken]; + return [[self _runDeleteCommand:command forObject:object] continueWithBlock:^id(BFTask *fetchTask) { + @strongify(self); + PFCommandResult *result = fetchTask.result; + return [[self processDeleteResultAsync:result.result forObject:object] continueWithBlock:^id(BFTask *task) { + // Propagate the result of network task if it's faulted, cancelled. + if (fetchTask.faulted || fetchTask.cancelled) { + return fetchTask; + } + // Propagate the result of processDeleteResult otherwise. + return task; + }]; + }]; + }]; +} + +- (BFTask *)_runDeleteCommand:(PFRESTCommand *)command forObject:(PFObject *)object { + return [self.dataSource.commandRunner runCommandAsync:command withOptions:PFCommandRunningOptionRetryIfFailed]; +} + +- (BFTask *)processDeleteResultAsync:(NSDictionary *)result forObject:(PFObject *)object { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + BOOL deleted = (result != nil); + [object _setDeleted:deleted]; + return nil; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController_Private.h new file mode 100644 index 0000000..7ca5abc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectController_Private.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectController.h" + +@class PFRESTCommand; + +@interface PFObjectController () + +///-------------------------------------- +/// @name Fetch +///-------------------------------------- + +- (BFTask *)_runFetchCommand:(PFRESTCommand *)command forObject:(PFObject *)object; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectControlling.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectControlling.h new file mode 100644 index 0000000..e57a645 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Controller/PFObjectControlling.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFObjectControlling + +///-------------------------------------- +/// @name Fetch +///-------------------------------------- + +/*! + Fetches an object asynchronously. + + @param object Object to fetch. + @param sessionToken Session token to use. + + @returns `BFTask` with result set to `PFObject`. + */ +- (BFTask *)fetchObjectAsync:(PFObject *)object withSessionToken:(nullable NSString *)sessionToken; + +- (BFTask *)processFetchResultAsync:(NSDictionary *)result forObject:(PFObject *)object; + +///-------------------------------------- +/// @name Delete +///-------------------------------------- + +/*! + Deletes an object asynchronously. + + @param object Object to fetch. + @param sessionToken Session token to use. + + @returns `BFTask` with result set to `nil`. + */ +- (BFTask *)deleteObjectAsync:(PFObject *)object withSessionToken:(nullable NSString *)sessionToken; + +//TODO: (nlutsenko) This needs removal, figure out how to kill it. +- (BFTask *)processDeleteResultAsync:(nullable NSDictionary *)result forObject:(PFObject *)object; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h new file mode 100644 index 0000000..9cbd1b0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +typedef NS_ENUM(NSUInteger, PFCurrentObjectStorageType) { + PFCurrentObjectStorageTypeFile = 1, + PFCurrentObjectStorageTypeOfflineStore, +}; + +@protocol PFCurrentObjectControlling + +@property (nonatomic, assign, readonly) PFCurrentObjectStorageType storageType; + +///-------------------------------------- +/// @name Current +///-------------------------------------- + +- (BFTask *)getCurrentObjectAsync; +- (BFTask *)saveCurrentObjectAsync:(PFObject *)object; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h new file mode 100644 index 0000000..b507e8a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFFieldOperation; +@class PFOperationSet; + +@interface PFObjectEstimatedData : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithServerData:(NSDictionary *)serverData + operationSetQueue:(NSArray *)operationSetQueue; ++ (instancetype)estimatedDataFromServerData:(NSDictionary *)serverData + operationSetQueue:(NSArray *)operationSetQueue; + +///-------------------------------------- +/// @name Read +///-------------------------------------- + +- (id)objectForKey:(NSString *)key; +- (id)objectForKeyedSubscript:(NSString *)keyedSubscript; + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, id obj, BOOL *stop))block; + +@property (nonatomic, copy, readonly) NSArray *allKeys; +@property (nonatomic, copy, readonly) NSDictionary *dictionaryRepresentation; + +///-------------------------------------- +/// @name Write +///-------------------------------------- + +- (id)applyFieldOperation:(PFFieldOperation *)operation forKey:(NSString *)key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m new file mode 100644 index 0000000..7fb5df5 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectEstimatedData.h" + +#import "PFObjectUtilities.h" + +@interface PFObjectEstimatedData () { + NSMutableDictionary *_dataDictionary; +} + +@end + +@implementation PFObjectEstimatedData + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _dataDictionary = [NSMutableDictionary dictionary]; + + return self; +} + +- (instancetype)initWithServerData:(NSDictionary *)serverData + operationSetQueue:(NSArray *)operationSetQueue { + self = [super init]; + if (!self) return nil; + + // Don't use mutableCopy to make sure we never initialize _dataDictionary to `nil`. + _dataDictionary = [NSMutableDictionary dictionaryWithDictionary:serverData]; + for (PFOperationSet *operationSet in operationSetQueue) { + [PFObjectUtilities applyOperationSet:operationSet toDictionary:_dataDictionary]; + } + + return self; +} + ++ (instancetype)estimatedDataFromServerData:(NSDictionary *)serverData + operationSetQueue:(NSArray *)operationSetQueue { + return [[self alloc] initWithServerData:serverData operationSetQueue:operationSetQueue]; +} + +///-------------------------------------- +#pragma mark - Read +///-------------------------------------- + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, id obj, BOOL *stop))block { + [_dataDictionary enumerateKeysAndObjectsUsingBlock:block]; +} + +- (id)objectForKey:(NSString *)key { + return [_dataDictionary objectForKey:key]; +} + +- (id)objectForKeyedSubscript:(NSString *)keyedSubscript { + return [_dataDictionary objectForKeyedSubscript:keyedSubscript]; +} + +- (NSArray *)allKeys { + return [_dataDictionary allKeys]; +} + +- (NSDictionary *)dictionaryRepresentation { + return [_dataDictionary copy]; +} + +///-------------------------------------- +#pragma mark - Write +///-------------------------------------- + +- (id)applyFieldOperation:(PFFieldOperation *)operation forKey:(NSString *)key { + return [PFObjectUtilities newValueByApplyingFieldOperation:operation toDictionary:_dataDictionary forKey:key]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h new file mode 100644 index 0000000..8537ddf --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" +#import "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +@interface PFObjectFilePersistenceController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Objects +///-------------------------------------- + +/*! + Loads and creates a PFObject from file. + + @param key File name to use. + + @returns `BFTask` with `PFObject` or `nil` result. + */ +- (BFTask *)loadPersistentObjectAsyncForKey:(NSString *)key; + +/*! + Saves a given object to a file with name. + + @param object Object to save. + @param key File name to use. + + @returns `BFTask` with `nil` result. + */ +- (BFTask *)persistObjectAsync:(PFObject *)object forKey:(NSString *)key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m new file mode 100644 index 0000000..38fdcd1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectFilePersistenceController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFFileManager.h" +#import "PFJSONSerialization.h" +#import "PFMacros.h" +#import "PFMultiProcessFileLockController.h" +#import "PFObjectFileCoder.h" +#import "PFObjectPrivate.h" + +@implementation PFObjectFilePersistenceController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Objects +///-------------------------------------- + +- (BFTask *)loadPersistentObjectAsyncForKey:(NSString *)key { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + + NSString *path = [self.dataSource.fileManager parseDataItemPathForPathComponent:key]; + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:path]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:path]; + return nil; + } + + NSError *error = nil; + NSData *jsonData = [NSData dataWithContentsOfFile:path + options:NSDataReadingMappedIfSafe + error:&error]; + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:path]; + + if (error) { + return [BFTask taskWithError:error]; + } + return jsonData; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSData *jsonData = task.result; + if (jsonData) { + PFObject *object = [PFObjectFileCoder objectFromData:jsonData usingDecoder:[PFDecoder objectDecoder]]; + return object; + } + + return nil; + }]; +} + +- (BFTask *)persistObjectAsync:(PFObject *)object forKey:(NSString *)key { + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + + NSData *data = [PFObjectFileCoder dataFromObject:object usingEncoder:[PFPointerObjectEncoder objectEncoder]]; + + NSString *filePath = [self.dataSource.fileManager parseDataItemPathForPathComponent:key]; + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:filePath]; + + return [[PFFileManager writeDataAsync:data toFile:filePath] continueWithBlock:^id(BFTask *task) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:filePath]; + return nil; + }]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h new file mode 100644 index 0000000..541056b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +/*! + A disk-based map of local ids to global Parse objectIds. Every entry in this + map has a retain count, and the entry will be removed from the map if the + retain count reaches 0. Every time a localId is written out to disk, its retain + count should be incremented. When the reference on disk is deleted, it should + be decremented. Some entries in this map may not have an object id yet. + This class is thread-safe. + */ +@interface PFObjectLocalIdStore : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)storeWithDataSource:(id)dataSource; + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSString *)createLocalId; +- (void)retainLocalIdOnDisk:(NSString *)localId; +- (void)releaseLocalIdOnDisk:(NSString *)localId; + +- (void)setObjectId:(NSString *)objectId forLocalId:(NSString *)localId; +- (NSString *)objectIdForLocalId:(NSString *)localId; + +// For testing only. +- (BOOL)clear; +- (void)clearInMemoryCache; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m new file mode 100644 index 0000000..7c88c3e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m @@ -0,0 +1,291 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectLocalIdStore.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFFileManager.h" +#import "PFInternalUtils.h" +#import "PFJSONSerialization.h" +#import "PFLogging.h" +#import "Parse_Private.h" + +static NSString *const _PFObjectLocalIdStoreDiskFolderPath = @"LocalId"; + +///-------------------------------------- +#pragma mark - PFObjectLocalIdStoreMapEntry +///-------------------------------------- + +/*! + * Internal class representing all the information we know about a local id. + */ +@interface PFObjectLocalIdStoreMapEntry : NSObject + +@property (nonatomic, strong) NSString *objectId; +@property (atomic, assign) int referenceCount; + +- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithFile:(NSString *)filePath; + +@end + +@implementation PFObjectLocalIdStoreMapEntry + +- (instancetype)init { + return [super init]; +} + +- (instancetype)initWithFile:(NSString *)filePath { + self = [self init]; + if (!self) return nil; + + NSData *jsonData = [NSData dataWithContentsOfFile:filePath]; + NSDictionary *dictionary = [PFJSONSerialization JSONObjectFromData:jsonData]; + + _objectId = [dictionary[@"objectId"] copy]; + _referenceCount = [dictionary[@"referenceCount"] intValue]; + + return self; +} + +- (void)writeToFile:(NSString *)filePath { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[@"referenceCount"] = @(self.referenceCount); + if (self.objectId) { + dictionary[@"objectId"] = self.objectId; + } + + NSData *jsonData = [PFJSONSerialization dataFromJSONObject:dictionary]; + [[PFFileManager writeDataAsync:jsonData toFile:filePath] waitForResult:nil withMainThreadWarning:NO]; +} + +@end + +///-------------------------------------- +#pragma mark - PFObjectLocalIdStore +///-------------------------------------- + +@interface PFObjectLocalIdStore () { + NSString *_diskPath; + NSObject *_lock; + NSMutableDictionary *_inMemoryCache; +} + +@end + +@implementation PFObjectLocalIdStore + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +/*! + * Creates a new LocalIdManager with default options. + */ +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + _lock = [[NSObject alloc] init]; + _inMemoryCache = [NSMutableDictionary dictionary]; + + // Construct the path to the disk storage directory. + _diskPath = [[Parse _currentManager].fileManager parseDataItemPathForPathComponent:_PFObjectLocalIdStoreDiskFolderPath]; + + NSError *error = nil; + [[PFFileManager createDirectoryIfNeededAsyncAtPath:_diskPath] waitForResult:&error withMainThreadWarning:NO]; + if (error) { + PFLogError(PFLoggingTagCommon, @"Unable to create directories for local id storage with error: %@", error); + } + + return self; +} + ++ (instancetype)storeWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +/*! + * Returns Yes if localId has the right basic format for a local id. + */ ++ (BOOL)isLocalId:(NSString *)localId { + if ([localId length] != 22U) { + return NO; + } + if (![localId hasPrefix:@"local_"]) { + return NO; + } + for (int i = 6; i < [localId length]; ++i) { + if (!ishexnumber([localId characterAtIndex:i])) { + return NO; + } + } + return YES; +} + +/*! + * Grabs one entry in the local id map off the disk. + */ +- (PFObjectLocalIdStoreMapEntry *)getMapEntry:(NSString *)localId { + PFConsistencyAssert([[self class] isLocalId:localId], @"Tried to get invalid local id: \"%@\".", localId); + + PFObjectLocalIdStoreMapEntry *entry = nil; + + NSString *file = [_diskPath stringByAppendingPathComponent:localId]; + if (![[NSFileManager defaultManager] isReadableFileAtPath:file]) { + entry = [[PFObjectLocalIdStoreMapEntry alloc] init]; + } else { + entry = [[PFObjectLocalIdStoreMapEntry alloc] initWithFile:file]; + } + + // If there's an objectId in memory, make sure it matches the one in the + // file. This is in case the id was retained on disk *after* it was resolved. + if (!entry.objectId) { + NSString *objectId = [_inMemoryCache objectForKey:localId]; + if (objectId) { + entry.objectId = objectId; + if (entry.referenceCount > 0) { + [self putMapEntry:entry forLocalId:localId]; + } + } + } + + return entry; +} + +/*! + * Writes one entry to the local id map on disk. + */ +- (void)putMapEntry:(PFObjectLocalIdStoreMapEntry *)entry forLocalId:(NSString *)localId { + PFConsistencyAssert([[self class] isLocalId:localId], @"Tried to get invalid local id: \"%@\".", localId); + + NSString *file = [_diskPath stringByAppendingPathComponent:localId]; + [entry writeToFile:file]; +} + +/*! + * Removes an entry from the local id map on disk. + */ +- (void)removeMapEntry:(NSString *)localId { + PFConsistencyAssert([[self class] isLocalId:localId], @"Tried to get invalid local id: \"%@\".", localId); + + NSString *file = [_diskPath stringByAppendingPathComponent:localId]; + [[NSFileManager defaultManager] removeItemAtPath:file error:nil]; +} + +/*! + * Creates a new local id in the map. + */ +- (NSString *)createLocalId { + @synchronized (_lock) { + // Generate a new random string of upper and lower case letters. + + // Start by generating a number. It will be the localId as a base-52 number. + // It has to be a uint64_t because log256(52^10) ~= 7.13 bytes. + uint64_t localIdNumber = (((uint64_t)arc4random()) << 32) | ((uint64_t)arc4random()); + NSString *localId = [NSString stringWithFormat:@"local_%016llx", localIdNumber]; + + PFConsistencyAssert([[self class] isLocalId:localId], @"Generated an invalid local id: \"%@\".", localId); + + return localId; + } +} + +/*! + * Increments the retain count of a local id on disk. + */ +- (void)retainLocalIdOnDisk:(NSString *)localId { + @synchronized (_lock) { + PFObjectLocalIdStoreMapEntry *entry = [self getMapEntry:localId]; + entry.referenceCount++; + [self putMapEntry:entry forLocalId:localId]; + } +} + +/*! + * Decrements the retain count of a local id on disk. + * If the retain count hits zero, the id is forgotten forever. + */ +- (void)releaseLocalIdOnDisk:(NSString *)localId { + @synchronized (_lock) { + PFObjectLocalIdStoreMapEntry *entry = [self getMapEntry:localId]; + if (--entry.referenceCount > 0) { + [self putMapEntry:entry forLocalId:localId]; + } else { + [self removeMapEntry:localId]; + } + } +} + +/*! + * Sets the objectId associated with a given local id. + */ +- (void)setObjectId:(NSString *)objectId forLocalId:(NSString *)localId { + @synchronized (_lock) { + PFObjectLocalIdStoreMapEntry *entry = [self getMapEntry:localId]; + if (entry.referenceCount > 0) { + entry.objectId = objectId; + [self putMapEntry:entry forLocalId:localId]; + } + [_inMemoryCache setObject:objectId forKey:localId]; + } +} + +/*! + * Returns the objectId associated with a given local id. + * Returns nil if no objectId is yet known for the lcoal id. + */ +- (NSString *)objectIdForLocalId:(NSString *)localId { + @synchronized (_lock) { + NSString *objectId = [_inMemoryCache objectForKey:localId]; + if (objectId) { + return objectId; + } + + PFObjectLocalIdStoreMapEntry *entry = [self getMapEntry:localId]; + return entry.objectId; + } +} + +/*! + * Removes all local ids from the disk and memory caches. + */ +- (BOOL)clear { + @synchronized (_lock) { + [self clearInMemoryCache]; + + BOOL empty = ([[[[NSFileManager defaultManager] enumeratorAtPath:_diskPath] allObjects] count] == 0); + + [[NSFileManager defaultManager] removeItemAtPath:_diskPath error:nil]; + + [[NSFileManager defaultManager] createDirectoryAtPath:_diskPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + return !empty; + } +} + +/*! + * Removes all local ids from the memory cache. + */ +- (void)clearInMemoryCache { + @synchronized (_lock) { + [_inMemoryCache removeAllObjects]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.h new file mode 100644 index 0000000..5456ffa --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFDecoder; +@class PFEncoder; +@class PFFieldOperation; + +/*! + A set of field-level operations that can be performed on an object, corresponding to one + command. For example, all the data for a single call to save() will be packaged here. It is + assumed that the PFObject that owns the operations handles thread-safety. + */ +@interface PFOperationSet : NSObject + +/*! + Returns true if this set corresponds to a call to saveEventually. + */ +@property (nonatomic, assign, getter=isSaveEventually) BOOL saveEventually; + +/*! + A unique id for this operation set. + */ +@property (nonatomic, copy, readonly) NSString *uuid; + +@property (nonatomic, copy) NSDate *updatedAt; + +/*! + Merges the changes from the given operation set into this one. Most typically, this is what + happens when a save fails and changes need to be rolled into the next save. + */ +- (void)mergeOperationSet:(PFOperationSet *)other; + +/*! + Converts this operation set into its REST format for serializing to the pinning store + */ +- (NSDictionary *)RESTDictionaryUsingObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs; + +/*! + The inverse of RESTDictionaryUsingObjectEncoder. + Creates a new OperationSet from the given NSDictionary + */ ++ (PFOperationSet *)operationSetFromRESTDictionary:(NSDictionary *)data + usingDecoder:(PFDecoder *)decoder; + +///-------------------------------------- +/// @name Accessors +///-------------------------------------- + +- (id)objectForKey:(id)aKey; +- (id)objectForKeyedSubscript:(id)aKey; +- (NSUInteger)count; +- (NSEnumerator *)keyEnumerator; + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, PFFieldOperation *operation, BOOL *stop))block; + +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setObject:(id)anObject forKeyedSubscript:(id)aKey; +- (void)removeObjectForKey:(id)aKey; +- (void)removeAllObjects; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.m new file mode 100644 index 0000000..f1df813 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/OperationSet/PFOperationSet.m @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFOperationSet.h" + +#import "PFACL.h" +#import "PFACLPrivate.h" +#import "PFDecoder.h" +#import "PFEncoder.h" +#import "PFFieldOperation.h" +#import "PFInternalUtils.h" + +NSString *const PFOperationSetKeyUUID = @"__uuid"; +NSString *const PFOperationSetKeyIsSaveEventually = @"__isSaveEventually"; +NSString *const PFOperationSetKeyUpdatedAt = @"__updatedAt"; +NSString *const PFOperationSetKeyACL = @"ACL"; + +@interface PFOperationSet() + +@property (nonatomic, strong) NSMutableDictionary *dictionary; + +@end + +@implementation PFOperationSet + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + return [self initWithUUID:[[NSUUID UUID] UUIDString]]; +} + +- (instancetype)initWithUUID:(NSString *)uuid { + self = [super init]; + if (!self) return nil; + + _dictionary = [NSMutableDictionary dictionary]; + _uuid = [uuid copy]; + + _updatedAt = [NSDate date]; + + return self; +} + +///-------------------------------------- +#pragma mark - Merge +///-------------------------------------- + +- (void)mergeOperationSet:(PFOperationSet *)other { + [other.dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + PFFieldOperation *localOperation = self.dictionary[key]; + PFFieldOperation *remoteOperation = other.dictionary[key]; + if (localOperation != nil) { + localOperation = [localOperation mergeWithPrevious:remoteOperation]; + self.dictionary[key] = localOperation; + } else { + self.dictionary[key] = remoteOperation; + } + }]; + self.updatedAt = [NSDate date]; +} + +///-------------------------------------- +#pragma mark - Encoding +///-------------------------------------- + +- (NSDictionary *)RESTDictionaryUsingObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs { + NSMutableDictionary *operationSetResult = [[NSMutableDictionary alloc] init]; + [self.dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + operationSetResult[key] = [obj encodeWithObjectEncoder:objectEncoder]; + }]; + + operationSetResult[PFOperationSetKeyUUID] = self.uuid; + operationSetResult[PFOperationSetKeyUpdatedAt] = [objectEncoder encodeObject:self.updatedAt]; + + if (self.saveEventually) { + operationSetResult[PFOperationSetKeyIsSaveEventually] = @YES; + } + *operationSetUUIDs = @[ self.uuid ]; + return operationSetResult; +} + ++ (PFOperationSet *)operationSetFromRESTDictionary:(NSDictionary *)data + usingDecoder:(PFDecoder *)decoder { + NSMutableDictionary *mutableData = [data mutableCopy]; + NSString *inputUUID = mutableData[PFOperationSetKeyUUID]; + [mutableData removeObjectForKey:PFOperationSetKeyUUID]; + PFOperationSet *operationSet = nil; + if (inputUUID == nil) { + operationSet = [[PFOperationSet alloc] init]; + } else { + operationSet = [[PFOperationSet alloc] initWithUUID:inputUUID]; + } + + NSNumber *saveEventuallyFlag = mutableData[PFOperationSetKeyIsSaveEventually]; + if (saveEventuallyFlag) { + operationSet.saveEventually = [saveEventuallyFlag boolValue]; + [mutableData removeObjectForKey:PFOperationSetKeyIsSaveEventually]; + } + + NSDate *updatedAt = mutableData[PFOperationSetKeyUpdatedAt]; + [mutableData removeObjectForKey:PFOperationSetKeyUpdatedAt]; + + [mutableData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + id value = [decoder decodeObject:obj]; + PFFieldOperation *fieldOperation = nil; + if ([key isEqualToString:PFOperationSetKeyACL]) { + // TODO (hallucinogen): where to use the decoder? + value = [PFACL ACLWithDictionary:obj]; + } + if ([value isKindOfClass:[PFFieldOperation class]]) { + fieldOperation = value; + } else { + fieldOperation = [PFSetOperation setWithValue:value]; + } + operationSet[key] = fieldOperation; + }]; + operationSet.updatedAt = updatedAt ? [decoder decodeObject:updatedAt] : nil; + + return operationSet; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (id)objectForKey:(id)aKey { + return self.dictionary[aKey]; +} + +- (id)objectForKeyedSubscript:(id)aKey { + return [self objectForKey:aKey]; +} + +- (NSUInteger)count { + return [self.dictionary count]; +} + +- (NSEnumerator *)keyEnumerator { + return [self.dictionary keyEnumerator]; +} + +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, PFFieldOperation *operation, BOOL *stop))block { + [self.dictionary enumerateKeysAndObjectsUsingBlock:block]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + self.dictionary[aKey] = anObject; + self.updatedAt = [NSDate date]; +} + +- (void)setObject:(id)anObject forKeyedSubscript:(id)key { + [self setObject:anObject forKey:key]; +} + +- (void)removeObjectForKey:(id)key { + [self.dictionary removeObjectForKey:key]; + self.updatedAt = [NSDate date]; +} + +- (void)removeAllObjects { + [self.dictionary removeAllObjects]; + self.updatedAt = [NSDate date]; +} + +///-------------------------------------- +#pragma mark - NSFastEnumeration +///-------------------------------------- + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(id __unsafe_unretained [])buffer + count:(NSUInteger)len { + return [self.dictionary countByEnumeratingWithState:state objects:buffer count:len]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + PFOperationSet *operationSet = [[[self class] allocWithZone:zone] initWithUUID:self.uuid]; + operationSet.dictionary = [self.dictionary mutableCopy]; + operationSet.updatedAt = [self.updatedAt copy]; + operationSet.saveEventually = self.saveEventually; + return operationSet; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PFObjectPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PFObjectPrivate.h new file mode 100644 index 0000000..949e589 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PFObjectPrivate.h @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDecoder.h" +#import "PFEncoder.h" +#import "PFMulticastDelegate.h" +#import "PFObjectControlling.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFCurrentUserController; +@class PFFieldOperation; +@class PFJSONCacheItem; +@class PFMultiCommand; +@class PFObjectEstimatedData; +@class PFObjectFileCodingLogic; +@class PFObjectState; +@class PFObjectSubclassingController; +@class PFOperationSet; +@class PFPinningObjectStore; +@class PFRESTCommand; +@class PFTaskQueue; + +///-------------------------------------- +#pragma mark - PFObjectPrivateSubclass +///-------------------------------------- + +@protocol PFObjectPrivateSubclass + +@required + +///-------------------------------------- +/// @name State +///-------------------------------------- + ++ (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className + objectId:(NSString *)objectId + isComplete:(BOOL)complete; + +@optional + +///-------------------------------------- +/// @name Before Save +///-------------------------------------- + +/*! + Called before an object is going to be saved. Called in a context of object lock. + Subclasses can override this method to do any custom updates before an object gets saved. + */ +- (void)_objectWillSave; + +@end + +///-------------------------------------- +#pragma mark - PFObject +///-------------------------------------- + +// Extension for property methods. +@interface PFObject () + +/*! + @returns Current object state. + */ +@property (nonatomic, copy) PFObjectState *_state; +@property (nonatomic, copy) NSMutableSet *_availableKeys; + +- (instancetype)initWithObjectState:(PFObjectState *)state; ++ (instancetype)objectWithClassName:(NSString *)className + objectId:(NSString *)objectid + completeData:(BOOL)completeData; ++ (instancetype)objectWithoutDataWithClassName:(NSString *)className localId:(NSString *)localId; + +- (PFTaskQueue *)taskQueue; + +- (PFObjectEstimatedData *)_estimatedData; + +#if PARSE_OSX_ONLY +// Not available publicly, but available for testing + +- (instancetype)refresh; +- (instancetype)refresh:(NSError **)error; +- (void)refreshInBackgroundWithBlock:(PFObjectResultBlock)block; +- (void)refreshInBackgroundWithTarget:(id)target selector:(SEL)selector; + +#endif + +///-------------------------------------- +/// @name Validation +///-------------------------------------- + +- (BFTask PF_GENERIC(PFVoid) *)_validateFetchAsync NS_REQUIRES_SUPER; +- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync NS_REQUIRES_SUPER; + +/*! + Validate the save eventually operation with the current state. + The result of this task is ignored. The error/cancellation/exception will prevent `saveEventually`. + + @returns Task that encapsulates the validation. + */ +- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync NS_REQUIRES_SUPER; + +///-------------------------------------- +/// @name Pin +///-------------------------------------- +- (BFTask *)_pinInBackgroundWithName:(NSString *)name includeChildren:(BOOL)includeChildren; ++ (BFTask *)_pinAllInBackground:(NSArray *)objects withName:(NSString *)name includeChildren:(BOOL)includeChildren; + ++ (PFPinningObjectStore *)pinningObjectStore; ++ (id)objectController; ++ (PFObjectFileCodingLogic *)objectFileCodingLogic; ++ (PFCurrentUserController *)currentUserController; + +///-------------------------------------- +#pragma mark - Subclassing +///-------------------------------------- + ++ (PFObjectSubclassingController *)subclassingController; + +@end + +@interface PFObject (Private) + +/*! + Returns the object that should be used to synchronize all internal data access. + */ +- (NSObject *)lock; + +/*! + Blocks until all outstanding operations have completed. + */ +- (void)waitUntilFinished; + +- (NSDictionary *)_collectFetchedObjects; + +///-------------------------------------- +#pragma mark - Static methods for Subclassing +///-------------------------------------- + +/*! + Unregisters a class registered using registerSubclass: + If we ever expose thsi method publicly, we must change the underlying implementation + to have stack behavior. Currently unregistering a custom class for a built-in will + leave the built-in unregistered as well. + @param subclass the subclass + */ ++ (void)unregisterSubclass:(Class)subclass; + +///-------------------------------------- +#pragma mark - Children helpers +///-------------------------------------- +- (BFTask *)_saveChildrenInBackgroundWithCurrentUser:(PFUser *)currentUser sessionToken:(NSString *)sessionToken; + +///-------------------------------------- +#pragma mark - Dirtiness helpers +///-------------------------------------- +- (BOOL)isDirty:(BOOL)considerChildren; +- (void)_setDirty:(BOOL)dirty; + +- (void)performOperation:(PFFieldOperation *)operation forKey:(NSString *)key; +- (void)setHasBeenFetched:(BOOL)fetched; +- (void)_setDeleted:(BOOL)deleted; + +- (BOOL)isDataAvailableForKey:(NSString *)key; + +- (BOOL)_hasChanges; +- (BOOL)_hasOutstandingOperations; +- (PFOperationSet *)unsavedChanges; + +///-------------------------------------- +#pragma mark - Validations +///-------------------------------------- +- (void)_checkSaveParametersWithCurrentUser:(PFUser *)currentUser; +/*! + Checks if Parse class name could be used to initialize a given instance of PFObject or it's subclass. + */ ++ (void)_assertValidInstanceClassName:(NSString *)className; + +///-------------------------------------- +#pragma mark - Serialization helpers +///-------------------------------------- +- (NSString *)getOrCreateLocalId; +- (void)resolveLocalId; + ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + completeData:(BOOL)completeData; + ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + selectedKeys:(NSArray *)selectedKeys; + ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + completeData:(BOOL)completeData + decoder:(PFDecoder *)decoder; ++ (BFTask *)_migrateObjectInBackgroundFromFile:(NSString *)fileName toPin:(NSString *)pinName; ++ (BFTask *)_migrateObjectInBackgroundFromFile:(NSString *)fileName + toPin:(NSString *)pinName + usingMigrationBlock:(BFContinuationBlock)block; + +- (NSMutableDictionary *)_convertToDictionaryForSaving:(PFOperationSet *)changes + withObjectEncoder:(PFEncoder *)encoder; + +///-------------------------------------- +#pragma mark - REST operations +///-------------------------------------- +- (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs; +- (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs + state:(PFObjectState *)state + operationSetQueue:(NSArray *)operationSetQueue; + +- (void)mergeFromRESTDictionary:(NSDictionary *)object + withDecoder:(PFDecoder *)decoder; + +///-------------------------------------- +#pragma mark - Data helpers +///-------------------------------------- +- (void)checkForChangesToMutableContainers; +- (void)rebuildEstimatedData; + +///-------------------------------------- +#pragma mark - Command handlers +///-------------------------------------- +- (PFObject *)mergeFromObject:(PFObject *)other; + +- (void)_mergeAfterSaveWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder; +- (void)_mergeAfterFetchWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData; +- (void)_mergeFromServerWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData; + +- (BFTask *)handleSaveResultAsync:(NSDictionary *)result; + +///-------------------------------------- +#pragma mark - Asynchronous operations +///-------------------------------------- +- (void)startSave; +- (BFTask *)_enqueueSaveEventuallyWithChildren:(BOOL)saveChildren; +- (BFTask *)saveAsync:(BFTask *)toAwait; +- (BFTask *)fetchAsync:(BFTask *)toAwait; +- (BFTask *)deleteAsync:(BFTask *)toAwait; + +///-------------------------------------- +#pragma mark - Command constructors +///-------------------------------------- +- (PFRESTCommand *)_constructSaveCommandForChanges:(PFOperationSet *)changes + sessionToken:(NSString *)sessionToken + objectEncoder:(PFEncoder *)encoder; +- (PFRESTCommand *)_currentDeleteCommandWithSessionToken:(NSString *)sessionToken; + +///-------------------------------------- +#pragma mark - Misc helpers +///-------------------------------------- +- (NSString *)displayClassName; +- (NSString *)displayObjectId; + +- (void)registerSaveListener:(void (^)(id result, NSError *error))callback; +- (void)unregisterSaveListener:(void (^)(id result, NSError *error))callback; +- (PFACL *)ACLWithoutCopying; + +///-------------------------------------- +#pragma mark - Get and set +///-------------------------------------- + +- (void)_setObject:(id)object + forKey:(NSString *)key + onlyIfDifferent:(BOOL)onlyIfDifferent; + +///-------------------------------------- +#pragma mark - Subclass Helpers +///-------------------------------------- + +/*! + This method is called by -[PFObject init]; changes made to the object during this + method will not mark the object as dirty. PFObject uses this method to to apply the + default ACL; subclasses which override this method shold be sure to call the super + implementation if they want to honor the default ACL. + */ +- (void)setDefaultValues; + +/*! + This method allows subclasses to determine whether a default ACL should be applied + to new instances. + */ +- (BOOL)needsDefaultACL; + +@end + +@interface PFObject () { + PFMulticastDelegate *saveDelegate; +} + +@property (nonatomic, strong) PFMulticastDelegate *saveDelegate; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.h new file mode 100644 index 0000000..66950c7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFPin; + +@interface PFPinningObjectStore : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)storeWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Pin +///-------------------------------------- + +/*! + Gets pin with name equals to given name. + + @param name Pin Name. + + @returns `BFTask` with `PFPin` result if pinning succeeds. + */ +- (BFTask *)fetchPinAsyncWithName:(NSString *)name; + +/*! + Pins given objects to the pin. Creates new pin if the pin with such name is not found. + + @param objects Array of `PFObject`s to pin. + @param name Pin Name. + @param includeChildren Whether children of `objects` should be pinned as well. + + @returns `BFTask` with `@YES` result. + */ +- (BFTask *)pinObjectsAsync:(nullable NSArray *)objects + withPinName:(NSString *)name + includeChildren:(BOOL)includeChildren; + +///-------------------------------------- +/// @name Unpin +///-------------------------------------- + +/*! + Unpins given array of objects from the pin. + + @param objects Objects to unpin. + @param name Pin name. + + @returns `BFTask` with `@YES` result. + */ +- (BFTask *)unpinObjectsAsync:(nullable NSArray *)objects withPinName:(NSString *)name; + +/*! + Unpins all objects from the pin. + + @param name Pin name. + + @returns `BFTask` with `YES` result. + */ +- (BFTask *)unpinAllObjectsAsyncWithPinName:(NSString *)name; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.m new file mode 100644 index 0000000..b731df1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/PinningStore/PFPinningObjectStore.m @@ -0,0 +1,163 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPinningObjectStore.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFMacros.h" +#import "PFOfflineStore.h" +#import "PFPin.h" +#import "PFQueryPrivate.h" + +@interface PFPinningObjectStore () { + NSMapTable *_pinCacheTable; + dispatch_queue_t _pinCacheAccessQueue; + BFExecutor *_pinCacheAccessExecutor; +} + +@end + +@implementation PFPinningObjectStore + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _pinCacheTable = [NSMapTable strongToWeakObjectsMapTable]; + _pinCacheAccessQueue = dispatch_queue_create("com.parse.object.pin.cache", DISPATCH_QUEUE_SERIAL); + _pinCacheAccessExecutor = [BFExecutor executorWithDispatchQueue:_pinCacheAccessQueue]; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)storeWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Pin +///-------------------------------------- + +- (BFTask *)fetchPinAsyncWithName:(NSString *)name { + @weakify(self); + return [BFTask taskFromExecutor:_pinCacheAccessExecutor withBlock:^id{ + BFTask *cachedTask = [_pinCacheTable objectForKey:name] ?: [BFTask taskWithResult:nil]; + // We need to call directly to OfflineStore since we don't want/need a user to query for ParsePins + cachedTask = [cachedTask continueWithBlock:^id(BFTask *task) { + @strongify(self); + PFQuery *query = [[PFPin query] whereKey:PFPinKeyName equalTo:name]; + PFOfflineStore *store = self.dataSource.offlineStore; + return [[store findAsyncForQueryState:query.state + user:nil + pin:nil] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *result = task.result; + // TODO (hallucinogen): What do we do if there are more than 1 result? + PFPin *pin = (result.count != 0 ? result.firstObject : [PFPin pinWithName:name]); + return pin; + }]; + }]; + // Put the task back into the cache. + [_pinCacheTable setObject:cachedTask forKey:name]; + return cachedTask; + }]; +} + +- (BFTask *)pinObjectsAsync:(NSArray *)objects withPinName:(NSString *)name includeChildren:(BOOL)includeChildren { + if (objects.count == 0) { + return [BFTask taskWithResult:@YES]; + } + + @weakify(self); + return [[[self fetchPinAsyncWithName:name] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFPin *pin = task.result; + PFOfflineStore *store = self.dataSource.offlineStore; + //TODO (hallucinogen): some stuff @grantland mentioned can't be done maybe needs to be done here + //TODO (grantland): change to use relations. currently the related PO are only getting saved + //TODO (grantland): can't add and then remove + + // Hack to store collection in a pin + NSMutableArray *modified = pin.objects; + if (modified == nil) { + modified = [objects mutableCopy]; + } else { + for (PFObject *object in objects) { + if (![modified containsObject:object]) { + [modified addObject:object]; + } + } + } + pin.objects = modified; + + BFTask *saveTask = nil; + if (includeChildren) { + saveTask = [store saveObjectLocallyAsync:pin includeChildren:YES]; + } else { + saveTask = [store saveObjectLocallyAsync:pin withChildren:pin.objects]; + } + return saveTask; + }] continueWithSuccessResult:@YES]; +} + +///-------------------------------------- +#pragma mark - Unpin +///-------------------------------------- + +- (BFTask *)unpinObjectsAsync:(NSArray *)objects withPinName:(NSString *)name { + if (objects.count == 0) { + return [BFTask taskWithResult:@YES]; + } + + @weakify(self); + return [[[self fetchPinAsyncWithName:name] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFPin *pin = task.result; + NSMutableArray *modified = pin.objects; + if (!modified) { + // Nothing to unpin + return task; + } + + //TODO (hallucinogen): some stuff @grantland mentioned can't be done maybe needs to be done here + //TODO (grantland): change to use relations. currently the related PO are only getting saved + //TODO (grantland): can't add and then remove + + PFOfflineStore *store = self.dataSource.offlineStore; + + [modified removeObjectsInArray:objects]; + if (modified.count == 0) { + return [store unpinObjectAsync:pin]; + } + pin.objects = modified; + + return [store saveObjectLocallyAsync:pin includeChildren:YES]; + }] continueWithSuccessResult:@YES]; +} + +- (BFTask *)unpinAllObjectsAsyncWithPinName:(NSString *)name { + @weakify(self); + return [[self fetchPinAsyncWithName:name] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFPin *pin = task.result; + return [[self.dataSource.offlineStore unpinObjectAsync:pin] continueWithSuccessResult:@YES]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.h new file mode 100644 index 0000000..70cae09 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectState.h" + +@class PFOperationSet; + +@interface PFMutableObjectState : PFObjectState + +@property (nonatomic, copy, readwrite) NSString *parseClassName; +@property (nonatomic, copy, readwrite) NSString *objectId; + +@property (nonatomic, strong, readwrite) NSDate *createdAt; +@property (nonatomic, strong, readwrite) NSDate *updatedAt; + +@property (nonatomic, copy, readwrite) NSDictionary *serverData; + +@property (nonatomic, assign, readwrite, getter=isComplete) BOOL complete; +@property (nonatomic, assign, readwrite, getter=isDeleted) BOOL deleted; + +///-------------------------------------- +/// @name Accessors +///-------------------------------------- + +- (void)setServerDataObject:(id)object forKey:(NSString *)key; +- (void)removeServerDataObjectForKey:(NSString *)key; +- (void)removeServerDataObjectsForKeys:(NSArray *)keys; + +- (void)setCreatedAtFromString:(NSString *)string; +- (void)setUpdatedAtFromString:(NSString *)string; + +///-------------------------------------- +/// @name Apply +///-------------------------------------- + +- (void)applyState:(PFObjectState *)state; +- (void)applyOperationSet:(PFOperationSet *)operationSet; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.m new file mode 100644 index 0000000..edfd652 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFMutableObjectState.m @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableObjectState.h" + +#import "PFDateFormatter.h" +#import "PFObjectState_Private.h" + +@implementation PFMutableObjectState + +@dynamic parseClassName; +@dynamic objectId; +@dynamic createdAt; +@dynamic updatedAt; +@dynamic serverData; +@dynamic complete; +@dynamic deleted; + +///-------------------------------------- +#pragma mark - PFMutableObjectState +///-------------------------------------- + +#pragma mark Accessors + +- (void)setServerDataObject:(id)object forKey:(NSString *)key { + [super setServerDataObject:object forKey:key]; +} + +- (void)removeServerDataObjectForKey:(NSString *)key { + [super removeServerDataObjectForKey:key]; +} + +- (void)removeServerDataObjectsForKeys:(NSArray *)keys { + [super removeServerDataObjectsForKeys:keys]; +} + +- (void)setCreatedAtFromString:(NSString *)string { + [super setCreatedAtFromString:string]; +} + +- (void)setUpdatedAtFromString:(NSString *)string { + [super setUpdatedAtFromString:string]; +} + +#pragma mark Apply + +- (void)applyState:(PFObjectState *)state { + [super applyState:state]; +} + +- (void)applyOperationSet:(PFOperationSet *)operationSet { + [super applyOperationSet:operationSet]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.h new file mode 100644 index 0000000..a7d9744 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFEncoder; + +@interface PFObjectState : NSObject + +@property (nonatomic, copy, readonly) NSString *parseClassName; +@property (nonatomic, copy, readonly) NSString *objectId; + +@property (nonatomic, strong, readonly) NSDate *createdAt; +@property (nonatomic, strong, readonly) NSDate *updatedAt; + +@property (nonatomic, copy, readonly) NSDictionary *serverData; + +@property (nonatomic, assign, readonly, getter=isComplete) BOOL complete; +@property (nonatomic, assign, readonly, getter=isDeleted) BOOL deleted; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithState:(PFObjectState *)state NS_REQUIRES_SUPER; +- (instancetype)initWithParseClassName:(NSString *)parseClassName; +- (instancetype)initWithParseClassName:(NSString *)parseClassName + objectId:(NSString *)objectId + isComplete:(BOOL)complete; + ++ (instancetype)stateWithState:(PFObjectState *)state NS_REQUIRES_SUPER; ++ (instancetype)stateWithParseClassName:(NSString *)parseClassName; ++ (instancetype)stateWithParseClassName:(NSString *)parseClassName + objectId:(NSString *)objectId + isComplete:(BOOL)complete; + +///-------------------------------------- +/// @name Coding +///-------------------------------------- + +/*! + Encodes all fields in `serverData`, `objectId`, `createdAt` and `updatedAt` into objects suitable for JSON/Persistence. + + @note `parseClassName` isn't automatically added to the dictionary. + + @param objectEncoder Encoder to use to encode custom objects. + + @returns `NSDictionary` instance representing object state. + */ +- (NSDictionary *)dictionaryRepresentationWithObjectEncoder:(PFEncoder *)objectEncoder NS_REQUIRES_SUPER; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.m new file mode 100644 index 0000000..fec73f4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState.m @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectState.h" +#import "PFObjectState_Private.h" + +#import "PFDateFormatter.h" +#import "PFEncoder.h" +#import "PFMutableObjectState.h" +#import "PFObjectConstants.h" +#import "PFObjectUtilities.h" + +@implementation PFObjectState + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _serverData = [NSMutableDictionary dictionary]; + + return [super init]; +} + +- (instancetype)initWithState:(PFObjectState *)state { + self = [self init]; + if (!self) return nil; + + _parseClassName = [state.parseClassName copy]; + _objectId = [state.objectId copy]; + + _updatedAt = state.updatedAt; + _createdAt = state.createdAt; + + _serverData = [state.serverData mutableCopy] ?: [NSMutableDictionary dictionary]; + + _complete = state.complete; + _deleted = state.deleted; + + return self; +} + +- (instancetype)initWithParseClassName:(NSString *)parseClassName { + return [self initWithParseClassName:parseClassName objectId:nil isComplete:NO]; +} + +- (instancetype)initWithParseClassName:(NSString *)parseClassName + objectId:(NSString *)objectId + isComplete:(BOOL)complete { + self = [self init]; + if (!self) return nil; + + _parseClassName = [parseClassName copy]; + _objectId = [objectId copy]; + _complete = complete; + + return self; +} + ++ (instancetype)stateWithState:(PFObjectState *)state { + return [[self alloc] initWithState:state]; +} + ++ (instancetype)stateWithParseClassName:(NSString *)parseClassName { + return [[self alloc] initWithParseClassName:parseClassName]; +} + ++ (instancetype)stateWithParseClassName:(NSString *)parseClassName + objectId:(NSString *)objectId + isComplete:(BOOL)complete { + return [[self alloc] initWithParseClassName:parseClassName + objectId:objectId + isComplete:complete]; +} + +///-------------------------------------- +#pragma mark - Accessors +///--------------------------------------s + +- (void)setServerData:(NSDictionary *)serverData { + if (self.serverData != serverData) { + _serverData = [serverData mutableCopy]; + } +} + +///-------------------------------------- +#pragma mark - Coding +///-------------------------------------- + +- (NSDictionary *)dictionaryRepresentationWithObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + if (self.objectId) { + result[PFObjectObjectIdRESTKey] = self.objectId; + } + if (self.createdAt) { + result[PFObjectCreatedAtRESTKey] = [[PFDateFormatter sharedFormatter] preciseStringFromDate:self.createdAt]; + } + if (self.updatedAt) { + result[PFObjectUpdatedAtRESTKey] = [[PFDateFormatter sharedFormatter] preciseStringFromDate:self.updatedAt]; + } + [self.serverData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + result[key] = [objectEncoder encodeObject:obj]; + }]; + return [result copy]; +} + +///-------------------------------------- +#pragma mark - PFObjectState (Mutable) +///-------------------------------------- + +#pragma mark Accessors + +- (void)setServerDataObject:(id)object forKey:(NSString *)key { + _serverData[key] = object; +} + +- (void)removeServerDataObjectForKey:(NSString *)key { + [_serverData removeObjectForKey:key]; +} + +- (void)removeServerDataObjectsForKeys:(NSArray *)keys { + [_serverData removeObjectsForKeys:keys]; +} + +- (void)setCreatedAtFromString:(NSString *)string { + self.createdAt = [[PFDateFormatter sharedFormatter] dateFromString:string]; +} + +- (void)setUpdatedAtFromString:(NSString *)string { + self.updatedAt = [[PFDateFormatter sharedFormatter] dateFromString:string]; +} + +#pragma mark Apply + +- (void)applyState:(PFObjectState *)state { + if (state.objectId) { + self.objectId = state.objectId; + } + if (state.createdAt) { + self.createdAt = state.createdAt; + } + if (state.updatedAt) { + self.updatedAt = state.updatedAt; + } + [_serverData addEntriesFromDictionary:state.serverData]; + + self.complete |= state.complete; +} + +- (void)applyOperationSet:(PFOperationSet *)operationSet { + [PFObjectUtilities applyOperationSet:operationSet toDictionary:_serverData]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (id)copyWithZone:(NSZone *)zone { + return [[PFObjectState allocWithZone:zone] initWithState:self]; +} + +///-------------------------------------- +#pragma mark - NSMutableCopying +///-------------------------------------- + +- (id)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableObjectState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState_Private.h new file mode 100644 index 0000000..d5f8d63 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/State/PFObjectState_Private.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectState.h" + +@class PFOperationSet; + +@interface PFObjectState () { +@protected + NSString *_parseClassName; + NSString *_objectId; + NSDate *_createdAt; + NSDate *_updatedAt; + NSMutableDictionary *_serverData; + + BOOL _complete; + BOOL _deleted; +} + +@property (nonatomic, copy, readwrite) NSString *parseClassName; +@property (nonatomic, copy, readwrite) NSString *objectId; +@property (nonatomic, strong, readwrite) NSDate *createdAt; +@property (nonatomic, strong, readwrite) NSDate *updatedAt; +@property (nonatomic, copy, readwrite) NSMutableDictionary *serverData; + +@property (nonatomic, assign, readwrite, getter=isComplete) BOOL complete; +@property (nonatomic, assign, readwrite, getter=isDeleted) BOOL deleted; + +@end + +@interface PFObjectState (Mutable) + +///-------------------------------------- +/// @name Accessors +///-------------------------------------- + +- (void)setServerDataObject:(id)object forKey:(NSString *)key; +- (void)removeServerDataObjectForKey:(NSString *)key; +- (void)removeServerDataObjectsForKeys:(NSArray *)keys; + +- (void)setCreatedAtFromString:(NSString *)string; +- (void)setUpdatedAtFromString:(NSString *)string; + +///-------------------------------------- +/// @name Apply +///-------------------------------------- + +- (void)applyState:(PFObjectState *)state NS_REQUIRES_SUPER; +- (void)applyOperationSet:(PFOperationSet *)operationSet NS_REQUIRES_SUPER; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h new file mode 100644 index 0000000..3db23d7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFPropertyInfo; + +@interface PFObjectSubclassInfo : NSObject + +@property (atomic, strong) Class subclass; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithSubclass:(Class)kls NS_DESIGNATED_INITIALIZER; ++ (instancetype)subclassInfoWithSubclass:(Class)kls; + +- (PFPropertyInfo *)propertyInfoForSelector:(SEL)cmd isSetter:(BOOL *)isSetter; +- (NSMethodSignature *)forwardingMethodSignatureForSelector:(SEL)cmd; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m new file mode 100644 index 0000000..8005b1a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectSubclassInfo.h" + +#import + +#import "PFAssert.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFPropertyInfo_Private.h" + +///-------------------------------------- +#pragma mark - Helper +///-------------------------------------- + +static BOOL startsWith(const char *string, const char *prefix) { + // Keep iterating in lockstep. If we run out of prefix letters first, + // this is a valid prefix. + for (; *string && *prefix && *prefix == *string; ++string, ++prefix) + ; + return !*prefix; +} + +// This method helps us get our bearings regardless of whether we were passed +// setFoo: or foo. We'll always exit this method by setting outPair to +// [accessor, mutator] and returns the property they correspond to. If the +// property cannot be found, returns NULL and outPair is undefined. +// An objc_property_t is an opaque struct pointer containing a SEL name and char * +// type information which follows a DSL explained in the Objective-C Runtime Reference. +static objc_property_t getAccessorMutatorPair(Class klass, SEL sel, SEL outPair[2]) { + const char *selName = sel_getName(sel); + ptrdiff_t selNameByteLen = strlen(selName) + 1; + char temp[selNameByteLen + 4]; + + if (startsWith(selName, "set")) { + outPair[1] = sel; + memcpy(temp, selName + 3, selNameByteLen - 3); + temp[0] -= 'A' - 'a'; + + temp[selNameByteLen - 5] = 0; // drop ':' + outPair[0] = sel_registerName(temp); + } else { + outPair[0] = sel; + sprintf(temp, "set%s:", selName); + if (selName[0] >= 'a' && selName[0] <= 'z') { + temp[3] += 'A' - 'a'; + } + outPair[1] = sel_registerName(temp); + } + + const char *propName = sel_getName(outPair[0]); + objc_property_t property = class_getProperty(klass, propName); + if (!property) { + // The user could have broken convention and declared an upper case property. + memcpy(temp, propName, strlen(propName) + 1); + temp[0] += 'A' - 'a'; + outPair[0] = sel_registerName(temp); + property = class_getProperty(klass, temp); + } + return property; +} + +@implementation PFObjectSubclassInfo { + dispatch_queue_t _dataAccessQueue; + NSMutableDictionary *_knownProperties; + NSMutableDictionary *_knownMethodSignatures; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithSubclass:(Class)kls { + self = [super init]; + if (!self) return nil; + + _dataAccessQueue = dispatch_queue_create("com.parse.object.subclassing.data.access", DISPATCH_QUEUE_SERIAL); + _subclass = kls; + + _knownProperties = [NSMutableDictionary dictionary]; + _knownMethodSignatures = [NSMutableDictionary dictionary]; + + return self; +} + ++ (instancetype)subclassInfoWithSubclass:(Class)kls { + return [[self alloc] initWithSubclass:kls]; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (PFPropertyInfo *)propertyInfoForSelector:(SEL)cmd isSetter:(BOOL *)isSetter { + __block PFPropertyInfo *result = nil; + dispatch_sync(_dataAccessQueue, ^{ + result = [self _rawPropertyInfoForSelector:cmd]; + }); + + if (isSetter) { + *isSetter = (cmd == result.setterSelector); + } + + return result; +} + +- (NSMethodSignature *)forwardingMethodSignatureForSelector:(SEL)cmd { + __block NSMethodSignature *result = nil; + NSString *selectorString = NSStringFromSelector(cmd); + + // NSMethodSignature can be fairly heavyweight, so let's agressively cache this here. + dispatch_sync(_dataAccessQueue, ^{ + result = _knownMethodSignatures[selectorString]; + if (result) { + return; + } + + PFPropertyInfo *propertyInfo = [self _rawPropertyInfoForSelector:cmd]; + if (!propertyInfo) { + return; + } + + BOOL isSetter = (cmd == propertyInfo.setterSelector); + NSString *typeEncoding = propertyInfo.typeEncoding; + + // Property type encoding includes the class name as well. + // This is fine, except for the fact that NSMethodSignature hates that. + NSUInteger startLocation = [typeEncoding rangeOfString:@"\"" options:0].location; + NSUInteger endLocation = [typeEncoding rangeOfString:@"\"" + options:NSBackwardsSearch | NSAnchoredSearch].location; + + if (startLocation != NSNotFound && endLocation != NSNotFound) { + typeEncoding = [typeEncoding substringToIndex:startLocation]; + } + + NSString *objcTypes = ([NSString stringWithFormat:(isSetter ? @"v@:%@" : @"%@@:"), typeEncoding]); + result = [NSMethodSignature signatureWithObjCTypes:[objcTypes UTF8String]]; + + _knownMethodSignatures[selectorString] = result; + }); + + return result; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (PFPropertyInfo *)_rawPropertyInfoForSelector:(SEL)cmd { + PFPropertyInfo *result = nil; + NSString *selectorString = NSStringFromSelector(cmd); + result = _knownProperties[selectorString]; + if (result) { + return result; + } + + SEL propertySelectors[2]; + objc_property_t property = getAccessorMutatorPair(self.subclass, cmd, propertySelectors); + if (!property) { + return nil; + } + + // Check if we've registered this property with a different name. + NSString *propertyName = @(property_getName(property)); + result = _knownProperties[propertyName]; + if (result) { + // Re-register it with the name we just searched for for faster future lookup. + _knownProperties[selectorString] = result; + return result; + } + + const char *attributes = property_getAttributes(property); + if (strstr(attributes, "T@\"PFRelation\",") == attributes && !strstr(attributes, ",R")) { + PFLogWarning(PFLoggingTagCommon, + @"PFRelation properties are always readonly, but %@.%@ was declared otherwise.", + self.subclass, selectorString); + } + + result = [PFPropertyInfo propertyInfoWithClass:self.subclass name:propertyName]; + + _knownProperties[result.name] = result; + if (result.getterSelector) { + _knownProperties[NSStringFromSelector(result.getterSelector)] = result; + } + if (result.setterSelector) { + _knownProperties[NSStringFromSelector(result.setterSelector)] = result; + } + + return result; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h new file mode 100644 index 0000000..ef7977b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFObject; +@protocol PFSubclassing; + +@interface PFObjectSubclassingController : NSObject + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +//TODO: (nlutsenko, richardross) Make it not terrible aka don't have singletons. ++ (instancetype)defaultController; ++ (void)clearDefaultController; + +///-------------------------------------- +/// @name Registration +///-------------------------------------- + +- (Class)subclassForParseClassName:(NSString *)parseClassName; +- (void)registerSubclass:(Class)kls; +- (void)unregisterSubclass:(Class)kls; + +///-------------------------------------- +/// @name Forwarding +///-------------------------------------- + +- (NSMethodSignature *)forwardingMethodSignatureForSelector:(SEL)cmd ofClass:(Class)kls; +- (BOOL)forwardObjectInvocation:(NSInvocation *)invocation withObject:(PFObject *)object; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m new file mode 100644 index 0000000..878a816 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m @@ -0,0 +1,317 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectSubclassingController.h" + +#import + +#import "PFAssert.h" +#import "PFMacros.h" +#import "PFObject.h" +#import "PFObjectSubclassInfo.h" +#import "PFPropertyInfo_Private.h" +#import "PFPropertyInfo_Runtime.h" +#import "PFSubclassing.h" + +// CFNumber does not use number type 0, we take advantage of that here. +#define kCFNumberTypeUnknown 0 + +static CFNumberType PFNumberTypeForObjCType(const char *encodedType) { +// To save anyone in the future from some major headaches, sanity check here. +#if kCFNumberTypeMax > UINT8_MAX +#error kCFNumberTypeMax has been changed! This solution will no longer work. +#endif + + // Organizing the table this way makes it nicely fit into two cache lines. This makes lookups nearly free, even more + // so if repeated. + static uint8_t types[128] = { + // Core types. + ['c'] = kCFNumberCharType, + ['i'] = kCFNumberIntType, + ['s'] = kCFNumberShortType, + ['l'] = kCFNumberLongType, + ['q'] = kCFNumberLongLongType, + + // CFNumber (and NSNumber, actually) does not store unsigned types. + // This may cause some strange issues when dealing with values near the max for that type. + // We should investigate this if it becomes a problem. + ['C'] = kCFNumberCharType, + ['I'] = kCFNumberIntType, + ['S'] = kCFNumberShortType, + ['L'] = kCFNumberLongType, + ['Q'] = kCFNumberLongLongType, + + // Floating point + ['f'] = kCFNumberFloatType, + ['d'] = kCFNumberDoubleType, + + // C99 & CXX boolean. We are keeping this here for decoding, as you can safely use CFNumberGetBytes on a + // CFBoolean, and extract it into a char. + ['B'] = kCFNumberCharType, + }; + + return (CFNumberType)types[encodedType[0]]; +} + +static NSNumber *PFNumberCreateSafe(const char *typeEncoding, const void *bytes) { + // NOTE: This is required because NSJSONSerialization treats all NSNumbers with the 'char' type as numbers, not + // booleans. As such, we must treat any and all boolean type encodings as explicit booleans, otherwise we will + // send '1' and '0' to the api server rather than 'true' and 'false'. + // + // TODO (richardross): When we drop support for 10.9/iOS 7, remove the 'c' encoding and only use the new 'B' + // encoding. + if (typeEncoding[0] == 'B' || typeEncoding[0] == 'c') { + return [NSNumber numberWithBool:*(BOOL *)bytes]; + } + + CFNumberType numberType = PFNumberTypeForObjCType(typeEncoding); + PFConsistencyAssert(numberType != kCFNumberTypeUnknown, @"Unsupported type encoding %s!", typeEncoding); + return (__bridge_transfer NSNumber *)CFNumberCreate(NULL, numberType, bytes); +} + +@implementation PFObjectSubclassingController { + dispatch_queue_t _registeredSubclassesAccessQueue; + NSMutableDictionary *_registeredSubclasses; + NSMutableDictionary *_unregisteredSubclasses; +} + +static PFObjectSubclassingController *defaultController_; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _registeredSubclassesAccessQueue = dispatch_queue_create("com.parse.object.subclassing", DISPATCH_QUEUE_SERIAL); + _registeredSubclasses = [NSMutableDictionary dictionary]; + _unregisteredSubclasses = [NSMutableDictionary dictionary]; + + return self; +} + ++ (instancetype)defaultController { + if (!defaultController_) { + defaultController_ = [[PFObjectSubclassingController alloc] init]; + } + return defaultController_; +} + ++ (void)clearDefaultController { + defaultController_ = nil; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (Class)subclassForParseClassName:(NSString *)parseClassName { + __block Class result = nil; + pf_sync_with_throw(_registeredSubclassesAccessQueue, ^{ + result = [_registeredSubclasses[parseClassName] subclass]; + }); + return result; +} + +- (void)registerSubclass:(Class)kls { + pf_sync_with_throw(_registeredSubclassesAccessQueue, ^{ + [self _rawRegisterSubclass:kls]; + }); +} + +- (void)unregisterSubclass:(Class)class { + pf_sync_with_throw(_registeredSubclassesAccessQueue, ^{ + NSString *parseClassName = [class parseClassName]; + Class registeredClass = [_registeredSubclasses[parseClassName] subclass]; + + // Make it a no-op if the class itself is not registered or + // if there is another class registered under the same name. + if (registeredClass == nil || + ![registeredClass isEqual:class]) { + return; + } + + [_registeredSubclasses removeObjectForKey:parseClassName]; + }); +} + +- (BOOL)forwardObjectInvocation:(NSInvocation *)invocation withObject:(PFObject *)object { + PFObjectSubclassInfo *subclassInfo = [self _subclassInfoForClass:[object class]]; + + BOOL isSetter = NO; + PFPropertyInfo *propertyInfo = [subclassInfo propertyInfoForSelector:invocation.selector isSetter:&isSetter]; + if (!propertyInfo) { + return NO; + } + + if (isSetter) { + [self _forwardSetterInvocation:invocation forProperty:propertyInfo withObject:object]; + } else { + [self _forwardGetterInvocation:invocation forProperty:propertyInfo withObject:object]; + } + return YES; +} + +- (NSMethodSignature *)forwardingMethodSignatureForSelector:(SEL)cmd ofClass:(Class)kls { + PFObjectSubclassInfo *subclassInfo = [self _subclassInfoForClass:kls]; + return [subclassInfo forwardingMethodSignatureForSelector:cmd]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (void)_forwardGetterInvocation:(NSInvocation *)invocation + forProperty:(PFPropertyInfo *)propertyInfo + withObject:(PFObject *)object { + PFConsistencyAssert(invocation.methodSignature.numberOfArguments == 2, @"Getter should take no arguments!"); + PFConsistencyAssert(invocation.methodSignature.methodReturnType[0] != 'v', @"A getter cannot return void!"); + + const char *methodReturnType = [invocation.methodSignature methodReturnType]; + void *returnValueBytes = alloca([invocation.methodSignature methodReturnLength]); + + if (propertyInfo.ivar) { + object_getIvarValue_safe(object, propertyInfo.ivar, returnValueBytes, propertyInfo.associationType); + } else { + __autoreleasing id dictionaryValue = nil; + if ([propertyInfo.typeEncoding isEqualToString:@"@\"PFRelation\""]) { + dictionaryValue = [object relationForKey:propertyInfo.name]; + } else { + dictionaryValue = object[propertyInfo.name]; + + // TODO: (richardross) Investigate why we were orignally copying the result of -objectForKey, + // as this doens't seem right. + if (propertyInfo.associationType == PFPropertyInfoAssociationTypeCopy) { + dictionaryValue = [dictionaryValue copy]; + } + } + + if (dictionaryValue == nil || [dictionaryValue isKindOfClass:[NSNull class]]) { + memset(returnValueBytes, 0, invocation.methodSignature.methodReturnLength); + } else if (methodReturnType[0] == '@') { + memcpy(returnValueBytes, (void *) &dictionaryValue, sizeof(id)); + } else if ([dictionaryValue isKindOfClass:[NSNumber class]]) { + CFNumberGetValue((__bridge CFNumberRef) dictionaryValue, + PFNumberTypeForObjCType(methodReturnType), + returnValueBytes); + } else { + // TODO:(richardross)Support C-style structs that automatically convert to JSON via NSValue? + PFConsistencyAssert(false, @"Unsupported type encoding %s!", methodReturnType); + } + } + + [invocation setReturnValue:returnValueBytes]; +} + +- (void)_forwardSetterInvocation:(NSInvocation *)invocation + forProperty:(PFPropertyInfo *)propertyInfo + withObject:(PFObject *)object { + PFConsistencyAssert(invocation.methodSignature.numberOfArguments == 3, @"Setter should only take 1 argument!"); + + PFObject *sourceObject = object; + const char *argumentType = [invocation.methodSignature getArgumentTypeAtIndex:2]; + + NSUInteger argumentValueSize = 0; + NSGetSizeAndAlignment(argumentType, &argumentValueSize, NULL); + + void *argumentValueBytes = alloca(argumentValueSize); + [invocation getArgument:argumentValueBytes atIndex:2]; + + if (propertyInfo.ivar) { + object_setIvarValue_safe(sourceObject, propertyInfo.ivar, argumentValueBytes, propertyInfo.associationType); + } else { + id dictionaryValue = nil; + + if (argumentType[0] == '@') { + dictionaryValue = *(__unsafe_unretained id *)argumentValueBytes; + + if (propertyInfo.associationType == PFPropertyInfoAssociationTypeCopy) { + dictionaryValue = [dictionaryValue copy]; + } + } else { + dictionaryValue = PFNumberCreateSafe(argumentType, argumentValueBytes); + } + + if (dictionaryValue == nil) { + [sourceObject removeObjectForKey:propertyInfo.name]; + } else { + sourceObject[propertyInfo.name] = dictionaryValue; + } + } +} + +- (PFObjectSubclassInfo *)_subclassInfoForClass:(Class)kls { + __block PFObjectSubclassInfo *result = nil; + pf_sync_with_throw(_registeredSubclassesAccessQueue, ^{ + if (class_respondsToSelector(object_getClass(kls), @selector(parseClassName))) { + result = _registeredSubclasses[[kls parseClassName]]; + } + + // TODO: (nlutsenko, richardross) Don't let unregistered subclasses have dynamic property resolution. + if (!result) { + result = [PFObjectSubclassInfo subclassInfoWithSubclass:kls]; + _unregisteredSubclasses[NSStringFromClass(kls)] = result; + } + }); + return result; +} + +// Reverse compatibility note: many people may have built PFObject subclasses before +// we officially supported them. Our implementation can do cool stuff, but requires +// the parseClassName class method. +- (void)_rawRegisterSubclass:(Class)kls { + PFConsistencyAssert([kls conformsToProtocol:@protocol(PFSubclassing)], + @"Can only call +registerSubclass on subclasses conforming to PFSubclassing."); + + NSString *parseClassName = [kls parseClassName]; + + // Bug detection: don't allow subclasses of subclasses (i.e. custom user classes) + // to change the value of +parseClassName + if ([kls superclass] != [PFObject class]) { + // We compare Method definitions against the PFObject version witout invoking it + // because that Method could throw on an intermediary class which is + // not meant for direct use. + Method baseImpl = class_getClassMethod([PFObject class], @selector(parseClassName)); + Method superImpl = class_getClassMethod([kls superclass], @selector(parseClassName)); + + PFConsistencyAssert(superImpl == baseImpl || + [parseClassName isEqualToString:[[kls superclass] parseClassName]], + @"Subclasses of subclasses may not have separate +parseClassName " + "definitions. %@ should inherit +parseClassName from %@.", + kls, [kls superclass]); + } + + Class current = [_registeredSubclasses[parseClassName] subclass]; + if (current && current != kls) { + // We've already registered a more specific subclass (i.e. we're calling + // registerSubclass:PFUser after MYUser + if ([current isSubclassOfClass:kls]) { + return; + } + + PFConsistencyAssert([kls isSubclassOfClass:current], + @"Tried to register both %@ and %@ as the native PFObject subclass " + "of %@. Cannot determine the right class to use because neither " + "inherits from the other.", current, kls, parseClassName); + } + + // Move the subclass info from unregisteredSubclasses dictionary to registered ones, or create if it doesn't exist. + NSString *className = NSStringFromClass(kls); + PFObjectSubclassInfo *subclassInfo = _unregisteredSubclasses[className]; + if (subclassInfo) { + [_unregisteredSubclasses removeObjectForKey:className]; + } else { + subclassInfo = [PFObjectSubclassInfo subclassInfoWithSubclass:kls]; + } + _registeredSubclasses[[kls parseClassName]] = subclassInfo; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.h new file mode 100644 index 0000000..a94952d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class PFFieldOperation; +@class PFOperationSet; + +@interface PFObjectUtilities : NSObject + +///-------------------------------------- +/// @name Operations +///-------------------------------------- + ++ (id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation + toDictionary:(NSMutableDictionary *)dictionary + forKey:(NSString *)key; ++ (void)applyOperationSet:(PFOperationSet *)operationSet toDictionary:(NSMutableDictionary *)dictionary; + +///-------------------------------------- +/// @name Equality +///-------------------------------------- + ++ (BOOL)isObject:(nullable id)objectA equalToObject:(nullable id)objectB; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.m new file mode 100644 index 0000000..9b5f1e1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Object/Utilities/PFObjectUtilities.m @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectUtilities.h" + +#import "PFFieldOperation.h" +#import "PFOperationSet.h" + +@implementation PFObjectUtilities + +///-------------------------------------- +#pragma mark - Operations +///-------------------------------------- + ++ (id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation + toDictionary:(NSMutableDictionary *)dictionary + forKey:(NSString *)key { + id oldValue = dictionary[key]; + id newValue = [operation applyToValue:oldValue forKey:key]; + if (newValue) { + dictionary[key] = newValue; + } else { + [dictionary removeObjectForKey:key]; + } + return newValue; +} + ++ (void)applyOperationSet:(PFOperationSet *)operationSet toDictionary:(NSMutableDictionary *)dictionary { + [operationSet enumerateKeysAndObjectsUsingBlock:^(NSString *key, PFFieldOperation *obj, BOOL *stop) { + [self newValueByApplyingFieldOperation:obj toDictionary:dictionary forKey:key]; + }]; +} + +///-------------------------------------- +#pragma mark - Equality +///-------------------------------------- + ++ (BOOL)isObject:(id)objectA equalToObject:(id)objectB { + return (objectA == objectB || (objectA != nil && [objectA isEqual:objectB])); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.h new file mode 100644 index 0000000..bddaf30 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +typedef void(^PFAlertViewCompletion)(NSUInteger selectedOtherButtonIndex); + +@interface PFAlertView : NSObject + ++ (void)showAlertWithTitle:(NSString *)title + message:(NSString *)message + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + completion:(PFAlertViewCompletion)completion NS_EXTENSION_UNAVAILABLE_IOS(""); + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.m new file mode 100644 index 0000000..e17fa6d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAlertView.m @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAlertView.h" + +@interface PFAlertView () + +@property (nonatomic, copy) PFAlertViewCompletion completion; + +@end + +@implementation PFAlertView + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (void)showAlertWithTitle:(NSString *)title + message:(NSString *)message + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + completion:(PFAlertViewCompletion)completion { + if ([UIAlertController class] != nil) { + __block UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + void (^alertActionHandler)(UIAlertAction *) = [^(UIAlertAction *action) { + if (completion) { + // This block intentionally retains alertController, and releases it afterwards. + if (action.style == UIAlertActionStyleCancel) { + completion(NSNotFound); + } else { + NSUInteger index = [alertController.actions indexOfObject:action]; + completion(index - 1); + } + } + alertController = nil; + } copy]; + + [alertController addAction:[UIAlertAction actionWithTitle:cancelButtonTitle + style:UIAlertActionStyleCancel + handler:alertActionHandler]]; + + for (NSString *buttonTitle in otherButtonTitles) { + [alertController addAction:[UIAlertAction actionWithTitle:buttonTitle + style:UIAlertActionStyleDefault + handler:alertActionHandler]]; + } + + UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow; + UIViewController *viewController = keyWindow.rootViewController; + while (viewController.presentedViewController) { + viewController = viewController.presentedViewController; + } + + [viewController presentViewController:alertController animated:YES completion:nil]; + } else { +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 + __block PFAlertView *pfAlertView = [[self alloc] init]; + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title + message:message + delegate:nil + cancelButtonTitle:cancelButtonTitle + otherButtonTitles:nil]; + + for (NSString *buttonTitle in otherButtonTitles) { + [alertView addButtonWithTitle:buttonTitle]; + } + + pfAlertView.completion = ^(NSUInteger index) { + if (completion) { + completion(index); + } + + pfAlertView = nil; + }; + + alertView.delegate = pfAlertView; + [alertView show]; +#endif + } +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 + +///-------------------------------------- +#pragma mark - UIAlertViewDelegate +///-------------------------------------- + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + if (self.completion) { + if (buttonIndex == alertView.cancelButtonIndex) { + self.completion(NSNotFound); + } else { + self.completion(buttonIndex - 1); + } + } +} + +#endif + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.h new file mode 100644 index 0000000..7bf1c24 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +#if TARGET_OS_IOS +#import +#elif TARGET_OS_WATCH +@class UIApplication; +#elif TARGET_OS_MAC +#import +@compatibility_alias UIApplication NSApplication; +#endif + +/*! + `PFApplication` class provides a centralized way to get the information about the current application, + or the environment it's running in. Please note, that all device specific things - should go to . + */ +@interface PFApplication : NSObject + +@property (nonatomic, strong, readonly) UIApplication *systemApplication; + +@property (nonatomic, assign, readonly, getter=isAppStoreEnvironment) BOOL appStoreEnvironment; +@property (nonatomic, assign, readonly, getter=isExtensionEnvironment) BOOL extensionEnvironment; + +@property (nonatomic, assign) NSInteger iconBadgeNumber; + ++ (instancetype)currentApplication; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.m new file mode 100644 index 0000000..a602fa1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFApplication.m @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFApplication.h" + +#if TARGET_OS_IOS +#import +#elif !TARGET_OS_WATCH && TARGET_OS_MAC +#import +#endif + +@implementation PFApplication + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)currentApplication { + static PFApplication *application; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + application = [[self alloc] init]; + }); + return application; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (BOOL)isAppStoreEnvironment { +#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR + return ([[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"] == nil); +#endif + + return NO; +} + +- (BOOL)isExtensionEnvironment { + return [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; +} + +- (NSInteger)iconBadgeNumber { +#if TARGET_OS_WATCH + return 0; +#elif TARGET_OS_IOS + return self.systemApplication.applicationIconBadgeNumber; +#elif TARGET_OS_MAC + // Make sure not to use `NSApp` here, because it doesn't work sometimes, + // `NSApplication +sharedApplication` does though. + NSString *badgeLabel = [[NSApplication sharedApplication] dockTile].badgeLabel; + if (badgeLabel.length == 0) { + return 0; + } + + NSScanner *scanner = [NSScanner localizedScannerWithString:badgeLabel]; + + NSInteger number = 0; + [scanner scanInteger:&number]; + if (scanner.scanLocation != badgeLabel.length) { + return 0; + } + + return number; +#endif +} + +- (void)setIconBadgeNumber:(NSInteger)iconBadgeNumber { + if (self.iconBadgeNumber != iconBadgeNumber) { +#if TARGET_OS_IOS + self.systemApplication.applicationIconBadgeNumber = iconBadgeNumber; +#elif !TARGET_OS_WATCH + [[NSApplication sharedApplication] dockTile].badgeLabel = [@(iconBadgeNumber) stringValue]; +#endif + } +} + +- (UIApplication *)systemApplication { +#if TARGET_OS_WATCH + return nil; +#else + // Workaround to make `sharedApplication` still be called even if compiling for App Extensions or WatchKit apps. + return [UIApplication performSelector:@selector(sharedApplication)]; +#endif +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAssert.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAssert.h new file mode 100644 index 0000000..35277e0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAssert.h @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +#ifndef Parse_PFAssert_h +#define Parse_PFAssert_h + +/*! + Raises an `NSInvalidArgumentException` if the `condition` does not pass. + Use `description` to supply the way to fix the exception. + */ +#define PFParameterAssert(condition, description, ...) \ + do {\ + if (!(condition)) { \ + [NSException raise:NSInvalidArgumentException \ + format:description, ##__VA_ARGS__]; \ + } \ + } while(0) + +/*! + Raises an `NSRangeException` if the `condition` does not pass. + Use `description` to supply the way to fix the exception. + */ +#define PFRangeAssert(condition, description, ...) \ + do {\ + if (!(condition)) { \ + [NSException raise:NSRangeException \ + format:description, ##__VA_ARGS__]; \ + } \ +} while(0) + +/*! + Raises an `NSInternalInconsistencyException` if the `condition` does not pass. + Use `description` to supply the way to fix the exception. + */ +#define PFConsistencyAssert(condition, description, ...) \ + do { \ + if (!(condition)) { \ + [NSException raise:NSInternalInconsistencyException \ + format:description, ##__VA_ARGS__]; \ + } \ + } while(0) + +/*! + Always raises `NSInternalInconsistencyException` with details + about the method used and class that received the message + */ +#define PFNotDesignatedInitializer() \ +do { \ + PFConsistencyAssert(NO, \ + @"%@ is not the designated initializer for instances of %@.", \ + NSStringFromSelector(_cmd), \ + NSStringFromClass([self class])); \ + return nil; \ +} while (0) + +/*! + Raises `NSInternalInconsistencyException` if current thread is not main thread. + */ +#define PFAssertMainThread() \ +do { \ + PFConsistencyAssert([NSThread isMainThread], @"This method must be called on the main thread."); \ +} while (0) + +/*! + Raises `NSInternalInconsistencyException` if current thread is not the required one. + */ +#define PFAssertIsOnThread(thread) \ +do { \ + PFConsistencyAssert([NSThread currentThread] == thread, \ + @"This method must be called only on thread: %@.", thread); \ +} while (0) + +/*! + Raises `NSInternalInconsistencyException` if the current queue + is not the same as the queue provided. + Make sure you mark the queue first via `PFMarkDispatchQueue` + */ +#define PFAssertIsOnDispatchQueue(queue) \ +do { \ + void *mark = PFOSObjectPointer(queue); \ + PFConsistencyAssert(dispatch_get_specific(mark) == mark, \ + @"%s must be executed on %s", \ + __PRETTY_FUNCTION__, dispatch_queue_get_label(queue)); \ +} while (0) + +#endif diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.h new file mode 100644 index 0000000..45da5dc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFAsyncTaskQueue : NSObject + ++ (instancetype)taskQueue; + +- (BFTask *)enqueue:(BFContinuationBlock)block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.m new file mode 100644 index 0000000..2dae167 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFAsyncTaskQueue.m @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAsyncTaskQueue.h" + +#import + +#import "BFTask+Private.h" + +@interface PFAsyncTaskQueue() + +@property (nonatomic, strong) dispatch_queue_t syncQueue; +@property (nonatomic, strong) BFTask *tail; + +@end + +@implementation PFAsyncTaskQueue + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _tail = [BFTask taskWithResult:nil]; + _syncQueue = dispatch_queue_create("com.parse.asynctaskqueue.sync", DISPATCH_QUEUE_SERIAL); + + return self; +} + ++ (instancetype)taskQueue { + return [[self alloc] init]; +} + +///-------------------------------------- +#pragma mark - Enqueue +///-------------------------------------- + +- (BFTask *)enqueue:(BFContinuationBlock)block { + BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; + dispatch_async(_syncQueue, ^{ + _tail = [_tail continueAsyncWithBlock:block]; + [_tail continueAsyncWithBlock:^id(BFTask *task) { + if (task.faulted) { + NSError *error = task.error; + if (error) { + [source trySetError:error]; + } else { + [source trySetException:task.exception]; + } + } else if (task.cancelled) { + [source trySetCancelled]; + } else { + [source trySetResult:task.result]; + } + return task; + }]; + }); + return source.task; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.h new file mode 100644 index 0000000..4a7d44f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFBase64Encoder : NSObject + ++ (NSData *)dataFromBase64String:(NSString *)string; ++ (NSString *)base64StringFromData:(NSData *)data; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.m new file mode 100644 index 0000000..07fb5d0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBase64Encoder.m @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBase64Encoder.h" + +@implementation PFBase64Encoder + ++ (NSData *)dataFromBase64String:(NSString *)string { + if (!string) { + return [NSData data]; + } + return [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters]; +} + ++ (NSString *)base64StringFromData:(NSData *)data { + if (!data) { + return [NSString string]; + } + return [data base64EncodedStringWithOptions:0]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.h new file mode 100644 index 0000000..535403c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.h @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +typedef NS_ENUM(uint8_t, PFPropertyInfoAssociationType) { + PFPropertyInfoAssociationTypeDefault, // Assign for c-types, strong for objc-types. + PFPropertyInfoAssociationTypeAssign, + PFPropertyInfoAssociationTypeStrong, + PFPropertyInfoAssociationTypeWeak, + PFPropertyInfoAssociationTypeCopy, + PFPropertyInfoAssociationTypeMutableCopy, +}; + +@interface PFPropertyAttributes : NSObject + +@property (nonatomic, assign, readonly) PFPropertyInfoAssociationType associationType; + +- (instancetype)initWithAssociationType:(PFPropertyInfoAssociationType)associationType NS_DESIGNATED_INITIALIZER; + ++ (instancetype)attributes; ++ (instancetype)attributesWithAssociationType:(PFPropertyInfoAssociationType)associationType; + +@end + +@protocol PFBaseStateSubclass + +/*! + This is the list of properties that should be used automatically for the methods implemented by PFBaseState. + + It should be a dictionary in the format of @{ @"<#property name#>": [PFPropertyAttributes attributes] } + This will be automatically cached by PFBaseState, no need for you to cache it yourself. + + @return a dictionary of property attributes + */ ++ (NSDictionary *)propertyAttributes; + +@end + +/*! + Shared base class for all state objects. + Implements -init, -description, -debugDescription, -hash, -isEqual:, -compareTo:, etc. for you. + */ +@interface PFBaseState : NSObject + +- (instancetype)initWithState:(PFBaseState *)otherState; ++ (instancetype)stateWithState:(PFBaseState *)otherState; + +- (NSComparisonResult)compare:(PFBaseState *)other; + +/*! + Returns a dictionary representation of this object. + + Essentially, it takes the values for the keys of this object, and stuffs them in the dictionary. + It will call -dictionaryRepresentation on any objects it contains, in order to handle base states + contained in this base state. + + If a value is `nil`, it will be replaced with [NSNull null], to ensure all keys exist in the dictionary. + + If you don't like this behavior, you can overwrite the method + -nilValueForProperty:(NSString *) property + to return either nil to skip the key, or a value to use in it's place. + + @return A dictionary representation of this object state. + */ +- (NSDictionary *)dictionaryRepresentation; + +- (id)debugQuickLookObject; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.m new file mode 100644 index 0000000..dc6af22 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFBaseState.m @@ -0,0 +1,267 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +#import +#import + +#import "PFAssert.h" +#import "PFHash.h" +#import "PFMacros.h" +#import "PFPropertyInfo.h" + +///-------------------------------------- +#pragma mark - Helpers +///-------------------------------------- + +@implementation PFPropertyAttributes + +- (instancetype)init { + return [self initWithAssociationType:PFPropertyInfoAssociationTypeDefault]; +} + +- (instancetype)initWithAssociationType:(PFPropertyInfoAssociationType)associationType { + self = [super init]; + if (!self) return nil; + + _associationType = associationType; + + return self; +} + ++ (instancetype)attributes { + return [[self alloc] init]; +} + ++ (instancetype)attributesWithAssociationType:(PFPropertyInfoAssociationType)associationType { + return [[self alloc] initWithAssociationType:associationType]; +} + +@end + +@interface PFBaseState () { + BOOL _initializing; +} + +@end + +@implementation PFBaseState + +///-------------------------------------- +#pragma mark - Property Info +///-------------------------------------- + ++ (NSSet *)_propertyInfo { + static void *_propertyMapKey = &_propertyMapKey; + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.parse.basestate.propertyinfo", DISPATCH_QUEUE_SERIAL); + }); + + __block NSMutableSet *results = nil; + dispatch_sync(queue, ^{ + results = objc_getAssociatedObject(self, _propertyMapKey); + if (results) { + return; + } + + NSDictionary *attributesMap = [(id)self propertyAttributes]; + results = [[NSMutableSet alloc] initWithCapacity:attributesMap.count]; + + [attributesMap enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [results addObject:[PFPropertyInfo propertyInfoWithClass:self + name:key + associationType:[obj associationType]]]; + }]; + + objc_setAssociatedObject(self, _propertyMapKey, results, OBJC_ASSOCIATION_RETAIN); + }); + + return results; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + // To prevent a recursive init function. + if (_initializing) { + return [super init]; + } + + _initializing = YES; + return [self initWithState:nil]; +} + +- (instancetype)initWithState:(id)otherState { + if (!_initializing) { + _initializing = YES; + + self = [self init]; + if (!self) return nil; + } + + NSSet *ourProperties = [[self class] _propertyInfo]; + NSSet *theirProperties = [[otherState class] _propertyInfo]; + + NSMutableSet *shared = [ourProperties mutableCopy]; + [shared intersectSet:theirProperties]; + + for (PFPropertyInfo *property in shared) { + [property takeValueFrom:otherState toObject:self]; + } + + return self; +} + ++ (instancetype)stateWithState:(PFBaseState *)otherState { + return [[self alloc] initWithState:otherState]; +} + +///-------------------------------------- +#pragma mark - Hashing +///-------------------------------------- + +- (NSUInteger)hash { + NSUInteger result = 0; + + for (PFPropertyInfo *property in [[self class] _propertyInfo]) { + result = PFIntegerPairHash(result, [[property getWrappedValueFrom:self] hash]); + } + + return result; +} + +///-------------------------------------- +#pragma mark - Comparison +///-------------------------------------- + +- (NSComparisonResult)compare:(PFBaseState *)other { + PFParameterAssert([other isKindOfClass:[PFBaseState class]], + @"Cannot compatre to an object that isn't a PFBaseState"); + + NSSet *ourProperties = [[self class] _propertyInfo]; + NSSet *theirProperties = [[other class] _propertyInfo]; + + NSMutableSet *shared = [ourProperties mutableCopy]; + [shared intersectSet:theirProperties]; + + for (PFPropertyInfo *info in shared) { + id ourValue = [info getWrappedValueFrom:self]; + id theirValue = [info getWrappedValueFrom:other]; + + if (![ourValue respondsToSelector:@selector(compare:)]) { + continue; + } + + NSComparisonResult result = [ourValue compare:theirValue]; + if (result != NSOrderedSame) { + return result; + } + } + + return NSOrderedSame; +} + +///-------------------------------------- +#pragma mark - Equality +///-------------------------------------- + +- (BOOL)isEqual:(id)other { + if (self == other) { + return YES; + } + + if (![other isKindOfClass:[PFBaseState class]]) { + return NO; + } + + NSSet *ourProperties = [[self class] _propertyInfo]; + NSSet *theirProperties = [[other class] _propertyInfo]; + + NSMutableSet *shared = [ourProperties mutableCopy]; + [shared intersectSet:theirProperties]; + + for (PFPropertyInfo *info in shared) { + id ourValue = [info getWrappedValueFrom:self]; + id theirValue = [info getWrappedValueFrom:other]; + + if (ourValue != theirValue && ![ourValue isEqual:theirValue]) { + return NO; + } + } + + return YES; +} + +///-------------------------------------- +#pragma mark - Description +///-------------------------------------- + +// This allows us to easily use the same implementation for description and debugDescription +- (NSString *)descriptionWithValueSelector:(SEL)toPerform { + NSMutableString *results = [NSMutableString stringWithFormat:@"<%@: %p", [self class], self]; + + for (PFPropertyInfo *property in [[self class] _propertyInfo]) { + id propertyValue = [property getWrappedValueFrom:self]; + NSString *propertyDescription = objc_msgSend_safe(NSString *)(propertyValue, toPerform); + + [results appendFormat:@", %@: %@", property.name, propertyDescription]; + } + + [results appendString:@">"]; + return results; +} + +- (NSString *)description { + return [self descriptionWithValueSelector:_cmd]; +} + +- (NSString *)debugDescription { + return [self descriptionWithValueSelector:_cmd]; +} + +///-------------------------------------- +#pragma mark - Dictionary/QuickLook representation +///-------------------------------------- + +- (id)nilValueForProperty:(NSString *)propertyName { + return [NSNull null]; +} + +// Implementation detail - this returns a mutable dictionary with mutable leaves. +- (NSDictionary *)dictionaryRepresentation { + NSSet *properties = [[self class] _propertyInfo]; + NSMutableDictionary *results = [[NSMutableDictionary alloc] initWithCapacity:properties.count]; + + for (PFPropertyInfo *info in properties) { + id value = [info getWrappedValueFrom:self]; + + if (value == nil) { + value = [self nilValueForProperty:info.name]; + + if (value == nil) { + continue; + } + } + + results[info.name] = value; + } + + return results; +} + +- (id)debugQuickLookObject { + return [[self dictionaryRepresentation] description]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.h new file mode 100644 index 0000000..9c298e2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFCategoryLoader : NSObject + ++ (void)loadPrivateCategories; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.m new file mode 100644 index 0000000..1a38f40 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCategoryLoader.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCategoryLoader.h" + +#import "BFTask+Private.h" + +@implementation PFCategoryLoader + ++ (void)loadPrivateCategories { + forceLoadCategory_BFTask_Private(); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.h new file mode 100644 index 0000000..4d780cf --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEventuallyQueue.h" + +@class PFCommandCacheTestHelper; +@class PFObject; + +/*! + ParseCommandCache manages an on-disk cache of commands to be executed, and a thread with a standard run loop + that executes the commands. There should only ever be one instance of this class, because multiple instances + would be running separate threads trying to read and execute the same commands. + */ +@interface PFCommandCache : PFEventuallyQueue + +@property (nonatomic, copy, readonly) NSString *diskCachePath; +@property (nonatomic, assign, readonly) unsigned long long diskCacheSize; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +/*! + Creates the command cache object for all ParseObjects with default configuration. + This command cache is used to locally store save commands created by the [PFObject saveEventually]. + When a PFCommandCache is instantiated, it will begin running its run loop, + which will start by processing any commands already stored in the on-disk queue. + */ ++ (instancetype)newDefaultCommandCacheWithCommandRunner:(id)commandRunner + cacheFolderPath:(NSString *)cacheFolderPath; + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval NS_UNAVAILABLE; + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval + diskCachePath:(NSString *)diskCachePath + diskCacheSize:(unsigned long long)diskCacheSize NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.m new file mode 100644 index 0000000..6889964 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache.m @@ -0,0 +1,330 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandCache.h" + +#include +#include + +#import +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCoreManager.h" +#import "PFErrorUtilities.h" +#import "PFEventuallyQueue_Private.h" +#import "PFFileManager.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFMultiProcessFileLockController.h" +#import "PFObject.h" +#import "PFObjectLocalIdStore.h" +#import "PFObjectPrivate.h" +#import "PFRESTCommand.h" +#import "Parse_Private.h" + +static NSString *const _PFCommandCacheDiskCacheDirectoryName = @"Command Cache"; + +static const NSString *PFCommandCachePrefixString = @"Command"; +static unsigned long long const PFCommandCacheDefaultDiskCacheSize = 10 * 1024 * 1024; // 10 MB + +@interface PFCommandCache () { + unsigned int _fileCounter; +} + +@property (nonatomic, assign, readwrite, setter=_setDiskCacheSize:) unsigned long long diskCacheSize; + +@end + +@implementation PFCommandCache + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)newDefaultCommandCacheWithCommandRunner:(id)commandRunner + cacheFolderPath:(NSString *)cacheFolderPath { + NSString *diskCachePath = [cacheFolderPath stringByAppendingPathComponent:_PFCommandCacheDiskCacheDirectoryName]; + diskCachePath = [diskCachePath stringByStandardizingPath]; + PFCommandCache *cache = [[PFCommandCache alloc] initWithCommandRunner:commandRunner + maxAttemptsCount:PFEventuallyQueueDefaultMaxAttemptsCount + retryInterval:PFEventuallyQueueDefaultTimeoutRetryInterval + diskCachePath:diskCachePath + diskCacheSize:PFCommandCacheDefaultDiskCacheSize]; + [cache start]; + return cache; +} + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval + diskCachePath:(NSString *)diskCachePath + diskCacheSize:(unsigned long long)diskCacheSize { + self = [super initWithCommandRunner:commandRunner maxAttemptsCount:attemptsCount retryInterval:retryInterval]; + if (!self) return nil; + + _diskCachePath = diskCachePath; + _diskCacheSize = diskCacheSize; + _fileCounter = 0; + + [self _createDiskCachePathIfNeeded]; + + return self; +} + +///-------------------------------------- +#pragma mark - Controlling Queue +///-------------------------------------- + +- (void)removeAllCommands { + [self pause]; + + [super removeAllCommands]; + + NSArray *commandIdentifiers = [self _pendingCommandIdentifiers]; + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:[commandIdentifiers count]]; + + for (NSString *identifier in commandIdentifiers) { + BFTask *task = [self _removeFileForCommandWithIdentifier:identifier]; + [tasks addObject:task]; + } + + [[BFTask taskForCompletionOfAllTasks:tasks] waitUntilFinished]; + + [self resume]; +} + +///-------------------------------------- +#pragma mark - PFEventuallyQueue +///-------------------------------------- + +- (void)_simulateReboot { + [super _simulateReboot]; + [self _createDiskCachePathIfNeeded]; +} + +///-------------------------------------- +#pragma mark - PFEventuallyQueueSubclass +///-------------------------------------- + +- (NSString *)_newIdentifierForCommand:(id)command { + // Start with current time - so we can sort identifiers and get the oldest one first. + return [NSString stringWithFormat:@"%@-%016qx-%08x-%@", + PFCommandCachePrefixString, + (unsigned long long)[NSDate timeIntervalSinceReferenceDate], + _fileCounter++, + [[NSUUID UUID] UUIDString]]; +} + +- (NSArray *)_pendingCommandIdentifiers { + NSArray *result = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.diskCachePath error:nil]; + // Only accept files that starts with "Command" since sometimes the directory is filled with garbage + // e.g.: https://phab.parse.com/file/info/PHID-FILE-qgbwk7sm7kcyaks6n4j7/ + result = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF BEGINSWITH %@", PFCommandCachePrefixString]]; + + return [result sortedArrayUsingSelector:@selector(compare:)]; +} + +- (id)_commandWithIdentifier:(NSString *)identifier error:(NSError **)error { + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:self.diskCachePath]; + + NSError *innerError = nil; + NSData *jsonData = [NSData dataWithContentsOfFile:[self _filePathForCommandWithIdentifier:identifier] + options:NSDataReadingUncached + error:&innerError]; + + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:self.diskCachePath]; + + if (innerError || !jsonData) { + NSString *message = [NSString stringWithFormat:@"Failed to read command from cache. %@", + innerError ? [innerError localizedDescription] : @""]; + innerError = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:message]; + if (error) { + *error = innerError; + } + return nil; + } + + id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData + options:0 + error:&innerError]; + if (innerError) { + NSString *message = [NSString stringWithFormat:@"Failed to deserialiaze command from cache. %@", + [innerError localizedDescription]]; + innerError = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:message]; + } else { + if ([PFRESTCommand isValidDictionaryRepresentation:jsonObject]) { + return [PFRESTCommand commandFromDictionaryRepresentation:jsonObject]; + } + innerError = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:@"Failed to construct eventually command from cache." + shouldLog:NO]; + } + if (innerError && error) { + *error = innerError; + } + + return nil; +} + +- (BFTask *)_enqueueCommandInBackground:(id)command + object:(PFObject *)object + identifier:(NSString *)identifier { + return [self _saveCommandToCacheInBackground:command object:object identifier:identifier]; +} + +- (BFTask *)_didFinishRunningCommand:(id)command + withIdentifier:(NSString *)identifier + resultTask:(BFTask *)resultTask { + // Get the new objectId and mark the new localId so it can be resolved. + if (command.localId) { + NSDictionary *dictionaryResult = nil; + if ([resultTask.result isKindOfClass:[NSDictionary class]]) { + dictionaryResult = resultTask.result; + } else if ([resultTask.result isKindOfClass:[PFCommandResult class]]) { + PFCommandResult *commandResult = resultTask.result; + dictionaryResult = commandResult.result; + } + + if (dictionaryResult != nil) { + NSString *objectId = dictionaryResult[@"objectId"]; + if (objectId) { + [[Parse _currentManager].coreManager.objectLocalIdStore setObjectId:objectId forLocalId:command.localId]; + } + } + } + + [[self _removeFileForCommandWithIdentifier:identifier] waitUntilFinished]; + return [super _didFinishRunningCommand:command withIdentifier:identifier resultTask:resultTask]; +} + +- (BFTask *)_waitForOperationSet:(PFOperationSet *)operationSet eventuallyPin:(PFEventuallyPin *)eventuallyPin { + // Do nothing. This is only relevant in PFPinningEventuallyQueue. Looks super hacky you said? Yes it is! + return [BFTask taskWithResult:nil]; +} + +///-------------------------------------- +#pragma mark - Disk Cache +///-------------------------------------- + +- (BFTask *)_cleanupDiskCacheWithRequiredFreeSize:(NSUInteger)requiredSize { + return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + NSUInteger size = requiredSize; + + NSMutableDictionary *commandSizes = [NSMutableDictionary dictionary]; + + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:self.diskCachePath]; + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath]; + + NSString *identifier = nil; + while ((identifier = [enumerator nextObject])) { + NSNumber *fileSize = [enumerator fileAttributes][NSFileSize]; + if (fileSize) { + commandSizes[identifier] = fileSize; + size += [fileSize unsignedIntegerValue]; + } + } + + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:self.diskCachePath]; + + if (size > self.diskCacheSize) { + // Get identifiers and sort them to remove oldest commands first + NSArray *identifiers = [[commandSizes allKeys] sortedArrayUsingSelector:@selector(compare:)]; + for (NSString *identifier in identifiers) @autoreleasepool { + [self _removeFileForCommandWithIdentifier:identifier]; + size -= [commandSizes[identifier] unsignedIntegerValue]; + + if (size <= self.diskCacheSize) { + break; + } + [commandSizes removeObjectForKey:identifier]; + } + } + + return [BFTask taskWithResult:nil]; + }]; +} + +- (void)_setDiskCacheSize:(unsigned long long)diskCacheSize { + _diskCacheSize = diskCacheSize; +} + +///-------------------------------------- +#pragma mark - Files +///-------------------------------------- + +- (BFTask *)_saveCommandToCacheInBackground:(id)command + object:(PFObject *)object + identifier:(NSString *)identifier { + if (object != nil && object.objectId == nil) { + command.localId = [object getOrCreateLocalId]; + } + + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:[command dictionaryRepresentation] + options:0 + error:&error]; + NSUInteger commandSize = [data length]; + if (commandSize > self.diskCacheSize) { + error = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:@"Failed to run command, because it's too big."]; + } else if (commandSize == 0) { + error = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:@"Failed to run command, because it's empty."]; + } + + if (error) { + return [BFTask taskWithError:error]; + } + + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:self.diskCachePath]; + return [[[self _cleanupDiskCacheWithRequiredFreeSize:commandSize] continueWithBlock:^id(BFTask *task) { + NSString *filePath = [self _filePathForCommandWithIdentifier:identifier]; + return [PFFileManager writeDataAsync:data toFile:filePath]; + }] continueWithBlock:^id(BFTask *task) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:self.diskCachePath]; + return task; + }]; + }]; +} + +- (BFTask *)_removeFileForCommandWithIdentifier:(NSString *)identifier { + NSString *filePath = [self _filePathForCommandWithIdentifier:identifier]; + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:self.diskCachePath]; + return [PFFileManager removeItemAtPathAsync:filePath withFileLock:NO]; + }] continueWithBlock:^id(BFTask *task) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:self.diskCachePath]; + return task; // Roll-forward the previous task. + }]; +} + +- (NSString *)_filePathForCommandWithIdentifier:(NSString *)identifier { + return [self.diskCachePath stringByAppendingPathComponent:identifier]; +} + +- (void)_createDiskCachePathIfNeeded { + [[PFFileManager createDirectoryIfNeededAsyncAtPath:_diskCachePath] waitForResult:nil withMainThreadWarning:NO]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache_Private.h new file mode 100644 index 0000000..869ce66 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandCache_Private.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandCache.h" + +@interface PFCommandCache () + +- (void)_setDiskCacheSize:(unsigned long long)diskCacheSize; + +@end; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.h new file mode 100644 index 0000000..a87d667 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFCommandResult : NSObject + +@property (nonatomic, strong, readonly) id result; +@property (nullable, nonatomic, copy, readonly) NSString *resultString; +@property (nullable, nonatomic, strong, readonly) NSHTTPURLResponse *httpResponse; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithResult:(NSDictionary *)result + resultString:(nullable NSString *)resultString + httpResponse:(nullable NSHTTPURLResponse *)response NS_DESIGNATED_INITIALIZER; ++ (instancetype)commandResultWithResult:(NSDictionary *)result + resultString:(nullable NSString *)resultString + httpResponse:(nullable NSHTTPURLResponse *)response; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.m new file mode 100644 index 0000000..e83f2c3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCommandResult.m @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCommandResult.h" + +#import "PFAssert.h" + +@implementation PFCommandResult + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithResult:(NSDictionary *)result + resultString:(NSString *)resultString + httpResponse:(NSHTTPURLResponse *)response { + self = [super init]; + if (!self) return nil; + + _result = result; + _resultString = [resultString copy]; + _httpResponse = response; + + return self; +} + ++ (instancetype)commandResultWithResult:(NSDictionary *)result + resultString:(NSString *)resultString + httpResponse:(NSHTTPURLResponse *)response { + return [[self alloc] initWithResult:result resultString:resultString httpResponse:response]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreDataProvider.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreDataProvider.h new file mode 100644 index 0000000..021e974 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreDataProvider.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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. + */ + +#ifndef Parse_PFCoreDataProvider_h +#define Parse_PFCoreDataProvider_h + +NS_ASSUME_NONNULL_BEGIN + +///-------------------------------------- +/// @name Object +///-------------------------------------- + +@class PFObjectController; + +@protocol PFObjectControllerProvider + +@property (nonatomic, strong) PFObjectController *objectController; + +@end + +@class PFObjectBatchController; + +@protocol PFObjectBatchController + +@property (nonatomic, strong, readonly) PFObjectBatchController *objectBatchController; + +@end + +@class PFObjectFilePersistenceController; + +@protocol PFObjectFilePersistenceControllerProvider + +@property (nonatomic, strong, readonly) PFObjectFilePersistenceController *objectFilePersistenceController; + +@end + +@class PFObjectLocalIdStore; + +@protocol PFObjectLocalIdStoreProvider + +@property (nonatomic, strong) PFObjectLocalIdStore *objectLocalIdStore; + +@end + +///-------------------------------------- +/// @name User +///-------------------------------------- + +@class PFUserAuthenticationController; + +@protocol PFUserAuthenticationControllerProvider + +@property (nonatomic, strong) PFUserAuthenticationController *userAuthenticationController; + +@end + +@class PFCurrentUserController; + +@protocol PFCurrentUserControllerProvider + +@property (nonatomic, strong) PFCurrentUserController *currentUserController; + +@end + +@class PFUserController; + +@protocol PFUserControllerProvider + +@property (nonatomic, strong) PFUserController *userController; + +@end + +///-------------------------------------- +/// @name Installation +///-------------------------------------- + +@class PFCurrentInstallationController; + +@protocol PFCurrentInstallationControllerProvider + +@property (nonatomic, strong) PFCurrentInstallationController *currentInstallationController; + +@end + +@class PFInstallationController; + +@protocol PFInstallationControllerProvider + +@property (nonatomic, strong) PFInstallationController *installationController; + +@end + +#endif + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.h new file mode 100644 index 0000000..19e2fca --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.h @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFDataProvider.h" + +@class PFInstallationIdentifierStore; + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFCoreManagerDataSource + + +@property (nonatomic, strong, readonly) PFInstallationIdentifierStore *installationIdentifierStore; + +@end + +@class PFCloudCodeController; +@class PFConfigController; +@class PFFileController; +@class PFObjectFilePersistenceController; +@class PFObjectSubclassingController; +@class PFPinningObjectStore; +@class PFQueryController; +@class PFSessionController; + +@interface PFCoreManager : NSObject + + +@property (nonatomic, weak, readonly) id dataSource; + +@property (nonatomic, strong) PFQueryController *queryController; +@property (nonatomic, strong) PFFileController *fileController; +@property (nonatomic, strong) PFCloudCodeController *cloudCodeController; +@property (nonatomic, strong) PFConfigController *configController; +@property (nonatomic, strong) PFSessionController *sessionController; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)managerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name ObjectFilePersistenceController +///-------------------------------------- + +- (void)unloadObjectFilePersistenceController; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.m new file mode 100644 index 0000000..c2b02dc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFCoreManager.m @@ -0,0 +1,447 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreManager.h" + +#import "PFAssert.h" +#import "PFCachedQueryController.h" +#import "PFCloudCodeController.h" +#import "PFConfigController.h" +#import "PFCurrentInstallationController.h" +#import "PFCurrentUserController.h" +#import "PFFileController.h" +#import "PFInstallationController.h" +#import "PFLocationManager.h" +#import "PFMacros.h" +#import "PFObjectBatchController.h" +#import "PFObjectController.h" +#import "PFObjectFilePersistenceController.h" +#import "PFObjectLocalIdStore.h" +#import "PFObjectSubclassingController.h" +#import "PFOfflineObjectController.h" +#import "PFOfflineQueryController.h" +#import "PFPinningObjectStore.h" +#import "PFSessionController.h" +#import "PFUserAuthenticationController.h" +#import "PFUserController.h" + +@interface PFCoreManager () { + dispatch_queue_t _locationManagerAccessQueue; + dispatch_queue_t _controllerAccessQueue; + dispatch_queue_t _objectLocalIdStoreAccessQueue; +} + +@end + +@implementation PFCoreManager + +@synthesize locationManager = _locationManager; + +@synthesize queryController = _queryController; +@synthesize fileController = _fileController; +@synthesize cloudCodeController = _cloudCodeController; +@synthesize configController = _configController; +@synthesize objectController = _objectController; +@synthesize objectBatchController = _objectBatchController; +@synthesize objectFilePersistenceController = _objectFilePersistenceController; +@synthesize objectLocalIdStore = _objectLocalIdStore; +@synthesize pinningObjectStore = _pinningObjectStore; +@synthesize userAuthenticationController = _userAuthenticationController; +@synthesize sessionController = _sessionController; +@synthesize currentInstallationController = _currentInstallationController; +@synthesize currentUserController = _currentUserController; +@synthesize userController = _userController; +@synthesize installationController = _installationController; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + _locationManagerAccessQueue = dispatch_queue_create("com.parse.core.locationManager", DISPATCH_QUEUE_SERIAL); + _controllerAccessQueue = dispatch_queue_create("com.parse.core.controller.accessQueue", DISPATCH_QUEUE_SERIAL); + _objectLocalIdStoreAccessQueue = dispatch_queue_create("com.parse.core.object.localIdStore", DISPATCH_QUEUE_SERIAL); + + return self; +} + ++ (instancetype)managerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - LocationManager +///-------------------------------------- + +- (PFLocationManager *)locationManager { + __block PFLocationManager *manager; + dispatch_sync(_locationManagerAccessQueue, ^{ + if (!_locationManager) { + _locationManager = [[PFLocationManager alloc] init]; + } + manager = _locationManager; + }); + return manager; +} + +///-------------------------------------- +#pragma mark - QueryController +///-------------------------------------- + +- (PFQueryController *)queryController { + __block PFQueryController *queryController; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_queryController) { + id dataSource = self.dataSource; + if (dataSource.offlineStoreLoaded) { + _queryController = [PFOfflineQueryController controllerWithCommonDataSource:dataSource + coreDataSource:self]; + } else { + _queryController = [PFCachedQueryController controllerWithCommonDataSource:dataSource]; + } + } + queryController = _queryController; + }); + return queryController; +} + +- (void)setQueryController:(PFQueryController *)queryController { + dispatch_sync(_controllerAccessQueue, ^{ + _queryController = queryController; + }); +} + +///-------------------------------------- +#pragma mark - FileController +///-------------------------------------- + +- (PFFileController *)fileController { + __block PFFileController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_fileController) { + _fileController = [PFFileController controllerWithDataSource:self.dataSource]; + } + controller = _fileController; + }); + return controller; +} + +- (void)setFileController:(PFFileController *)fileController { + dispatch_sync(_controllerAccessQueue, ^{ + _fileController = fileController; + }); +} + +///-------------------------------------- +#pragma mark - CloudCodeController +///-------------------------------------- + +- (PFCloudCodeController *)cloudCodeController { + __block PFCloudCodeController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_cloudCodeController) { + _cloudCodeController = [[PFCloudCodeController alloc] initWithCommandRunner:self.dataSource.commandRunner]; + } + controller = _cloudCodeController; + }); + return controller; +} + +- (void)setCloudCodeController:(PFCloudCodeController *)cloudCodeController { + dispatch_sync(_controllerAccessQueue, ^{ + _cloudCodeController = cloudCodeController; + }); +} + +///-------------------------------------- +#pragma mark - ConfigController +///-------------------------------------- + +- (PFConfigController *)configController { + __block PFConfigController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_configController) { + id dataSource = self.dataSource; + _configController = [[PFConfigController alloc] initWithFileManager:dataSource.fileManager + commandRunner:dataSource.commandRunner]; + } + controller = _configController; + }); + return controller; +} + +- (void)setConfigController:(PFConfigController *)configController { + dispatch_sync(_controllerAccessQueue, ^{ + _configController = configController; + }); +} + +///-------------------------------------- +#pragma mark - ObjectController +///-------------------------------------- + +- (PFObjectController *)objectController { + __block PFObjectController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_objectController) { + id dataSource = self.dataSource; + if (dataSource.offlineStoreLoaded) { + _objectController = [PFOfflineObjectController controllerWithDataSource:dataSource]; + } else { + _objectController = [PFObjectController controllerWithDataSource:dataSource]; + } + } + controller = _objectController; + }); + return controller; +} + +- (void)setObjectController:(PFObjectController *)controller { + dispatch_sync(_controllerAccessQueue, ^{ + _objectController = controller; + }); +} + +///-------------------------------------- +#pragma mark - ObjectBatchController +///-------------------------------------- + +- (PFObjectBatchController *)objectBatchController { + __block PFObjectBatchController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_objectBatchController) { + _objectBatchController = [PFObjectBatchController controllerWithDataSource:self.dataSource]; + } + controller = _objectBatchController; + }); + return controller; +} + +///-------------------------------------- +#pragma mark - ObjectFilePersistenceController +///-------------------------------------- + +- (PFObjectFilePersistenceController *)objectFilePersistenceController { + __block PFObjectFilePersistenceController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_objectFilePersistenceController) { + _objectFilePersistenceController = [PFObjectFilePersistenceController controllerWithDataSource:self.dataSource]; + } + controller = _objectFilePersistenceController; + }); + return controller; +} + +- (void)unloadObjectFilePersistenceController { + dispatch_sync(_controllerAccessQueue, ^{ + _objectFilePersistenceController = nil; + }); +} + +///-------------------------------------- +#pragma mark - Pinning Object Store +///-------------------------------------- + +- (PFPinningObjectStore *)pinningObjectStore { + __block PFPinningObjectStore *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_pinningObjectStore) { + _pinningObjectStore = [PFPinningObjectStore storeWithDataSource:self.dataSource]; + } + controller = _pinningObjectStore; + }); + return controller; +} + +- (void)setPinningObjectStore:(PFPinningObjectStore *)pinningObjectStore { + dispatch_sync(_controllerAccessQueue, ^{ + _pinningObjectStore = pinningObjectStore; + }); +} + +///-------------------------------------- +#pragma mark - Object LocalId Store +///-------------------------------------- + +- (PFObjectLocalIdStore *)objectLocalIdStore { + __block PFObjectLocalIdStore *store = nil; + @weakify(self); + dispatch_sync(_objectLocalIdStoreAccessQueue, ^{ + @strongify(self); + if (!_objectLocalIdStore) { + _objectLocalIdStore = [[PFObjectLocalIdStore alloc] initWithDataSource:self.dataSource]; + } + store = _objectLocalIdStore; + }); + return store; +} + +- (void)setObjectLocalIdStore:(PFObjectLocalIdStore *)objectLocalIdStore { + dispatch_sync(_objectLocalIdStoreAccessQueue, ^{ + _objectLocalIdStore = objectLocalIdStore; + }); +} + +///-------------------------------------- +#pragma mark - UserAuthenticationController +///-------------------------------------- + +- (PFUserAuthenticationController *)userAuthenticationController { + __block PFUserAuthenticationController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_userAuthenticationController) { + _userAuthenticationController = [PFUserAuthenticationController controllerWithDataSource:self]; + } + controller = _userAuthenticationController; + }); + return controller; +} + +- (void)setUserAuthenticationController:(PFUserAuthenticationController *)userAuthenticationController { + dispatch_sync(_controllerAccessQueue, ^{ + _userAuthenticationController = userAuthenticationController; + }); +} + +///-------------------------------------- +#pragma mark - SessionController +///-------------------------------------- + +- (PFSessionController *)sessionController { + __block PFSessionController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_sessionController) { + _sessionController = [PFSessionController controllerWithDataSource:self.dataSource]; + } + controller = _sessionController; + }); + return controller; +} + +- (void)setSessionController:(PFSessionController *)sessionController { + dispatch_sync(_controllerAccessQueue, ^{ + _sessionController = sessionController; + }); +} + +#if !TARGET_OS_WATCH + +///-------------------------------------- +#pragma mark - Current Installation Controller +///-------------------------------------- + +- (PFCurrentInstallationController *)currentInstallationController { + __block PFCurrentInstallationController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_currentInstallationController) { + id dataSource = self.dataSource; + PFCurrentObjectStorageType storageType = (dataSource.offlineStore ? + PFCurrentObjectStorageTypeOfflineStore : + PFCurrentObjectStorageTypeFile); + _currentInstallationController = [PFCurrentInstallationController controllerWithStorageType:storageType + commonDataSource:dataSource + coreDataSource:self]; + } + controller = _currentInstallationController; + }); + return controller; +} + +- (void)setCurrentInstallationController:(PFCurrentInstallationController *)controller { + dispatch_sync(_controllerAccessQueue, ^{ + _currentInstallationController = controller; + }); +} + +#endif + +///-------------------------------------- +#pragma mark - Current User Controller +///-------------------------------------- + +- (PFCurrentUserController *)currentUserController { + __block PFCurrentUserController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_currentUserController) { + id dataSource = self.dataSource; + PFCurrentObjectStorageType storageType = (dataSource.offlineStore ? + PFCurrentObjectStorageTypeOfflineStore : + PFCurrentObjectStorageTypeFile); + _currentUserController = [PFCurrentUserController controllerWithStorageType:storageType + commonDataSource:dataSource + coreDataSource:self]; + } + controller = _currentUserController; + }); + return controller; +} + +- (void)setCurrentUserController:(PFCurrentUserController *)currentUserController { + dispatch_sync(_controllerAccessQueue, ^{ + _currentUserController = currentUserController; + }); +} + +#if !TARGET_OS_WATCH + +///-------------------------------------- +#pragma mark - Installation Controller +///-------------------------------------- + +- (PFInstallationController *)installationController { + __block PFInstallationController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_installationController) { + _installationController = [PFInstallationController controllerWithDataSource:self]; + } + controller = _installationController; + }); + return controller; +} + +- (void)setInstallationController:(PFInstallationController *)installationController { + dispatch_sync(_controllerAccessQueue, ^{ + _installationController = installationController; + }); +} + +#endif + +///-------------------------------------- +#pragma mark - User Controller +///-------------------------------------- + +- (PFUserController *)userController { + __block PFUserController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_userController) { + _userController = [PFUserController controllerWithCommonDataSource:self.dataSource + coreDataSource:self]; + } + controller = _userController; + }); + return controller; +} + +- (void)setUserController:(PFUserController *)userController { + dispatch_sync(_controllerAccessQueue, ^{ + _userController = userController; + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDataProvider.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDataProvider.h new file mode 100644 index 0000000..3813c4d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDataProvider.h @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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. + */ + +#ifndef Parse_PFDataProviders_h +#define Parse_PFDataProviders_h + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFCommandRunning; + +@protocol PFCommandRunnerProvider + +@property (nonatomic, strong, readonly) id commandRunner; + +@end + +@class PFFileManager; + +@protocol PFFileManagerProvider + +@property (nonatomic, strong, readonly) PFFileManager *fileManager; + +@end + +@class PFOfflineStore; + +@protocol PFOfflineStoreProvider + +@property (nullable, nonatomic, strong) PFOfflineStore *offlineStore; +@property (nonatomic, assign, readonly, getter=isOfflineStoreLoaded) BOOL offlineStoreLoaded; + +@end + +@class PFEventuallyQueue; + +@protocol PFEventuallyQueueProvider + +@property (nonatomic, strong, readonly) PFEventuallyQueue *eventuallyQueue; + +@end + +@class PFKeychainStore; + +@protocol PFKeychainStoreProvider + +@property (nonatomic, strong, readonly) PFKeychainStore *keychainStore; + +@end + +@class PFKeyValueCache; + +@protocol PFKeyValueCacheProvider + +@property (nonatomic, strong, readonly) PFKeyValueCache *keyValueCache; + +@end + +@class PFLocationManager; + +@protocol PFLocationManagerProvider + +@property (nonatomic, strong, readonly) PFLocationManager *locationManager; + +@end + +@class PFPinningObjectStore; + +@protocol PFPinningObjectStoreProvider + +@property (nonatomic, strong) PFPinningObjectStore *pinningObjectStore; + +@end + +@class PFInstallationIdentifierStore; + +@protocol PFInstallationIdentifierStoreProvider + +@property (nonatomic, strong, readonly) PFInstallationIdentifierStore *installationIdentifierStore; + +@end + +#endif + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.h new file mode 100644 index 0000000..d258e76 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFDateFormatter : NSObject + ++ (instancetype)sharedFormatter; + +///-------------------------------------- +/// @name String from Date +///-------------------------------------- + +/*! + Converts `NSDate` into `NSString` representation using the following format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + + @param date `NSDate` to convert. + + @returns Formatted `NSString` representation. + */ +- (NSString *)preciseStringFromDate:(NSDate *)date; + +///-------------------------------------- +/// @name Date from String +///-------------------------------------- + +/*! + Converts `NSString` representation of a date into `NSDate` object. + + @discussion Following date formats are supported: + YYYY-MM-DD + YYYY-MM-DD HH:MM'Z' + YYYY-MM-DD HH:MM:SS'Z' + YYYY-MM-DD HH:MM:SS.SSS'Z' + YYYY-MM-DDTHH:MM'Z' + YYYY-MM-DDTHH:MM:SS'Z' + YYYY-MM-DDTHH:MM:SS.SSS'Z' + + @param string `NSString` representation to convert. + + @returns `NSDate` incapsulating the date. + */ +- (NSDate *)dateFromString:(NSString *)string; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.m new file mode 100644 index 0000000..c4a6ba2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDateFormatter.m @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDateFormatter.h" + +#import + +@interface PFDateFormatter () { + dispatch_queue_t _synchronizationQueue; + + sqlite3 *_sqliteDatabase; + sqlite3_stmt *_stringToDateStatement; +} + +@property (nonatomic, strong, readonly) NSDateFormatter *preciseDateFormatter; + +@end + +@implementation PFDateFormatter + +@synthesize preciseDateFormatter = _preciseDateFormatter; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)sharedFormatter { + static PFDateFormatter *formatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + formatter = [[self alloc] init]; + }); + return formatter; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _synchronizationQueue = dispatch_queue_create("com.parse.dateFormatter", DISPATCH_QUEUE_SERIAL); + + //TODO: (nlutsenko) Check for error here. + sqlite3_open(":memory:", &_sqliteDatabase); + sqlite3_prepare_v2(_sqliteDatabase, + "SELECT strftime('%s', ?), strftime('%f', ?);", + -1, + &_stringToDateStatement, + NULL); + + return self; +} + +- (void)dealloc { + sqlite3_finalize(_stringToDateStatement); + sqlite3_close(_sqliteDatabase); +} + +///-------------------------------------- +#pragma mark - Date Formatters +///-------------------------------------- + +- (NSDateFormatter *)preciseDateFormatter { + if (!_preciseDateFormatter) { + _preciseDateFormatter = [[NSDateFormatter alloc] init]; + _preciseDateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + _preciseDateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + _preciseDateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + } + return _preciseDateFormatter; +} + +///-------------------------------------- +#pragma mark - String from Date +///-------------------------------------- + +- (NSString *)preciseStringFromDate:(NSDate *)date { + __block NSString *string = nil; + dispatch_sync(_synchronizationQueue, ^{ + string = [self.preciseDateFormatter stringFromDate:date]; + }); + return string; +} + +///-------------------------------------- +#pragma mark - Date from String +///-------------------------------------- + +- (NSDate *)dateFromString:(NSString *)string { + __block sqlite3_int64 interval = 0; + __block double seconds = 0.0; + dispatch_sync(_synchronizationQueue, ^{ + const char *utf8String = [string UTF8String]; + + sqlite3_bind_text(_stringToDateStatement, 1, utf8String, -1, SQLITE_STATIC); + sqlite3_bind_text(_stringToDateStatement, 2, utf8String, -1, SQLITE_STATIC); + + if (sqlite3_step(_stringToDateStatement) == SQLITE_ROW) { + interval = sqlite3_column_int64(_stringToDateStatement, 0); + seconds = sqlite3_column_double(_stringToDateStatement, 1); + } + + sqlite3_reset(_stringToDateStatement); + sqlite3_clear_bindings(_stringToDateStatement); + }); + // Extract the fraction component of the seconds + double sintegral = 0.0; + double sfraction = modf(seconds, &sintegral); + + return [NSDate dateWithTimeIntervalSince1970:(double)interval + sfraction]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.h new file mode 100644 index 0000000..b0e5074 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFDecoder : NSObject + +/*! + Globally available shared instance of PFDecoder. + */ ++ (PFDecoder *)objectDecoder; + +/*! + Takes a complex object that was deserialized and converts encoded + dictionaries into the proper Parse types. This is the inverse of + encodeObject:allowUnsaved:allowObjects:seenObjects:. + */ +- (nullable id)decodeObject:(nullable id)object; + +@end + +/*! + Extends the normal JSON to PFObject decoding to also deal with placeholders for new objects + that have been saved offline. + */ +@interface PFOfflineDecoder : PFDecoder + ++ (instancetype)decoderWithOfflineObjects:(nullable NSDictionary *)offlineObjects; + +@end + +/*! + A subclass of PFDecoder which can keep PFObject that has been fetched instead of creating a new instance. + */ +@interface PFKnownParseObjectDecoder : PFDecoder + ++ (instancetype)decoderWithFetchedObjects:(nullable NSDictionary *)fetchedObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.m new file mode 100644 index 0000000..9cd045a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDecoder.m @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDecoder.h" + +#import "PFBase64Encoder.h" +#import "PFDateFormatter.h" +#import "PFFieldOperation.h" +#import "PFFieldOperationDecoder.h" +#import "PFFile_Private.h" +#import "PFGeoPointPrivate.h" +#import "PFInternalUtils.h" +#import "PFMacros.h" +#import "PFObjectPrivate.h" +#import "PFRelationPrivate.h" + +///-------------------------------------- +#pragma mark - PFDecoder +///-------------------------------------- + +@implementation PFDecoder + +#pragma mark Init + ++ (PFDecoder *)objectDecoder { + static PFDecoder *decoder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + decoder = [[PFDecoder alloc] init]; + }); + return decoder; +} + +#pragma mark Decode + +- (id)decodeDictionary:(NSDictionary *)dictionary { + NSString *op = dictionary[@"__op"]; + if (op) { + return [[PFFieldOperationDecoder defaultDecoder] decode:dictionary withDecoder:self]; + } + + NSString *type = dictionary[@"__type"]; + if (type) { + if ([type isEqualToString:@"Date"]) { + return [[PFDateFormatter sharedFormatter] dateFromString:dictionary[@"iso"]]; + + } else if ([type isEqualToString:@"Bytes"]) { + return [PFBase64Encoder dataFromBase64String:dictionary[@"base64"]]; + + } else if ([type isEqualToString:@"GeoPoint"]) { + return [PFGeoPoint geoPointWithDictionary:dictionary]; + + } else if ([type isEqualToString:@"Relation"]) { + return [PFRelation relationFromDictionary:dictionary withDecoder:self]; + + } else if ([type isEqualToString:@"File"]) { + return [PFFile fileWithName:dictionary[@"name"] + url:dictionary[@"url"]]; + + } else if ([type isEqualToString:@"Pointer"]) { + NSString *objectId = dictionary[@"objectId"]; + NSString *localId = dictionary[@"localId"]; + NSString *className = dictionary[@"className"]; + if (localId) { + // This is a PFObject deserialized off the local disk, which has a localId + // that will need to be resolved before the object can be sent over the network. + // Its localId should be known to PFObjectLocalIdStore. + return [self _decodePointerForClassName:className localId:localId]; + } else { + return [self _decodePointerForClassName:className objectId:objectId]; + } + + } else if ([type isEqualToString:@"Object"]) { + NSString *className = dictionary[@"className"]; + + NSMutableDictionary *data = [dictionary mutableCopy]; + [data removeObjectForKey:@"__type"]; + [data removeObjectForKey:@"className"]; + NSDictionary *result = [self decodeDictionary:data]; + + return [PFObject _objectFromDictionary:result + defaultClassName:className + completeData:YES + decoder:self]; + + } else { + // We don't know how to decode this, so just leave it as a dictionary. + return dictionary; + } + } + + NSMutableDictionary *newDictionary = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + newDictionary[key] = [self decodeObject:obj]; + }]; + return newDictionary; +} + +- (id)_decodePointerForClassName:(NSString *)className objectId:(NSString *)objectId { + return [PFObject objectWithoutDataWithClassName:className objectId:objectId]; +} + +- (id)_decodePointerForClassName:(NSString *)className localId:(NSString *)localId { + return [PFObject objectWithoutDataWithClassName:className localId:localId]; +} + +- (id)decodeArray:(NSArray *)array { + NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count]; + for (id value in array) { + [newArray addObject:[self decodeObject:value]]; + } + return newArray; +} + +- (id)decodeObject:(id)object { + if ([object isKindOfClass:[NSDictionary class]]) { + return [self decodeDictionary:object]; + } else if ([object isKindOfClass:[NSArray class]]) { + return [self decodeArray:object]; + } + return object; +} + +@end + +///-------------------------------------- +#pragma mark - PFOfflineDecoder +///-------------------------------------- + +@interface PFOfflineDecoder () + +/*! + A map of UUID to Task that will be finished once the given PFObject is loaded. + The Tasks should all be finished before decode is called. + */ +@property (nonatomic, copy) NSDictionary *offlineObjects; + +@end + +@implementation PFOfflineDecoder + ++ (instancetype)decoderWithOfflineObjects:(NSDictionary *)offlineObjects { + PFOfflineDecoder *decoder = [[self alloc] init]; + decoder.offlineObjects = offlineObjects; + return decoder; +} + +#pragma mark PFDecoder + +- (id)decodeObject:(id)object { + if ([object isKindOfClass:[NSDictionary class]] && + [((NSDictionary *)object)[@"__type"] isEqualToString:@"OfflineObject"]) { + NSString *uuid = ((NSDictionary *)object)[@"uuid"]; + return ((BFTask *)self.offlineObjects[uuid]).result; + } + + // Embedded objects can't show up here, because we never stored them that way offline. + return [super decodeObject:object]; +} + +@end + +///-------------------------------------- +#pragma mark - PFKnownParseObjectDecoder +///-------------------------------------- + +@interface PFKnownParseObjectDecoder () + +@property (nonatomic, copy) NSDictionary *fetchedObjects; + +@end + +@implementation PFKnownParseObjectDecoder + ++ (instancetype)decoderWithFetchedObjects:(NSDictionary *)fetchedObjects { + PFKnownParseObjectDecoder *decoder = [[self alloc] init]; + decoder.fetchedObjects = fetchedObjects; + return decoder; +} + +- (id)_decodePointerForClassName:(NSString *)className objectId:(NSString *)objectId { + if (_fetchedObjects != nil && _fetchedObjects[objectId]) { + return _fetchedObjects[objectId]; + } + return [super _decodePointerForClassName:className objectId:objectId]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.h new file mode 100644 index 0000000..6e62a3c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFDevice : NSObject + +@property (nonatomic, copy, readonly) NSString *detailedModel; + +@property (nonatomic, copy, readonly) NSString *operatingSystemFullVersion; +@property (nonatomic, copy, readonly) NSString *operatingSystemVersion; +@property (nonatomic, copy, readonly) NSString *operatingSystemBuild; + +@property (nonatomic, assign, readonly, getter=isJailbroken) BOOL jailbroken; + ++ (instancetype)currentDevice; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.m new file mode 100644 index 0000000..b918012 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFDevice.m @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDevice.h" + +#import + +#if TARGET_OS_WATCH +#import +#elif TARGET_OS_IOS +#import +#elif TARGET_OS_MAC +#import +#endif + +#include +#include +#include + +static NSString *PFDeviceSysctlByName(NSString *name) { + const char *charName = [name UTF8String]; + + size_t size; + sysctlbyname(charName, NULL, &size, NULL, 0); + char *answer = (char*)malloc(size); + + if (answer == NULL) { + return nil; + } + + sysctlbyname(charName, answer, &size, NULL, 0); + NSString *string = [NSString stringWithUTF8String:answer]; + free(answer); + + return string; +} + +@implementation PFDevice + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)currentDevice { + static PFDevice *device; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + device = [[self alloc] init]; + }); + return device; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSString *)detailedModel { + NSString *name = PFDeviceSysctlByName(@"hw.machine"); + if (!name) { +#if TARGET_OS_WATCH + name = [WKInterfaceDevice currentDevice].model; +#elif TARGET_OS_IOS + name = [UIDevice currentDevice].model; +#elif TARGET_OS_MAC + name = @"Mac"; +#endif + } + return name; +} + +- (NSString *)operatingSystemFullVersion { + NSString *version = self.operatingSystemVersion; + NSString *build = self.operatingSystemBuild; + if (build.length) { + version = [version stringByAppendingFormat:@" (%@)", build]; + } + return version; +} +- (NSString *)operatingSystemVersion { +#if TARGET_OS_IOS + return [UIDevice currentDevice].systemVersion; +#elif TARGET_OS_WATCH + NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion; + return [NSString stringWithFormat:@"%d.%d.%d", + (int)version.majorVersion, + (int)version.minorVersion, + (int)version.patchVersion]; +#elif TARGET_OS_MAC + NSProcessInfo *info = [NSProcessInfo processInfo]; + if ([info respondsToSelector:@selector(operatingSystemVersion)]) { + NSOperatingSystemVersion version = info.operatingSystemVersion; + return [NSString stringWithFormat:@"%d.%d.%d", + (int)version.majorVersion, + (int)version.minorVersion, + (int)version.patchVersion]; + } else { + // TODO: (nlutsenko) Remove usage of this method, when we drop support for OSX 10.9 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + SInt32 major, minor, bugfix; + if (Gestalt(gestaltSystemVersionMajor, &major) == noErr && + Gestalt(gestaltSystemVersionMinor, &minor) == noErr && + Gestalt(gestaltSystemVersionBugFix, &bugfix) == noErr) { + return [NSString stringWithFormat:@"%d.%d.%d", major, minor, bugfix]; + } +#pragma clang diagnostic pop + return [[NSProcessInfo processInfo] operatingSystemVersionString]; + } +#endif +} + +- (NSString *)operatingSystemBuild { + return PFDeviceSysctlByName(@"kern.osversion"); +} + +- (BOOL)isJailbroken { + BOOL jailbroken = NO; +#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR + DIR *dir = opendir("/"); + if (dir != NULL) { + jailbroken = YES; + closedir(dir); + } +#endif + return jailbroken; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.h new file mode 100644 index 0000000..9482755 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.h @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; +@class PFOfflineStore; +@class PFSQLiteDatabase; + +///-------------------------------------- +/// @name Encoders +///-------------------------------------- + +@interface PFEncoder : NSObject + ++ (instancetype)objectEncoder; + +- (id)encodeObject:(id)object; +- (id)encodeParseObject:(PFObject *)object; + +@end + +/*! + Encoding strategy that rejects PFObject. + */ +@interface PFNoObjectEncoder : PFEncoder + +@end + +/*! + Encoding strategy that encodes PFObject to PFPointer with objectId or with localId. + */ +@interface PFPointerOrLocalIdObjectEncoder : PFEncoder + +@end + +/*! + Encoding strategy that encodes PFObject to PFPointer with objectId and rejects + unsaved PFObject. + */ +@interface PFPointerObjectEncoder : PFPointerOrLocalIdObjectEncoder + +@end + +/*! + Encoding strategy that can encode objects that are available offline. After using this encoder, + you must call encodeFinished and wait for its result to be finished before the results of the + encoding will be valid. + */ +@interface PFOfflineObjectEncoder : PFEncoder + ++ (instancetype)objectEncoderWithOfflineStore:(PFOfflineStore *)store database:(PFSQLiteDatabase *)database; + +- (BFTask *)encodeFinished; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.m new file mode 100644 index 0000000..6f9ce64 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEncoder.m @@ -0,0 +1,250 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEncoder.h" + +#import "PFACLPrivate.h" +#import "PFAssert.h" +#import "PFBase64Encoder.h" +#import "PFDateFormatter.h" +#import "PFFieldOperation.h" +#import "PFFile_Private.h" +#import "PFGeoPointPrivate.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFRelationPrivate.h" + +@implementation PFEncoder + ++ (instancetype)objectEncoder { + static PFEncoder *encoder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + encoder = [[PFEncoder alloc] init]; + }); + return encoder; +} + +- (id)encodeObject:(id)object { + if ([object isKindOfClass:[PFObject class]]) { + return [self encodeParseObject:object]; + } else if ([object isKindOfClass:[NSData class]]) { + return @{ + @"__type" : @"Bytes", + @"base64" : [PFBase64Encoder base64StringFromData:object] + }; + + } else if ([object isKindOfClass:[NSDate class]]) { + return @{ + @"__type" : @"Date", + @"iso" : [[PFDateFormatter sharedFormatter] preciseStringFromDate:object] + }; + + } else if ([object isKindOfClass:[PFFile class]]) { + if (((PFFile *)object).isDirty) { + // TODO: (nlutsenko) Figure out what to do with things like an unsaved file + // in a mutable container, where we don't normally want to allow serializing + // such a thing inside an object. + // + // Returning this empty object is strictly wrong, but we have to have *something* + // to put into an object's mutable container cache, and this is just about the + // best we can do right now. + // + // [NSException raise:NSInternalInconsistencyException + // format:@"Tried to serialize an unsaved file."]; + return @{ @"__type" : @"File" }; + } + return @{ + @"__type" : @"File", + @"url" : ((PFFile *)object).state.urlString, + @"name" : ((PFFile *)object).name + }; + + } else if ([object isKindOfClass:[PFFieldOperation class]]) { + // Always encode PFFieldOperation with PFPointerOrLocalId + return [object encodeWithObjectEncoder:[PFPointerOrLocalIdObjectEncoder objectEncoder]]; + } else if ([object isKindOfClass:[PFACL class]]) { + // TODO (hallucinogen): pass object encoder here + return [object encodeIntoDictionary]; + + } else if ([object isKindOfClass:[PFGeoPoint class]]) { + // TODO (hallucinogen): pass object encoder here + return [object encodeIntoDictionary]; + + } else if ([object isKindOfClass:[PFRelation class]]) { + // TODO (hallucinogen): pass object encoder here + return [object encodeIntoDictionary]; + + } else if ([object isKindOfClass:[NSArray class]]) { + NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[object count]]; + for (id elem in object) { + [newArray addObject:[self encodeObject:elem]]; + } + return newArray; + + } else if ([object isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:[object count]]; + [object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + dict[key] = [self encodeObject:obj]; + }]; + return dict; + } + + return object; +} + +- (id)encodeParseObject:(PFObject *)object { + // Do nothing here + return nil; +} + +@end + +///-------------------------------------- +#pragma mark - PFNoObjectEncoder +///-------------------------------------- + +@implementation PFNoObjectEncoder + ++ (instancetype)objectEncoder { + static PFNoObjectEncoder *encoder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + encoder = [[PFNoObjectEncoder alloc] init]; + }); + return encoder; +} + +- (id)encodeParseObject:(PFObject *)object { + [NSException raise:NSInternalInconsistencyException format:@"PFObjects are not allowed here."]; + return nil; +} + +@end + +///-------------------------------------- +#pragma mark - PFPointerOrLocalIdObjectEncoder +///-------------------------------------- + +@implementation PFPointerOrLocalIdObjectEncoder + ++ (instancetype)objectEncoder { + static PFPointerOrLocalIdObjectEncoder *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[PFPointerOrLocalIdObjectEncoder alloc] init]; + }); + return instance; +} + +- (id)encodeParseObject:(PFObject *)object { + if (object.objectId) { + return @{ + @"__type" : @"Pointer", + @"objectId" : object.objectId, + @"className" : object.parseClassName + }; + } + return @{ + @"__type" : @"Pointer", + @"localId" : [object getOrCreateLocalId], + @"className" : object.parseClassName + }; +} + +@end + +///-------------------------------------- +#pragma mark - PFPointerObjectEncoder +///-------------------------------------- + +@implementation PFPointerObjectEncoder + ++ (instancetype)objectEncoder { + static PFPointerObjectEncoder *encoder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + encoder = [[self alloc] init]; + }); + return encoder; +} + +- (id)encodeParseObject:(PFObject *)object { + PFConsistencyAssert(object.objectId, @"Tried to save an object with a new, unsaved child."); + return [super encodeParseObject:object]; +} + +@end + +///-------------------------------------- +#pragma mark - PFOfflineObjectEncoder +///-------------------------------------- + +@interface PFOfflineObjectEncoder () + +@property (nonatomic, assign) PFOfflineStore *store; +@property (nonatomic, assign) PFSQLiteDatabase *database; +@property (nonatomic, strong) NSMutableArray *tasks; +@property (nonatomic, strong) NSObject *tasksLock; // TODO: (nlutsenko) Avoid using @synchronized + +@end + +@implementation PFOfflineObjectEncoder + ++ (instancetype)objectEncoder { + PFNotDesignatedInitializer(); + return nil; +} + ++ (instancetype)objectEncoderWithOfflineStore:(PFOfflineStore *)store database:(PFSQLiteDatabase *)database { + PFOfflineObjectEncoder *encoder = [[self alloc] init]; + encoder.store = store; + encoder.database = database; + encoder.tasks = [NSMutableArray array]; + encoder.tasksLock = [[NSObject alloc] init]; + return encoder; +} + +- (id)encodeParseObject:(PFObject *)object { + if (object.objectId) { + return @{ + @"__type" : @"Pointer", + @"objectId" : object.objectId, + @"className" : object.parseClassName + }; + } else { + NSMutableDictionary *result = [@{ @"__type" : @"OfflineObject" } mutableCopy]; + @synchronized(self.tasksLock) { + BFTask *uuidTask = [self.store getOrCreateUUIDAsyncForObject:object database:self.database]; + [uuidTask continueWithSuccessBlock:^id(BFTask *task) { + result[@"uuid"] = task.result; + return nil; + }]; + [self.tasks addObject:uuidTask]; + } + return result; + } +} + +- (BFTask *)encodeFinished { + return [[BFTask taskForCompletionOfAllTasks:self.tasks] continueWithBlock:^id(BFTask *ignore) { + @synchronized (self.tasksLock) { + // TODO (hallucinogen) It might be better to return an aggregate error here + for (BFTask *task in self.tasks) { + if (task.cancelled || task.error != nil) { + return task; + } + } + [self.tasks removeAllObjects]; + return [BFTask taskWithResult:nil]; + } + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.h new file mode 100644 index 0000000..a5656f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFErrorUtilities : NSObject + +/*! + Construct an error object from a code and a message. + + @description Note that this logs all errors given to it. + You should use `errorWithCode:message:shouldLog:` to explicitly control whether it logs. + + @param code Parse Error Code + @param message Error description + + @return Instance of `NSError` or `nil`. + */ ++ (nullable NSError *)errorWithCode:(NSInteger)code message:(NSString *)message; ++ (nullable NSError *)errorWithCode:(NSInteger)code message:(NSString *)message shouldLog:(BOOL)shouldLog; + +/*! + Construct an error object from a result dictionary the API returned. + + @description Note that this logs all errors given to it. + You should use `errorFromResult:shouldLog:` to explicitly control whether it logs. + + @param result Network command result. + + @return Instance of `NSError` or `nil`. + */ ++ (nullable NSError *)errorFromResult:(NSDictionary *)result; ++ (nullable NSError *)errorFromResult:(NSDictionary *)result shouldLog:(BOOL)shouldLog; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.m new file mode 100644 index 0000000..a3f060d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFErrorUtilities.m @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFErrorUtilities.h" + +#import "PFConstants.h" +#import "PFLogging.h" + +@implementation PFErrorUtilities + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message { + return [self errorWithCode:code message:message shouldLog:YES]; +} + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message shouldLog:(BOOL)shouldLog { + NSDictionary *result = @{ @"code" : @(code), + @"error" : message }; + return [self errorFromResult:result shouldLog:shouldLog]; +} + ++ (NSError *)errorFromResult:(NSDictionary *)result { + return [self errorFromResult:result shouldLog:YES]; +} + ++ (NSError *)errorFromResult:(NSDictionary *)result shouldLog:(BOOL)shouldLog { + NSInteger errorCode = [[result objectForKey:@"code"] integerValue]; + + NSString *errorExplanation = [result objectForKey:@"error"]; + + if (shouldLog) { + PFLogError(PFLoggingTagCommon, + @"%@ (Code: %ld, Version: %@)", errorExplanation, (long)errorCode, PARSE_VERSION); + } + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:result]; + if (errorExplanation) { + userInfo[NSLocalizedDescriptionKey] = errorExplanation; + } + return [NSError errorWithDomain:PFParseErrorDomain code:errorCode userInfo:userInfo]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.h new file mode 100644 index 0000000..de6e754 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.h @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObject.h" +#import "PFSubclassing.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@protocol PFNetworkCommand; + +extern NSString *const PFEventuallyPinPinName; + +// Cache policies +typedef NS_ENUM(NSUInteger, PFEventuallyPinType) { + PFEventuallyPinTypeSave = 1, + PFEventuallyPinTypeDelete, + PFEventuallyPinTypeCommand +}; + +/*! + PFEventuallyPin represents PFCommand that's save locally so that it can be executed eventually. + + Properties of PFEventuallyPin: + - time + Used for sort order when querying for all EventuallyPins. + - type + PFEventuallyPinTypeSave or PFEventuallyPinTypeDelete. + - object + The object the operation should notify when complete. + - operationSetUUID + The operationSet to be completed. + - sessionToken + The user that instantiated the operation. + */ +@interface PFEventuallyPin : PFObject + +@property (nonatomic, copy, readonly) NSString *uuid; + +@property (nonatomic, assign, readonly) PFEventuallyPinType type; + +@property (nonatomic, strong, readonly) PFObject *object; + +@property (nonatomic, copy, readonly) NSString *operationSetUUID; + +@property (nonatomic, copy, readonly) NSString *sessionToken; + +@property (nonatomic, strong, readonly) id command; + +///-------------------------------------- +#pragma mark - Eventually Pin +///-------------------------------------- + +/*! + Wrap given PFObject and PFCommand in a PFEventuallyPin with auto-generated UUID. + */ ++ (BFTask *)pinEventually:(PFObject *)object forCommand:(id)command; + +/*! + Wrap given PFObject and PFCommand in a PFEventuallyPin with given UUID. + */ ++ (BFTask *)pinEventually:(PFObject *)object forCommand:(id)command withUUID:(NSString *)uuid; + ++ (BFTask *)findAllEventuallyPin; + ++ (BFTask *)findAllEventuallyPinWithExcludeUUIDs:(NSArray *)excludeUUIDs; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.m new file mode 100644 index 0000000..aa9e0d4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyPin.m @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEventuallyPin.h" + +#import + +#import "PFAssert.h" +#import "PFHTTPRequest.h" +#import "PFInternalUtils.h" +#import "PFObject+Subclass.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFQuery.h" +#import "PFRESTCommand.h" + +NSString *const PFEventuallyPinPinName = @"_eventuallyPin"; + +NSString *const PFEventuallyPinKeyUUID = @"uuid"; +NSString *const PFEventuallyPinKeyTime = @"time"; +NSString *const PFEventuallyPinKeyType = @"type"; +NSString *const PFEventuallyPinKeyObject = @"object"; +NSString *const PFEventuallyPinKeyOperationSetUUID = @"operationSetUUID"; +NSString *const PFEventuallyPinKeySessionToken = @"sessionToken"; +NSString *const PFEventuallyPinKeyCommand = @"command"; + +@implementation PFEventuallyPin + +///-------------------------------------- +#pragma mark - PFSubclassing +///-------------------------------------- + ++ (NSString *)parseClassName { + return @"_EventuallyPin"; +} + +// Validates a class name. We override this to only allow the pin class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[self parseClassName]], + @"Cannot initialize a PFEventuallyPin with a custom class name."); +} + +- (BOOL)needsDefaultACL { + return NO; +} + +///-------------------------------------- +#pragma mark - Getter +///-------------------------------------- + +- (NSString *)uuid { + return self[PFEventuallyPinKeyUUID]; +} + +- (PFEventuallyPinType)type { + return [self[PFEventuallyPinKeyType] intValue]; +} + +- (PFObject *)object { + return self[PFEventuallyPinKeyObject]; +} + +- (NSString *)operationSetUUID { + return self[PFEventuallyPinKeyOperationSetUUID]; +} + +- (NSString *)sessionToken { + return self[PFEventuallyPinKeySessionToken]; +} + +- (id)command { + NSDictionary *dictionary = self[PFEventuallyPinKeyCommand]; + if ([PFRESTCommand isValidDictionaryRepresentation:dictionary]) { + return [PFRESTCommand commandFromDictionaryRepresentation:dictionary]; + } + return nil; +} + +///-------------------------------------- +#pragma mark - Eventually Pin +///-------------------------------------- + ++ (BFTask *)pinEventually:(PFObject *)object forCommand:(id)command { + return [self pinEventually:object forCommand:command withUUID:[[NSUUID UUID] UUIDString]]; +} + ++ (BFTask *)pinEventually:(PFObject *)object forCommand:(id)command withUUID:(NSString *)uuid { + PFEventuallyPinType type = [self _pinTypeForCommand:command]; + NSDictionary *commandDictionary = (type == PFEventuallyPinTypeCommand ? [command dictionaryRepresentation] : nil); + return [self _pinEventually:object + type:type + uuid:uuid + operationSetUUID:command.operationSetUUID + sessionToken:command.sessionToken + commandDictionary:commandDictionary]; +} + ++ (BFTask *)findAllEventuallyPin { + return [self findAllEventuallyPinWithExcludeUUIDs:nil]; +} + ++ (BFTask *)findAllEventuallyPinWithExcludeUUIDs:(NSArray *)excludeUUIDs { + PFQuery *query = [PFQuery queryWithClassName:self.parseClassName]; + [query fromPinWithName:PFEventuallyPinPinName]; + [query orderByAscending:PFEventuallyPinKeyTime]; + + if (excludeUUIDs != nil) { + [query whereKey:PFEventuallyPinKeyUUID notContainedIn:excludeUUIDs]; + } + + return [[query findObjectsInBackground] continueWithBlock:^id(BFTask *task) { + NSArray *pins = task.result; + NSMutableArray *fetchTasks = [NSMutableArray array]; + + for (PFEventuallyPin *pin in pins) { + PFObject *object = pin.object; + if (object != nil) { + [fetchTasks addObject:[object fetchFromLocalDatastoreInBackground]]; + } + } + + return [[BFTask taskForCompletionOfAllTasks:fetchTasks] continueWithBlock:^id(BFTask *task) { + return [BFTask taskWithResult:pins]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + ++ (BFTask *)_pinEventually:(PFObject *)object + type:(PFEventuallyPinType)type + uuid:(NSString *)uuid + operationSetUUID:(NSString *)operationSetUUID + sessionToken:(NSString *)sessionToken + commandDictionary:(NSDictionary *)commandDictionary { + PFEventuallyPin *pin = [[PFEventuallyPin alloc] init]; + pin[PFEventuallyPinKeyUUID] = uuid; + pin[PFEventuallyPinKeyTime] = [NSDate date]; + pin[PFEventuallyPinKeyType] = @(type); + if (object != nil) { + pin[PFEventuallyPinKeyObject] = object; + } + if (operationSetUUID != nil) { + pin[PFEventuallyPinKeyOperationSetUUID] = operationSetUUID; + } + if (sessionToken != nil) { + pin[PFEventuallyPinKeySessionToken] = sessionToken; + } + if (commandDictionary != nil) { + pin[PFEventuallyPinKeyCommand] = commandDictionary; + } + + // NOTE: This is needed otherwise ARC releases the pins before we have a chance to persist the new ones to disk, + // Which means we'd lose any columns on objects in eventually pins not currently in memory. + __block NSArray *existingPins = nil; + return [[[self findAllEventuallyPin] continueWithSuccessBlock:^id(BFTask *task) { + existingPins = task.result; + return [pin pinInBackgroundWithName:PFEventuallyPinPinName]; + }] continueWithSuccessBlock:^id(BFTask *task) { + existingPins = nil; + return pin; + }]; +} + ++ (PFEventuallyPinType)_pinTypeForCommand:(id)command { + PFEventuallyPinType type = PFEventuallyPinTypeCommand; + NSString *path = [(PFRESTCommand *)command httpPath]; + NSString *method = [(PFRESTCommand *)command httpMethod]; + if ([path hasPrefix:@"classes"]) { + if ([method isEqualToString:PFHTTPRequestMethodPOST] || + [method isEqualToString:PFHTTPRequestMethodPUT]) { + type = PFEventuallyPinTypeSave; + } else if ([method isEqualToString:PFHTTPRequestMethodDELETE]) { + type = PFEventuallyPinTypeDelete; + } + } + return type; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.h new file mode 100644 index 0000000..0ac4ea1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.h @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" +#import "PFNetworkCommand.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFEventuallyPin; +@class PFEventuallyQueueTestHelper; +@class PFObject; +@protocol PFCommandRunning; + +extern NSUInteger const PFEventuallyQueueDefaultMaxAttemptsCount; +extern NSTimeInterval const PFEventuallyQueueDefaultTimeoutRetryInterval; + +@interface PFEventuallyQueue : NSObject + +@property (nonatomic, strong, readonly) id commandRunner; + +@property (nonatomic, assign, readonly) NSUInteger maxAttemptsCount; +@property (nonatomic, assign, readonly) NSTimeInterval retryInterval; + +@property (nonatomic, assign, readonly) NSUInteger commandCount; + +/*! + Controls whether the queue should monitor network reachability and pause itself when there is no connection. + Default: `YES`. + */ +@property (atomic, assign, readonly) BOOL monitorsReachability PF_WATCH_UNAVAILABLE; +@property (nonatomic, assign, readonly, getter=isConnected) BOOL connected; + +// Gets notifications of various events happening in the command cache, so that tests can be synchronized. +@property (nonatomic, strong, readonly) PFEventuallyQueueTestHelper *testHelper; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval NS_DESIGNATED_INITIALIZER; + +///-------------------------------------- +/// @name Running Commands +///-------------------------------------- + +- (BFTask *)enqueueCommandInBackground:(id)command; +- (BFTask *)enqueueCommandInBackground:(id)command withObject:(PFObject *)object; + +///-------------------------------------- +/// @name Controlling Queue +///-------------------------------------- + +- (void)start NS_REQUIRES_SUPER; +- (void)resume NS_REQUIRES_SUPER; +- (void)pause NS_REQUIRES_SUPER; + +- (void)removeAllCommands NS_REQUIRES_SUPER; + +@end + +typedef enum { + PFEventuallyQueueEventCommandEnqueued, // A command was placed into the queue. + PFEventuallyQueueEventCommandNotEnqueued, // A command could not be placed into the queue. + + PFEventuallyQueueEventCommandSucceded, // A command has successfully running on the server. + PFEventuallyQueueEventCommandFailed, // A command has failed on the server. + + PFEventuallyQueueEventObjectUpdated, // An object's data was updated after a command completed. + PFEventuallyQueueEventObjectRemoved, // An object was removed because it was deleted before creation. + + PFEventuallyQueueEventCount // The total number of items in this enum. +} PFEventuallyQueueTestHelperEvent; + +@interface PFEventuallyQueueTestHelper : NSObject { + dispatch_semaphore_t events[PFEventuallyQueueEventCount]; +} + +- (void)clear; +- (void)notify:(PFEventuallyQueueTestHelperEvent)event; +- (BOOL)waitFor:(PFEventuallyQueueTestHelperEvent)event; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.m new file mode 100644 index 0000000..80e025d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue.m @@ -0,0 +1,503 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEventuallyQueue.h" +#import "PFEventuallyQueue_Private.h" + +#import +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFErrorUtilities.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFRESTCommand.h" +#import "PFReachability.h" +#import "PFTaskQueue.h" + +NSUInteger const PFEventuallyQueueDefaultMaxAttemptsCount = 5; +NSTimeInterval const PFEventuallyQueueDefaultTimeoutRetryInterval = 600.0f; + +@interface PFEventuallyQueue () +#if !TARGET_OS_WATCH + +#endif + +@property (atomic, assign, readwrite) BOOL monitorsReachability; +@property (atomic, assign, getter=isRunning) BOOL running; + +@end + +@implementation PFEventuallyQueue + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval { + self = [super init]; + if (!self) return nil; + + _commandRunner = commandRunner; + _maxAttemptsCount = attemptsCount; + _retryInterval = retryInterval; + + // Set up all the queues + NSString *queueBaseLabel = [NSString stringWithFormat:@"com.parse.%@", NSStringFromClass([self class])]; + + _synchronizationQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.synchronization", + queueBaseLabel] UTF8String], + DISPATCH_QUEUE_SERIAL); + PFMarkDispatchQueue(_synchronizationQueue); + _synchronizationExecutor = [BFExecutor executorWithDispatchQueue:_synchronizationQueue]; + + _processingQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.processing", + queueBaseLabel] UTF8String], + DISPATCH_QUEUE_SERIAL); + PFMarkDispatchQueue(_processingQueue); + + _processingQueueSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, _processingQueue); + + _commandEnqueueTaskQueue = [[PFTaskQueue alloc] init]; + + _taskCompletionSources = [NSMutableDictionary dictionary]; + _testHelper = [[PFEventuallyQueueTestHelper alloc] init]; + + [self _startMonitoringNetworkReachability]; + + return self; +} + +- (void)dealloc { + [self _stopMonitoringNetworkReachability]; +} + +///-------------------------------------- +#pragma mark - Enqueueing Commands +///-------------------------------------- + +- (BFTask *)enqueueCommandInBackground:(id)command { + return [self enqueueCommandInBackground:command withObject:nil]; +} + +- (BFTask *)enqueueCommandInBackground:(id)command withObject:(PFObject *)object { + PFParameterAssert(command, @"Cannot enqueue nil command."); + + BFTaskCompletionSource *taskCompletionSource = [BFTaskCompletionSource taskCompletionSource]; + + @weakify(self); + [_commandEnqueueTaskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + @strongify(self); + + NSString *identifier = [self _newIdentifierForCommand:command]; + return [[[self _enqueueCommandInBackground:command + object:object + identifier:identifier] continueWithBlock:^id(BFTask *task) { + if (task.error || task.exception || task.cancelled) { + [self.testHelper notify:PFEventuallyQueueEventCommandNotEnqueued]; + if (task.error) { + taskCompletionSource.error = task.error; + } else if (task.exception) { + taskCompletionSource.exception = task.exception; + } else if (task.cancelled) { + [taskCompletionSource cancel]; + } + } else { + [self.testHelper notify:PFEventuallyQueueEventCommandEnqueued]; + } + + return task; + }] continueWithExecutor:_synchronizationExecutor withSuccessBlock:^id(BFTask *task) { + [self _didEnqueueCommand:command withIdentifier:identifier taskCompletionSource:taskCompletionSource]; + return nil; + }]; + }]; + }]; + + return taskCompletionSource.task; +} + +- (BFTask *)_enqueueCommandInBackground:(id)command + object:(PFObject *)object + identifier:(NSString *)identifier { + // This enforces implementing this method in subclasses + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (void)_didEnqueueCommand:(id)command + withIdentifier:(NSString *)identifier + taskCompletionSource:(BFTaskCompletionSource *)taskCompletionSource { + PFAssertIsOnDispatchQueue(_synchronizationQueue); + + _taskCompletionSources[identifier] = taskCompletionSource; + dispatch_source_merge_data(_processingQueueSource, 1); + + if (_retryingSemaphore) { + dispatch_semaphore_signal(_retryingSemaphore); + } +} + +///-------------------------------------- +#pragma mark - Pending Commands +///-------------------------------------- + +- (NSArray *)_pendingCommandIdentifiers { + return nil; +} + +- (id)_commandWithIdentifier:(NSString *)identifier error:(NSError **)error { + return nil; +} + +- (NSString *)_newIdentifierForCommand:(id)command { + return nil; +} + +- (NSUInteger)commandCount { + return [[self _pendingCommandIdentifiers] count]; +} + +///-------------------------------------- +#pragma mark - Controlling Queue +///-------------------------------------- + +- (void)start { + dispatch_source_set_event_handler(_processingQueueSource, ^{ + [self _runCommands]; + }); + [self resume]; +} + +- (void)resume { + if (self.running) { + return; + } + self.running = YES; + dispatch_resume(_processingQueueSource); + dispatch_source_merge_data(_processingQueueSource, 1); +} + +- (void)pause { + if (!self.running) { + return; + } + self.running = NO; + dispatch_suspend(_processingQueueSource); +} + +- (void)removeAllCommands { + dispatch_sync(_synchronizationQueue, ^{ + [_taskCompletionSources removeAllObjects]; + }); +} + +///-------------------------------------- +#pragma mark - Running Commands +///-------------------------------------- + +- (void)_runCommands { + PFAssertIsOnDispatchQueue(_processingQueue); + + [self _runCommandsWithRetriesCount:self.maxAttemptsCount]; +} + +- (void)_runCommandsWithRetriesCount:(NSUInteger)retriesCount { + PFAssertIsOnDispatchQueue(_processingQueue); + + if (!self.running || !self.connected) { + return; + } + + // Expect sorted result from _pendingCommandIdentifiers + NSArray *commandIdentifiers = [self _pendingCommandIdentifiers]; + BOOL shouldRetry = NO; + for (NSString *identifier in commandIdentifiers) { + NSError *error = nil; + id command = [self _commandWithIdentifier:identifier error:&error]; + if (!command || error) { + if (!error) { + error = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:@"Failed to dequeue an eventually command." + shouldLog:NO]; + } + BFTask *task = [BFTask taskWithError:error]; + [self _didFinishRunningCommand:command withIdentifier:identifier resultTask:task]; + continue; + } + + __block BFTaskCompletionSource *taskCompletionSource = nil; + dispatch_sync(_synchronizationQueue, ^{ + taskCompletionSource = _taskCompletionSources[identifier]; + }); + + BFTask *resultTask = nil; + PFCommandResult *result = nil; + @try { + resultTask = [self _runCommand:command withIdentifier:identifier]; + result = [resultTask waitForResult:&error]; + } + @catch (NSException *exception) { + error = [NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorInvalidPointer + userInfo:@{ @"message" : @"Failed to run an eventually command.", + @"exception" : exception }]; + resultTask = [BFTask taskWithError:error]; + } + + if (error) { + BOOL permanent = (![error.userInfo[@"temporary"] boolValue] && + ([[error domain] isEqualToString:PFParseErrorDomain] || + [error code] != kPFErrorConnectionFailed)); + + if (!permanent) { + PFLogWarning(PFLoggingTagCommon, + @"Attempt at runEventually command timed out. Waiting %f seconds. %d retries remaining.", + self.retryInterval, + (int)retriesCount); + + __block dispatch_semaphore_t semaphore = NULL; + dispatch_sync(_synchronizationQueue, ^{ + _retryingSemaphore = dispatch_semaphore_create(0); + semaphore = _retryingSemaphore; + }); + + dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, + (int64_t)(self.retryInterval * NSEC_PER_SEC)); + + long waitResult = dispatch_semaphore_wait(semaphore, timeoutTime); + dispatch_sync(_synchronizationQueue, ^{ + _retryingSemaphore = NULL; + }); + + if (waitResult == 0) { + // We haven't waited long enough, but if we lost the connection, or should stop, just quit. + return; + } + + // We need to go out of the loop. + if (retriesCount > 0) { + shouldRetry = YES; + break; + } + } + + PFLogError(PFLoggingTagCommon, @"Failed to run command eventually with error: %@", error); + } + + // Post processing shouldn't make the queue retry the command. + resultTask = [self _didFinishRunningCommand:command withIdentifier:identifier resultTask:resultTask]; + [resultTask waitForResult:nil]; + + // Notify anyone waiting that the operation is completed. + if (resultTask.error) { + taskCompletionSource.error = resultTask.error; + } else if (resultTask.exception) { + taskCompletionSource.exception = resultTask.exception; + } else if (resultTask.cancelled) { + [taskCompletionSource cancel]; + } else { + taskCompletionSource.result = resultTask.result; + } + } + + // Retry here so that we're in cleaner state. + if (shouldRetry) { + return [self _runCommandsWithRetriesCount:(retriesCount - 1)]; + } +} + +- (BFTask *)_runCommand:(id)command withIdentifier:(NSString *)identifier { + if ([command isKindOfClass:[PFRESTCommand class]]) { + return [self.commandRunner runCommandAsync:(PFRESTCommand *)command withOptions:0]; + } + + NSString *reason = [NSString stringWithFormat:@"Can't find a compatible runner for command %@.", command]; + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:reason + userInfo:nil]; + return [BFTask taskWithException:exception]; +} + +- (BFTask *)_didFinishRunningCommand:(id)command + withIdentifier:(NSString *)identifier + resultTask:(BFTask *)resultTask { + PFConsistencyAssert(resultTask.completed, @"Task should be completed."); + + dispatch_sync(_synchronizationQueue, ^{ + [_taskCompletionSources removeObjectForKey:identifier]; + }); + + if (resultTask.exception || resultTask.error || resultTask.cancelled) { + [self.testHelper notify:PFEventuallyQueueEventCommandFailed]; + } else { + [self.testHelper notify:PFEventuallyQueueEventCommandSucceded]; + } + + return resultTask; +} + +- (BFTask *)_waitForOperationSet:(PFOperationSet *)operationSet + eventuallyPin:(PFEventuallyPin *)eventuallyPin { + return [BFTask taskWithResult:nil]; +} + +///-------------------------------------- +#pragma mark - Reachability +///-------------------------------------- + +- (void)_startMonitoringNetworkReachability { +#if TARGET_OS_WATCH + self.connected = YES; +#else + if (self.monitorsReachability) { + return; + } + self.monitorsReachability = YES; + + [[PFReachability sharedParseReachability] addListener:self]; + + // Set the initial connected status + self.connected = ([PFReachability sharedParseReachability].currentState != PFReachabilityStateNotReachable); +#endif +} + +- (void)_stopMonitoringNetworkReachability { +#if !TARGET_OS_WATCH + if (!self.monitorsReachability) { + return; + } + + [[PFReachability sharedParseReachability] removeListener:self]; + + self.monitorsReachability = NO; + self.connected = YES; +#endif +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +/*! Manually sets the network connection status. */ +- (void)setConnected:(BOOL)connected { + BFTaskCompletionSource *barrier = [BFTaskCompletionSource taskCompletionSource]; + dispatch_async(_processingQueue, ^{ + dispatch_sync(_synchronizationQueue, ^{ + if (self.connected != connected) { + _connected = connected; + if (connected) { + dispatch_source_merge_data(_processingQueueSource, 1); + } + } + }); + barrier.result = nil; + }); + if (connected) { + dispatch_async(_synchronizationQueue, ^{ + if (_retryingSemaphore) { + dispatch_semaphore_signal(_retryingSemaphore); + } + }); + } + [barrier.task waitForResult:nil]; +} + +///-------------------------------------- +#pragma mark - Test Helper Method +///-------------------------------------- + +/*! Makes this command cache forget all the state it keeps during a single run of the app. */ +- (void)_simulateReboot { + // Make sure there is no command pending enqueuing + [[[[_commandEnqueueTaskQueue enqueue:^BFTask *(BFTask *toAwait) { + return toAwait; + }] continueWithExecutor:_synchronizationExecutor withBlock:^id(BFTask *task) { + // Remove all state task completion sources + [_taskCompletionSources removeAllObjects]; + return nil; + }] continueWithExecutor:[BFExecutor executorWithDispatchQueue:_processingQueue] withBlock:^id(BFTask *task) { + // Let all operations in the queue run at least once + return nil; + }] waitUntilFinished]; +} + +/*! Test helper to return how many commands are being retained in memory by the cache. */ +- (int)_commandsInMemory { + return (int)[_taskCompletionSources count]; +} + +/*! Called by PFObject whenever an object has been updated after a saveEventually. */ +- (void)_notifyTestHelperObjectUpdated { + [self.testHelper notify:PFEventuallyQueueEventObjectUpdated]; +} + +- (void)_setMaxAttemptsCount:(NSUInteger)attemptsCount { + _maxAttemptsCount = attemptsCount; +} + +- (void)_setRetryInterval:(NSTimeInterval)retryInterval { + _retryInterval = retryInterval; +} + +#if !TARGET_OS_WATCH + +///-------------------------------------- +#pragma mark - Reachability +///-------------------------------------- + +- (void)reachability:(PFReachability *)reachability didChangeReachabilityState:(PFReachabilityState)state { + if (self.monitorsReachability) { + self.connected = (state != PFReachabilityStateNotReachable); + } +} + +#endif + +@end + +// PFEventuallyQueueTestHelper gets notifications of various events happening in the command cache, +// so that tests can be synchronized. See CommandTests.m for examples of how to use this. + +@implementation PFEventuallyQueueTestHelper + +- (instancetype)init { + self = [super init]; + if (self) { + [self clear]; + } + return self; +} + +- (void)clear { + for (int i = 0; i < PFEventuallyQueueEventCount; ++i) { + events[i] = dispatch_semaphore_create(0); + } +} + +- (void)notify:(PFEventuallyQueueTestHelperEvent)event { + dispatch_semaphore_signal(events[event]); +} + +- (BOOL)waitFor:(PFEventuallyQueueTestHelperEvent)event { + // Wait 1 second for a permit from the semaphore. + return (dispatch_semaphore_wait(events[event], dispatch_time(DISPATCH_TIME_NOW, 10LL * NSEC_PER_SEC)) == 0); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue_Private.h new file mode 100644 index 0000000..3e576f3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFEventuallyQueue_Private.h @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEventuallyQueue.h" + +@class BFExecutor; +@class PFEventuallyPin; +@class PFObject; +@class PFOperationSet; +@class PFTaskQueue; + +extern NSUInteger const PFEventuallyQueueDefaultMaxAttemptsCount; +extern NSTimeInterval const PFEventuallyQueueDefaultTimeoutRetryInterval; + +@class BFTaskCompletionSource; + +@interface PFEventuallyQueue () +{ +@protected + BFExecutor *_synchronizationExecutor; + dispatch_queue_t _synchronizationQueue; + +@private + dispatch_queue_t _processingQueue; + dispatch_source_t _processingQueueSource; + + dispatch_semaphore_t _retryingSemaphore; + + NSMutableDictionary *_taskCompletionSources; + + /*! + Task queue that will enqueue command enqueueing task so that we enqueue the command + one at a time. + */ + PFTaskQueue *_commandEnqueueTaskQueue; +} + +@property (nonatomic, assign, readwrite, getter=isConnected) BOOL connected; + +/*! + This method is used to do some work after the command is finished running and + either succeeded or dropped from queue with error/exception. + + @param command Command that was run. + @param identifier Unique identifier of the command + @param resultTask Task that represents the result of running a command. + @returns A continuation task in case the EventuallyQueue need to do something. + Typically this will return back given resultTask. + */ +- (BFTask *)_didFinishRunningCommand:(id)command + withIdentifier:(NSString *)identifier + resultTask:(BFTask *)resultTask; + +///-------------------------------------- +/// @name Reachability +///-------------------------------------- + +- (void)_startMonitoringNetworkReachability; +- (void)_stopMonitoringNetworkReachability; + +///-------------------------------------- +/// @name Test Helper +///-------------------------------------- + +- (void)_setMaxAttemptsCount:(NSUInteger)attemptsCount; + +- (void)_setRetryInterval:(NSTimeInterval)retryInterval; + +- (void)_simulateReboot NS_REQUIRES_SUPER; + +- (int)_commandsInMemory; + +- (void)_notifyTestHelperObjectUpdated; + +@end + +@protocol PFEventuallyQueueSubclass + +///-------------------------------------- +/// @name Pending Commands +///-------------------------------------- + + +/*! + Generates a new identifier for a command so that it can be sorted later by this identifier. + */ +- (NSString *)_newIdentifierForCommand:(id)command; + +/*! + This method is triggered on batch processing of the queue. + It will capture the identifiers and use them to execute commands. + + @returns An array of identifiers of all commands that are pending sorted by the order they're enqueued. + */ +- (NSArray *)_pendingCommandIdentifiers; + +/*! + This method should return a command for a given identifier. + + @param identifier An identifier of a command, that was in array returned by <_pendingCommandIdentifiers> + @param error Pointer to `NSError *` that should be set if the method failed to construct/retrieve a command. + + @returns A command that needs to be run, or `nil` if there was an error. + */ +- (id)_commandWithIdentifier:(NSString *)identifier error:(NSError **)error; + +///-------------------------------------- +/// @name Running Commands +///-------------------------------------- + +/*! + This method serves as a way to do any kind of work to enqueue a command properly. + If the task fails with an error/exception or is cancelled - execution won't start. + + @param command Command that needs to be enqueued + @param object The object on which the command is run against. + @param identifier Unique identifier used to represent a command. + @returns Task that is resolved when the command is complete enqueueing. + */ +- (BFTask *)_enqueueCommandInBackground:(id)command + object:(PFObject *)object + identifier:(NSString *)identifier; + +- (BFTask *)_waitForOperationSet:(PFOperationSet *)operationSet + eventuallyPin:(PFEventuallyPin *)eventuallyPin; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.h new file mode 100644 index 0000000..91e5700 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.h @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFExecutor; +@class BFTask PF_GENERIC(__covariant BFGenericType); + +typedef NS_OPTIONS(uint8_t, PFFileManagerOptions) { + PFFileManagerOptionSkipBackup = 1 << 0, +}; + +@interface PFFileManager : NSObject + +///-------------------------------------- +/// @name Class +///-------------------------------------- + ++ (BOOL)isApplicationGroupContainerReachableForGroupIdentifier:(NSString *)applicationGroup; + ++ (BFTask *)createDirectoryIfNeededAsyncAtPath:(NSString *)path; ++ (BFTask *)createDirectoryIfNeededAsyncAtPath:(NSString *)path + withOptions:(PFFileManagerOptions)options + executor:(BFExecutor *)executor; + ++ (BFTask *)writeStringAsync:(NSString *)string toFile:(NSString *)filePath; ++ (BFTask *)writeDataAsync:(NSData *)data toFile:(NSString *)filePath; + ++ (BFTask *)copyItemAsyncAtPath:(NSString *)fromPath toPath:(NSString *)toPath; ++ (BFTask *)moveItemAsyncAtPath:(NSString *)fromPath toPath:(NSString *)toPath; + ++ (BFTask *)moveContentsOfDirectoryAsyncAtPath:(NSString *)fromPath + toDirectoryAtPath:(NSString *)toPath + executor:(BFExecutor *)executor; + ++ (BFTask *)removeItemAtPathAsync:(NSString *)path; ++ (BFTask *)removeItemAtPathAsync:(NSString *)path withFileLock:(BOOL)useFileLock; ++ (BFTask *)removeDirectoryContentsAsyncAtPath:(NSString *)path; + +///-------------------------------------- +/// @name Instance +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithApplicationIdentifier:(NSString *)applicationIdentifier + applicationGroupIdentifier:(NSString *)applicationGroupIdentifier NS_DESIGNATED_INITIALIZER; + +/*! + Returns /Library/Private Documents/Parse + for non-user generated data that shouldn't be deleted by iOS, such as "offline data". + + See https://developer.apple.com/library/ios/#qa/qa1699/_index.html + */ +- (NSString *)parseDefaultDataDirectoryPath; +- (NSString *)parseLocalSandboxDataDirectoryPath; +- (NSString *)parseDataDirectoryPath_DEPRECATED; + +/*! + The path including directories that we save data to for a given filename. + If the file isn't found in the new "Private Documents" location, but is in the old "Documents" location, + moves it and returns the new location. + */ +- (NSString *)parseDataItemPathForPathComponent:(NSString *)pathComponent; + +- (NSString *)parseCacheItemPathForPathComponent:(NSString *)component; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.m new file mode 100644 index 0000000..a48a6c8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFFileManager.m @@ -0,0 +1,367 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFileManager.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFLogging.h" +#import "PFMultiProcessFileLockController.h" + +static NSString *const _PFFileManagerParseDirectoryName = @"Parse"; + +static NSDictionary *_PFFileManagerDefaultDirectoryFileAttributes() { +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + return @{ NSFileProtectionKey : NSFileProtectionCompleteUntilFirstUserAuthentication }; +#else + return nil; +#endif +} + +static NSDataWritingOptions _PFFileManagerDefaultDataWritingOptions() { + NSDataWritingOptions options = NSDataWritingAtomic; +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + options |= NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication; +#endif + return options; +} + +@interface PFFileManager () + +@property (nonatomic, copy) NSString *applicationIdentifier; +@property (nonatomic, copy) NSString *applicationGroupIdentifier; + +@end + +@implementation PFFileManager + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (BOOL)isApplicationGroupContainerReachableForGroupIdentifier:(NSString *)applicationGroup { + return ([[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:applicationGroup] != nil); +} + ++ (BFTask *)writeStringAsync:(NSString *)string toFile:(NSString *)filePath { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; + return [self writeDataAsync:data toFile:filePath]; + }]; +} + ++ (BFTask *)writeDataAsync:(NSData *)data toFile:(NSString *)filePath { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSError *error = nil; + [data writeToFile:filePath + options:_PFFileManagerDefaultDataWritingOptions() + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + ++ (BFTask *)createDirectoryIfNeededAsyncAtPath:(NSString *)path { + return [self createDirectoryIfNeededAsyncAtPath:path + withOptions:PFFileManagerOptionSkipBackup + executor:[BFExecutor defaultPriorityBackgroundExecutor]]; +} + ++ (BFTask *)createDirectoryIfNeededAsyncAtPath:(NSString *)path + withOptions:(PFFileManagerOptions)options + executor:(BFExecutor *)executor { + return [BFTask taskFromExecutor:executor withBlock:^id{ + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + NSError *error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:_PFFileManagerDefaultDirectoryFileAttributes() + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + } + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + if (options & PFFileManagerOptionSkipBackup) { + [self _skipBackupOnPath:path]; + } +#endif + return nil; + }]; +} + ++ (BFTask *)copyItemAsyncAtPath:(NSString *)fromPath toPath:(NSString *)toPath { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSError *error = nil; + [[NSFileManager defaultManager] copyItemAtPath:fromPath toPath:toPath error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + ++ (BFTask *)moveItemAsyncAtPath:(NSString *)fromPath toPath:(NSString *)toPath { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSError *error = nil; + [[NSFileManager defaultManager] moveItemAtPath:fromPath toPath:toPath error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + ++ (BFTask *)moveContentsOfDirectoryAsyncAtPath:(NSString *)fromPath + toDirectoryAtPath:(NSString *)toPath + executor:(BFExecutor *)executor { + if ([fromPath isEqualToString:toPath]) { + return [BFTask taskWithResult:nil]; + } + + return [[[self createDirectoryIfNeededAsyncAtPath:toPath + withOptions:PFFileManagerOptionSkipBackup + executor:executor] continueWithSuccessBlock:^id(BFTask *task) { + NSError *error = nil; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:fromPath + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return contents; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *contents = task.result; + if ([contents count] == 0) { + return nil; + } + + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:[contents count]]; + for (NSString *path in contents) { + BFTask *task = [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSError *error = nil; + NSString *fromFilePath = [fromPath stringByAppendingPathComponent:path]; + NSString *toFilePath = [toPath stringByAppendingPathComponent:path]; + [[NSFileManager defaultManager] moveItemAtPath:fromFilePath + toPath:toFilePath + error:&error]; + if (error) { + return [BFTask taskWithError:error]; + } + return nil; + }]; + [tasks addObject:task]; + } + return [BFTask taskForCompletionOfAllTasks:tasks]; + }]; +} + ++ (BFTask *)removeDirectoryContentsAsyncAtPath:(NSString *)path { + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:path]; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSError *error = nil; + NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:path error:&error]; + if (error) { + PFLogError(PFLoggingTagCommon, @"Failed to list directory: %@", path); + return [BFTask taskWithError:error]; + } + + NSMutableArray *fileTasks = [NSMutableArray array]; + for (NSString *fileName in fileNames) { + NSString *filePath = [path stringByAppendingPathComponent:fileName]; + BFTask *fileTask = [[self removeItemAtPathAsync:filePath withFileLock:NO] continueWithBlock:^id(BFTask *task) { + if (task.faulted) { + PFLogError(PFLoggingTagCommon, @"Failed to delete file: %@ with error: %@", filePath, task.error); + } + return task; + }]; + [fileTasks addObject:fileTask]; + } + return [BFTask taskForCompletionOfAllTasks:fileTasks]; + }] continueWithBlock:^id(BFTask *task) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:path]; + return task; + }]; +} + ++ (BFTask *)removeItemAtPathAsync:(NSString *)path { + return [self removeItemAtPathAsync:path withFileLock:YES]; +} + ++ (BFTask *)removeItemAtPathAsync:(NSString *)path withFileLock:(BOOL)useFileLock { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + if (useFileLock) { + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:path]; + } + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:path]) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; + if (error) { + if (useFileLock) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:path]; + } + return [BFTask taskWithError:error]; + } + } + if (useFileLock) { + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:path]; + } + return nil; + }]; +} + +///-------------------------------------- +#pragma mark - Instance +///-------------------------------------- + +#pragma mark Init + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithApplicationIdentifier:(NSString *)applicationIdentifier + applicationGroupIdentifier:(NSString *)applicationGroupIdentifier { + self = [super init]; + if (!self) return nil; + + _applicationIdentifier = [applicationIdentifier copy]; + _applicationGroupIdentifier = [applicationGroupIdentifier copy]; + + return self; +} + +#pragma mark Public + +- (NSString *)parseDefaultDataDirectoryPath { + // NSHomeDirectory: Returns the path to either the user's or application's + // home directory, depending on the platform. Sandboxed by default on iOS. +#if PARSE_IOS_ONLY + NSString *directoryPath = nil; + if (self.applicationGroupIdentifier) { + NSURL *containerPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:self.applicationGroupIdentifier]; + directoryPath = [[containerPath path] stringByAppendingPathComponent:_PFFileManagerParseDirectoryName]; + directoryPath = [directoryPath stringByAppendingPathComponent:self.applicationIdentifier]; + } else { + return [self parseLocalSandboxDataDirectoryPath]; + } +#else + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString *directoryPath = [paths firstObject]; + directoryPath = [directoryPath stringByAppendingPathComponent:_PFFileManagerParseDirectoryName]; + directoryPath = [directoryPath stringByAppendingPathComponent:self.applicationIdentifier]; +#endif + + BFTask *createDirectoryTask = [[self class] createDirectoryIfNeededAsyncAtPath:directoryPath + withOptions:PFFileManagerOptionSkipBackup + executor:[BFExecutor immediateExecutor]]; + [createDirectoryTask waitForResult:nil withMainThreadWarning:NO]; + + return directoryPath; +} + +- (NSString *)parseLocalSandboxDataDirectoryPath { +#if TARGET_OS_IPHONE + NSString *library = [NSHomeDirectory() stringByAppendingPathComponent:@"Library"]; + NSString *privateDocuments = [library stringByAppendingPathComponent:@"Private Documents"]; + NSString *directoryPath = [privateDocuments stringByAppendingPathComponent:_PFFileManagerParseDirectoryName]; + BFTask *createDirectoryTask = [[self class] createDirectoryIfNeededAsyncAtPath:directoryPath + withOptions:PFFileManagerOptionSkipBackup + executor:[BFExecutor immediateExecutor]]; + [createDirectoryTask waitForResult:nil withMainThreadWarning:NO]; + + return directoryPath; +#else + return [self parseDefaultDataDirectoryPath]; +#endif +} + +- (NSString *)parseDataDirectoryPath_DEPRECATED { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder + NSString *parseDirPath = [documentsDirectory stringByAppendingPathComponent:_PFFileManagerParseDirectoryName]; + + // If this old directory is still on disk, but empty, delete it. + if ([[NSFileManager defaultManager] fileExistsAtPath:parseDirPath]) { + NSError *error = nil; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:parseDirPath error:&error]; + if (error == nil && [contents count] == 0) { + [[NSFileManager defaultManager] removeItemAtPath:parseDirPath error:nil]; + } + } + + return parseDirPath; +} + +- (NSString *)parseDataItemPathForPathComponent:(NSString *)pathComponent { + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *currentLocation = [[self parseDefaultDataDirectoryPath] stringByAppendingPathComponent:pathComponent]; + if (![fileManager fileExistsAtPath:currentLocation]) { + NSString *deprecatedDir = [self parseDataDirectoryPath_DEPRECATED]; + NSString *deprecatedLocation = [deprecatedDir stringByAppendingPathComponent:pathComponent]; + if ([fileManager fileExistsAtPath:deprecatedLocation]) { + [fileManager moveItemAtPath:deprecatedLocation toPath:currentLocation error:nil]; + // If the deprecated dir is still on disk, delete it. + if ([fileManager fileExistsAtPath:deprecatedDir]) { + NSError *error = nil; + NSArray *contents = [fileManager contentsOfDirectoryAtPath:deprecatedDir error:&error]; + if (!error && [contents count] == 0) { + [fileManager removeItemAtPath:deprecatedDir error:nil]; + } + } + } + } + return currentLocation; +} + +- (NSString *)parseCacheItemPathForPathComponent:(NSString *)component { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *folderPath = [paths firstObject]; + folderPath = [folderPath stringByAppendingPathComponent:_PFFileManagerParseDirectoryName]; +#if !TARGET_OS_IPHONE + // We append the applicationId in case the OS X application isn't sandboxed, + // to avoid collisions in the generic ~/Library/Caches/Parse/------ dir. + folderPath = [folderPath stringByAppendingPathComponent:self.applicationIdentifier]; +#endif + folderPath = [folderPath stringByAppendingPathComponent:component]; + return [folderPath stringByStandardizingPath]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +// Skips all backups on the provided path. ++ (BOOL)_skipBackupOnPath:(NSString *)path { + if (path == nil) { + return NO; + } + + NSError *error = nil; + + NSURL *url = [NSURL fileURLWithPath:path]; + BOOL success = [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&error]; + if (!success) { + PFLogError(PFLoggingTagCommon, + @"Unable to exclude %@ from backup with error: %@", [url lastPathComponent], error); + } + + return success; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFGeoPointPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFGeoPointPrivate.h new file mode 100644 index 0000000..7883ef9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFGeoPointPrivate.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern const double EARTH_RADIUS_MILES; +extern const double EARTH_RADIUS_KILOMETERS; + +@class PFGeoPoint; + +@interface PFGeoPoint (Private) + +// Internal commands + +/* + Gets the encoded format for an GeoPoint. + */ +- (NSDictionary *)encodeIntoDictionary; + +/*! + Creates an GeoPoint from its encoded format. + */ ++ (instancetype)geoPointWithDictionary:(NSDictionary *)dictionary; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.h new file mode 100644 index 0000000..e97af69 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern NSUInteger PFIntegerPairHash(NSUInteger a, NSUInteger b); + +extern NSUInteger PFDoublePairHash(double a, double b); + +extern NSUInteger PFDoubleHash(double d); + +extern NSUInteger PFLongHash(unsigned long long l); + +extern NSString *PFMD5HashFromData(NSData *data); +extern NSString *PFMD5HashFromString(NSString *string); diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.m new file mode 100644 index 0000000..4fb33f8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFHash.m @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFHash.h" + +#import + +// +// Thank you Thomas Wang for 32/64 bit mix hash +// http://www.concentric.net/~Ttwang/tech/inthash.htm +// +// Above link is now dead, please visit +// http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm +// + +extern NSUInteger PFIntegerPairHash(NSUInteger a, NSUInteger b) { + return PFLongHash(((unsigned long long)a) << 32 | b); +} + +extern NSUInteger PFDoublePairHash(double a, double b) { + return PFIntegerPairHash(PFDoubleHash(a), PFDoubleHash(b)); +} + +extern NSUInteger PFDoubleHash(double d) { + union { + double key; + uint64_t bits; + } u; + u.key = d; + return PFLongHash(u.bits); +} + +extern NSUInteger PFLongHash(unsigned long long l) { + l = (~l) + (l << 18); // key = (key << 18) - key - 1; + l ^= (l >> 31); + l *= 21; // key = (key + (key << 2)) + (key << 4); + l ^= (l >> 11); + l += (l << 6); + l ^= (l >> 22); + return (NSUInteger)l; +} + +extern NSString *PFMD5HashFromData(NSData *data) { + unsigned char md[CC_MD5_DIGEST_LENGTH]; + + // NOTE: `__block` variables of a struct type seem to be bugged. The compiler emits instructions to read + // from the stack past where they're supposed to exist. This fixes that, by only using a traditional pointer. + CC_MD5_CTX ctx_val = { 0 }; + CC_MD5_CTX *ctx_ptr = &ctx_val; + CC_MD5_Init(ctx_ptr); + [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) { + CC_MD5_Update(ctx_ptr , bytes, (CC_LONG)byteRange.length); + }]; + CC_MD5_Final(md, ctx_ptr); + + NSString *string = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + md[0], md[1], + md[2], md[3], + md[4], md[5], + md[6], md[7], + md[8], md[9], + md[10], md[11], + md[12], md[13], + md[14], md[15]]; + return string; +} + +extern NSString *PFMD5HashFromString(NSString *string) { + return PFMD5HashFromData([string dataUsingEncoding:NSUTF8StringEncoding]); +} diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.h new file mode 100644 index 0000000..eedf09e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.h @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEncoder.h" + +@class PFFileManager; +@class PFKeychainStore; +@class PFNetworkCommand; + +@interface PFInternalUtils : NSObject + ++ (NSString *)parseServerURLString; ++ (void)setParseServer:(NSString *)server; + ++ (NSNumber *)fileSizeOfFileAtPath:(NSString *)filePath error:(NSError **)error; + +/** + Clears system time zone cache, gets the name of the time zone + and caches it. This method is completely thread-safe. + */ ++ (NSString *)currentSystemTimeZoneName; + +/** + * Performs selector on the target, only if the target and selector are non-nil, + * as well as target responds to selector + */ ++ (void)safePerformSelector:(SEL)selector withTarget:(id)target object:(id)object object:(id)anotherObject; + ++ (NSNumber *)addNumber:(NSNumber *)first withNumber:(NSNumber *)second; + +// +// Given an NSDictionary/NSArray/NSNumber/NSString even nested ones +// Generates a cache key that can be used to identify this object ++ (NSString *)cacheKeyForObject:(id)object; + +/**! + * Does a deep traversal of every item in object, calling block on every one. + * @param object The object or array to traverse deeply. + * @param block The block to call for every item. It will be passed the item + * as an argument. If it returns a truthy value, that value will replace the + * item in its parent container. + * @return The result of calling block on the top-level object itself. + **/ ++ (id)traverseObject:(id)object usingBlock:(id (^)(id object))block; + +/*! + This method will split an array into multiple arrays, each with up to maximum components count. + + @param array Array to split. + @param components Number of components that should be used as a max per each subarray. + + @return Array of arrays constructed by splitting the array. + */ ++ (NSArray *)arrayBySplittingArray:(NSArray *)array withMaximumComponentsPerSegment:(NSUInteger)components; + ++ (id)_stringWithFormat:(NSString *)format arguments:(NSArray *)arguments; +@end + +@interface PFJSONCacheItem : NSObject + +@property (nonatomic, copy, readonly) NSString *hashValue; + +- (instancetype)initWithObject:(id)object; ++ (PFJSONCacheItem *)cacheFromObject:(id)object; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.m new file mode 100644 index 0000000..0b585bb --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFInternalUtils.m @@ -0,0 +1,298 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInternalUtils.h" + +#include +#include + +#import + +#import "PFACLPrivate.h" +#import "PFAssert.h" +#import "PFDateFormatter.h" +#import "BFTask+Private.h" +#import "PFFieldOperation.h" +#import "PFFile_Private.h" +#import "PFGeoPointPrivate.h" +#import "PFKeyValueCache.h" +#import "PFKeychainStore.h" +#import "PFLogging.h" +#import "PFEncoder.h" +#import "PFObjectPrivate.h" +#import "PFRelationPrivate.h" +#import "PFUserPrivate.h" +#import "Parse.h" +#import "PFFileManager.h" +#import "PFJSONSerialization.h" +#import "PFMultiProcessFileLockController.h" +#import "PFHash.h" + +#if TARGET_OS_IOS +#import "PFProduct.h" +#endif + +static NSString *parseServer_; + +@implementation PFInternalUtils + ++ (void)initialize { + if (self == [PFInternalUtils class]) { + [self setParseServer:kPFParseServer]; + } +} + ++ (NSString *)parseServerURLString { + return parseServer_; +} + +// Useful for testing. +// Beware of race conditions if you call setParseServer while something else may be using +// httpClient. ++ (void)setParseServer:(NSString *)server { + parseServer_ = [server copy]; +} + ++ (NSString *)currentSystemTimeZoneName { + static NSLock *methodLock; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + methodLock = [[NSLock alloc] init]; + }); + + [methodLock lock]; + [NSTimeZone resetSystemTimeZone]; + NSString *systemTimeZoneName = [[NSTimeZone systemTimeZone].name copy]; + [methodLock unlock]; + + return systemTimeZoneName; +} + ++ (void)safePerformSelector:(SEL)selector withTarget:(id)target object:(id)object object:(id)anotherObject { + if (target == nil || selector == nil || ![target respondsToSelector:selector]) { + return; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [target performSelector:selector withObject:object withObject:anotherObject]; +#pragma clang diagnostic pop +} + ++ (NSNumber *)fileSizeOfFileAtPath:(NSString *)filePath error:(NSError **)error { + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath + error:error]; + return attributes[NSFileSize]; +} + +///-------------------------------------- +#pragma mark - Serialization +///-------------------------------------- + ++ (NSNumber *)addNumber:(NSNumber *)first withNumber:(NSNumber *)second { + const char *objcType = [first objCType]; + + if (strcmp(objcType, @encode(BOOL)) == 0) { + return @([first boolValue] + [second boolValue]); + } else if (strcmp(objcType, @encode(char)) == 0) { + return @([first charValue] + [second charValue]); + } else if (strcmp(objcType, @encode(double)) == 0) { + return @([first doubleValue] + [second doubleValue]); + } else if (strcmp(objcType, @encode(float)) == 0) { + return @([first floatValue] + [second floatValue]); + } else if (strcmp(objcType, @encode(int)) == 0) { + return @([first intValue] + [second intValue]); + } else if (strcmp(objcType, @encode(long)) == 0) { + return @([first longValue] + [second longValue]); + } else if (strcmp(objcType, @encode(long long)) == 0) { + return @([first longLongValue] + [second longLongValue]); + } else if (strcmp(objcType, @encode(short)) == 0) { + return @([first shortValue] + [second shortValue]); + } else if (strcmp(objcType, @encode(unsigned char)) == 0) { + return @([first unsignedCharValue] + [second unsignedCharValue]); + } else if (strcmp(objcType, @encode(unsigned int)) == 0) { + return @([first unsignedIntValue] + [second unsignedIntValue]); + } else if (strcmp(objcType, @encode(unsigned long)) == 0) { + return @([first unsignedLongValue] + [second unsignedLongValue]); + } else if (strcmp(objcType, @encode(unsigned long long)) == 0) { + return @([first unsignedLongLongValue] + [second unsignedLongLongValue]); + } else if (strcmp(objcType, @encode(unsigned short)) == 0) { + return @([first unsignedShortValue] + [second unsignedShortValue]); + } + + // Fall back to int? + return @([first intValue] + [second intValue]); +} + +///-------------------------------------- +#pragma mark - CacheKey +///-------------------------------------- + +#pragma mark Public + ++ (NSString *)cacheKeyForObject:(id)object { + NSMutableString *string = [NSMutableString string]; + [self appendObject:object toString:string]; + return string; +} + +#pragma mark Private + ++ (void)appendObject:(id)object toString:(NSMutableString *)string { + if ([object isKindOfClass:[NSDictionary class]]) { + [self appendDictionary:object toString:string]; + } else if ([object isKindOfClass:[NSArray class]]) { + [self appendArray:object toString:string]; + } else if ([object isKindOfClass:[NSString class]]) { + [string appendFormat:@"\"%@\"", object]; + } else if ([object isKindOfClass:[NSNumber class]]) { + [self appendNumber:object toString:string]; + } else if ([object isKindOfClass:[NSNull class]]) { + [self appendNullToString:string]; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Couldn't create cache key from %@", object]; + } +} + ++ (void)appendDictionary:(NSDictionary *)dictionary toString:(NSMutableString *)string { + [string appendString:@"{"]; + + NSArray *keys = [[dictionary allKeys] sortedArrayUsingSelector:@selector(compare:)]; + for (NSString *key in keys) { + [string appendFormat:@"%@:", key]; + + id value = [dictionary objectForKey:key]; + [self appendObject:value toString:string]; + + [string appendString:@","]; + } + + [string appendString:@"}"]; +} + ++ (void)appendArray:(NSArray *)array toString:(NSMutableString *)string { + [string appendString:@"["]; + for (id object in array) { + [self appendObject:object toString:string]; + [string appendString:@","]; + } + [string appendString:@"]"]; +} + ++ (void)appendNumber:(NSNumber *)number toString:(NSMutableString *)string { + [string appendFormat:@"%@", [number stringValue]]; +} + ++ (void)appendNullToString:(NSMutableString *)string { + [string appendString:@"null"]; +} + ++ (id)traverseObject:(id)object usingBlock:(id (^)(id object))block seenObjects:(NSMutableSet *)seen { + if ([object isKindOfClass:[PFObject class]]) { + if ([seen containsObject:object]) { + // We've already visited this object in this call. + return object; + } + [seen addObject:object]; + + for (NSString *key in [(PFObject *)object allKeys]) { + [self traverseObject:object[key] usingBlock:block seenObjects:seen]; + } + + return block(object); + } else if ([object isKindOfClass:[NSArray class]]) { + NSMutableArray *newArray = [object mutableCopy]; + [object enumerateObjectsUsingBlock:^(id child, NSUInteger idx, BOOL *stop) { + id newChild = [self traverseObject:child usingBlock:block seenObjects:seen]; + if (newChild) { + newArray[idx] = newChild; + } + }]; + return block(newArray); + } else if ([object isKindOfClass:[NSDictionary class]]) { + NSMutableDictionary *newDictionary = [object mutableCopy]; + [object enumerateKeysAndObjectsUsingBlock:^(id key, id child, BOOL *stop) { + id newChild = [self traverseObject:child usingBlock:block seenObjects:seen]; + if (newChild) { + newDictionary[key] = newChild; + } + }]; + return block(newDictionary); + } + + return block(object); +} + ++ (id)traverseObject:(id)object usingBlock:(id (^)(id object))block { + NSMutableSet *seen = [[NSMutableSet alloc] init]; + id result = [self traverseObject:object usingBlock:block seenObjects:seen]; + return result; +} + ++ (NSArray *)arrayBySplittingArray:(NSArray *)array withMaximumComponentsPerSegment:(NSUInteger)components { + if ([array count] <= components) { + return @[ array ]; + } + + NSMutableArray *splitArray = [NSMutableArray array]; + NSInteger index = 0; + + while (index < [array count]) { + NSInteger length = MIN([array count] - index, components); + + NSArray *subarray = [array subarrayWithRange:NSMakeRange(index, length)]; + [splitArray addObject:subarray]; + + index += length; + } + + return splitArray; +} + ++ (id)_stringWithFormat:(NSString *)format arguments:(NSArray *)arguments { + // We cannot reliably construct a va_list for 64-bit, so hard code up to N args. + const int maxNumArgs = 10; + PFRangeAssert(arguments.count <= maxNumArgs, @"Maximum of %d format args allowed", maxNumArgs); + NSMutableArray *args = [arguments mutableCopy]; + for (NSUInteger i = arguments.count; i < maxNumArgs; i++) { + [args addObject:@""]; + } + return [NSString stringWithFormat:format, + args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]]; +} + +@end + +// A PFJSONCacheItem is a pairing of a json string with its hash value. +// This is used by our mutable container checking. +@implementation PFJSONCacheItem + +- (instancetype)initWithObject:(id)object { + if (self = [super init]) { + NSObject *encoded = [[PFPointerOrLocalIdObjectEncoder objectEncoder] encodeObject:object]; + NSData *jsonData = [PFJSONSerialization dataFromJSONObject:encoded]; + _hashValue = PFMD5HashFromData(jsonData); + } + return self; +} + +- (BOOL)isEqual:(id)otherCache { + if (![otherCache isKindOfClass:[PFJSONCacheItem class]]) { + return NO; + } + + return [self.hashValue isEqualToString:[otherCache hashValue]]; +} + ++ (PFJSONCacheItem *)cacheFromObject:(id)object { + return [[PFJSONCacheItem alloc] initWithObject:object]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.h new file mode 100644 index 0000000..e6fb16c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFJSONSerialization : NSObject + +/*! + The object passed in must be one of: + * NSString + * NSNumber + * NSDictionary + * NSArray + * NSNull + + @returns NSData of JSON representing the passed in object. + */ ++ (nullable NSData *)dataFromJSONObject:(id)object; + +/*! + The object passed in must be one of: + * NSString + * NSNumber + * NSDictionary + * NSArray + * NSNull + + @returns NSString of JSON representing the passed in object. + */ ++ (nullable NSString *)stringFromJSONObject:(id)object; + +/*! + Takes a JSON string and returns the NSDictionaries and NSArrays in it. + You should still call decodeObject if you want Parse types. + */ ++ (nullable id)JSONObjectFromData:(NSData *)data; + +/*! + Takes a JSON string and returns the NSDictionaries and NSArrays in it. + You should still call decodeObject if you want Parse types. + */ ++ (nullable id)JSONObjectFromString:(NSString *)string; + +/*! + @abstract Takes a file path to json file and returns the NSDictionaries and NSArrays in it. + + @description You should still call decodeObject if you want Parse types. + + @param filePath File path to a file. + + @return Decoded object. + */ ++ (nullable id)JSONObjectFromFileAtPath:(NSString *)filePath; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.m new file mode 100644 index 0000000..c2c72fe --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFJSONSerialization.m @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFJSONSerialization.h" + +#import "PFAssert.h" +#import "PFLogging.h" + +@implementation PFJSONSerialization + ++ (NSData *)dataFromJSONObject:(id)object { + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error]; + PFParameterAssert(data && !error, @"PFObject values must be serializable to JSON"); + + return data; +} + ++ (NSString *)stringFromJSONObject:(id)object { + NSData *data = [self dataFromJSONObject:object]; + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +} + ++ (id)JSONObjectFromData:(NSData *)data { + NSError *error = nil; + id object = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&error]; + if (!object || error != nil) { + PFLogError(PFLoggingTagCommon, @"JSON deserialization failed with error: %@", [error description]); + } + + return object; +} + ++ (id)JSONObjectFromString:(NSString *)string { + return [self JSONObjectFromData:[string dataUsingEncoding:NSUTF8StringEncoding]]; +} + ++ (id)JSONObjectFromFileAtPath:(NSString *)filePath { + NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:filePath]; + if (!stream) { + return nil; + } + + [stream open]; + + NSError *streamError = stream.streamError; + // Check if stream failed to open, because there is no such file. + if (streamError && [streamError.domain isEqualToString:NSPOSIXErrorDomain] && streamError.code == ENOENT) { + [stream close]; // Still close the stream. + return nil; + } + + NSError *error = nil; + id object = [NSJSONSerialization JSONObjectWithStream:stream options:0 error:&error]; + if (!object || error) { + PFLogError(PFLoggingTagCommon, @"JSON deserialization failed with error: %@", error.description); + } + + [stream close]; + + return object; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.h new file mode 100644 index 0000000..3d7c06e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const PFKeychainStoreDefaultService; + +/*! + PFKeychainStore is NSUserDefaults-like wrapper on top of Keychain. + It supports any object, with NSCoding support. Every object is serialized using NSKeyedArchiver. + + All objects are available after the first device unlock and are not backed up. + */ +@interface PFKeychainStore : NSObject + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithService:(NSString *)service NS_DESIGNATED_INITIALIZER; + +- (nullable id)objectForKey:(NSString *)key; +- (nullable id)objectForKeyedSubscript:(NSString *)key; + +- (BOOL)setObject:(nullable id)object forKey:(NSString *)key; +- (BOOL)setObject:(nullable id)object forKeyedSubscript:(NSString *)key; +- (BOOL)removeObjectForKey:(NSString *)key; +- (BOOL)removeAllObjects; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.m new file mode 100644 index 0000000..747ff10 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFKeychainStore.m @@ -0,0 +1,200 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFKeychainStore.h" + +#import "PFAssert.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "Parse.h" + +NSString *const PFKeychainStoreDefaultService = @"com.parse.sdk"; + +@interface PFKeychainStore () { + dispatch_queue_t _synchronizationQueue; +} + +@property (nonatomic, copy, readonly) NSString *service; +@property (nonatomic, copy, readonly) NSDictionary *keychainQueryTemplate; + +@end + +@implementation PFKeychainStore + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (NSDictionary *)_keychainQueryTemplateForService:(NSString *)service { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + if ([service length]) { + query[(__bridge NSString *)kSecAttrService] = service; + } + query[(__bridge NSString *)kSecClass] = (__bridge id)kSecClassGenericPassword; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-pointer-compare" + if (&kSecAttrAccessible != nil) { + query[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + } +#pragma clang diagnostic pop + + return [query copy]; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithService:(NSString *)service { + self = [super init]; + if (!self) return nil; + + _service = service; + _keychainQueryTemplate = [[self class] _keychainQueryTemplateForService:service]; + + NSString *queueLabel = [NSString stringWithFormat:@"com.parse.keychain.%@", service]; + _synchronizationQueue = dispatch_queue_create([queueLabel UTF8String], DISPATCH_QUEUE_CONCURRENT); + PFMarkDispatchQueue(_synchronizationQueue); + + return self; +} + +///-------------------------------------- +#pragma mark - Read +///-------------------------------------- + +- (id)objectForKey:(NSString *)key { + __block NSData *data = nil; + dispatch_sync(_synchronizationQueue, ^{ + data = [self _dataForKey:key]; + }); + + if (data) { + id object = nil; + @try { + object = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + } + @catch (NSException *exception) {} + + return object; + } + return nil; +} + +- (id)objectForKeyedSubscript:(NSString *)key { + return [self objectForKey:key]; +} + +- (NSData *)_dataForKey:(NSString *)key { + NSMutableDictionary *query = [self.keychainQueryTemplate mutableCopy]; + + query[(__bridge NSString *)kSecAttrAccount] = key; + query[(__bridge NSString *)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + query[(__bridge NSString *)kSecReturnData] = (__bridge id)kCFBooleanTrue; + + //recover data + CFDataRef data = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&data); + if (status != errSecSuccess && status != errSecItemNotFound) { + PFLogError(PFLoggingTagCommon, + @"PFKeychainStore failed to get object for key '%@', with error: %ld", key, (long)status); + } + return CFBridgingRelease(data); +} + +///-------------------------------------- +#pragma mark - Write +///-------------------------------------- + +- (BOOL)setObject:(id)object forKey:(NSString *)key { + NSParameterAssert(key != nil); + + if (!object) { + return [self removeObjectForKey:key]; + } + + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object]; + if (!data) { + return NO; + } + + NSMutableDictionary *query = [self.keychainQueryTemplate mutableCopy]; + query[(__bridge NSString *)kSecAttrAccount] = key; + + NSDictionary *update = @{ (__bridge NSString *)kSecValueData : data }; + + __block OSStatus status = errSecSuccess; + dispatch_barrier_sync(_synchronizationQueue,^{ + if ([self _dataForKey:key]) { + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update); + } else { + [query addEntriesFromDictionary:update]; + status = SecItemAdd((__bridge CFDictionaryRef)query, NULL); + } + }); + + if (status != errSecSuccess) { + PFLogError(PFLoggingTagCommon, + @"PFKeychainStore failed to set object for key '%@', with error: %ld", key, (long)status); + } + + return (status == errSecSuccess); +} + +- (BOOL)setObject:(id)object forKeyedSubscript:(NSString *)key { + return [self setObject:object forKey:key]; +} + +- (BOOL)removeObjectForKey:(NSString *)key { + __block BOOL value = NO; + dispatch_barrier_sync(_synchronizationQueue, ^{ + value = [self _removeObjectForKey:key]; + }); + return value; +} + +- (BOOL)_removeObjectForKey:(NSString *)key { + PFAssertIsOnDispatchQueue(_synchronizationQueue); + NSMutableDictionary *query = [self.keychainQueryTemplate mutableCopy]; + query[(__bridge NSString *)kSecAttrAccount] = key; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + return (status == errSecSuccess); +} + +- (BOOL)removeAllObjects { + NSMutableDictionary *query = [self.keychainQueryTemplate mutableCopy]; + query[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; + query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + + __block BOOL value = YES; + dispatch_barrier_sync(_synchronizationQueue, ^{ + CFArrayRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status != errSecSuccess) { + return; + } + + for (NSDictionary *item in CFBridgingRelease(result)) { + NSString *key = item[(__bridge id)kSecAttrAccount]; + value = [self _removeObjectForKey:key]; + if (!value) { + return; + } + } + }); + return value; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.h new file mode 100644 index 0000000..b1f115c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 CLLocation; +@class CLLocationManager; + +#if TARGET_OS_IPHONE + +@class UIApplication; + +#endif + +typedef void(^PFLocationManagerLocationUpdateBlock)(CLLocation *location, NSError *error); + +/*! + PFLocationManager is an internal class which wraps a CLLocationManager and + returns an updated CLLocation via the provided block. + + When -addBlockForCurrentLocation is called, the CLLocationManager's + -startUpdatingLocations is called, and upon CLLocationManagerDelegate callback + (either success or failure), any handlers that were passed to this class will + be called _once_ with the updated location, then removed. The CLLocationManager + stopsUpdatingLocation upon a single failure or success case, so that the next + location request is guaranteed a speedily returned CLLocation. + */ +@interface PFLocationManager : NSObject + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithSystemLocationManager:(CLLocationManager *)manager; + +#if TARGET_OS_IPHONE + +- (instancetype)initWithSystemLocationManager:(CLLocationManager *)manager + application:(UIApplication *)application + bundle:(NSBundle *)bundle NS_DESIGNATED_INITIALIZER; + +#endif + +///-------------------------------------- +#pragma mark - Current Location +///-------------------------------------- + +- (void)addBlockForCurrentLocation:(PFLocationManagerLocationUpdateBlock)handler; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.m new file mode 100644 index 0000000..82286bc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLocationManager.m @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFLocationManager.h" + +#import + +#import "PFConstants.h" +#import "PFGeoPoint.h" +#import "PFApplication.h" + +@interface PFLocationManager () + +@property (nonatomic, strong) CLLocationManager *locationManager; +@property (nonatomic, strong) NSBundle *bundle; +@property (nonatomic, strong) UIApplication *application; + +// We use blocks and not BFTasks because Tasks don't gain us much - we still +// have to manually hold onto them so that they can be resolved in the +// CLLocationManager callback. +@property (nonatomic, strong) NSMutableSet *blockSet; + +@end + +@implementation PFLocationManager + +///-------------------------------------- +#pragma mark - CLLocationManager +///-------------------------------------- + ++ (CLLocationManager *)_newSystemLocationManager { + __block CLLocationManager *manager = nil; + + // CLLocationManager should be created only on main thread, as it needs a run loop to serve delegate callbacks + dispatch_block_t block = ^{ + manager = [[CLLocationManager alloc] init]; + }; + if ([[NSThread currentThread] isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } + return manager; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + CLLocationManager *manager = [[self class] _newSystemLocationManager]; + return [self initWithSystemLocationManager:manager]; +} + +- (instancetype)initWithSystemLocationManager:(CLLocationManager *)manager { + return [self initWithSystemLocationManager:manager + application:[PFApplication currentApplication].systemApplication + bundle:[NSBundle mainBundle]]; +} + +- (instancetype)initWithSystemLocationManager:(CLLocationManager *)manager + application:(UIApplication *)application + bundle:(NSBundle *)bundle { + self = [super init]; + if (!self) return nil; + + _blockSet = [NSMutableSet setWithCapacity:1]; + _locationManager = manager; + _locationManager.delegate = self; + _bundle = bundle; + _application = application; + + return self; +} + +///-------------------------------------- +#pragma mark - Dealloc +///-------------------------------------- + +- (void)dealloc { + _locationManager.delegate = nil; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (void)addBlockForCurrentLocation:(PFLocationManagerLocationUpdateBlock)handler { + @synchronized (self.blockSet) { + [self.blockSet addObject:[handler copy]]; + } + +#if TARGET_OS_WATCH + if ([self.bundle objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) { + [self.locationManager requestWhenInUseAuthorization]; + } else { + [self.locationManager requestAlwaysAuthorization]; + } + [self.locationManager requestLocation]; +#elif TARGET_OS_IOS + if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { + if (self.application.applicationState != UIApplicationStateBackground && + [self.bundle objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) { + [self.locationManager requestWhenInUseAuthorization]; + } else { + [self.locationManager requestAlwaysAuthorization]; + } + } + [self.locationManager startUpdatingLocation]; +#elif TARGET_OS_MAC + [self.locationManager startUpdatingLocation]; +#endif +} + +///-------------------------------------- +#pragma mark - CLLocationManagerDelegate +///-------------------------------------- + +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { + CLLocation *location = [locations lastObject]; + + [manager stopUpdatingLocation]; + + NSMutableSet *callbacks = [NSMutableSet setWithCapacity:1]; + @synchronized (self.blockSet) { + [callbacks setSet:self.blockSet]; + [self.blockSet removeAllObjects]; + } + for (PFLocationManagerLocationUpdateBlock block in callbacks) { + block(location, nil); + } +} + +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { + [manager stopUpdatingLocation]; + + NSMutableSet *callbacks = nil; + @synchronized (self.blockSet) { + callbacks = [self.blockSet copy]; + [self.blockSet removeAllObjects]; + } + for (PFLocationManagerLocationUpdateBlock block in callbacks) { + block(nil, error); + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.h new file mode 100644 index 0000000..2a8858e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +typedef uint8_t PFLoggingTag; + +@interface PFLogger : NSObject + +@property (atomic, assign) PFLogLevel logLevel; + +///-------------------------------------- +/// @name Shared Logger +///-------------------------------------- + +/*! +A shared instance of `PFLogger` that should be used for all logging. + +@returns An shared singleton instance of `PFLogger`. +*/ ++ (instancetype)sharedLogger; //TODO: (nlutsenko) Convert to use an instance everywhere instead of a shared singleton. + +///-------------------------------------- +/// @name Logging Messages +///-------------------------------------- + +/*! + Logs a message at a specific level for a tag. + If current logging level doesn't include this level - this method does nothing. + + @param level Logging Level + @param tag Logging Tag + @param format Format to use for the log message. + */ +- (void)logMessageWithLevel:(PFLogLevel)level + tag:(PFLoggingTag)tag + format:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4); + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.m new file mode 100644 index 0000000..d309096 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogger.m @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFLogger.h" + +#import "PFApplication.h" +#import "PFLogging.h" + +@implementation PFLogger + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (NSString *)_descriptionForLoggingTag:(PFLoggingTag)tag { + NSString *description = nil; + switch (tag) { + case PFLoggingTagCommon: + break; + case PFLoggingTagCrashReporting: + description = @"Crash Reporting"; + break; + default: + break; + } + return description; +} + ++ (NSString *)_descriptionForLogLevel:(PFLogLevel)logLevel { + NSString *description = nil; + switch (logLevel) { + case PFLogLevelNone: + break; + case PFLogLevelError: + description = @"Error"; + break; + case PFLogLevelWarning: + description = @"Warning"; + break; + case PFLogLevelInfo: + description = @"Info"; + break; + default: + break; + } + return description; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)sharedLogger { + static PFLogger *logger; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + logger = [[PFLogger alloc] init]; + }); + return logger; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _logLevel = ([PFApplication currentApplication].appStoreEnvironment ? PFLogLevelNone : PFLogLevelWarning); + + return self; +} + +///-------------------------------------- +#pragma mark - Logging Messages +///-------------------------------------- + +- (void)logMessageWithLevel:(PFLogLevel)level + tag:(PFLoggingTag)tag + format:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4) { + if (level > self.logLevel || level == PFLogLevelNone || !format) { + return; + } + + va_list args; + va_start(args, format); + + NSMutableString *message = [NSMutableString stringWithFormat:@"[%@]", [[self class] _descriptionForLogLevel:level]]; + + NSString *tagDescription = [[self class] _descriptionForLoggingTag:tag]; + if (tagDescription) { + [message appendFormat:@"[%@]", tagDescription]; + } + + [message appendFormat:@": %@", format]; + + NSLogv(message, args); + + va_end(args); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogging.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogging.h new file mode 100644 index 0000000..90a4410 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFLogging.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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. + */ + +#ifndef Parse_PFLogging_h +#define Parse_PFLogging_h + +# import + +#import "PFLogger.h" + +static const PFLoggingTag PFLoggingTagCommon = 0; +static const PFLoggingTag PFLoggingTagCrashReporting = 100; + +#define PFLog(level, loggingTag, frmt, ...) \ +[[PFLogger sharedLogger] logMessageWithLevel:level tag:loggingTag format:(frmt), ##__VA_ARGS__] + +#define PFLogError(tag, frmt, ...) \ +PFLog(PFLogLevelError, (tag), (frmt), ##__VA_ARGS__) + +#define PFLogWarning(tag, frmt, ...) \ +PFLog(PFLogLevelWarning, (tag), (frmt), ##__VA_ARGS__) + +#define PFLogInfo(tag, frmt, ...) \ +PFLog(PFLogLevelInfo, (tag), (frmt), ##__VA_ARGS__) + +#define PFLogDebug(tag, frmt, ...) \ +PFLog(PFLogLevelDebug, (tag), (frmt), ##__VA_ARGS__) + +#define PFLogException(exception) \ +PFLogError(PFLoggingTagCommon, @"Caught \"%@\" with reason \"%@\"%@", \ +exception.name, exception, \ +[exception callStackSymbols] ? [NSString stringWithFormat:@":\n%@.", [exception callStackSymbols]] : @"") + +#endif diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMacros.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMacros.h new file mode 100644 index 0000000..4f53214 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMacros.h @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +#ifndef Parse_PFMacros_h +#define Parse_PFMacros_h + +/*! + This macro allows to create NSSet via subscript. + */ +#define PF_SET(...) [NSSet setWithObjects:__VA_ARGS__, nil] + +/*! + This macro is a handy thing for converting libSystem objects to (void *) pointers. + If you are targeting OSX 10.8+ and iOS 6.0+ - this is no longer required. + */ +#if OS_OBJECT_USE_OBJC + #define PFOSObjectPointer(object) \ + (__bridge void *)(object) +#else + #define PFOSObjectPointer(object) \ + (void *)(object) +#endif + +/*! + Mark a queue in order to be able to check PFAssertIsOnMarkedQueue. + */ +#define PFMarkDispatchQueue(queue) \ +dispatch_queue_set_specific((queue), \ + PFOSObjectPointer(queue), \ + PFOSObjectPointer(queue), \ + NULL) + +///-------------------------------------- +/// @name Memory Management +/// +/// The following macros are influenced and include portions of libextobjc. +///-------------------------------------- + +/*! + Creates a __weak version of the variable provided, + which can later be safely used or converted into strong variable via @strongify. + */ +#define weakify(var) \ +try {} @catch (...) {} \ +__weak __typeof__(var) var ## _weak = var; + +/*! + Creates a strong shadow reference of the variable provided. + Variable must have previously been passed to @weakify. + */ +#define strongify(var) \ +try {} @catch (...) {} \ +__strong __typeof__(var) var = var ## _weak; + +///-------------------------------------- +/// @name KVC +///-------------------------------------- + +/*! + This macro ensures that object.key exists at compile time. + It can accept a chained key path. + */ +#define keypath(TYPE, PATH) \ +(((void)(NO && ((void)((TYPE *)(nil)).PATH, NO)), # PATH)) + +///-------------------------------------- +/// @name Runtime +///-------------------------------------- + +/*! + Using objc_msgSend directly is bad, very bad. Doing so without casting could result in stack-smashing on architectures + (*cough* x86 *cough*) that use strange methods of returning values of different types. + + The objc_msgSend_safe macro ensures that we properly cast the function call to use the right conventions when passing + parameters and getting return values. This also fixes some issues with ARC and objc_msgSend directly, though strange + things can happen when receiving values from NS_RETURNS_RETAINED methods. + */ +#define objc_msgSend(...) _Pragma("GCC error \"Use objc_msgSend_safe() instead!\"") +#define objc_msgSend_safe(returnType, argTypes...) ((returnType (*)(id, SEL, ##argTypes))(objc_msgSend)) + +/*! + This exists because if we throw an exception from dispatch_sync, it doesn't 'bubble up' to the calling thread. + This simply wraps dispatch_sync and properly throws the exception back to the calling thread, not the thread that + the exception was originally raised on. + + @param queue The queue to execute on + @param block The block to execute + + @see dispatch_sync + */ +#define pf_sync_with_throw(queue, block) \ + do { \ + __block NSException *caught = nil; \ + dispatch_sync(queue, ^{ \ + @try { block(); } \ + @catch (NSException *ex) { \ + caught = ex; \ + } \ + }); \ + if (caught) @throw caught; \ + } while (0) + +/*! + To prevent retain cycles by OCMock, this macro allows us to capture a weak reference to return from a stubbed method. + */ +#define andReturnWeak(variable) _andDo( \ + ({ \ + __weak typeof(variable) variable ## _weak = (variable); \ + ^(NSInvocation *invocation) { \ + __autoreleasing typeof(variable) variable ## _block = variable ## _weak; \ + [invocation setReturnValue:&(variable ## _block)]; \ + }; \ + }) \ +) + +/*! + This exists to use along with bolts generic tasks. Instead of returning a BFTask with no generic type, or a generic + type of 'NSNull' when there is no usable result from a task, we use the type 'PFVoid', which will always have a value + of 'nil'. + + This allows us to more easily descern between methods that have not yet updated the return type of their tasks, as well + as provide a more enforced API contract to the caller (as sending any message to PFVoid will result in a compile time + error). + */ +@class _PFVoid_Nonexistant; +typedef _PFVoid_Nonexistant *PFVoid; + +#endif diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.h new file mode 100644 index 0000000..7a54dc3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 an event that can be subscribed to by multiple observers. + */ +@interface PFMulticastDelegate : NSObject { +@private + NSMutableArray *callbacks; +} + +/*! + Subscribes a block for callback. + + Important: if you ever plan to be able to unsubscribe the block, you must copy the block + before passing it to subscribe, and use the same instance for unsubscribe. + */ +- (void)subscribe:(void(^)(id result, NSError *error))block; +- (void)unsubscribe:(void(^)(id result, NSError *error))block; +- (void)invoke:(id)result error:(NSError *)error; +- (void)clear; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.m new file mode 100644 index 0000000..9d49fa8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFMulticastDelegate.m @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMulticastDelegate.h" + +@implementation PFMulticastDelegate + +- (instancetype)init { + if (self = [super init]) { + callbacks = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)subscribe:(void(^)(id result, NSError *error))block { + [callbacks addObject:block]; +} + +- (void)unsubscribe:(void(^)(id result, NSError *error))block { + [callbacks removeObject:block]; +} + +- (void)invoke:(id)result error:(NSError *)error { + NSArray *callbackCopy = [callbacks copy]; + for (void (^block)(id result, NSError *error) in callbackCopy) { + block(result, error); + } +} +- (void)clear { + [callbacks removeAllObjects]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFNetworkCommand.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFNetworkCommand.h new file mode 100644 index 0000000..6502923 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFNetworkCommand.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@protocol PFNetworkCommand + +///-------------------------------------- +/// @name Properties +///-------------------------------------- + +@property (nonatomic, copy, readonly) NSString *sessionToken; +@property (nonatomic, copy, readonly) NSString *operationSetUUID; + +// If this command creates an object that is referenced by some other command, +// then this localId will be updated with the new objectId that is returned. +@property (nonatomic, copy) NSString *localId; + +///-------------------------------------- +/// @name Encoding/Decoding +///-------------------------------------- + ++ (instancetype)commandFromDictionaryRepresentation:(NSDictionary *)dictionary; +- (NSDictionary *)dictionaryRepresentation; + ++ (BOOL)isValidDictionaryRepresentation:(NSDictionary *)dictionary; + +///-------------------------------------- +/// @name Local Identifiers +///-------------------------------------- + +/*! + Replaces all local ids in this command with the correct objectId for that object. + This should be called before sending the command over the network, so that there + are no local ids sent to the Parse Cloud. If any local id refers to an object that + has not yet been saved, and thus has no objectId, then this method raises an + exception. + */ +- (void)resolveLocalIds; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.h new file mode 100644 index 0000000..17a0499 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFEventuallyQueue.h" + +@interface PFPinningEventuallyQueue : PFEventuallyQueue + +///-------------------------------------- +/// @name Init +///-------------------------------------- + ++ (instancetype)newDefaultPinningEventuallyQueueWithCommandRunner:(id)commandRunner; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.m new file mode 100644 index 0000000..0d039d2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFPinningEventuallyQueue.m @@ -0,0 +1,327 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPinningEventuallyQueue.h" + +#import +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFErrorUtilities.h" +#import "PFEventuallyPin.h" +#import "PFEventuallyQueue_Private.h" +#import "PFMacros.h" +#import "PFObjectPrivate.h" +#import "PFOperationSet.h" +#import "PFRESTCommand.h" +#import "PFTaskQueue.h" + +@interface PFPinningEventuallyQueue () { + /*! + Queue for reading/writing eventually operations from LDS. Makes all reads/writes atomic + operations. + */ + PFTaskQueue *_taskQueue; + + /*! + List of `PFEventuallyPin.uuid` that are currently queued in `_processingQueue`. This contains + uuid of PFEventuallyPin that's enqueued. + */ + NSMutableArray *_eventuallyPinUUIDQueue; + + /*! + Map of eventually operation UUID to matching PFEventuallyPin. This contains PFEventuallyPin + that's enqueued. + */ + NSMutableDictionary *_uuidToEventuallyPin; + + /*! + Map OperationSetUUID to PFOperationSet + */ + NSMutableDictionary *_operationSetUUIDToOperationSet; + + /*! + Map OperationSetUUID to PFEventuallyPin + */ + NSMutableDictionary *_operationSetUUIDToEventuallyPin; +} + +@end + +@implementation PFPinningEventuallyQueue + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)newDefaultPinningEventuallyQueueWithCommandRunner:(id)commandRunner { + PFPinningEventuallyQueue *queue = [[self alloc] initWithCommandRunner:commandRunner + maxAttemptsCount:PFEventuallyQueueDefaultMaxAttemptsCount + retryInterval:PFEventuallyQueueDefaultTimeoutRetryInterval]; + [queue start]; + return queue; +} + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner + maxAttemptsCount:(NSUInteger)attemptsCount + retryInterval:(NSTimeInterval)retryInterval { + self = [super initWithCommandRunner:commandRunner maxAttemptsCount:attemptsCount retryInterval:retryInterval]; + if (!self) return nil; + + _taskQueue = [[PFTaskQueue alloc] init]; + + dispatch_sync(_synchronizationQueue, ^{ + _eventuallyPinUUIDQueue = [NSMutableArray array]; + _uuidToEventuallyPin = [NSMutableDictionary dictionary]; + _operationSetUUIDToOperationSet = [NSMutableDictionary dictionary]; + _operationSetUUIDToEventuallyPin = [NSMutableDictionary dictionary]; + }); + + // Populate Eventually Pin to make sure we pre-loaded any existing data. + [self _populateEventuallyPinAsync]; + + return self; +} + +///-------------------------------------- +#pragma mark - Controlling Queue +///-------------------------------------- + +- (void)removeAllCommands { + [super removeAllCommands]; + + BFTask *removeTask = [_taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueWithBlock:^id(BFTask *task) { + return [[PFEventuallyPin findAllEventuallyPin] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *eventuallyPins = task.result; + NSMutableArray *unpinTasks = [NSMutableArray array]; + + for (PFEventuallyPin *eventuallyPin in eventuallyPins) { + [unpinTasks addObject:[eventuallyPin unpinInBackgroundWithName:PFEventuallyPinPinName]]; + } + + return [BFTask taskForCompletionOfAllTasks:unpinTasks]; + }]; + }]; + }]; + + [removeTask waitForResult:nil]; + // Clear in-memory data + dispatch_sync(_synchronizationQueue, ^{ + [_eventuallyPinUUIDQueue removeAllObjects]; + [_uuidToEventuallyPin removeAllObjects]; + [_operationSetUUIDToEventuallyPin removeAllObjects]; + [_operationSetUUIDToOperationSet removeAllObjects]; + }); +} + +- (void)_simulateReboot { + [super _simulateReboot]; + + [_eventuallyPinUUIDQueue removeAllObjects]; + [_uuidToEventuallyPin removeAllObjects]; + [_operationSetUUIDToEventuallyPin removeAllObjects]; + [_operationSetUUIDToOperationSet removeAllObjects]; + + [self _populateEventuallyPinAsync]; +} + +///-------------------------------------- +#pragma mark - PFEventuallyQueueSubclass +///-------------------------------------- + +- (NSString *)_newIdentifierForCommand:(id)command { + return [[NSUUID UUID] UUIDString]; +} + +- (NSArray *)_pendingCommandIdentifiers { + [[self _populateEventuallyPinAsync] waitForResult:nil]; + + NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + PFEventuallyPin *pin = _uuidToEventuallyPin[evaluatedObject]; + // Filter out all pins that don't have `operationSet` data ready yet + // to make sure we send the command with all the changes. + if (pin.operationSetUUID) { + return (_operationSetUUIDToEventuallyPin[pin.operationSetUUID] != nil); + } + return YES; + }]; + return [_eventuallyPinUUIDQueue filteredArrayUsingPredicate:predicate]; +} + +- (id)_commandWithIdentifier:(NSString *)identifier error:(NSError **)error { + // Should be populated by `_pendingCommandIdentifiers` + PFEventuallyPin *eventuallyPin = _uuidToEventuallyPin[identifier]; + + // TODO (hallucinogen): this is a temporary hack. We need to change this to match the Android one. + // We need to construct the command just right when we want to execute it. Or else it will ask for localId + // when there's unsaved child. + switch (eventuallyPin.type) { + case PFEventuallyPinTypeSave: { + PFOperationSet *operationSet = _operationSetUUIDToOperationSet[eventuallyPin.operationSetUUID]; + return [eventuallyPin.object _constructSaveCommandForChanges:operationSet + sessionToken:eventuallyPin.sessionToken + objectEncoder:[PFPointerObjectEncoder objectEncoder]]; + } + case PFEventuallyPinTypeDelete: + return [eventuallyPin.object _currentDeleteCommandWithSessionToken:eventuallyPin.sessionToken]; + default: + break; + } + + id command = eventuallyPin.command; + if (!command && error) { + *error = [PFErrorUtilities errorWithCode:kPFErrorInternalServer + message:@"Failed to construct eventually command from cache." + shouldLog:NO]; + } + return command; +} + +- (BFTask *)_enqueueCommandInBackground:(id)command + object:(PFObject *)object + identifier:(NSString *)identifier { + return [_taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task){ + return [PFEventuallyPin pinEventually:object forCommand:command withUUID:identifier]; + }]; + }]; +} + +- (BFTask *)_didFinishRunningCommand:(id)command + withIdentifier:(NSString *)identifier + resultTask:(BFTask *)resultTask { + // Delete the commands regardless, even if it failed. Otherwise we'll just keep trying it forever. + // We don't need to wait for taskQueue since it will not be queued again since this + // PFEventuallyPin is still in `_eventuallyPinUUIDQueue` + PFEventuallyPin *eventuallyPin = _uuidToEventuallyPin[identifier]; + BFTask *unpinTask = [eventuallyPin unpinInBackgroundWithName:PFEventuallyPinPinName]; + unpinTask = [unpinTask continueWithBlock:^id(BFTask *task) { + // Remove data from memory. + dispatch_sync(_synchronizationQueue, ^{ + [_uuidToEventuallyPin removeObjectForKey:identifier]; + [_eventuallyPinUUIDQueue removeObject:identifier]; + }); + + if (resultTask.cancelled || resultTask.exception || resultTask.error) { + return resultTask; + } + + if (eventuallyPin.operationSetUUID) { + // Remove only if the operation succeeded + dispatch_sync(_synchronizationQueue, ^{ + [_operationSetUUIDToOperationSet removeObjectForKey:eventuallyPin.operationSetUUID]; + [_operationSetUUIDToEventuallyPin removeObjectForKey:eventuallyPin.operationSetUUID]; + }); + } + + PFCommandResult *commandResult = resultTask.result; + switch (eventuallyPin.type) { + case PFEventuallyPinTypeSave: { + + task = [task continueWithBlock:^id(BFTask *task) { + return [eventuallyPin.object handleSaveResultAsync:commandResult.result]; + }]; + break; + } + + case PFEventuallyPinTypeDelete: { + task = [task continueWithBlock:^id(BFTask *task) { + PFObject *object = eventuallyPin.object; + id controller = [[object class] objectController]; + return [controller processDeleteResultAsync:commandResult.result forObject:object]; + }]; + break; + } + + default:break; + } + + return task; + }]; + + // Notify event listener that we finished running. + return [[super _didFinishRunningCommand:command + withIdentifier:identifier + resultTask:resultTask] continueWithBlock:^id(BFTask *task) { + return unpinTask; + }]; +} + +/*! + Synchronizes PFObject taskQueue (Many) and PFPinningEventuallyQueue taskQueue (None). Each queue will be held + until both are ready, matched on operationSetUUID. Once both are ready, the eventually task will run. + */ +- (BFTask *)_waitForOperationSet:(PFOperationSet *)operationSet eventuallyPin:(PFEventuallyPin *)eventuallyPin { + if (eventuallyPin != nil && eventuallyPin.type != PFEventuallyPinTypeSave) { + // If not save, then we don't have to do anything special. + return [BFTask taskWithResult:nil]; + } + + // TODO (hallucinogen): actually wait for PFObject taskQueue and PFPinningEventually taskQueue + + __block NSString *uuid = nil; + dispatch_sync(_synchronizationQueue, ^{ + if (operationSet != nil) { + uuid = operationSet.uuid; + _operationSetUUIDToOperationSet[uuid] = operationSet; + } + if (eventuallyPin != nil) { + uuid = eventuallyPin.operationSetUUID; + _operationSetUUIDToEventuallyPin[uuid] = eventuallyPin; + } + }); + if (uuid == nil) { + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Either operationSet or eventuallyPin must be set" + userInfo:nil]; + return [BFTask taskWithException:exception]; + } + return [BFTask taskWithResult:nil]; +} + +///-------------------------------------- +#pragma mark - Eventually Pin +///-------------------------------------- + +- (BFTask *)_populateEventuallyPinAsync { + return [_taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [[toAwait continueWithBlock:^id(BFTask *task) { + return [PFEventuallyPin findAllEventuallyPinWithExcludeUUIDs:_eventuallyPinUUIDQueue]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *eventuallyPins = task.result; + + for (PFEventuallyPin *eventuallyPin in eventuallyPins) { + // If it's enqueued already, we don't need to run it again. + if ([_eventuallyPinUUIDQueue containsObject:eventuallyPin.operationSetUUID]) { + continue; + } + + // Make sure the data is in memory. + dispatch_sync(_synchronizationQueue, ^{ + [_eventuallyPinUUIDQueue addObject:eventuallyPin.uuid]; + _uuidToEventuallyPin[eventuallyPin.uuid] = eventuallyPin; + }); + + // For now we don't care whether this will fail or not. + [[self _waitForOperationSet:nil eventuallyPin:eventuallyPin] waitForResult:nil]; + } + + return task; + }]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.h new file mode 100644 index 0000000..8e6242a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFReachability; + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(uint8_t, PFReachabilityState) { + PFReachabilityStateNotReachable, + PFReachabilityStateReachableViaWiFi, + PFReachabilityStateReachableViaCell, +}; + +@protocol PFReachabilityListener + +- (void)reachability:(PFReachability *)reachability didChangeReachabilityState:(PFReachabilityState)state; + +@end + +PF_WATCH_UNAVAILABLE @interface PFReachability : NSObject + +@property (nonatomic, assign, readonly) PFReachabilityState currentState; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithURL:(NSURL *)url NS_DESIGNATED_INITIALIZER; + +/* + Returns a shared singleton instance, + that could be used to check if Parse is reachable + */ ++ (instancetype)sharedParseReachability; + +/* + Adds a weak reference to the listener, + callbacks are executed on the main thread when status or flags change. + */ +- (void)addListener:(id)listener; + +/* + Removes weak reference to the listener. + */ +- (void)removeListener:(id)listener; + +/* + Removes all references to all listener objects. + */ +- (void)removeAllListeners; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.m new file mode 100644 index 0000000..b14c7e0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFReachability.m @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFReachability.h" + +#import + +#import "PFAssert.h" +#import "PFConstants.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFWeakValue.h" + +@interface PFReachability () { + dispatch_queue_t _synchronizationQueue; + NSMutableArray *_listenersArray; + + SCNetworkReachabilityRef _networkReachability; +} + +@property (nonatomic, assign, readwrite) SCNetworkReachabilityFlags flags; + +@end + +static void _reachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { + NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); + PFReachability *reachability = (__bridge PFReachability *)info; + reachability.flags = flags; +} + +@implementation PFReachability + +@synthesize flags = _flags; + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (BOOL)_reachabilityStateForFlags:(SCNetworkConnectionFlags)flags { + PFReachabilityState reachabilityState = PFReachabilityStateNotReachable; + + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { + // if target host is not reachable + return reachabilityState; + } + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) { + // if target host is reachable and no connection is required + // then we'll assume (for now) that your on Wi-Fi + reachabilityState = PFReachabilityStateReachableViaWiFi; + } + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) { + // ... and the connection is on-demand (or on-traffic) if the + // calling application is using the CFSocketStream or higher APIs + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) { + // ... and no [user] intervention is needed + reachabilityState = PFReachabilityStateReachableViaWiFi; + } + } + +#if TARGET_OS_IPHONE + if (((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) && + ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)) { + // ... but WWAN connections are OK if the calling application + // is using the CFNetwork (CFSocketStream?) APIs. + // ... and a network connection is not required (kSCNetworkReachabilityFlagsConnectionRequired) + // which could be et w/connection flag (e.g. IsWWAN) indicating type of connection required. + reachabilityState = PFReachabilityStateReachableViaCell; + } +#endif + + return reachabilityState; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithURL:(NSURL *)url { + self = [super init]; + if (!self) return nil; + + _synchronizationQueue = dispatch_queue_create("com.parse.reachability", DISPATCH_QUEUE_CONCURRENT); + _listenersArray = [NSMutableArray array]; + [self _startMonitoringReachabilityWithURL:url]; + + return self; +} + ++ (instancetype)sharedParseReachability { + static PFReachability *reachability; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *serverUrlAsString = [NSString stringWithFormat:@"%@/%ld", kPFParseServer, (long)PARSE_API_VERSION]; + NSURL *serverUrl = [NSURL URLWithString:serverUrlAsString]; + reachability = [[self alloc] initWithURL:serverUrl]; + }); + return reachability; +} + +///-------------------------------------- +#pragma mark - Dealloc +///-------------------------------------- + +- (void)dealloc { + if (_networkReachability != NULL) { + SCNetworkReachabilitySetCallback(_networkReachability, NULL, NULL); + SCNetworkReachabilitySetDispatchQueue(_networkReachability, NULL); + CFRelease(_networkReachability); + _networkReachability = NULL; + } +} + +///-------------------------------------- +#pragma mark - Listeners +///-------------------------------------- + +- (void)addListener:(id)listener { + PFWeakValue *value = [PFWeakValue valueWithWeakObject:listener]; + dispatch_barrier_sync(_synchronizationQueue, ^{ + [_listenersArray addObject:value]; + }); +} + +- (void)removeListener:(id)listener { + dispatch_barrier_sync(_synchronizationQueue, ^{ + [_listenersArray filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + id weakObject = [evaluatedObject weakObject]; + return (weakObject == nil || weakObject == listener); + }]]; + }); +} + +- (void)removeAllListeners { + dispatch_barrier_sync(_synchronizationQueue, ^{ + [_listenersArray removeAllObjects]; + }); +} + +- (void)_notifyAllListeners { + @weakify(self); + dispatch_async(_synchronizationQueue, ^{ + @strongify(self); + PFReachabilityState state = [[self class] _reachabilityStateForFlags:_flags]; + for (PFWeakValue *value in _listenersArray) { + [value.weakObject reachability:self didChangeReachabilityState:state]; + } + + dispatch_barrier_async(_synchronizationQueue, ^{ + [_listenersArray filterUsingPredicate:[NSPredicate predicateWithFormat:@"SELf.weakObject != nil"]]; + }); + }); +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setFlags:(SCNetworkReachabilityFlags)flags { + dispatch_barrier_async(_synchronizationQueue, ^{ + _flags = flags; + [self _notifyAllListeners]; + }); +} + +- (SCNetworkReachabilityFlags)flags { + __block SCNetworkReachabilityFlags flags; + dispatch_sync(_synchronizationQueue, ^{ + flags = _flags; + }); + return flags; +} + +- (PFReachabilityState)currentState { + return [[self class] _reachabilityStateForFlags:self.flags]; +} + +///-------------------------------------- +#pragma mark - Reachability +///-------------------------------------- + +- (void)_startMonitoringReachabilityWithURL:(NSURL *)url { + dispatch_barrier_async(_synchronizationQueue, ^{ + _networkReachability = SCNetworkReachabilityCreateWithName(NULL, [[url host] UTF8String]); + if (_networkReachability != NULL) { + // Set the initial flags + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(_networkReachability, &flags); + self.flags = flags; + + // Set up notification for changes in reachability. + SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + if (SCNetworkReachabilitySetCallback(_networkReachability, _reachabilityCallback, &context)) { + if (!SCNetworkReachabilitySetDispatchQueue(_networkReachability, _synchronizationQueue)) { + PFLogError(PFLoggingTagCommon, @"Unable to start listening for network connectivity status."); + } + } + } + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.h new file mode 100644 index 0000000..c2a9a3e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +@interface PFTaskQueue : NSObject + +// The lock for this task queue. +@property (nonatomic, strong, readonly) NSObject *mutex; + +/*! + Enqueues a task created by the given block. Then block is given a task to + await once state is snapshotted (e.g. after capturing session tokens at the + time of the save call. Awaiting this task will wait for the created task's + turn in the queue. + */ +- (BFTask *)enqueue:(BFTask *(^)(BFTask *toAwait))taskStart; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.m new file mode 100644 index 0000000..fb6d111 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFTaskQueue.m @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFTaskQueue.h" + +#import + +@interface PFTaskQueue () + +@property (nonatomic, strong, readwrite) BFTask *tail; +@property (nonatomic, strong, readwrite) NSObject *mutex; + +@end + +@implementation PFTaskQueue + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + self.mutex = [[NSObject alloc] init]; + + return self; +} + +- (BFTask *)enqueue:(BFTask *(^)(BFTask *toAwait))taskStart { + @synchronized (self.mutex) { + BFTask *oldTail = self.tail ?: [BFTask taskWithResult:nil]; + + // The task created by taskStart is responsible for waiting on the + // task passed to it before doing its work. This gives it an opportunity + // to do startup work or save state before waiting for its turn in the queue. + BFTask *task = taskStart(oldTail); + + // The tail task should be dependent on the old tail as well as the newly-created + // task. This prevents cancellation of the new task from causing the queue to run + // out of order. + self.tail = [BFTask taskForCompletionOfAllTasks:@[oldTail, task]]; + + return task; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.h new file mode 100644 index 0000000..2ff1e47 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFWeakValue : NSObject + +@property (nonatomic, weak, readonly) id weakObject; + ++ (instancetype)valueWithWeakObject:(id)object; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.m new file mode 100644 index 0000000..a129202 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PFWeakValue.m @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFWeakValue.h" + +@interface PFWeakValue () + +@property (nonatomic, weak, readwrite) id weakObject; + +@end + +@implementation PFWeakValue + ++ (instancetype)valueWithWeakObject:(id)object { + PFWeakValue *value = [[self alloc] init]; + value.weakObject = object; + return value; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseInternal.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseInternal.h new file mode 100644 index 0000000..58e17fc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseInternal.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAssert.h" +#import "PFCommandCache.h" +#import "PFEventuallyQueue.h" +#import "PFFieldOperation.h" +#import "PFGeoPointPrivate.h" +#import "PFInternalUtils.h" +#import "PFKeyValueCache.h" +#import "PFObjectPrivate.h" +#import "PFUserPrivate.h" +#import "ParseModule.h" + +@interface Parse (ParseModules) + ++ (void)enableParseModule:(id)module; ++ (void)disableParseModule:(id)module; ++ (BOOL)isModuleEnabled:(id)module; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.h new file mode 100644 index 0000000..67328ab --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" +#import "PFOfflineStore.h" +#import "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFAnalyticsController; +@class PFCoreManager; +@class PFInstallationIdentifierStore; +@class PFKeychainStore; +@class PFPurchaseController; +@class PFPushManager; + +@interface ParseManager : NSObject + +@property (nonatomic, copy, readonly) NSString *applicationId; +@property (nonatomic, copy, readonly) NSString *clientKey; + +@property (nonatomic, copy, readonly) NSString *applicationGroupIdentifier; +@property (nonatomic, copy, readonly) NSString *containingApplicationIdentifier; + +@property (nonatomic, strong, readonly) PFCoreManager *coreManager; +@property (nonatomic, strong) PFPushManager *pushManager; + +@property (nonatomic, strong) PFAnalyticsController *analyticsController; + +#if TARGET_OS_IOS +@property (nonatomic, strong) PFPurchaseController *purchaseController; +#endif + +///-------------------------------------- +/// @name Initialization +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; + +/*! + Initializes an instance of ParseManager class. + + @param applicationId ApplicationId of Parse app. + @param clientKey ClientKey of Parse app. + + @returns `ParseManager` instance. + */ +- (instancetype)initWithApplicationId:(NSString *)applicationId + clientKey:(NSString *)clientKey NS_DESIGNATED_INITIALIZER; + +/*! + Configures ParseManager with specified properties. + + @param applicationGroupIdentifier Shared AppGroup container identifier. + @param containingApplicationIdentifier Containg application bundle identifier (for extensions). + @param localDataStoreEnabled `BOOL` flag to enable local datastore or not. + */ +- (void)configureWithApplicationGroupIdentifier:(NSString *)applicationGroupIdentifier + containingApplicationIdentifier:(NSString *)containingApplicationIdentifier + enabledLocalDataStore:(BOOL)localDataStoreEnabled; + +///-------------------------------------- +/// @name Offline Store +///-------------------------------------- + +- (void)loadOfflineStoreWithOptions:(PFOfflineStoreOptions)options; + +///-------------------------------------- +/// @name Eventually Queue +///-------------------------------------- + +- (void)clearEventuallyQueue; + +///-------------------------------------- +/// @name Core Manager +///-------------------------------------- + +- (void)unloadCoreManager; + +///-------------------------------------- +/// @name Preloading +///-------------------------------------- + +- (BFTask *)preloadDiskObjectsToMemoryAsync; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.m new file mode 100644 index 0000000..74756c3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseManager.m @@ -0,0 +1,466 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "ParseManager.h" + +#import + +#import "BFTask+Private.h" +#import "PFAnalyticsController.h" +#import "PFAssert.h" +#import "PFCommandCache.h" +#import "PFConfig.h" +#import "PFCoreManager.h" +#import "PFFileManager.h" +#import "PFInstallationIdentifierStore.h" +#import "PFKeyValueCache.h" +#import "PFKeychainStore.h" +#import "PFLogging.h" +#import "PFMultiProcessFileLockController.h" +#import "PFPinningEventuallyQueue.h" +#import "PFPushManager.h" +#import "PFUser.h" +#import "PFURLSessionCommandRunner.h" + +#if !TARGET_OS_WATCH +#import "PFInstallation.h" +#endif + +#if TARGET_OS_IOS +#import "PFPurchaseController.h" +#import "PFProduct.h" +#endif + +static NSString *const _ParseApplicationIdFileName = @"applicationId"; + +@interface ParseManager () +{ + dispatch_queue_t _offlineStoreAccessQueue; + dispatch_queue_t _eventuallyQueueAccessQueue; + dispatch_queue_t _keychainStoreAccessQueue; + dispatch_queue_t _fileManagerAccessQueue; + dispatch_queue_t _installationIdentifierStoreAccessQueue; + dispatch_queue_t _commandRunnerAccessQueue; + dispatch_queue_t _keyValueCacheAccessQueue; + dispatch_queue_t _coreManagerAccessQueue; + dispatch_queue_t _pushManagerAccessQueue; + dispatch_queue_t _controllerAccessQueue; + + dispatch_queue_t _preloadQueue; +} + +@end + +@implementation ParseManager + +@synthesize keychainStore = _keychainStore; +@synthesize fileManager = _fileManager; +@synthesize offlineStore = _offlineStore; +@synthesize eventuallyQueue = _eventuallyQueue; +@synthesize installationIdentifierStore = _installationIdentifierStore; +@synthesize commandRunner = _commandRunner; +@synthesize keyValueCache = _keyValueCache; +@synthesize coreManager = _coreManager; +@synthesize analyticsController = _analyticsController; +@synthesize pushManager = _pushManager; +#if TARGET_OS_IOS +@synthesize purchaseController = _purchaseController; +#endif + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey { + self = [super init]; + if (!self) return nil; + + _offlineStoreAccessQueue = dispatch_queue_create("com.parse.offlinestore.access", DISPATCH_QUEUE_CONCURRENT); + _eventuallyQueueAccessQueue = dispatch_queue_create("com.parse.eventuallyqueue.access", DISPATCH_QUEUE_SERIAL); + _keychainStoreAccessQueue = dispatch_queue_create("com.parse.keychainstore.access", DISPATCH_QUEUE_SERIAL); + _fileManagerAccessQueue = dispatch_queue_create("com.parse.filemanager.access", DISPATCH_QUEUE_SERIAL); + _installationIdentifierStoreAccessQueue = dispatch_queue_create("com.parse.installationidentifierstore.access", + DISPATCH_QUEUE_SERIAL); + _commandRunnerAccessQueue = dispatch_queue_create("com.parse.commandrunner.access", DISPATCH_QUEUE_SERIAL); + _keyValueCacheAccessQueue = dispatch_queue_create("com.parse.keyvaluecache.access", DISPATCH_QUEUE_SERIAL); + _coreManagerAccessQueue = dispatch_queue_create("com.parse.coreManager.access", DISPATCH_QUEUE_SERIAL); + _pushManagerAccessQueue = dispatch_queue_create("com.parse.pushManager.access", DISPATCH_QUEUE_SERIAL); + _controllerAccessQueue = dispatch_queue_create("com.parse.controller.access", DISPATCH_QUEUE_SERIAL); + _preloadQueue = dispatch_queue_create("com.parse.preload", DISPATCH_QUEUE_SERIAL); + + _applicationId = [applicationId copy]; + _clientKey = [clientKey copy]; + + return self; +} + +- (void)configureWithApplicationGroupIdentifier:(NSString *)applicationGroupIdentifier + containingApplicationIdentifier:(NSString *)containingApplicationIdentifier + enabledLocalDataStore:(BOOL)localDataStoreEnabled { + _applicationGroupIdentifier = [applicationGroupIdentifier copy]; + _containingApplicationIdentifier = [containingApplicationIdentifier copy]; + + // Migrate any data if it's required. + [self _migrateSandboxDataToApplicationGroupContainerIfNeeded]; + + // Make sure the data on disk for Parse is for the current application. + [self _checkApplicationId]; + + if (localDataStoreEnabled) { + PFOfflineStoreOptions options = (_applicationGroupIdentifier ? + PFOfflineStoreOptionAlwaysFetchFromSQLite : 0); + [self loadOfflineStoreWithOptions:options]; + } +} + +///-------------------------------------- +#pragma mark - Offline Store +///-------------------------------------- + +- (void)loadOfflineStoreWithOptions:(PFOfflineStoreOptions)options { + PFConsistencyAssert(!_offlineStore, @"Can't load offline store more than once."); + dispatch_barrier_sync(_offlineStoreAccessQueue, ^{ + _offlineStore = [[PFOfflineStore alloc] initWithFileManager:self.fileManager options:options]; + }); +} + +- (void)setOfflineStore:(PFOfflineStore *)offlineStore { + dispatch_barrier_sync(_offlineStoreAccessQueue, ^{ + _offlineStore = offlineStore; + }); +} + +- (PFOfflineStore *)offlineStore { + __block PFOfflineStore *offlineStore = nil; + dispatch_sync(_offlineStoreAccessQueue, ^{ + offlineStore = _offlineStore; + }); + return offlineStore; +} + +- (BOOL)isOfflineStoreLoaded { + return (self.offlineStore != nil); +} + +///-------------------------------------- +#pragma mark - Eventually Queue +///-------------------------------------- + +- (PFEventuallyQueue *)eventuallyQueue { + __block PFEventuallyQueue *queue = nil; + dispatch_sync(_eventuallyQueueAccessQueue, ^{ + if (!_eventuallyQueue || + (self.offlineStoreLoaded && [_eventuallyQueue isKindOfClass:[PFCommandCache class]]) || + (!self.offlineStoreLoaded && [_eventuallyQueue isKindOfClass:[PFPinningEventuallyQueue class]])) { + + id commandRunner = self.commandRunner; + + PFCommandCache *commandCache = [self _newCommandCache]; + _eventuallyQueue = (self.offlineStoreLoaded ? + [PFPinningEventuallyQueue newDefaultPinningEventuallyQueueWithCommandRunner:commandRunner] + : + commandCache); + + // We still need to clear out the old command cache even if we're using Pinning in case + // anything is left over when the user upgraded. Checking number of pending and then + // clearing should be enough. + if (self.offlineStoreLoaded && commandCache.commandCount > 0) { + [commandCache removeAllCommands]; + } + } + queue = _eventuallyQueue; + }); + return queue; +} + +- (PFCommandCache *)_newCommandCache { + // Construct the path to the cache directory in /Library/Private Documents/Parse/Command Cache + // This isn't in the "Library/Caches" directory because we don't want the OS clearing it for us. + // It falls under the category of "offline data". + // See https://developer.apple.com/library/ios/#qa/qa1699/_index.html + NSString *folderPath = [self.fileManager parseDefaultDataDirectoryPath]; + return [PFCommandCache newDefaultCommandCacheWithCommandRunner:self.commandRunner cacheFolderPath:folderPath]; +} + +- (void)clearEventuallyQueue { + dispatch_sync(_preloadQueue, ^{ + dispatch_sync(_eventuallyQueueAccessQueue, ^{ + [_eventuallyQueue removeAllCommands]; + [_eventuallyQueue pause]; + _eventuallyQueue = nil; + }); + }); +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +#pragma mark KeychainStore + +- (PFKeychainStore *)keychainStore { + __block PFKeychainStore *store = nil; + dispatch_sync(_keychainStoreAccessQueue, ^{ + if (!_keychainStore) { + NSString *bundleIdentifier = (_containingApplicationIdentifier ?: [[NSBundle mainBundle] bundleIdentifier]); + NSString *service = [NSString stringWithFormat:@"%@.%@", bundleIdentifier, PFKeychainStoreDefaultService]; + _keychainStore = [[PFKeychainStore alloc] initWithService:service]; + } + store = _keychainStore; + }); + return store; +} + +#pragma mark FileManager + +- (PFFileManager *)fileManager { + __block PFFileManager *fileManager = nil; + dispatch_sync(_fileManagerAccessQueue, ^{ + if (!_fileManager) { + _fileManager = [[PFFileManager alloc] initWithApplicationIdentifier:self.applicationId + applicationGroupIdentifier:self.applicationGroupIdentifier]; + } + fileManager = _fileManager; + }); + return fileManager; +} + +#pragma mark InstallationIdentifierStore + +- (PFInstallationIdentifierStore *)installationIdentifierStore { + __block PFInstallationIdentifierStore *store = nil; + dispatch_sync(_installationIdentifierStoreAccessQueue, ^{ + if (!_installationIdentifierStore) { + _installationIdentifierStore = [[PFInstallationIdentifierStore alloc] initWithFileManager:self.fileManager]; + } + store = _installationIdentifierStore; + }); + return store; +} + +#pragma mark CommandRunner + +- (id)commandRunner { + __block id runner = nil; + dispatch_sync(_commandRunnerAccessQueue, ^{ + if (!_commandRunner) { + _commandRunner = [PFURLSessionCommandRunner commandRunnerWithDataSource:self + applicationId:self.applicationId + clientKey:self.clientKey]; + } + runner = _commandRunner; + }); + return runner; +} + +#pragma mark KeyValueCache + +- (PFKeyValueCache *)keyValueCache { + __block PFKeyValueCache *cache = nil; + dispatch_sync(_keyValueCacheAccessQueue, ^{ + if (!_keyValueCache) { + NSString *path = [self.fileManager parseCacheItemPathForPathComponent:@"../ParseKeyValueCache/"]; + _keyValueCache = [[PFKeyValueCache alloc] initWithCacheDirectoryPath:path]; + } + cache = _keyValueCache; + }); + return cache; +} + +#pragma mark CoreManager + +- (PFCoreManager *)coreManager { + __block PFCoreManager *manager = nil; + dispatch_sync(_coreManagerAccessQueue, ^{ + if (!_coreManager) { + _coreManager = [PFCoreManager managerWithDataSource:self]; + } + manager = _coreManager; + }); + return manager; +} + +- (void)unloadCoreManager { + dispatch_sync(_coreManagerAccessQueue, ^{ + _coreManager = nil; + }); +} + +#if !TARGET_OS_WATCH + +#pragma mark PushManager + +- (PFPushManager *)pushManager { + __block PFPushManager *manager = nil; + dispatch_sync(_pushManagerAccessQueue, ^{ + if (!_pushManager) { + _pushManager = [PFPushManager managerWithCommonDataSource:self coreDataSource:self.coreManager]; + } + manager = _pushManager; + }); + return manager; +} + +- (void)setPushManager:(PFPushManager *)pushManager { + dispatch_sync(_pushManagerAccessQueue, ^{ + _pushManager = pushManager; + }); +} + +#endif + +#pragma mark AnalyticsController + +- (PFAnalyticsController *)analyticsController { + __block PFAnalyticsController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_analyticsController) { + _analyticsController = [[PFAnalyticsController alloc] initWithDataSource:self]; + } + controller = _analyticsController; + }); + return controller; +} + +- (void)setAnalyticsController:(PFAnalyticsController *)analyticsController { + dispatch_sync(_controllerAccessQueue, ^{ + if (_analyticsController != analyticsController) { + _analyticsController = analyticsController; + } + }); +} + +#if TARGET_OS_IOS + +#pragma mark PurchaseController + +- (PFPurchaseController *)purchaseController { + __block PFPurchaseController *controller = nil; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_purchaseController) { + _purchaseController = [PFPurchaseController controllerWithCommandRunner:self.commandRunner + fileManager:self.fileManager + bundle:[NSBundle mainBundle]]; + } + controller = _purchaseController; + }); + return controller; +} + +- (void)setPurchaseController:(PFPurchaseController *)purchaseController { + dispatch_sync(_controllerAccessQueue, ^{ + _purchaseController = purchaseController; + }); +} + +#endif + +///-------------------------------------- +#pragma mark - Preloading +///-------------------------------------- + +- (BFTask *)preloadDiskObjectsToMemoryAsync { + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor executorWithDispatchQueue:_preloadQueue] withBlock:^id{ + @strongify(self); + [PFUser currentUser]; + [PFConfig currentConfig]; +#if !TARGET_OS_WATCH + [PFInstallation currentInstallation]; +#endif + + [self eventuallyQueue]; + + return nil; + }]; +} + +///-------------------------------------- +#pragma mark - ApplicationId +///-------------------------------------- + +/*! + Verifies that the data stored on disk for Parse was generated using the same application that is running now. + */ +- (void)_checkApplicationId { + NSFileManager *systemFileManager = [NSFileManager defaultManager]; + + // Make sure the current version of the cache is for this application id. + NSString *applicationIdFile = [self.fileManager parseDataItemPathForPathComponent:_ParseApplicationIdFileName]; + [[PFMultiProcessFileLockController sharedController] beginLockedContentAccessForFileAtPath:applicationIdFile]; + + if ([systemFileManager fileExistsAtPath:applicationIdFile]) { + NSError *error = nil; + NSString *applicationId = [NSString stringWithContentsOfFile:applicationIdFile + encoding:NSUTF8StringEncoding + error:&error]; + if (!error && ![applicationId isEqualToString:self.applicationId]) { + // The application id has changed, so everything on disk is invalid. + [self.keychainStore removeAllObjects]; + [self.keyValueCache removeAllObjects]; + + NSArray *tasks = @[ + // Remove the contents only, but don't delete the folder. + [PFFileManager removeDirectoryContentsAsyncAtPath:[self.fileManager parseDefaultDataDirectoryPath]], + // Completely remove everything in deprecated folder. + [PFFileManager removeItemAtPathAsync:[self.fileManager parseDataDirectoryPath_DEPRECATED]] + ]; + [[BFTask taskForCompletionOfAllTasks:tasks] waitForResult:nil withMainThreadWarning:NO]; + } + } + + if (![systemFileManager fileExistsAtPath:applicationIdFile]) { + NSError *error = nil; + BFTask *writeTask = [PFFileManager writeStringAsync:self.applicationId toFile:applicationIdFile]; + [writeTask waitForResult:&error withMainThreadWarning:NO]; + if (error) { + PFLogError(PFLoggingTagCommon, @"Unable to create applicationId file with error: %@", error); + } + } + + [[PFMultiProcessFileLockController sharedController] endLockedContentAccessForFileAtPath:applicationIdFile]; +} + +///-------------------------------------- +#pragma mark - Data Sharing +///-------------------------------------- + +- (void)_migrateSandboxDataToApplicationGroupContainerIfNeeded { + // There is no need to migrate anything on OSX, since we are using globally available folder. +#if TARGET_OS_IOS + // Do nothing if there is no application group container or containing application is specified. + if (!self.applicationGroupIdentifier || self.containingApplicationIdentifier) { + return; + } + + NSString *localSandboxDataPath = [self.fileManager parseLocalSandboxDataDirectoryPath]; + NSString *dataPath = [self.fileManager parseDefaultDataDirectoryPath]; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:localSandboxDataPath error:nil]; + if ([contents count] != 0) { + // If moving files fails - just log the error, but don't fail. + NSError *error = nil; + [[PFFileManager moveContentsOfDirectoryAsyncAtPath:localSandboxDataPath + toDirectoryAtPath:dataPath + executor:[BFExecutor immediateExecutor]] waitForResult:&error]; + if (error) { + PFLogError(PFLoggingTagCommon, + @"Failed to migrate local sandbox data to shared container with error %@", + [error localizedDescription]); + } else { + [[PFFileManager removeItemAtPathAsync:localSandboxDataPath withFileLock:NO] waitForResult:nil]; + } + } +#endif +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.h new file mode 100644 index 0000000..a9a1a49 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@protocol ParseModule + +- (void)parseDidInitializeWithApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey; + +@end + +@interface ParseModuleCollection : NSObject + +- (void)addParseModule:(id)module; +- (void)removeParseModule:(id)module; + +- (BOOL)containsModule:(id)module; +- (NSUInteger)modulesCount; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.m new file mode 100644 index 0000000..5167762 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ParseModule.m @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "ParseModule.h" + +///-------------------------------------- +#pragma mark - ParseModuleCollection +///-------------------------------------- + +typedef void (^ParseModuleEnumerationBlock)(id module, BOOL *stop, BOOL *remove); + +@interface ParseModuleCollection () + +@property (atomic, strong) dispatch_queue_t collectionQueue; +@property (atomic, strong) NSPointerArray *modules; + +@end + +@implementation ParseModuleCollection + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (self) { + _collectionQueue = dispatch_queue_create("com.parse.ParseModuleCollection", DISPATCH_QUEUE_SERIAL); + _modules = [NSPointerArray weakObjectsPointerArray]; + } + return self; +} + +///-------------------------------------- +#pragma mark - Collection +///-------------------------------------- + +- (void)addParseModule:(id)module { + if (module == nil) { + return; + } + + [self performCollectionAccessBlock:^{ + [self.modules addPointer:(__bridge void *)module]; + }]; +} + +- (void)removeParseModule:(id)module { + if (module == nil) { + return; + } + + [self enumerateModulesWithBlock:^(id enumeratedModule, BOOL *stop, BOOL *remove) { + *remove = (module == enumeratedModule); + }]; +} + +- (BOOL)containsModule:(id)module { + __block BOOL retValue = NO; + [self enumerateModulesWithBlock:^(id enumeratedModule, BOOL *stop, BOOL *remove) { + if (module == enumeratedModule) { + retValue = YES; + *stop = YES; + } + }]; + return retValue; +} + +- (NSUInteger)modulesCount { + return [self.modules count]; +} + +///-------------------------------------- +#pragma mark - ParseModule +///-------------------------------------- + +- (void)parseDidInitializeWithApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey { + [self enumerateModulesWithBlock:^(id module, BOOL *stop, BOOL *remove) { + dispatch_async(dispatch_get_main_queue(), ^{ + [module parseDidInitializeWithApplicationId:applicationId clientKey:clientKey]; + }); + }]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (void)performCollectionAccessBlock:(dispatch_block_t)block { + dispatch_sync(self.collectionQueue, block); +} + +/*! + Enumerates all existing modules in this collection. + + NOTE: This **will modify the contents of the collection** if any of the modules were deallocated since last loop. + + @param block the block to enumerate with. + */ +- (void)enumerateModulesWithBlock:(ParseModuleEnumerationBlock)block { + [self performCollectionAccessBlock:^{ + NSMutableIndexSet *toRemove = [[NSMutableIndexSet alloc] init]; + + NSUInteger index = 0; + BOOL stop = NO; + + for (__strong id module in self.modules) { + BOOL remove = module == nil; + if (!remove) { + block(module, &stop, &remove); + } + + if (remove) { + [toRemove addIndex:index]; + } + + if (stop) break; + index++; + } + + // NSPointerArray doesn't have a -removeObjectsAtIndexes:... WHY!?!? + for (index = toRemove.firstIndex; index != NSNotFound; index = [toRemove indexGreaterThanIndex:index]) { + [self.modules removePointerAtIndex:index]; + } + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Parse_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Parse_Private.h new file mode 100644 index 0000000..176dd1f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Parse_Private.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "ParseManager.h" + +@class PFEventuallyQueue; + +@interface Parse () + ++ (void)_resetDataSharingIdentifiers; + ++ (ParseManager *)_currentManager; ++ (void)_clearCurrentManager; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/PFProduct+Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/PFProduct+Private.h new file mode 100644 index 0000000..af69e41 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/PFProduct+Private.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFProduct.h" + +typedef enum { + PFProductDownloadStateStart, + PFProductDownloadStateDownloading, + PFProductDownloadStateDownloaded +} PFProductDownloadState; + +@interface PFProduct () { + NSDecimalNumber *price; + NSLocale *priceLocale; + NSInteger progress; + NSString *contentPath; +} + +/// The properties below are transient properties, not stored on Parse's server. +/*! + The price of the product, discovered via iTunes Connect. + */ +@property (nonatomic, strong) NSDecimalNumber *price; + +/*! + The price locale of the product. + */ +@property (nonatomic, strong) NSLocale *priceLocale; + +/*! + The progress of the download, if one is in progress. It's an integer between 0 and 100. + */ +@property (nonatomic, assign) NSInteger progress; + +/*! + The content path of the download. + */ +@property (nonatomic, strong) NSString *contentPath; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h new file mode 100644 index 0000000..2c9c3da --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +PF_WATCH_UNAVAILABLE @interface PFProductsRequestResult : NSObject + +@property (nonatomic, copy, readonly) NSSet *validProducts; +@property (nonatomic, copy, readonly) NSSet *invalidProductIdentifiers; + +- (instancetype)initWithProductsResponse:(SKProductsResponse *)response; + +@end + +/*! + * This class is responsible for handling the first part of an IAP handshake. + * It sends a request to iTunes Connect with a set of product identifiers, and iTunes returns + * with a list of valid and invalid products. The class then proceeds to call the completion block passed in. + */ +@interface PFProductsRequestHandler : NSObject + +- (instancetype)initWithProductsRequest:(SKProductsRequest *)request; + +- (BFTask *)findProductsAsync; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m new file mode 100644 index 0000000..4dbce94 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFProductsRequestHandler.h" + +#import +#import + +@implementation PFProductsRequestResult + +- (instancetype)initWithProductsResponse:(SKProductsResponse *)response { + self = [super init]; + if (!self) return nil; + + _validProducts = [NSSet setWithArray:response.products]; + _invalidProductIdentifiers = [NSSet setWithArray:response.invalidProductIdentifiers]; + + return self; +} + +@end + +@interface PFProductsRequestHandler () + +@property (nonatomic, strong) BFTaskCompletionSource *taskCompletionSource; +@property (nonatomic, strong) SKProductsRequest *productsRequest; + +@end + +@implementation PFProductsRequestHandler + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithProductsRequest:(SKProductsRequest *)request { + self = [super init]; + if (!self) return nil; + + _productsRequest = request; + _productsRequest.delegate = self; + + return self; +} + +///-------------------------------------- +#pragma mark - Dealloc +///-------------------------------------- + +- (void)dealloc { + // Clear the delegate, as it's still an `assign`, instead of `weak` + _productsRequest.delegate = nil; +} + +///-------------------------------------- +#pragma mark - Find +///-------------------------------------- + +- (BFTask *)findProductsAsync { + _taskCompletionSource = [BFTaskCompletionSource taskCompletionSource]; + [_productsRequest start]; + return _taskCompletionSource.task; +} + +///-------------------------------------- +#pragma mark - SKProductsRequestDelegate +///-------------------------------------- + +- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { + PFProductsRequestResult *result = [[PFProductsRequestResult alloc] initWithProductsResponse:response]; + [self.taskCompletionSource trySetResult:result]; +} + +- (void)request:(SKRequest *)request didFailWithError:(NSError *)error { + [self.taskCompletionSource trySetError:error]; + + // according to documentation, this method does not call requestDidFinish + request.delegate = nil; +} + +- (void)requestDidFinish:(SKRequest *)request { + // the documentation assures that this is the point safe to get rid of the request + request.delegate = nil; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.h new file mode 100644 index 0000000..efd4c17 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFPropertyInfo : NSObject + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithClass:(Class)kls + name:(NSString *)propertyName; + +- (instancetype)initWithClass:(Class)kls + name:(NSString *)propertyName + associationType:(PFPropertyInfoAssociationType)associationType NS_DESIGNATED_INITIALIZER; + ++ (instancetype)propertyInfoWithClass:(Class)kls + name:(NSString *)propertyName; + ++ (instancetype)propertyInfoWithClass:(Class)kls + name:(NSString *)propertyName + associationType:(PFPropertyInfoAssociationType)associationType; + +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, readonly) PFPropertyInfoAssociationType associationType; + +/*! + Returns the value of this property, + properly wrapped from the target object. + When possible, just invokes the property. + When not, uses -valueForKey:. + */ +- (nullable id)getWrappedValueFrom:(id)object; +- (void)setWrappedValue:(nullable id)value forObject:(id)object; + +// Moves the value from one object to the other, based on the association type given. +- (void)takeValueFrom:(id)one toObject:(id)two; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.m new file mode 100644 index 0000000..9d1273c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo.m @@ -0,0 +1,212 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPropertyInfo_Private.h" + +#import + +#import "PFAssert.h" +#import "PFMacros.h" +#import "PFPropertyInfo_Runtime.h" + +static inline NSString *safeStringWithPropertyAttributeValue(objc_property_t property, const char *attribute) { + char *value = property_copyAttributeValue(property, attribute); + if (!value) + return nil; + + // NSString initWithBytesNoCopy doesn't seem to work, so fall back to the CF counterpart. + return (__bridge_transfer NSString *)CFStringCreateWithCStringNoCopy(NULL, + value, + kCFStringEncodingUTF8, + kCFAllocatorMalloc); +} + +static inline NSString *stringByCapitalizingFirstCharacter(NSString *string) { + return [NSString stringWithFormat:@"%C%@", + (unichar)toupper([string characterAtIndex:0]), + [string substringFromIndex:1]]; +} + +@implementation PFPropertyInfo + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithClass:(Class)kls name:(NSString *)propertyName { + return [self initWithClass:kls name:propertyName associationType:_associationType]; +} + +- (instancetype)initWithClass:(Class)kls name:(NSString *)propertyName + associationType:(PFPropertyInfoAssociationType)associationType { + self = [super init]; + if (!self) return nil; + + _sourceClass = kls; + _name = [propertyName copy]; + _associationType = associationType; + + objc_property_t objcProperty = class_getProperty(kls, [_name UTF8String]); + + do { + _ivar = class_getInstanceVariable(kls, [safeStringWithPropertyAttributeValue(objcProperty, "V") UTF8String]); + if (_ivar) break; + + // Walk the superclass heirarchy for the property definition. Because property attributes are not inherited + // (but property definitions *are*), we must be careful to ensure that the variable was never actually + // implemented and synthesized in a superclass. Note if the same property is synthesized in multiple classes + // with different iVars, we take the class furthest from the root class as the 'source of truth'. + Class superClass = class_getSuperclass(kls); + while (superClass) { + objc_property_t superProperty = class_getProperty(superClass, [_name UTF8String]); + if (!superProperty) break; + + _ivar = class_getInstanceVariable(superClass, [safeStringWithPropertyAttributeValue(superProperty, "V") UTF8String]); + if (_ivar) break; + + superClass = class_getSuperclass(superClass); + } + + if (_ivar) break; + + // Attempt to infer the variable name. + _ivar = class_getInstanceVariable(kls, [[@"_" stringByAppendingString:_name] UTF8String]); + if (_ivar) break; + + _ivar = class_getInstanceVariable(kls, [_name UTF8String]); + } while (0); + + _typeEncoding = safeStringWithPropertyAttributeValue(objcProperty, "T"); + _object = [_typeEncoding hasPrefix:@"@"]; + + NSString *propertyGetter = safeStringWithPropertyAttributeValue(objcProperty, "G") ?: _name; + _getterSelector = NSSelectorFromString(propertyGetter); + + BOOL readonly = safeStringWithPropertyAttributeValue(objcProperty, "R") != nil; + NSString *propertySetter = safeStringWithPropertyAttributeValue(objcProperty, "S"); + if (propertySetter == nil && !readonly) { + propertySetter = [NSString stringWithFormat:@"set%@:", stringByCapitalizingFirstCharacter(_name)]; + } + + _setterSelector = NSSelectorFromString(propertySetter); + + if (_associationType == PFPropertyInfoAssociationTypeDefault) { + BOOL isCopy = safeStringWithPropertyAttributeValue(objcProperty, "C") != nil; + BOOL isWeak = safeStringWithPropertyAttributeValue(objcProperty, "W") != nil; + BOOL isRetain = safeStringWithPropertyAttributeValue(objcProperty, "&") != nil; + + if (isWeak) { + _associationType = PFPropertyInfoAssociationTypeWeak; + } else if (isCopy) { + _associationType = PFPropertyInfoAssociationTypeCopy; + } else if (isRetain) { + _associationType = PFPropertyInfoAssociationTypeStrong; + } else { + _associationType = PFPropertyInfoAssociationTypeAssign; + } + } + + return self; +} + ++ (instancetype)propertyInfoWithClass:(Class)kls name:(NSString *)propertyName { + return [[self alloc] initWithClass:kls name:propertyName]; +} + ++ (instancetype)propertyInfoWithClass:(Class)kls name:(NSString *)propertyName + associationType:(PFPropertyInfoAssociationType)associationType { + return [[self alloc] initWithClass:kls name:propertyName associationType:associationType]; +} + +///-------------------------------------- +#pragma mark - Wrapping +///-------------------------------------- + +- (id)getWrappedValueFrom:(id)object { + if (self.object) { + return objc_msgSend_safe(id)(object, self.getterSelector); + } + + return [object valueForKey:self.name]; +} + +- (void)setWrappedValue:(id)value forObject:(id)object { + if (self.object && self.setterSelector) { + objc_msgSend_safe(void, id)(object, self.setterSelector, value); + return; + } + + [object setValue:value forKey:self.name]; +} + +///-------------------------------------- +#pragma mark - Taking +///-------------------------------------- + +- (void)takeValueFrom:(id)one toObject:(id)two { + if (!self.ivar) { + id wrappedValue = [self getWrappedValueFrom:one]; + [self setWrappedValue:wrappedValue forObject:two]; + + return; + } + + NSUInteger size = 0; + NSGetSizeAndAlignment(ivar_getTypeEncoding(self.ivar), &size, NULL); + + char valuePtr[size]; + bzero(valuePtr, size); + + NSInvocation *invocation = nil; + + // TODO: (richardross) Cache the method signatures, as those are fairly slow to calculate. + if (one && [one respondsToSelector:self.getterSelector]) { + NSMethodSignature *methodSignature = [one methodSignatureForSelector:self.getterSelector]; + invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; + + [invocation setTarget:one]; + [invocation setSelector:self.getterSelector]; + } + + [invocation invoke]; + [invocation getReturnValue:valuePtr]; + + object_setIvarValue_safe(two, self.ivar, valuePtr, self.associationType); +} + +///-------------------------------------- +#pragma mark - Equality +///-------------------------------------- + +- (NSUInteger)hash { + return 0; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + PFPropertyInfo *other = object; + + // If they're the same property and one of them subclasses the other, do no further checking. + return [self.name isEqual:other.name] && + ([self.sourceClass isSubclassOfClass:other.sourceClass] || + [other.sourceClass isSubclassOfClass:self.sourceClass]); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h new file mode 100644 index 0000000..db9ebea --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPropertyInfo.h" + +@interface PFPropertyInfo () + +@property (atomic, assign, readonly) Class sourceClass; +@property (atomic, assign, readonly, getter=isObject) BOOL object; + +@property (atomic, copy, readonly) NSString *typeEncoding; +@property (atomic, assign, readonly) Ivar ivar; + +@property (atomic, assign, readonly) SEL getterSelector; +@property (atomic, assign, readonly) SEL setterSelector; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h new file mode 100644 index 0000000..bc1b59e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPropertyInfo.h" + +#import + +/*! + @abstract Safely sets an object's instance variable to the variable in the specified address. + @discussion The Objective-C runtime's built-in methods for setting instance variables (`object_setIvar`) and + (`object_setInstanceVariable`), are both terrible. They never read any more than a single pointer, so they + fail for structs, as well as 64 bit numbers on 32 bit platforms. Because of this, we need a solution to allow us to + safely set instance variable values whose sizes may be significantly more than a pointer. + + @note Like most Objective-C runtime methods, this WILL fail if you try and set a bitfield, so please don't do that. + + @param obj The object to operate on. + @param ivar The ivar to set the new value for. + @param fromMemory The **address** of the new value to set. + @param associationType The association type of the new value. One of PFPropertyInfoAssociationType. + */ +extern void object_setIvarValue_safe(__unsafe_unretained id obj, Ivar ivar, void *fromMemory, uint8_t associationType); + +/*! + @abstract Safely gets an object's instance variable and puts it into the specified address. + @discussion The Objective-C runtime's built-in methods for getting instance variables (`object_getIvar`) and + (`object_getInstanceVariable`), are both terrible. They never read any more than a single pointer, so they + fail for structs, as well as 64 bit numbers on 32 bit platforms. Because of this, we need a solution to allow us to + safely get instance variable values whose sizes may be significantly more than a pointer. + + @note Like most Objective-C runtime methods, this WILL fail if you try and set a bitfield, so please don't do that. + + @param obj The object to operate on. + @param ivar The ivar to get the value from. + @param toMemory The address to copy the value into. + @param associationType The assocation type of the new value. One of PFPrropertyInfoAssocationType. + */ +extern void object_getIvarValue_safe(__unsafe_unretained id obj, Ivar ivar, void *toMemory, uint8_t associationType); diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m new file mode 100644 index 0000000..a2071f1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPropertyInfo_Runtime.h" + +#import +#import + +/*! + This macro is really interesting. Because ARC will insert implicit retains, releases and other memory managment code + that we don't want here, we have to basically trick ARC into treating the functions we want as functions with type + `void *`. The way we do that is actually via the linker - instead of coming up with some crazy macro to forward all + arguments along to the correct function, especially when some of these functions aren't in any public headers. + + They are, however, well defined, according to the clang official ARC runtime support document: + http://clang.llvm.org/docs/AutomaticReferenceCounting.html#id55 + + That means this is unlikely to ever break. + + The weakref attribute is documented here: + https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes + + And we use this to make sure our type-invariant functions actually call the proper underlying ones. + */ +#define NO_TYPECHECK_SYMBOL(ret, fn, args...) static ret fn ## _noTypeCheck (args) __attribute__((weakref(#fn))); +#define OBJECT_GETOFFSET_PTR(obj, offset) (void *) ((uintptr_t)obj + offset) + +NO_TYPECHECK_SYMBOL(void *, objc_loadWeak, void **); + +NO_TYPECHECK_SYMBOL(void *, objc_storeWeak, void **, void *); +NO_TYPECHECK_SYMBOL(void *, objc_storeStrong, void **, void *); + +NO_TYPECHECK_SYMBOL(void *, objc_autorelease, void *); +NO_TYPECHECK_SYMBOL(void *, objc_retainAutorelease, void *); + +void object_getIvarValue_safe(__unsafe_unretained id obj, Ivar ivar, void *toMemory, uint8_t associationType) { + ptrdiff_t offset = ivar_getOffset(ivar); + void *location = OBJECT_GETOFFSET_PTR(obj, offset); + + switch (associationType) { + case PFPropertyInfoAssociationTypeDefault: + [NSException raise:NSInvalidArgumentException format:@"Invalid association type Default!"]; + break; + + case PFPropertyInfoAssociationTypeAssign: { + NSUInteger size = 0; + NSGetSizeAndAlignment(ivar_getTypeEncoding(ivar), &size, NULL); + + memcpy(toMemory, location, size); + break; + } + + case PFPropertyInfoAssociationTypeWeak: { + void *results = objc_loadWeak_noTypeCheck(location); + + memcpy(toMemory, &results, sizeof(id)); + break; + } + + case PFPropertyInfoAssociationTypeStrong: + case PFPropertyInfoAssociationTypeCopy: + case PFPropertyInfoAssociationTypeMutableCopy: { + void *objectValue = *(void **)location; + objectValue = objc_retainAutorelease_noTypeCheck(objectValue); + + memcpy(toMemory, &objectValue, sizeof(id)); + break; + } + } +} + +void object_setIvarValue_safe(__unsafe_unretained id obj, Ivar ivar, void *fromMemory, uint8_t associationType) { + ptrdiff_t offset = ivar_getOffset(ivar); + void *location = OBJECT_GETOFFSET_PTR(obj, offset); + + NSUInteger size = 0; + NSGetSizeAndAlignment(ivar_getTypeEncoding(ivar), &size, NULL); + + void *newValue = NULL; + + switch (associationType) { + case PFPropertyInfoAssociationTypeDefault: + [NSException raise:NSInvalidArgumentException format:@"Invalid association type Default!"]; + return; + + case PFPropertyInfoAssociationTypeAssign: { + memcpy(location, fromMemory, size); + return; + } + + case PFPropertyInfoAssociationTypeWeak: { + objc_storeWeak_noTypeCheck(location, *(void **)fromMemory); + return; + } + + case PFPropertyInfoAssociationTypeStrong: + newValue = *(void **)fromMemory; + break; + + case PFPropertyInfoAssociationTypeCopy: + case PFPropertyInfoAssociationTypeMutableCopy: { + SEL command = (associationType == PFPropertyInfoAssociationTypeCopy) ? @selector(copy) + : @selector(mutableCopy); + + + void *(*objc_msgSend_casted)(void *, SEL) = (void *)objc_msgSend; + void *oldValue = *(void **)fromMemory; + + newValue = objc_msgSend_casted(oldValue, command); + newValue = objc_autorelease_noTypeCheck(newValue); + break; + } + } + + objc_storeStrong_noTypeCheck(location, newValue); +} diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.h new file mode 100644 index 0000000..dcd1e04 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFFileManager; +@class PFPaymentTransactionObserver; +@class PFProductsRequestResult; + +@protocol PFCommandRunning; +@class SKPaymentQueue; +@class SKPaymentTransaction; + +PF_WATCH_UNAVAILABLE @interface PFPurchaseController : NSObject + +@property (nonatomic, strong, readonly) id commandRunner; +@property (nonatomic, strong, readonly) PFFileManager *fileManager; +@property (nonatomic, strong, readonly) NSBundle *bundle; + +@property (nonatomic, strong) SKPaymentQueue *paymentQueue; +@property (nonatomic, strong, readonly) PFPaymentTransactionObserver *transactionObserver; + +@property (nonatomic, assign) Class productsRequestClass; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommandRunner:(id)commandRunner + fileManager:(PFFileManager *)fileManager + bundle:(NSBundle *)bundle NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner + fileManager:(PFFileManager *)fileManager + bundle:(NSBundle *)bundle; + +///-------------------------------------- +/// @name Products +///-------------------------------------- + +- (BFTask *)findProductsAsyncWithIdentifiers:(NSSet *)productIdentifiers; +- (BFTask *)buyProductAsyncWithIdentifier:(NSString *)productIdentifier; +- (BFTask *)downloadAssetAsyncForTransaction:(SKPaymentTransaction *)transaction + withProgressBlock:(PFProgressBlock)progressBlock + sessionToken:(NSString *)sessionToken; + +- (NSString *)assetContentPathForProductWithIdentifier:(NSString *)identifier fileName:(NSString *)fileName; +- (BOOL)canPurchase; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.m new file mode 100644 index 0000000..58f2110 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/Controller/PFPurchaseController.m @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPurchaseController.h" + +#import + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFConstants.h" +#import "PFDecoder.h" +#import "PFFileManager.h" +#import "PFFile_Private.h" +#import "PFHTTPRequest.h" +#import "PFMacros.h" +#import "PFPaymentTransactionObserver.h" +#import "PFProductsRequestHandler.h" +#import "PFRESTCommand.h" + +@interface PFPurchaseController () { + PFProductsRequestHandler *_currentProductsRequestHandler; +} + +@end + +@implementation PFPurchaseController + +@synthesize paymentQueue = _paymentQueue; +@synthesize transactionObserver = _transactionObserver; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner + fileManager:(PFFileManager *)fileManager + bundle:(NSBundle *)bundle { + self = [super init]; + if (!self) return nil; + + _commandRunner = commandRunner; + _fileManager = fileManager; + _bundle = bundle; + + return self; +} + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner + fileManager:(PFFileManager *)fileManager + bundle:(NSBundle *)bundle { + return [[self alloc] initWithCommandRunner:commandRunner fileManager:fileManager bundle:bundle]; +} + +///-------------------------------------- +#pragma mark - Dealloc +///-------------------------------------- + +- (void)dealloc { + if (_paymentQueue && _transactionObserver) { + [_paymentQueue removeTransactionObserver:_transactionObserver]; + } +} + +///-------------------------------------- +#pragma mark - Products +///-------------------------------------- + +- (BFTask *)findProductsAsyncWithIdentifiers:(NSSet *)productIdentifiers { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id { + @strongify(self); + Class requestClass = self.productsRequestClass ?: [SKProductsRequest class]; + SKProductsRequest *request = [[requestClass alloc] initWithProductIdentifiers:productIdentifiers]; + _currentProductsRequestHandler = [[PFProductsRequestHandler alloc] initWithProductsRequest:request]; + return [_currentProductsRequestHandler findProductsAsync]; + }] continueWithSuccessBlock:^id(BFTask *task) { + _currentProductsRequestHandler = nil; + return task; + }]; +} + +- (BFTask *)buyProductAsyncWithIdentifier:(NSString *)productIdentifier { + PFParameterAssert(productIdentifier, @"You must pass in a valid product identifier."); + + if (![self canPurchase]) { + NSError *error = [NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorPaymentDisabled + userInfo:nil]; + return [BFTask taskWithError:error]; + } + NSSet *identifiers = PF_SET(productIdentifier); + @weakify(self); + return [[self findProductsAsyncWithIdentifiers:identifiers] continueWithSuccessBlock:^id(BFTask *task) { + PFProductsRequestResult *result = task.result; + @strongify(self); + + for (NSString *invalidIdentifier in result.invalidProductIdentifiers) { + if ([invalidIdentifier isEqualToString:productIdentifier]) { + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorInvalidProductIdentifier + userInfo:nil]]; + } + } + + for (SKProduct *product in result.validProducts) { + if ([product.productIdentifier isEqualToString:productIdentifier]) { + BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; + [self.transactionObserver handle:productIdentifier runOnceBlock:^(NSError *error) { + if (error) { + [source trySetError:error]; + } else { + [source trySetResult:nil]; + } + }]; + SKPayment *payment = [SKPayment paymentWithProduct:product]; + [self.paymentQueue addPayment:payment]; + return source.task; + } + } + + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorProductNotFoundInAppStore + userInfo:nil]]; + }]; +} + +- (BFTask *)downloadAssetAsyncForTransaction:(SKPaymentTransaction *)transaction + withProgressBlock:(PFProgressBlock)progressBlock + sessionToken:(NSString *)sessionToken { + NSString *productIdentifier = transaction.payment.productIdentifier; + NSURL *appStoreReceiptURL = [self.bundle appStoreReceiptURL]; + if (!productIdentifier || !appStoreReceiptURL) { + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorReceiptMissing + userInfo:nil]]; + } + + NSError *error = nil; + NSData *appStoreReceipt = [NSData dataWithContentsOfURL:appStoreReceiptURL + options:NSDataReadingMappedIfSafe + error:&error]; + if (!appStoreReceipt || error) { + NSDictionary *userInfo = nil; + if (error) { + userInfo = @{ NSUnderlyingErrorKey : error }; + } + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorReceiptMissing + userInfo:userInfo]]; + } + + NSDictionary *params = [[PFEncoder objectEncoder] encodeObject:@{ @"receipt" : appStoreReceipt, + @"productIdentifier" : productIdentifier }]; + PFRESTCommand *command = [PFRESTCommand commandWithHTTPPath:@"validate_purchase" + httpMethod:PFHTTPRequestMethodPOST + parameters:params + sessionToken:sessionToken]; + BFTask *task = [self.commandRunner runCommandAsync:command withOptions:PFCommandRunningOptionRetryIfFailed]; + @weakify(self); + return [task continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + + PFCommandResult *result = task.result; + PFFile *file = [[PFDecoder objectDecoder] decodeObject:result.result]; + if (![file isKindOfClass:[PFFile class]]) { + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorInvalidPurchaseReceipt + userInfo:result.result]]; + } + + NSString *finalFilePath = [self assetContentPathForProductWithIdentifier:transaction.payment.productIdentifier + fileName:file.name]; + NSString *directoryPath = [finalFilePath stringByDeletingLastPathComponent]; + return [[[[[PFFileManager createDirectoryIfNeededAsyncAtPath:directoryPath] continueWithBlock:^id(BFTask *task) { + if (task.faulted) { + return [BFTask taskWithError:[NSError errorWithDomain:PFParseErrorDomain + code:kPFErrorProductDownloadFileSystemFailure + userInfo:nil]]; + } + return file; + }] continueWithSuccessBlock:^id(BFTask *task) { + return [file getDataStreamInBackgroundWithProgressBlock:progressBlock]; + }] continueWithSuccessBlock:^id(BFTask *task) { + NSString *cachedFilePath = [file _cachedFilePath]; + return [[PFFileManager copyItemAsyncAtPath:cachedFilePath + toPath:finalFilePath] continueWithBlock:^id(BFTask *task) { + // No-op file exists error. + if (task.error.code == NSFileWriteFileExistsError) { + return nil; + } + return task; + }]; + }] continueWithSuccessResult:finalFilePath]; + }]; +} + +- (NSString *)assetContentPathForProductWithIdentifier:(NSString *)identifier fileName:(NSString *)fileName { + // We store files locally at (ParsePrivateDir)/(ProductIdentifier)/filename + NSString *filePath = [self.fileManager parseDataItemPathForPathComponent:identifier]; + filePath = [filePath stringByAppendingPathComponent:fileName]; + return filePath; +} + +- (BOOL)canPurchase { + return [[self.paymentQueue class] canMakePayments]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (SKPaymentQueue *)paymentQueue { + if (!_paymentQueue) { + _paymentQueue = [SKPaymentQueue defaultQueue]; + } + return _paymentQueue; +} + +- (PFPaymentTransactionObserver *)transactionObserver { + if (!_transactionObserver) { + _transactionObserver = [[PFPaymentTransactionObserver alloc] init]; + [self.paymentQueue addTransactionObserver:_transactionObserver]; + } + return _transactionObserver; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h new file mode 100644 index 0000000..db0e43c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +/*! + * The PFPaymentTransactionObserver listens to the payment queue, processes a payment by running business logic, + * and completes the transaction. It's a complex interaction and best explained as follows: + * 1) an observer object is created and added to the payment queue, typically before IAP happens (but not necessarily), + * 2) PFPurchase creates a payment and adds it to the payment queue, + * 3) when the observer sees this payment, it runs the business logic associated with this payment, + * 4) when the business logic finishes, the observer completes the transaction. If the business logic does not finish, the transaction is not completed, which means the user does not get charged, + * 5) after the transaction finishes, custom UI logic is run. + */ +PF_WATCH_UNAVAILABLE @interface PFPaymentTransactionObserver : NSObject + +- (void)handle:(NSString *)productIdentifier block:(void (^)(SKPaymentTransaction *))block; +- (void)handle:(NSString *)productIdentifier runOnceBlock:(void (^)(NSError *))block; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m new file mode 100644 index 0000000..100750d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPaymentTransactionObserver_Private.h" + +#import "PFAssert.h" + +@implementation PFPaymentTransactionObserver + +@synthesize blocks; +@synthesize runOnceBlocks; +@synthesize lockObj; +@synthesize runOnceLockObj; + +///-------------------------------------- +#pragma mark - NSObject +///-------------------------------------- + +- (instancetype)init { + if (self = [super init]) { + blocks = [[NSMutableDictionary alloc] init]; + runOnceBlocks = [[NSMutableDictionary alloc] init]; + lockObj = [[NSObject alloc] init]; + runOnceLockObj = [[NSObject alloc] init]; + } + return self; +} + +///-------------------------------------- +#pragma mark - SKPaymentTransactionObserver +///-------------------------------------- + +- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { + for (SKPaymentTransaction *transaction in transactions) { + switch (transaction.transactionState) { + case SKPaymentTransactionStatePurchased: + case SKPaymentTransactionStateFailed: + case SKPaymentTransactionStateRestored: + [self completeTransaction:transaction fromPaymentQueue:queue]; + break; + default: + break; + } + } +} + +///-------------------------------------- +#pragma mark - PFPaymentTransactionObserver +///-------------------------------------- + +- (void)completeTransaction:(SKPaymentTransaction *)transaction fromPaymentQueue:(SKPaymentQueue *)queue { + NSString *productIdentifier = transaction.payment.productIdentifier; + + @synchronized(lockObj) { + void(^completion)(SKPaymentTransaction *) = self.blocks[productIdentifier]; + if (!transaction.error && completion) { + completion(transaction); + } + } + + @synchronized(runOnceLockObj) { + void(^runOnceBlock)(NSError *) = (void(^)(NSError *))[self.runOnceBlocks objectForKey:productIdentifier]; + if (runOnceBlock) { + runOnceBlock(transaction.error); + [self.runOnceBlocks removeObjectForKey:productIdentifier]; + } + } + + // Calling finish:transaction here prevents the user from registering another observer to handle this transaction. + [queue finishTransaction:transaction]; +} + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +- (void)handle:(NSString *)productIdentifier block:(void(^)(SKPaymentTransaction *))block { + @synchronized(lockObj) { + self.blocks[productIdentifier] = block; + } +} + +- (void)handle:(NSString *)productIdentifier runOnceBlock:(void(^)(NSError *))block { + @synchronized(runOnceLockObj) { + PFConsistencyAssert(self.runOnceBlocks[productIdentifier] == nil, + @"You cannot purchase a product that is in the process of being purchased."); + + if (!block) { + // Create a no-op action so that we can store it in the dictionary, + // this is useful because we use the existence of this block to test if + // the same product is being purchased at the time. + block = ^(NSError *error) { + }; + } + self.runOnceBlocks[productIdentifier] = block; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h new file mode 100644 index 0000000..268af07 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPaymentTransactionObserver.h" + +@interface PFPaymentTransactionObserver () + +@property (nonatomic, strong) NSMutableDictionary *blocks; +@property (nonatomic, strong) NSMutableDictionary *runOnceBlocks; +@property (nonatomic, strong) NSObject *lockObj; +@property (nonatomic, strong) NSObject *runOnceLockObj; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.h new file mode 100644 index 0000000..95bea76 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFPushChannelsController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Get +///-------------------------------------- + +- (BFTask *)getSubscribedChannelsAsync; + +///-------------------------------------- +/// @name Subscribe +///-------------------------------------- + +- (BFTask *)subscribeToChannelAsyncWithName:(NSString *)name; +- (BFTask *)unsubscribeFromChannelAsyncWithName:(NSString *)name; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.m new file mode 100644 index 0000000..e8d3d8e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/ChannelsController/PFPushChannelsController.m @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushChannelsController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCurrentInstallationController.h" +#import "PFErrorUtilities.h" +#import "PFInstallation.h" + +@interface PFPushChannelsController () + +@property (nonatomic, strong, readonly) PFCurrentInstallationController *currentInstallationController; + +@end + +@implementation PFPushChannelsController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithDataSource:(nonnull id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(nonnull id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Get +///-------------------------------------- + +- (BFTask *)getSubscribedChannelsAsync { + return [[self _getCurrentObjectAsync] continueWithSuccessBlock:^id(BFTask *task) { + PFInstallation *installation = task.result; + + BFTask *installationTask = (installation.objectId + ? (BFTask *)[installation fetchInBackground] + : (BFTask *)[installation saveInBackground]); + + return [installationTask continueWithSuccessBlock:^id(BFTask *task) { + return [NSSet setWithArray:installation.channels]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Subscribe +///-------------------------------------- + +- (BFTask *)subscribeToChannelAsyncWithName:(nonnull NSString *)name { + return [[self _getCurrentObjectAsync] continueWithSuccessBlock:^id(BFTask *task) { + PFInstallation *installation = task.result; + if ([installation.channels containsObject:name] && + ![installation isDirtyForKey:@"channels"]) { + return @YES; + } + + [installation addUniqueObject:name forKey:@"channels"]; + return [installation saveInBackground]; + }]; +} + +- (BFTask *)unsubscribeFromChannelAsyncWithName:(nonnull NSString *)name { + return [[self _getCurrentObjectAsync] continueWithSuccessBlock:^id(BFTask *task) { + PFInstallation *installation = task.result; + if (name.length != 0 && + ![installation.channels containsObject:name] && + ![installation isDirtyForKey:@"channels"]) { + return @YES; + } + [installation removeObject:name forKey:@"channels"]; + return [installation saveInBackground]; + }]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +- (BFTask *)_getCurrentObjectAsync { + return [[self.currentInstallationController getCurrentObjectAsync] continueWithSuccessBlock:^id(BFTask *task) { + PFInstallation *installation = task.result; + if (!installation.deviceToken) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorPushMisconfigured + message:@"There is no device token stored yet."]; + return [BFTask taskWithError:error]; + } + + return task; + }]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (PFCurrentInstallationController *)currentInstallationController { + return self.dataSource.currentInstallationController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.h new file mode 100644 index 0000000..0f66b42 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFPushState; +@protocol PFCommandRunning; + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFPushController : NSObject + +@property (nonatomic, strong, readonly) id commandRunner; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommandRunner:(id)commandRunner NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner; + +///-------------------------------------- +/// @name Sending Push +///-------------------------------------- + +/*! + Requests push notification to be sent for a given state. + + @param state State to use to send notifications. + @param sessionToken Current user session token. + + @returns `BFTask` with result set to `NSNumber` with `BOOL` identifying whether the request succeeded. + */ +- (BFTask *)sendPushNotificationAsyncWithState:(PFPushState *)state sessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.m new file mode 100644 index 0000000..36472de --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Controller/PFPushController.m @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandRunning.h" +#import "PFMacros.h" +#import "PFRESTPushCommand.h" + +@implementation PFPushController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommandRunner:(id)commandRunner { + self = [super init]; + if (!self) return nil; + + _commandRunner = commandRunner; + + return self; +} + ++ (instancetype)controllerWithCommandRunner:(id)commandRunner { + return [[self alloc] initWithCommandRunner:commandRunner]; +} + +///-------------------------------------- +#pragma mark - Sending Push +///-------------------------------------- + +- (BFTask *)sendPushNotificationAsyncWithState:(PFPushState *)state + sessionToken:(NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTPushCommand sendPushCommandWithPushState:state sessionToken:sessionToken]; + return [self.commandRunner runCommandAsync:command withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + return @(task.result != nil); + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.h new file mode 100644 index 0000000..9d2878a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFDataProvider.h" + +@class PFPushChannelsController; +@class PFPushController; + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFPushManager : NSObject + +@property (nonatomic, weak, readonly) id commonDataSource; +@property (nonatomic, weak, readonly) id coreDataSource; + +@property (nonatomic, strong) PFPushController *pushController; +@property (nonatomic, strong) PFPushChannelsController *channelsController; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)managerWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.m new file mode 100644 index 0000000..d02f681 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Manager/PFPushManager.m @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushManager.h" + +#import "PFAssert.h" +#import "PFMacros.h" +#import "PFPushChannelsController.h" +#import "PFPushController.h" + +@interface PFPushManager () { + dispatch_queue_t _controllerAccessQueue; +} + +@end + +@implementation PFPushManager + +@synthesize pushController = _pushController; +@synthesize channelsController = _channelsController; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + self = [super init]; + if (!self) return nil; + + _commonDataSource = commonDataSource; + _coreDataSource = coreDataSource; + _controllerAccessQueue = dispatch_queue_create("com.parse.push.controller.accessQueue", DISPATCH_QUEUE_SERIAL); + + return self; +} + ++ (instancetype)managerWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + return [[self alloc] initWithCommonDataSource:commonDataSource coreDataSource:coreDataSource]; +} + +///-------------------------------------- +#pragma mark - PushController +///-------------------------------------- + +- (PFPushController *)pushController { + __block PFPushController *controller; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_pushController) { + _pushController = [PFPushController controllerWithCommandRunner:self.commonDataSource.commandRunner]; + } + controller = _pushController; + }); + return controller; +} + +- (void)setPushController:(PFPushController *)pushController { + dispatch_sync(_controllerAccessQueue, ^{ + _pushController = pushController; + }); +} + +///-------------------------------------- +#pragma mark - Channels Controller +///-------------------------------------- + +- (PFPushChannelsController *)channelsController { + __block PFPushChannelsController *controller; + dispatch_sync(_controllerAccessQueue, ^{ + if (!_channelsController) { + _channelsController = [PFPushChannelsController controllerWithDataSource:self.coreDataSource]; + } + controller = _channelsController; + }); + return controller; +} + +- (void)setChannelsController:(PFPushChannelsController *)channelsController { + dispatch_sync(_controllerAccessQueue, ^{ + _channelsController = channelsController; + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/PFPushPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/PFPushPrivate.h new file mode 100644 index 0000000..d45d114 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/PFPushPrivate.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol PFPushInternalUtils + +@optional ++ (NSString *)convertDeviceTokenToString:(id)deviceToken; ++ (nullable NSString *)getDeviceTokenFromKeychain; ++ (void)clearDeviceToken; + +#if TARGET_OS_IPHONE + ++ (void)showAlertViewWithTitle:(nullable NSString *)title message:(nullable NSString *)message NS_EXTENSION_UNAVAILABLE_IOS(""); ++ (void)playVibrate; ++ (void)playAudioWithName:(nullable NSString *)audioName; + +#endif + +@end + +@interface PFPush (Private) + +// For unit testability ++ (Class)pushInternalUtilClass; ++ (void)setPushInternalUtilClass:(nullable Class)utilClass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.h new file mode 100644 index 0000000..3adab09 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushState.h" + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFMutablePushState : PFPushState + +@property (nullable, nonatomic, copy, readwrite) NSSet *channels; +@property (nullable, nonatomic, copy, readwrite) PFQueryState *queryState; + +@property (nullable, nonatomic, strong, readwrite) NSDate *expirationDate; +@property (nullable, nonatomic, copy, readwrite) NSNumber *expirationTimeInterval; + +@property (nullable, nonatomic, copy, readwrite) NSDictionary *payload; + +///-------------------------------------- +/// @name Payload +///-------------------------------------- + +- (void)setPayloadWithMessage:(nullable NSString *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.m new file mode 100644 index 0000000..998f75b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFMutablePushState.m @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutablePushState.h" + +#import "PFPushState_Private.h" + +@implementation PFMutablePushState + +@dynamic channels; +@dynamic queryState; +@dynamic expirationDate; +@dynamic expirationTimeInterval; +@dynamic payload; + +///-------------------------------------- +#pragma mark - Payload +///-------------------------------------- + +- (void)setPayloadWithMessage:(NSString *)message { + if (!message) { + self.payload = nil; + } else { + self.payload = @{ @"alert" : [message copy] }; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.h new file mode 100644 index 0000000..147756f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +@class PFQueryState; + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFPushState : PFBaseState + +@property (nullable, nonatomic, copy, readonly) NSSet *channels; +@property (nullable, nonatomic, copy, readonly) PFQueryState *queryState; + +@property (nullable, nonatomic, strong, readonly) NSDate *expirationDate; +@property (nullable, nonatomic, copy, readonly) NSNumber *expirationTimeInterval; + +@property (nullable, nonatomic, copy, readonly) NSDictionary *payload; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithState:(nullable PFPushState *)state; ++ (instancetype)stateWithState:(nullable PFPushState *)state; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.m new file mode 100644 index 0000000..6eaa245 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState.m @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushState.h" +#import "PFPushState_Private.h" + +#import "PFMutablePushState.h" +#import "PFQueryState.h" + +@implementation PFPushState + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + return @{ + @"channels": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"queryState": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"expirationDate": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeStrong], + @"expirationTimeInterval": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeStrong], + @"payload": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy] + }; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithState:(PFPushState *)state { + return [super initWithState:state]; +} + ++ (instancetype)stateWithState:(PFPushState *)state { + return [super stateWithState:state]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (id)copyWithZone:(NSZone *)zone { + return [[PFPushState allocWithZone:zone] initWithState:self]; +} + +///-------------------------------------- +#pragma mark - NSMutableCopying +///-------------------------------------- + +- (id)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutablePushState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState_Private.h new file mode 100644 index 0000000..33e1570 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/State/PFPushState_Private.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushState.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFPushState () + +@property (nullable, nonatomic, copy, readwrite) NSSet *channels; +@property (nullable, nonatomic, copy, readwrite) PFQueryState *queryState; + +@property (nullable, nonatomic, strong, readwrite) NSDate *expirationDate; +@property (nullable, nonatomic, copy, readwrite) NSNumber *expirationTimeInterval; + +@property (nullable, nonatomic, copy, readwrite) NSDictionary *payload; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.h new file mode 100644 index 0000000..e47c90e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushPrivate.h" + +NS_ASSUME_NONNULL_BEGIN + +PF_WATCH_UNAVAILABLE @interface PFPushUtilities : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.m new file mode 100644 index 0000000..39b3ba7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Push/Utilites/PFPushUtilities.m @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPushUtilities.h" + +#import + +#if TARGET_OS_IOS +#import + +#import "PFAlertView.h" +#endif + +#import "PFInstallationPrivate.h" +#import "PFKeychainStore.h" +#import "PFLogging.h" +#import "PFMacros.h" + +@implementation PFPushUtilities + +///-------------------------------------- +#pragma mark - PFPushInternalUtils +///-------------------------------------- + ++ (NSString *)convertDeviceTokenToString:(id)deviceToken { + if ([deviceToken isKindOfClass:[NSString class]]) { + return deviceToken; + } else { + NSMutableString *hexString = [NSMutableString string]; + const unsigned char *bytes = [deviceToken bytes]; + for (int i = 0; i < [deviceToken length]; i++) { + [hexString appendFormat:@"%02x", bytes[i]]; + } + return [NSString stringWithString:hexString]; + } +} + ++ (NSString *)getDeviceTokenFromKeychain { + // Used the first time we construct the currentInstallation, + // for backward compability with older SDKs. + PFKeychainStore *store = [[PFKeychainStore alloc] initWithService:@"ParsePush"]; + return store[@"ParsePush"]; +} + ++ (void)clearDeviceToken { + // Used in test case setup. + [[PFInstallation currentInstallation] _clearDeviceToken]; + [[[PFKeychainStore alloc] initWithService:@"ParsePush"] removeObjectForKey:@"ParsePush"]; +} + +#if TARGET_OS_IPHONE + ++ (void)showAlertViewWithTitle:(NSString *)title message:(NSString *)message { + NSString *cancelButtonTitle = NSLocalizedStringFromTableInBundle(@"OK", @"Parse", + [NSBundle bundleForClass:[self class]], + @"Default alert view cancel button title."); + [PFAlertView showAlertWithTitle:title + message:message + cancelButtonTitle:cancelButtonTitle + otherButtonTitles:nil + completion:nil]; +} + ++ (void)playAudioWithName:(NSString *)audioFileName { + SystemSoundID soundId = -1; + + if (audioFileName) { + NSURL *bundlePath = [[NSBundle mainBundle] URLForResource:[audioFileName stringByDeletingPathExtension] + withExtension:[audioFileName pathExtension]]; + + AudioServicesCreateSystemSoundID((__bridge CFURLRef)bundlePath, &soundId); + } + + if (soundId != -1) { + AudioServicesPlaySystemSound(soundId); + } +} + ++ (void)playVibrate { + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); +} + +#endif + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.h new file mode 100644 index 0000000..db0c057 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFCachedQueryController : PFQueryController + +@property (nonatomic, weak, readonly) id commonDataSource; + +- (instancetype)initWithCommonDataSource:(id)dataSource; ++ (instancetype)controllerWithCommonDataSource:(id)dataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.m new file mode 100644 index 0000000..d89a928 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFCachedQueryController.m @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCachedQueryController.h" + +#import + +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFDecoder.h" +#import "PFErrorUtilities.h" +#import "PFJSONSerialization.h" +#import "PFKeyValueCache.h" +#import "PFMacros.h" +#import "PFQueryState.h" +#import "PFRESTCommand.h" +#import "PFRESTQueryCommand.h" +#import "PFUser.h" + +@implementation PFCachedQueryController + +@dynamic commonDataSource; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithCommonDataSource:(id)dataSource { + return [super initWithCommonDataSource:dataSource]; +} + ++ (instancetype)controllerWithCommonDataSource:(id)dataSource { + return [super controllerWithCommonDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - PFQueryControllerSubclass +///-------------------------------------- + +- (BFTask *)runNetworkCommandAsync:(PFRESTCommand *)command + withCancellationToken:(BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + switch (queryState.cachePolicy) { + case kPFCachePolicyIgnoreCache: + { + return [self _runNetworkCommandAsync:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + } + break; + case kPFCachePolicyNetworkOnly: + { + return [[self _runNetworkCommandAsync:command + withCancellationToken:cancellationToken + forQueryState:queryState] continueWithSuccessBlock:^id(BFTask *task) { + return [self _saveCommandResultAsync:task.result forCommandCacheKey:command.cacheKey]; + } cancellationToken:cancellationToken]; + } + break; + case kPFCachePolicyCacheOnly: + { + return [self _runNetworkCommandAsyncFromCache:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + } + break; + case kPFCachePolicyNetworkElseCache: { + // Don't retry for network-else-cache, because it just slows things down. + BFTask *networkTask = [self _runNetworkCommandAsync:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + @weakify(self); + return [networkTask continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (task.cancelled || task.exception) { + return task; + } else if (task.error) { + return [self _runNetworkCommandAsyncFromCache:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + } + return [self _saveCommandResultAsync:task.result forCommandCacheKey:command.cacheKey]; + } cancellationToken:cancellationToken]; + } + break; + case kPFCachePolicyCacheElseNetwork: + { + BFTask *cacheTask = [self _runNetworkCommandAsyncFromCache:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + @weakify(self); + return [cacheTask continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (task.error) { + return [self _runNetworkCommandAsync:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + } + return task; + } cancellationToken:cancellationToken]; + } + break; + case kPFCachePolicyCacheThenNetwork: + PFConsistencyAssert(NO, @"kPFCachePolicyCacheThenNetwork is not implemented as a runner."); + break; + default: + PFConsistencyAssert(NO, @"Unrecognized cache policy: %d", queryState.cachePolicy); + break; + } + return nil; +} + +- (BFTask *)_runNetworkCommandAsync:(PFRESTCommand *)command + withCancellationToken:(BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState { + PFCommandRunningOptions options = 0; + // We don't want retries on NetworkElseCache, but rather instantly back-off to cache. + if (queryState.cachePolicy != kPFCachePolicyNetworkElseCache) { + options = PFCommandRunningOptionRetryIfFailed; + } + BFTask *networkTask = [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:options + cancellationToken:cancellationToken]; + return [networkTask continueWithSuccessBlock:^id(BFTask *task) { + if (queryState.cachePolicy == kPFCachePolicyNetworkOnly || + queryState.cachePolicy == kPFCachePolicyNetworkElseCache || + queryState.cachePolicy == kPFCachePolicyCacheElseNetwork) { + return [self _saveCommandResultAsync:task.result forCommandCacheKey:command.cacheKey]; + } + // Roll-forward the original result. + return task; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Cache +///-------------------------------------- + +- (NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { + return [PFRESTQueryCommand findCommandForQueryState:queryState withSessionToken:sessionToken].cacheKey; +} + +- (BOOL)hasCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { + // TODO: (nlutsenko) Once there is caching for `count`, the results for that command should also be checked. + // TODO: (nlutsenko) We should cache this result. + + NSString *cacheKey = [self cacheKeyForQueryState:queryState sessionToken:sessionToken]; + return ([self.commonDataSource.keyValueCache objectForKey:cacheKey maxAge:queryState.maxCacheAge] != nil); +} + +- (void)clearCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { + // TODO: (nlutsenko) Once there is caching for `count`, the results for that command should also be cleared. + NSString *cacheKey = [self cacheKeyForQueryState:queryState sessionToken:sessionToken]; + [self.commonDataSource.keyValueCache removeObjectForKey:cacheKey]; +} + +- (void)clearAllCachedResults { + [self.commonDataSource.keyValueCache removeAllObjects]; +} + +- (BFTask *)_runNetworkCommandAsyncFromCache:(PFRESTCommand *)command + withCancellationToken:(BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState { + NSString *jsonString = [self.commonDataSource.keyValueCache objectForKey:command.cacheKey + maxAge:queryState.maxCacheAge]; + if (!jsonString) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCacheMiss + message:@"Cache miss." + shouldLog:NO]; + return [BFTask taskWithError:error]; + } + + NSDictionary *object = [PFJSONSerialization JSONObjectFromString:jsonString]; + if (!object) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCacheMiss + message:@"Cache contains corrupted JSON."]; + return [BFTask taskWithError:error]; + } + + NSDictionary *decodedObject = [[PFDecoder objectDecoder] decodeObject:object]; + + PFCommandResult *result = [PFCommandResult commandResultWithResult:decodedObject + resultString:jsonString + httpResponse:nil]; + return [BFTask taskWithResult:result]; +} + +- (BFTask *)_saveCommandResultAsync:(PFCommandResult *)result forCommandCacheKey:(NSString *)cacheKey { + NSString *resultString = result.resultString; + if (resultString) { + [self.commonDataSource.keyValueCache setObject:resultString forKey:cacheKey]; + } + // Roll-forward the original result. + return [BFTask taskWithResult:result]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.h new file mode 100644 index 0000000..a7f0241 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFOfflineQueryController : PFQueryController + +@property (nonatomic, weak, readonly) id commonDataSource; +@property (nonatomic, weak, readonly) id coreDataSource; + +- (instancetype)initWithCommonDataSource:(id)dataSource NS_UNAVAILABLE; ++ (instancetype)controllerWithCommonDataSource:(id)dataSource NS_UNAVAILABLE; + +- (instancetype)initWithCommonDataSource:(id)dataSource + coreDataSource:(id)coreDataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithCommonDataSource:(id)dataSource + coreDataSource:(id)coreDataSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.m new file mode 100644 index 0000000..edca5d5 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFOfflineQueryController.m @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFOfflineQueryController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandRunning.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFPin.h" +#import "PFPinningObjectStore.h" +#import "PFQueryState.h" +#import "PFRESTCommand.h" +#import "PFRelationPrivate.h" + +@interface PFOfflineQueryController () { + PFOfflineStore *_offlineStore; // TODO: (nlutsenko) Lazy-load this via self.dataSource. +} + +@end + +@implementation PFOfflineQueryController + +@dynamic commonDataSource; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithCommonDataSource:(id)dataSource { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommonDataSource:(id)dataSource + coreDataSource:(id)coreDataSource { + self = [super initWithCommonDataSource:dataSource]; + if (!self) return nil; + + _offlineStore = dataSource.offlineStore; + _coreDataSource = coreDataSource; + + return self; +} + ++ (instancetype)controllerWithCommonDataSource:(id)dataSource + coreDataSource:(id)coreDataSource { + return [[self alloc] initWithCommonDataSource:dataSource coreDataSource:coreDataSource]; +} + +///-------------------------------------- +#pragma mark - Find +///-------------------------------------- + +- (BFTask *)findObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + if (queryState.queriesLocalDatastore) { + return [self _findObjectsFromLocalDatastoreAsyncForQueryState:queryState + withCancellationToken:cancellationToken + user:user]; + } + + NSDictionary *relationCondition = queryState.conditions[@"$relatedTo"]; + if (relationCondition) { + PFObject *object = relationCondition[@"object"]; + NSString *key = relationCondition[@"key"]; + if ([object isDataAvailableForKey:key]) { + PFRelation *relation = object[key]; + return [self _findObjectsAsyncInRelation:relation + ofObject:object + forQueryState:queryState + withCancellationToken:cancellationToken + user:user]; + } + } + + return [super findObjectsAsyncForQueryState:queryState withCancellationToken:cancellationToken user:user]; +} + +- (BFTask *)_findObjectsAsyncInRelation:(PFRelation *)relation + ofObject:(PFObject *)parentObject + forQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + return [[super findObjectsAsyncForQueryState:queryState + withCancellationToken:cancellationToken + user:user] continueWithSuccessBlock:^id(BFTask *fetchTask) { + + NSArray *objects = fetchTask.result; + for (PFObject *object in objects) { + [relation _addKnownObject:object]; + } + + return [[_offlineStore updateDataForObjectAsync:parentObject] continueWithBlock:^id(BFTask *task) { + // Roll-forward the result of find task instead of a result of update task. + return fetchTask; + } cancellationToken:cancellationToken]; + } cancellationToken:cancellationToken]; +} + + +- (BFTask *)_findObjectsFromLocalDatastoreAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + NSString *pinName = queryState.localDatastorePinName; + if (pinName) { + PFPinningObjectStore *objectStore = self.coreDataSource.pinningObjectStore; + return [objectStore fetchPinAsyncWithName:pinName]; + } + return nil; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFPin *pin = task.result; + return [_offlineStore findAsyncForQueryState:queryState user:user pin:pin]; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Count +///-------------------------------------- + +- (BFTask *)countObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + if (queryState.queriesLocalDatastore) { + return [self _countObjectsFromLocalDatastoreAsyncForQueryState:queryState + withCancellationToken:cancellationToken + user:user]; + } + return [super countObjectsAsyncForQueryState:queryState withCancellationToken:cancellationToken user:user]; +} + +- (BFTask *)_countObjectsFromLocalDatastoreAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + NSString *pinName = queryState.localDatastorePinName; + if (pinName) { + PFPinningObjectStore *controller = self.coreDataSource.pinningObjectStore; + return [controller fetchPinAsyncWithName:pinName]; + } + return nil; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFPin *pin = task.result; + return [_offlineStore countAsyncForQueryState:queryState user:user pin:pin]; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - PFQueryControllerSubclass +///-------------------------------------- + +- (BFTask *)runNetworkCommandAsync:(PFRESTCommand *)command + withCancellationToken:(BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState { + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed + cancellationToken:cancellationToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.h new file mode 100644 index 0000000..8c95ecb --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.h @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +@class BFCancellationToken; + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFQueryState; +@class PFRESTCommand; +@class PFCommandResult; +@class PFUser; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFQueryController : NSObject + +@property (nonatomic, weak, readonly) id commonDataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommonDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + ++ (instancetype)controllerWithCommonDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Find +///-------------------------------------- + +/*! + Finds objects from network or LDS for any given query state. + Supports cancellation and ACLed changes for a specific user. + + @param queryState Query state to use. + @param cancellationToken Cancellation token or `nil`. + @param user `user` to use for ACLs or `nil`. + + @returns Task that resolves to `NSArray` of `PFObject`s. + */ +- (BFTask *)findObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + user:(nullable PFUser *)user; // TODO: (nlutsenko) Pass `PFUserState` instead of user. + +///-------------------------------------- +/// @name Count +///-------------------------------------- + +/*! + Counts objects from network or LDS for any given query state. + Supports cancellation and ACLed changes for a specific user. + + @param queryState Query state to use. + @param cancellationToken Cancellation token or `nil`. + @param user `user` to use for ACLs or `nil`. + + @returns Task that resolves to `NSNumber` with a count of results. + */ +- (BFTask *)countObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + user:(nullable PFUser *)user; // TODO: (nlutsenko) Pass `PFUserState` instead of user. + +///-------------------------------------- +/// @name Caching +///-------------------------------------- + +- (NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; +- (BOOL)hasCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; + +- (void)clearCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; +- (void)clearAllCachedResults; + +@end + +@protocol PFQueryControllerSubclass + +/*! + Implementation should run a command on a network runner. + + @param command Command to run. + @param cancellationToken Cancellation token. + @param queryState Query state to run command for. + + @returns `BFTask` instance with result of `PFCommandResult`. + */ +- (BFTask *)runNetworkCommandAsync:(PFRESTCommand *)command + withCancellationToken:(nullable BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.m new file mode 100644 index 0000000..9b6c494 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Controller/PFQueryController.m @@ -0,0 +1,160 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryController.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFPin.h" +#import "PFQueryState.h" +#import "PFRESTQueryCommand.h" +#import "PFUser.h" +#import "Parse_Private.h" + +@interface PFQueryController () + +@end + +@implementation PFQueryController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithCommonDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _commonDataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithCommonDataSource:(id)dataSource { + return [[self alloc] initWithCommonDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Find +///-------------------------------------- + +- (BFTask *)findObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + NSDate *queryStart = (queryState.trace ? [NSDate date] : nil); + __block NSDate *querySent = nil; + + NSString *sessionToken = user.sessionToken; + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + PFRESTCommand *command = [PFRESTQueryCommand findCommandForQueryState:queryState withSessionToken:sessionToken]; + querySent = (queryState.trace ? [NSDate date] : nil); + return [self runNetworkCommandAsync:command + withCancellationToken:cancellationToken + forQueryState:queryState]; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + NSDate *queryReceived = (queryState.trace ? [NSDate date] : nil); + + NSArray *resultObjects = result.result[@"results"]; + NSMutableArray *foundObjects = [NSMutableArray arrayWithCapacity:resultObjects.count]; + if (resultObjects != nil) { + NSString *resultClassName = result.result[@"className"]; + if (!resultClassName) { + resultClassName = queryState.parseClassName; + } + NSArray *selectedKeys = queryState.selectedKeys.allObjects; + for (NSDictionary *resultObject in resultObjects) { + PFObject *object = [PFObject _objectFromDictionary:resultObject + defaultClassName:resultClassName + selectedKeys:selectedKeys]; + [foundObjects addObject:object]; + } + } + + NSString *traceLog = [result.result objectForKey:@"trace"]; + if (traceLog != nil) { + NSLog(@"Pre-processing took %f seconds\n%@Client side parsing took %f seconds", + [querySent timeIntervalSinceDate:queryStart], traceLog, + [queryReceived timeIntervalSinceNow]); + } + + return foundObjects; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Count +///-------------------------------------- + +- (BFTask *)countObjectsAsyncForQueryState:(PFQueryState *)queryState + withCancellationToken:(BFCancellationToken *)cancellationToken + user:(PFUser *)user { + NSString *sessionToken = user.sessionToken; + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + PFRESTQueryCommand *findCommand = [PFRESTQueryCommand findCommandForQueryState:queryState + withSessionToken:sessionToken]; + PFRESTCommand *countCommand = [PFRESTQueryCommand countCommandFromFindCommand:findCommand]; + return [self runNetworkCommandAsync:countCommand + withCancellationToken:cancellationToken + forQueryState:queryState]; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + return result.result[@"count"]; + } cancellationToken:cancellationToken]; +} + +///-------------------------------------- +#pragma mark - Caching +///-------------------------------------- + +- (NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { + return nil; +} + +- (BOOL)hasCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { + return NO; +} + +- (void)clearCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { +} + +- (void)clearAllCachedResults { +} + +///-------------------------------------- +#pragma mark - PFQueryControllerSubclass +///-------------------------------------- + +- (BFTask *)runNetworkCommandAsync:(PFRESTCommand *)command + withCancellationToken:(BFCancellationToken *)cancellationToken + forQueryState:(PFQueryState *)queryState { + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed + cancellationToken:cancellationToken]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/PFQueryPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/PFQueryPrivate.h new file mode 100644 index 0000000..149386e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/PFQueryPrivate.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryState.h" + +extern NSString *const PFQueryKeyNotEqualTo; +extern NSString *const PFQueryKeyLessThan; +extern NSString *const PFQueryKeyLessThanEqualTo; +extern NSString *const PFQueryKeyGreaterThan; +extern NSString *const PFQueryKeyGreaterThanOrEqualTo; +extern NSString *const PFQueryKeyContainedIn; +extern NSString *const PFQueryKeyNotContainedIn; +extern NSString *const PFQueryKeyContainsAll; +extern NSString *const PFQueryKeyNearSphere; +extern NSString *const PFQueryKeyWithin; +extern NSString *const PFQueryKeyRegex; +extern NSString *const PFQueryKeyExists; +extern NSString *const PFQueryKeyInQuery; +extern NSString *const PFQueryKeyNotInQuery; +extern NSString *const PFQueryKeySelect; +extern NSString *const PFQueryKeyDontSelect; +extern NSString *const PFQueryKeyRelatedTo; +extern NSString *const PFQueryKeyOr; +extern NSString *const PFQueryKeyQuery; +extern NSString *const PFQueryKeyKey; +extern NSString *const PFQueryKeyObject; + +extern NSString *const PFQueryOptionKeyMaxDistance; +extern NSString *const PFQueryOptionKeyBox; +extern NSString *const PFQueryOptionKeyRegexOptions; + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFObject; + +@interface PFQuery () + +@property (nonatomic, strong, readonly) PFQueryState *state; + +@end + +@interface PFQuery (Private) + +- (instancetype)whereRelatedToObject:(PFObject *)parent fromKey:(NSString *)key; +- (void)redirectClassNameForKey:(NSString *)key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.h new file mode 100644 index 0000000..e54a13c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.h @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryState.h" + +@interface PFMutableQueryState : PFQueryState + +@property (nonatomic, copy, readwrite) NSString *parseClassName; + +@property (nonatomic, assign, readwrite) NSInteger limit; +@property (nonatomic, assign, readwrite) NSInteger skip; + +///-------------------------------------- +/// @name Remote + Caching Options +///-------------------------------------- + +@property (nonatomic, assign, readwrite) PFCachePolicy cachePolicy; +@property (nonatomic, assign, readwrite) NSTimeInterval maxCacheAge; + +@property (nonatomic, assign, readwrite) BOOL trace; + +///-------------------------------------- +/// @name Local Datastore Options +///-------------------------------------- + +@property (nonatomic, assign, readwrite) BOOL shouldIgnoreACLs; +@property (nonatomic, assign, readwrite) BOOL shouldIncludeDeletingEventually; +@property (nonatomic, assign, readwrite) BOOL queriesLocalDatastore; +@property (nonatomic, copy, readwrite) NSString *localDatastorePinName; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithParseClassName:(NSString *)className; ++ (instancetype)stateWithParseClassName:(NSString *)className; + +///-------------------------------------- +/// @name Conditions +///-------------------------------------- + +- (void)setConditionType:(NSString *)type withObject:(id)object forKey:(NSString *)key; + +- (void)setEqualityConditionWithObject:(id)object forKey:(NSString *)key; +- (void)setRelationConditionWithObject:(id)object forKey:(NSString *)key; + +- (void)removeAllConditions; + +///-------------------------------------- +/// @name Sort +///-------------------------------------- + +- (void)sortByKey:(NSString *)key ascending:(BOOL)ascending; +- (void)addSortKey:(NSString *)key ascending:(BOOL)ascending; +- (void)addSortKeysFromSortDescriptors:(NSArray *)sortDescriptors; + +///-------------------------------------- +/// @name Includes +///-------------------------------------- + +- (void)includeKey:(NSString *)key; + +///-------------------------------------- +/// @name Selected Keys +///-------------------------------------- + +- (void)selectKeys:(NSArray *)keys; + +///-------------------------------------- +/// @name Redirect +///-------------------------------------- + +- (void)redirectClassNameForKey:(NSString *)key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.m new file mode 100644 index 0000000..3ac9be9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFMutableQueryState.m @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableQueryState.h" + +#import "PFQueryState_Private.h" + +@interface PFMutableQueryState () { + NSMutableDictionary *_conditions; + NSMutableArray *_sortKeys; + NSMutableSet *_includedKeys; + NSMutableDictionary *_extraOptions; +} + +@end + +@implementation PFMutableQueryState + +@synthesize conditions = _conditions; +@synthesize sortKeys = _sortKeys; +@synthesize includedKeys = _includedKeys; +@synthesize extraOptions = _extraOptions; + +@dynamic parseClassName; +@dynamic selectedKeys; +@dynamic limit; +@dynamic skip; +@dynamic cachePolicy; +@dynamic maxCacheAge; +@dynamic trace; +@dynamic shouldIgnoreACLs; +@dynamic shouldIncludeDeletingEventually; +@dynamic queriesLocalDatastore; +@dynamic localDatastorePinName; + +///-------------------------------------- +#pragma mark - Property Attributes +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + NSMutableDictionary *attributes = [[super propertyAttributes] mutableCopy]; + + attributes[@"conditions"] = [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeMutableCopy]; + attributes[@"sortKeys"] = [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeMutableCopy]; + attributes[@"includedKeys"] = [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeMutableCopy]; + attributes[@"extraOptions"] = [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeMutableCopy]; + + return attributes; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithParseClassName:(NSString *)className { + self = [self init]; + if (!self) return nil; + + _parseClassName = [className copy]; + + return self; +} + ++ (instancetype)stateWithParseClassName:(NSString *)className { + return [[self alloc] initWithParseClassName:className]; +} + +///-------------------------------------- +#pragma mark - Conditions +///-------------------------------------- + +- (void)setConditionType:(NSString *)type withObject:(id)object forKey:(NSString *)key { + NSMutableDictionary *conditionObject = nil; + + // Check if we already have some sort of condition + id existingCondition = _conditions[key]; + if ([existingCondition isKindOfClass:[NSMutableDictionary class]]) { + conditionObject = existingCondition; + } + if (!conditionObject) { + conditionObject = [NSMutableDictionary dictionary]; + } + conditionObject[type] = object; + + [self setEqualityConditionWithObject:conditionObject forKey:key]; +} + +- (void)setEqualityConditionWithObject:(id)object forKey:(NSString *)key { + if (!_conditions) { + _conditions = [NSMutableDictionary dictionary]; + } + _conditions[key] = object; +} + +- (void)setRelationConditionWithObject:(id)object forKey:(NSString *)key { + // We need to force saved PFObject here. + NSMutableDictionary *condition = [NSMutableDictionary dictionaryWithCapacity:2]; + condition[@"object"] = object; + condition[@"key"] = key; + [self setEqualityConditionWithObject:condition forKey:@"$relatedTo"]; +} + +- (void)removeAllConditions { + [_conditions removeAllObjects]; +} + +///-------------------------------------- +#pragma mark - Sort +///-------------------------------------- + +- (void)sortByKey:(NSString *)key ascending:(BOOL)ascending { + [_sortKeys removeAllObjects]; + [self addSortKey:key ascending:ascending]; +} + +- (void)addSortKey:(NSString *)key ascending:(BOOL)ascending { + if (!key) { + return; + } + + NSString *sortKey = (ascending ? key : [NSString stringWithFormat:@"-%@", key]); + if (!_sortKeys) { + _sortKeys = [NSMutableArray arrayWithObject:sortKey]; + } else { + [_sortKeys addObject:sortKey]; + } +} + +- (void)addSortKeysFromSortDescriptors:(NSArray *)sortDescriptors { + [_sortKeys removeAllObjects]; + for (NSSortDescriptor *sortDescriptor in sortDescriptors) { + [self addSortKey:sortDescriptor.key ascending:sortDescriptor.ascending]; + } +} + +///-------------------------------------- +#pragma mark - Includes +///-------------------------------------- + +- (void)includeKey:(NSString *)key { + if (!_includedKeys) { + _includedKeys = [NSMutableSet setWithObject:key]; + } else { + [_includedKeys addObject:key]; + } +} + +///-------------------------------------- +#pragma mark - Selected Keys +///-------------------------------------- + +- (void)selectKeys:(NSArray *)keys { + if (keys) { + _selectedKeys = (_selectedKeys ? [_selectedKeys setByAddingObjectsFromArray:keys] : [NSSet setWithArray:keys]); + } else { + _selectedKeys = nil; + } +} + +///-------------------------------------- +#pragma mark - Redirect +///-------------------------------------- + +- (void)redirectClassNameForKey:(NSString *)key { + if (!_extraOptions) { + _extraOptions = [NSMutableDictionary dictionary]; + } + _extraOptions[@"redirectClassNameForKey"] = key; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.h new file mode 100644 index 0000000..c97ff58 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +@interface PFQueryState : PFBaseState + +@property (nonatomic, copy, readonly) NSString *parseClassName; + +@property (nonatomic, copy, readonly) NSDictionary *conditions; + +@property (nonatomic, copy, readonly) NSArray *sortKeys; +@property (nonatomic, copy, readonly) NSString *sortOrderString; + +@property (nonatomic, copy, readonly) NSSet *includedKeys; +@property (nonatomic, copy, readonly) NSSet *selectedKeys; +@property (nonatomic, copy, readonly) NSDictionary *extraOptions; + +@property (nonatomic, assign, readonly) NSInteger limit; +@property (nonatomic, assign, readonly) NSInteger skip; + +///-------------------------------------- +/// @name Remote + Caching Options +///-------------------------------------- + +@property (nonatomic, assign, readonly) PFCachePolicy cachePolicy; +@property (nonatomic, assign, readonly) NSTimeInterval maxCacheAge; + +@property (nonatomic, assign, readonly) BOOL trace; + +///-------------------------------------- +/// @name Local Datastore Options +///-------------------------------------- + +/*! + If ignoreACLs is enabled, we don't check ACLs when querying from LDS. We also don't grab + `PFUser currentUser` since it's unnecessary when ignoring ACLs. + */ +@property (nonatomic, assign, readonly) BOOL shouldIgnoreACLs; +/*! + This is currently unused, but is here to allow future querying across objects that are in the + process of being deleted eventually. + */ +@property (nonatomic, assign, readonly) BOOL shouldIncludeDeletingEventually; +@property (nonatomic, assign, readonly) BOOL queriesLocalDatastore; +@property (nonatomic, copy, readonly) NSString *localDatastorePinName; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithState:(PFQueryState *)state; ++ (instancetype)stateWithState:(PFQueryState *)state; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.m new file mode 100644 index 0000000..d5da258 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState.m @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryState.h" +#import "PFQueryState_Private.h" + +#import "PFMutableQueryState.h" +#import "PFPropertyInfo.h" + +@implementation PFQueryState + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + return @{ + @"parseClassName": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"conditions": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"sortKeys": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"includedKeys": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"selectedKeys": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"extraOptions": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + + @"limit": [PFPropertyAttributes attributes], + @"skip": [PFPropertyAttributes attributes], + @"cachePolicy": [PFPropertyAttributes attributes], + @"maxCacheAge": [PFPropertyAttributes attributes], + + @"trace": [PFPropertyAttributes attributes], + @"shouldIgnoreACLs": [PFPropertyAttributes attributes], + @"shouldIncludeDeletingEventually": [PFPropertyAttributes attributes], + @"queriesLocalDatastore": [PFPropertyAttributes attributes], + + @"localDatastorePinName": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy] + }; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _cachePolicy = kPFCachePolicyIgnoreCache; + _maxCacheAge = INFINITY; + _limit = -1; + + return self; +} + +- (instancetype)initWithState:(PFQueryState *)state { + return [super initWithState:state]; +} + ++ (instancetype)stateWithState:(PFQueryState *)state { + return [super stateWithState:state]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSString *)sortOrderString { + return [self.sortKeys componentsJoinedByString:@","]; +} + +///-------------------------------------- +#pragma mark - Mutable Copying +///-------------------------------------- + +- (id)copyWithZone:(NSZone *)zone { + return [[PFQueryState allocWithZone:zone] initWithState:self]; +} + +- (instancetype)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableQueryState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState_Private.h new file mode 100644 index 0000000..006d3c2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/State/PFQueryState_Private.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryState.h" + +@interface PFQueryState () { +@protected + NSString *_parseClassName; + + NSDictionary *_conditions; + + NSArray *_sortKeys; + + NSSet *_includedKeys; + NSSet *_selectedKeys; + NSDictionary *_extraOptions; + + NSInteger _limit; + NSInteger _skip; + + PFCachePolicy _cachePolicy; + NSTimeInterval _maxCacheAge; + + BOOL _trace; + + BOOL _shouldIgnoreACLs; + BOOL _shouldIncludeDeletingEventually; + BOOL _queriesLocalDatastore; + NSString *_localDatastorePinName; +} + +@property (nonatomic, copy, readwrite) NSString *parseClassName; + +@property (nonatomic, assign, readwrite) NSInteger limit; +@property (nonatomic, assign, readwrite) NSInteger skip; + +///-------------------------------------- +/// @name Remote + Caching Options +///-------------------------------------- + +@property (nonatomic, assign, readwrite) PFCachePolicy cachePolicy; +@property (nonatomic, assign, readwrite) NSTimeInterval maxCacheAge; + +@property (nonatomic, assign, readwrite) BOOL trace; + +///-------------------------------------- +/// @name Local Datastore Options +///-------------------------------------- + +@property (nonatomic, assign, readwrite) BOOL shouldIgnoreACLs; +@property (nonatomic, assign, readwrite) BOOL shouldIncludeDeletingEventually; +@property (nonatomic, assign, readwrite) BOOL queriesLocalDatastore; +@property (nonatomic, copy, readwrite) NSString *localDatastorePinName; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.h new file mode 100644 index 0000000..59276df --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@interface PFQueryUtilities : NSObject + +///-------------------------------------- +/// @name Predicate +///-------------------------------------- + +/*! + Takes an arbitrary predicate and normalizes it to a form that can easily be converted to a `PFQuery`. + */ ++ (NSPredicate *)predicateByNormalizingPredicate:(NSPredicate *)predicate; + +///-------------------------------------- +/// @name Regex +///-------------------------------------- + +/*! + Converts a string into a regex that matches it. + + @param string String to convert from. + + @returns Query regex string from a string. + */ ++ (NSString *)regexStringForString:(NSString *)string; + +///-------------------------------------- +/// @name Errors +///-------------------------------------- + ++ (NSError *)objectNotFoundError; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.m new file mode 100644 index 0000000..5e9b717 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Query/Utilities/PFQueryUtilities.m @@ -0,0 +1,530 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQueryUtilities.h" + +#import "PFAssert.h" +#import "PFConstants.h" +#import "PFErrorUtilities.h" + +@implementation PFQueryUtilities + +///-------------------------------------- +#pragma mark - Predicate +///-------------------------------------- + ++ (NSPredicate *)predicateByNormalizingPredicate:(NSPredicate *)predicate { + return [self _hoistCommonPredicates:[self _normalizeToDNF:predicate]]; +} + +/*! + Traverses over all of the subpredicates in the given predicate, calling the given blocks to + transform any instances of NSPredicate. + */ ++ (NSPredicate *)_mapPredicate:(NSPredicate *)predicate + compoundBlock:(NSPredicate *(^)(NSCompoundPredicate *))compoundBlock + comparisonBlock:(NSPredicate *(^)(NSComparisonPredicate *predicate))comparisonBlock { + if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + if (compoundBlock) { + return compoundBlock((NSCompoundPredicate *)predicate); + } else { + NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate; + + NSMutableArray *newSubpredicates = [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + for (NSPredicate *subPredicate in compound.subpredicates) { + [newSubpredicates addObject:[self _mapPredicate:subPredicate + compoundBlock:compoundBlock + comparisonBlock:comparisonBlock]]; + } + + NSCompoundPredicateType type = compound.compoundPredicateType; + return [[NSCompoundPredicate alloc] initWithType:type subpredicates:newSubpredicates]; + } + } + + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + if (comparisonBlock) { + return comparisonBlock((NSComparisonPredicate *)predicate); + } else { + return predicate; + } + } + + [NSException raise:NSInternalInconsistencyException format:@"NSExpression predicates are not supported."]; + return nil; +} + +/*! + Returns a predicate that is the negation of the input predicate, or throws on error. + */ ++ (NSPredicate *)_negatePredicate:(NSPredicate *)predicate { + return [self _mapPredicate:predicate + compoundBlock:^NSPredicate *(NSCompoundPredicate *compound) { + switch (compound.compoundPredicateType) { + case NSNotPredicateType: { + return [compound.subpredicates objectAtIndex:0]; + } + case NSAndPredicateType: { + NSMutableArray *newSubpredicates = + [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + for (NSPredicate *subpredicate in compound.subpredicates) { + [newSubpredicates addObject:[self _negatePredicate:subpredicate]]; + } + return [NSCompoundPredicate orPredicateWithSubpredicates:newSubpredicates]; + } + case NSOrPredicateType: { + NSMutableArray *newSubpredicates = + [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + for (NSPredicate *subpredicate in compound.subpredicates) { + [newSubpredicates addObject:[self _negatePredicate:subpredicate]]; + } + return [NSCompoundPredicate andPredicateWithSubpredicates:newSubpredicates]; + } + default: { + [NSException raise:NSInternalInconsistencyException + format:@"This compound predicate cannot be negated. (%zd)", + compound.compoundPredicateType]; + return nil; + } + } + } comparisonBlock:^NSPredicate *(NSComparisonPredicate *comparison) { + NSPredicateOperatorType newType; + NSComparisonPredicateModifier newModifier = comparison.comparisonPredicateModifier; + SEL customSelector; + + switch (comparison.predicateOperatorType) { + case NSEqualToPredicateOperatorType: { + newType = NSNotEqualToPredicateOperatorType; + break; + } + case NSNotEqualToPredicateOperatorType: { + newType = NSEqualToPredicateOperatorType; + break; + } + case NSInPredicateOperatorType: { + newType = NSCustomSelectorPredicateOperatorType; + customSelector = NSSelectorFromString(@"notContainedIn:"); + break; + } + case NSLessThanPredicateOperatorType: { + newType = NSGreaterThanOrEqualToPredicateOperatorType; + break; + } + case NSLessThanOrEqualToPredicateOperatorType: { + newType = NSGreaterThanPredicateOperatorType; + break; + } + case NSGreaterThanPredicateOperatorType: { + newType = NSLessThanOrEqualToPredicateOperatorType; + break; + } + case NSGreaterThanOrEqualToPredicateOperatorType: { + newType = NSLessThanPredicateOperatorType; + break; + } + case NSBetweenPredicateOperatorType: { + [NSException raise:NSInternalInconsistencyException + format:@"A BETWEEN predicate was found after they should have been removed."]; + } + case NSMatchesPredicateOperatorType: + case NSLikePredicateOperatorType: + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSContainsPredicateOperatorType: + case NSCustomSelectorPredicateOperatorType: + default: { + [NSException raise:NSInternalInconsistencyException + format:@"This comparison predicate cannot be negated. (%@)", comparison]; + return nil; + } + } + + if (newType == NSCustomSelectorPredicateOperatorType) { + return [NSComparisonPredicate predicateWithLeftExpression:comparison.leftExpression + rightExpression:comparison.rightExpression + customSelector:customSelector]; + } else { + return [NSComparisonPredicate predicateWithLeftExpression:comparison.leftExpression + rightExpression:comparison.rightExpression + modifier:newModifier + type:newType + options:comparison.options]; + } + }]; +} + +/*! + Returns a version of the given predicate that contains no NSNotPredicateType compound predicates. + This greatly simplifies the diversity of predicates we have to handle later in the pipeline. + */ ++ (NSPredicate *)removeNegation:(NSPredicate *)predicate { + return [self _mapPredicate:predicate + compoundBlock:^NSPredicate *(NSCompoundPredicate *compound) { + // Remove negation from any subpredicates. + NSMutableArray *newSubpredicates = + [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + for (NSPredicate *subPredicate in [compound subpredicates]) { + [newSubpredicates addObject:[self removeNegation:subPredicate]]; + } + + // If this is a NOT predicate, return the negation of the subpredicate. + // Otherwise, just pass it on. + if (compound.compoundPredicateType == NSNotPredicateType) { + return [self _negatePredicate:[newSubpredicates objectAtIndex:0]]; + } else { + return [[NSCompoundPredicate alloc] initWithType:compound.compoundPredicateType + subpredicates:newSubpredicates]; + } + } comparisonBlock:nil]; +} + +/*! + Returns a version of the given predicate that contains no NSBetweenPredicateOperatorType predicates. + (A BETWEEN {C, D}) gets converted to (A >= C AND A <= D). + */ ++ (NSPredicate *)removeBetween:(NSPredicate *)predicate { + return [self _mapPredicate:predicate + compoundBlock:nil + comparisonBlock:^NSPredicate *(NSComparisonPredicate *predicate) { + if ([predicate predicateOperatorType] == NSBetweenPredicateOperatorType) { + NSComparisonPredicate *between = (NSComparisonPredicate *)predicate; + NSExpression *rhs = between.rightExpression; + + PFConsistencyAssert(rhs.expressionType == NSConstantValueExpressionType || + rhs.expressionType == NSAggregateExpressionType, + @"The right-hand side of a BETWEEN operation must be a value or literal."); + + PFConsistencyAssert([rhs.constantValue isKindOfClass:[NSArray class]], + @"The right-hand side of a BETWEEN operation must be an array."); + + NSArray *array = rhs.constantValue; + PFConsistencyAssert(array.count == 2, @"The right-hand side of a BETWEEN operation must have 2 items."); + + id minValue = array[0]; + id maxValue = array[1]; + + NSExpression *minExpression = ([minValue isKindOfClass:[NSExpression class]] + ? minValue + : [NSExpression expressionForConstantValue:minValue]); + NSExpression *maxExpression = ([maxValue isKindOfClass:[NSExpression class]] + ? maxValue + : [NSExpression expressionForConstantValue:maxValue]); + + return [NSCompoundPredicate andPredicateWithSubpredicates: + @[ [NSComparisonPredicate predicateWithLeftExpression:between.leftExpression + rightExpression:minExpression + modifier:between.comparisonPredicateModifier + type:NSGreaterThanOrEqualToPredicateOperatorType + options:between.options], + [NSComparisonPredicate predicateWithLeftExpression:between.leftExpression + rightExpression:maxExpression + modifier:between.comparisonPredicateModifier + type:NSLessThanOrEqualToPredicateOperatorType + options:between.options] + ]]; + } + return predicate; + }]; +} + +/*! + Returns a version of the given predicate that contains no Yoda conditions. + A Yoda condition is one where there's a constant on the LHS, such as (3 <= X). + The predicate returned by this method will instead have (X >= 3). + */ ++ (NSPredicate *)reverseYodaConditions:(NSPredicate *)predicate { + return [self _mapPredicate:predicate + compoundBlock:nil + comparisonBlock:^NSPredicate *(NSComparisonPredicate *comparison) { + if (comparison.leftExpression.expressionType == NSConstantValueExpressionType && + comparison.rightExpression.expressionType == NSKeyPathExpressionType) { + // This is a Yoda condition. + NSPredicateOperatorType newType; + switch ([comparison predicateOperatorType]) { + case NSEqualToPredicateOperatorType: { + newType = NSEqualToPredicateOperatorType; + break; + } + case NSNotEqualToPredicateOperatorType: { + newType = NSNotEqualToPredicateOperatorType; + break; + } + case NSLessThanPredicateOperatorType: { + newType = NSGreaterThanPredicateOperatorType; + break; + } + case NSLessThanOrEqualToPredicateOperatorType: { + newType = NSGreaterThanOrEqualToPredicateOperatorType; + break; + } + case NSGreaterThanPredicateOperatorType: { + newType = NSLessThanPredicateOperatorType; + break; + } + case NSGreaterThanOrEqualToPredicateOperatorType: { + newType = NSLessThanOrEqualToPredicateOperatorType; + break; + } + case NSInPredicateOperatorType: { + // This is like "5 IN X" where X is an array. + // Mongo handles this with syntax like "X = 5". + newType = NSEqualToPredicateOperatorType; + break; + } + case NSContainsPredicateOperatorType: + case NSMatchesPredicateOperatorType: + case NSLikePredicateOperatorType: + case NSBeginsWithPredicateOperatorType: + case NSEndsWithPredicateOperatorType: + case NSCustomSelectorPredicateOperatorType: + case NSBetweenPredicateOperatorType: + default: { + // We don't know how to reverse this Yoda condition, but maybe that's okay. + return predicate; + } + } + return [NSComparisonPredicate predicateWithLeftExpression:comparison.rightExpression + rightExpression:comparison.leftExpression + modifier:comparison.comparisonPredicateModifier + type:newType + options:comparison.options]; + } + return comparison; + }]; +} + +/*! + Returns a version of the given predicate converted to disjunctive normal form (DNF). + Unlike normalizeToDNF:error:, this method only accepts compound predicates, and assumes that + removeNegation:error: has already been applied to the given predicate. + */ ++ (NSPredicate *)asOrOfAnds:(NSCompoundPredicate *)compound { + // Convert the sub-predicates to DNF. + NSMutableArray *dnfSubpredicates = [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + for (NSPredicate *subpredicate in compound.subpredicates) { + if ([subpredicate isKindOfClass:[NSCompoundPredicate class]]) { + [dnfSubpredicates addObject:[self asOrOfAnds:(NSCompoundPredicate *)subpredicate]]; + } else { + [dnfSubpredicates addObject:subpredicate]; + } + } + + if (compound.compoundPredicateType == NSOrPredicateType) { + // We just need to flatten any child ORs into this OR. + NSMutableArray *newSubpredicates = [NSMutableArray arrayWithCapacity:dnfSubpredicates.count]; + for (NSPredicate *subpredicate in dnfSubpredicates) { + if ([subpredicate isKindOfClass:[NSCompoundPredicate class]] && + ((NSCompoundPredicate *)subpredicate).compoundPredicateType == NSOrPredicateType) { + for (NSPredicate *grandchild in ((NSCompoundPredicate *)subpredicate).subpredicates) { + [newSubpredicates addObject:grandchild]; + } + } else { + [newSubpredicates addObject:subpredicate]; + } + } + // There's no reason to wrap a single predicate in an OR. + if (newSubpredicates.count == 1) { + return newSubpredicates.lastObject; + } + return [NSCompoundPredicate orPredicateWithSubpredicates:newSubpredicates]; + } + + if (compound.compoundPredicateType == NSAndPredicateType) { + // This is tough. We need to take the cross product of all the subpredicates. + NSMutableArray *disjunction = [NSMutableArray arrayWithObject:@[]]; + for (NSPredicate *subpredicate in dnfSubpredicates) { + NSMutableArray *newDisjunction = [NSMutableArray array]; + if ([subpredicate isKindOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *subcompound = (NSCompoundPredicate *)subpredicate; + if (subcompound.compoundPredicateType == NSOrPredicateType) { + // We have to add every item in the OR to every AND list we have. + for (NSArray *conjunction in disjunction) { + for (NSPredicate *grandchild in subcompound.subpredicates) { + [newDisjunction addObject:[conjunction arrayByAddingObject:grandchild]]; + } + } + + } else if (subcompound.compoundPredicateType == NSAndPredicateType) { + // Just add all these conditions to all the conjunctions in progress. + for (NSArray *conjunction in disjunction) { + NSArray *grandchildren = subcompound.subpredicates; + [newDisjunction addObject:[conjunction arrayByAddingObjectsFromArray:grandchildren]]; + } + + } else { + [NSException raise:NSInternalInconsistencyException + format:@"[PFQuery asOrOfAnds:] found a compound query that wasn't OR or AND."]; + } + } else { + // Just add this condition to all the conjunctions in progress. + for (NSArray *conjunction in disjunction) { + [newDisjunction addObject:[conjunction arrayByAddingObject:subpredicate]]; + } + } + disjunction = newDisjunction; + } + + // Now disjunction contains an OR of ANDs. We just need to convert it to NSPredicates. + NSMutableArray *andPredicates = [NSMutableArray arrayWithCapacity:disjunction.count]; + for (NSArray *conjunction in disjunction) { + if (conjunction.count > 0) { + if (conjunction.count == 1) { + [andPredicates addObject:conjunction.lastObject]; + } else { + [andPredicates addObject:[NSCompoundPredicate + andPredicateWithSubpredicates:conjunction]]; + } + } + } + if (andPredicates.count == 1) { + return andPredicates.lastObject; + } else { + return [NSCompoundPredicate orPredicateWithSubpredicates:andPredicates]; + } + } + + [NSException raise:NSInternalInconsistencyException + format:@"[PFQuery asOrOfAnds:] was passed a compound query that wasn't OR or AND."]; + + return nil; +} + +/*! + Throws an exception if any comparison predicate inside this predicate has any modifiers, such as ANY, EVERY, etc. + */ ++ (void)assertNoPredicateModifiers:(NSPredicate *)predicate { + [self _mapPredicate:predicate + compoundBlock:nil + comparisonBlock:^NSPredicate *(NSComparisonPredicate *comparison) { + PFConsistencyAssert(comparison.comparisonPredicateModifier == NSDirectPredicateModifier, + @"Unsupported comparison predicate modifier %zd.", + comparison.comparisonPredicateModifier); + return comparison; + }]; +} + +/*! + Returns a version of the given predicate converted to disjunctive normal form (DNF), + known colloqially as an "or of ands", the only form of query that PFQuery accepts. + */ ++ (NSPredicate *)_normalizeToDNF:(NSPredicate *)predicate { + // Make sure they didn't use ANY, EVERY, etc. + [self assertNoPredicateModifiers:predicate]; + + // Change any BETWEEN operators to a conjunction. + predicate = [self removeBetween:predicate]; + + // Change any backwards (3 <= X) to the standardized (X >= 3). + predicate = [self reverseYodaConditions:predicate]; + + // Push any negation into the leaves. + predicate = [self removeNegation:predicate]; + + // Any comparison predicate is trivially DNF. + if (![predicate isKindOfClass:[NSCompoundPredicate class]]) { + return predicate; + } + + // It must be a compound predicate. Convert it to an OR of ANDs. + return [self asOrOfAnds:(NSCompoundPredicate *)predicate]; +} + +/*! + Takes a predicate like ((A AND B) OR (A AND C)) and rewrites it as the more efficient (A AND (B OR C)). + Assumes the input predicate is already in DNF. + // TODO: (nlutsenko): Move this logic into the server and remove it from here. + */ ++ (NSPredicate *)_hoistCommonPredicates:(NSPredicate *)predicate { + // This only makes sense for queries with a top-level OR. + if (!([predicate isKindOfClass:[NSCompoundPredicate class]] && + ((NSCompoundPredicate *)predicate).compoundPredicateType == NSOrPredicateType)) { + return predicate; + } + + // Find the set of predicates that are included in every branch of this OR. + NSArray *andPredicates = ((NSCompoundPredicate *)predicate).subpredicates; + NSMutableSet *common = nil; + for (NSPredicate *andPredicate in andPredicates) { + NSMutableSet *comparisonPredicates = nil; + if ([andPredicate isKindOfClass:[NSComparisonPredicate class]]) { + comparisonPredicates = [NSMutableSet setWithObject:andPredicate]; + } else { + comparisonPredicates = + [NSMutableSet setWithArray:((NSCompoundPredicate *)andPredicate).subpredicates]; + } + + if (!common) { + common = comparisonPredicates; + } else { + [common intersectSet:comparisonPredicates]; + } + } + + if (!common.count) { + return predicate; + } + + NSMutableArray *newAndPredicates = [NSMutableArray array]; + + // Okay, there were common sub-predicates. Hoist them up to this one. + for (NSPredicate *andPredicate in andPredicates) { + NSMutableSet *comparisonPredicates = nil; + if ([andPredicate isKindOfClass:[NSComparisonPredicate class]]) { + comparisonPredicates = [NSMutableSet setWithObject:andPredicate]; + } else { + comparisonPredicates = + [NSMutableSet setWithArray:((NSCompoundPredicate *)andPredicate).subpredicates]; + } + + for (NSPredicate *comparisonPredicate in common) { + [comparisonPredicates removeObject:comparisonPredicate]; + } + + if (comparisonPredicates.count == 0) { + // One of the OR predicates reduces to TRUE, so just return the hoisted part. + return [NSCompoundPredicate andPredicateWithSubpredicates:common.allObjects]; + } else if (comparisonPredicates.count == 1) { + [newAndPredicates addObject:comparisonPredicates.allObjects.lastObject]; + } else { + NSPredicate *newAndPredicate = + [NSCompoundPredicate andPredicateWithSubpredicates:comparisonPredicates.allObjects]; + [newAndPredicates addObject:newAndPredicate]; + } + } + + // Make an AND of the hoisted predicates and the OR of the modified subpredicates. + NSPredicate *newOrPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:newAndPredicates]; + NSArray *newPredicates = [@[ newOrPredicate ] arrayByAddingObjectsFromArray:common.allObjects]; + return [NSCompoundPredicate andPredicateWithSubpredicates:newPredicates]; +} + +///-------------------------------------- +#pragma mark - Regex +///-------------------------------------- + +/*! + This is used to create a regex string to match the input string. By using Q and E flags to match, we can do this + without requiring super expensive rewrites, but me must be careful to escape existing \E flags in the input string. + By replacing it with `\E\\E\Q`, the regex engine will end the old literal block, put in the user's `\E` string, and + Begin another literal block. + */ ++ (NSString *)regexStringForString:(NSString *)string { + return [NSString stringWithFormat:@"\\Q%@\\E", [string stringByReplacingOccurrencesOfString:@"\\E" + withString:@"\\E\\\\E\\Q"]]; +} + +///-------------------------------------- +#pragma mark - Errors +///-------------------------------------- + ++ (NSError *)objectNotFoundError { + return [PFErrorUtilities errorWithCode:kPFErrorObjectNotFound message:@"No results matched the query."]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/PFRelationPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/PFRelationPrivate.h new file mode 100644 index 0000000..26d26fd --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/PFRelationPrivate.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFDecoder; + +@interface PFRelation (Private) + ++ (PFRelation *)relationForObject:(PFObject *)parent forKey:(NSString *)key; ++ (PFRelation *)relationWithTargetClass:(NSString *)targetClass; ++ (PFRelation *)relationFromDictionary:(NSDictionary *)dictionary withDecoder:(PFDecoder *)decoder; +- (void)ensureParentIs:(PFObject *)someParent andKeyIs:(NSString *)someKey; +- (NSDictionary *)encodeIntoDictionary; +- (BOOL)_hasKnownObject:(PFObject *)object; +- (void)_addKnownObject:(PFObject *)object; +- (void)_removeKnownObject:(PFObject *)object; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.h new file mode 100644 index 0000000..3fd99ed --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRelationState.h" + +@interface PFMutableRelationState : PFRelationState + +@property (nonatomic, weak, readwrite) PFObject *parent; +@property (nonatomic, copy, readwrite) NSString *targetClass; +@property (nonatomic, copy, readwrite) NSMutableSet *knownObjects; +@property (nonatomic, copy, readwrite) NSString *key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.m new file mode 100644 index 0000000..6a92279 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFMutableRelationState.m @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableRelationState.h" + +#import "PFObject.h" +#import "PFRelationState_Private.h" + +@implementation PFMutableRelationState + +@dynamic parent; +@dynamic parentObjectId; +@dynamic parentClassName; +@dynamic targetClass; +@dynamic knownObjects; +@dynamic key; + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + NSMutableDictionary *parentAttributes = [[super propertyAttributes] mutableCopy]; + + parentAttributes[@"knownObjects"] = [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeMutableCopy]; + + return parentAttributes; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _knownObjects = [[NSMutableSet alloc] init]; + + return self; +} + +///-------------------------------------- +#pragma mark - Properties +///-------------------------------------- + +- (void)setParent:(PFObject *)parent { + if (_parent != parent || ![self.parentClassName isEqualToString:parent.parseClassName] || + ![self.parentObjectId isEqualToString:parent.objectId]) { + _parent = parent; + _parentClassName = [[parent parseClassName] copy]; + _parentObjectId = [[parent objectId] copy]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.h new file mode 100644 index 0000000..3ce8e80 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFBaseState.h" + +@class PFObject; + +@interface PFRelationState : PFBaseState + +@property (nonatomic, weak, readonly) PFObject *parent; +@property (nonatomic, copy, readonly) NSString *parentClassName; +@property (nonatomic, copy, readonly) NSString *parentObjectId; +@property (nonatomic, copy, readonly) NSString *targetClass; +@property (nonatomic, copy, readonly) NSSet *knownObjects; +@property (nonatomic, copy, readonly) NSString *key; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithState:(PFRelationState *)otherState; ++ (instancetype)stateWithState:(PFRelationState *)otherState; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.m new file mode 100644 index 0000000..bdf36c6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState.m @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRelationState.h" +#import "PFRelationState_Private.h" + +#import "PFMutableRelationState.h" + +@implementation PFRelationState + +///-------------------------------------- +#pragma mark - PFBaseStateSubclass +///-------------------------------------- + ++ (NSDictionary *)propertyAttributes { + return @{ + @"parent": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeWeak], + @"parentClassName": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"parentObjectId": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"targetClass": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"knownObjects": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + @"key": [PFPropertyAttributes attributesWithAssociationType:PFPropertyInfoAssociationTypeCopy], + }; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _knownObjects = [[NSSet alloc] init]; + + return self; +} + +- (instancetype)initWithState:(PFRelationState *)otherState { + return [super initWithState:otherState]; +} + ++ (instancetype)stateWithState:(PFRelationState *)otherState { + return [super stateWithState:otherState]; +} + +///-------------------------------------- +#pragma mark - Copying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[PFRelationState allocWithZone:zone] initWithState:self]; +} + +- (instancetype)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableRelationState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState_Private.h new file mode 100644 index 0000000..bf13b9e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Relation/State/PFRelationState_Private.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRelationState.h" + +@interface PFRelationState() { +@protected + __weak PFObject *_parent; + NSString *_parentClassName; + NSString *_parentObjectId; + NSSet *_knownObjects; + NSString *_key; +} + +@property (nonatomic, weak, readwrite) PFObject *parent; +@property (nonatomic, copy, readwrite) NSString *parentClassName; +@property (nonatomic, copy, readwrite) NSString *parentObjectId; +@property (nonatomic, copy, readwrite) NSString *targetClass; +@property (nonatomic, copy, readwrite) NSSet *knownObjects; +@property (nonatomic, copy, readwrite) NSString *key; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.h new file mode 100644 index 0000000..83d06e4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFDataProvider.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFSession; + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSessionController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Current Session +///-------------------------------------- + +- (BFTask *)getCurrentSessionAsyncWithSessionToken:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.m new file mode 100644 index 0000000..7abe535 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Controller/PFSessionController.m @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSessionController.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFObjectPrivate.h" +#import "PFRESTSessionCommand.h" +#import "PFSession.h" + +@implementation PFSessionController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Current Session +///-------------------------------------- + +- (BFTask *)getCurrentSessionAsyncWithSessionToken:(NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTSessionCommand getCurrentSessionCommandWithSessionToken:sessionToken]; + return [self.dataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + NSDictionary *dictionary = result.result; + PFSession *session = [PFSession _objectFromDictionary:dictionary + defaultClassName:[PFSession parseClassName] + completeData:YES]; + return session; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/PFSession_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/PFSession_Private.h new file mode 100644 index 0000000..b647585 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/PFSession_Private.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFSessionController; + +@interface PFSession () + +///-------------------------------------- +/// @name Session Controller +///-------------------------------------- + ++ (PFSessionController *)sessionController; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.h new file mode 100644 index 0000000..806d7da --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface PFSessionUtilities : NSObject + +///-------------------------------------- +/// @name Session Token +///-------------------------------------- + ++ (BOOL)isSessionTokenRevocable:(nullable NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.m new file mode 100644 index 0000000..4dff476 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/Session/Utilities/PFSessionUtilities.m @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSessionUtilities.h" + +@implementation PFSessionUtilities + +///-------------------------------------- +#pragma mark - Session Token +///-------------------------------------- + ++ (BOOL)isSessionTokenRevocable:(NSString *)sessionToken { + return (sessionToken && [sessionToken rangeOfString:@"r:"].location != NSNotFound); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.h new file mode 100644 index 0000000..7ca2a64 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.h @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern dispatch_queue_t PFThreadsafetyCreateQueueForObject(id object); +extern void PFThreadsafetySafeDispatchSync(dispatch_queue_t queue, dispatch_block_t block); diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.m new file mode 100644 index 0000000..e78f547 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/ThreadSafety/PFThreadsafety.m @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFThreadsafety.h" + +static void *const PFThreadsafetyQueueIDKey = (void *)&PFThreadsafetyQueueIDKey; + +dispatch_queue_t PFThreadsafetyCreateQueueForObject(id object) { + NSString *label = [NSStringFromClass([object class]) stringByAppendingString:@".synchronizationQueue"]; + dispatch_queue_t queue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_SERIAL); + + void *uuid = calloc(1, sizeof(uuid)); + dispatch_queue_set_specific(queue, PFThreadsafetyQueueIDKey, uuid, free); + + return queue; +} + +void PFThreadsafetySafeDispatchSync(dispatch_queue_t queue, dispatch_block_t block) { + void *uuidMine = dispatch_get_specific(PFThreadsafetyQueueIDKey); + void *uuidOther = dispatch_queue_get_specific(queue, PFThreadsafetyQueueIDKey); + + if (uuidMine == uuidOther) { + block(); + } else { + dispatch_sync(queue, block); + } +} diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h new file mode 100644 index 0000000..746c247 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFUser; + +@interface PFUserAuthenticationController : NSObject + +@property (nonatomic, weak, readonly) id dataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +- (instancetype)initWithDataSource:(id)dataSource; ++ (instancetype)controllerWithDataSource:(id)dataSource; + +///-------------------------------------- +/// @name Authentication Providers +///-------------------------------------- + +- (void)registerAuthenticationDelegate:(id)delegate forAuthType:(NSString *)authType; +- (void)unregisterAuthenticationDelegateForAuthType:(NSString *)authType; + +- (id)authenticationDelegateForAuthType:(NSString *)authType; + +///-------------------------------------- +/// @name Authentication +///-------------------------------------- + +- (BFTask PF_GENERIC(NSNumber *) *)restoreAuthenticationAsyncWithAuthData:(nullable NSDictionary *)authData + forAuthType:(NSString *)authType; +- (BFTask PF_GENERIC(NSNumber *) *)deauthenticateAsyncWithAuthType:(NSString *)authType; + +///-------------------------------------- +/// @name Log In +///-------------------------------------- + +- (BFTask *)logInUserAsyncWithAuthType:(NSString *)authType authData:(NSDictionary *)authData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.m new file mode 100644 index 0000000..2f50838 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.m @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserAuthenticationController.h" + +#import "BFTask+Private.h" +#import "PFMacros.h" +#import "PFUserPrivate.h" +#import "PFObjectPrivate.h" +#import "PFAnonymousUtils.h" +#import "PFAnonymousAuthenticationProvider.h" +#import "PFUserController.h" +#import "PFCurrentUserController.h" +#import "PFAssert.h" + +@interface PFUserAuthenticationController () { + dispatch_queue_t _dataAccessQueue; + NSMutableDictionary PF_GENERIC(NSString *, id) *_authenticationDelegates; +} + +@end + +@implementation PFUserAuthenticationController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithDataSource:(id)dataSource { + self = [super init]; + if (!self) return nil; + + _dataSource = dataSource; + _dataAccessQueue = dispatch_queue_create("com.parse.user.authenticationManager", DISPATCH_QUEUE_SERIAL); + _authenticationDelegates = [NSMutableDictionary dictionary]; + + return self; +} + ++ (instancetype)controllerWithDataSource:(id)dataSource { + return [[self alloc] initWithDataSource:dataSource]; +} + +///-------------------------------------- +#pragma mark - Authentication Providers +///-------------------------------------- + +- (void)registerAuthenticationDelegate:(id)delegate forAuthType:(NSString *)authType { + PFParameterAssert(delegate, @"Authentication delegate can't be `nil`."); + PFParameterAssert(authType, @"`authType` can't be `nil`."); + PFConsistencyAssert(![self authenticationDelegateForAuthType:authType], + @"Authentication delegate already registered for authType `%@`.", authType); + + dispatch_sync(_dataAccessQueue, ^{ + _authenticationDelegates[authType] = delegate; + }); + + // TODO: (nlutsenko) Decouple this further. + [[self.dataSource.currentUserController getCurrentUserAsyncWithOptions:0] continueWithSuccessBlock:^id(BFTask *task) { + PFUser *user = task.result; + [user synchronizeAuthDataWithAuthType:authType]; + return nil; + }]; +} + +- (void)unregisterAuthenticationDelegateForAuthType:(NSString *)authType { + if (!authType) { + return; + } + dispatch_sync(_dataAccessQueue, ^{ + [_authenticationDelegates removeObjectForKey:authType]; + }); +} + +- (id)authenticationDelegateForAuthType:(NSString *)authType { + if (!authType) { + return nil; + } + + __block id delegate = nil; + dispatch_sync(_dataAccessQueue, ^{ + delegate = _authenticationDelegates[authType]; + }); + return delegate; +} + +///-------------------------------------- +#pragma mark - Authentication +///-------------------------------------- + +- (BFTask PF_GENERIC(NSNumber *)*)restoreAuthenticationAsyncWithAuthData:(nullable NSDictionary *)authData + forAuthType:(NSString *)authType { + id provider = [self authenticationDelegateForAuthType:authType]; + if (!provider) { + return [BFTask taskWithResult:@YES]; + } + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id { + return [BFTask taskWithResult:@([provider restoreAuthenticationWithAuthData:authData])]; + }]; +} + +- (BFTask PF_GENERIC(NSNumber *)*)deauthenticateAsyncWithAuthType:(NSString *)authType { + return [self restoreAuthenticationAsyncWithAuthData:nil forAuthType:authType]; +} + +///-------------------------------------- +#pragma mark - Log In +///-------------------------------------- + +- (BFTask *)logInUserAsyncWithAuthType:(NSString *)authType authData:(NSDictionary *)authData { + //TODO: (nlutsenko) Make it fully async. + //TODO: (nlutsenko) Inject `PFUserController` here. + PFUser *currentUser = [PFUser currentUser]; + if (currentUser && [PFAnonymousUtils isLinkedWithUser:currentUser]) { + if ([currentUser isLazy]) { + PFUser *user = currentUser; + BFTask *resolveLaziness = nil; + NSDictionary *oldAnonymousData = nil; + @synchronized(user.lock) { + oldAnonymousData = user.authData[PFAnonymousUserAuthenticationType]; + + // Replace any anonymity with the new linked authData + [user stripAnonymity]; + + [user.authData setObject:authData forKey:authType]; + [user.linkedServiceNames addObject:authType]; + + resolveLaziness = [user resolveLazinessAsync:[BFTask taskWithResult:nil]]; + } + + return [resolveLaziness continueAsyncWithBlock:^id(BFTask *task) { + if (task.isCancelled || task.exception || task.error) { + [user.authData removeObjectForKey:authType]; + [user.linkedServiceNames removeObject:authType]; + [user restoreAnonymity:oldAnonymousData]; + return task; + } + return task.result; + }]; + } else { + return [[currentUser linkWithAuthTypeInBackground:authType + authData:authData] continueAsyncWithBlock:^id(BFTask *task) { + NSError *error = task.error; + if (error) { + if (error.code == kPFErrorAccountAlreadyLinked) { + // An account that's linked to the given authData already exists, + // so log in instead of trying to claim. + return [[PFUser userController] logInCurrentUserAsyncWithAuthType:authType + authData:authData + revocableSession:[PFUser _isRevocableSessionEnabled]]; + } else { + return task; + } + } + + return [BFTask taskWithResult:currentUser]; + }]; + } + } + return [[PFUser userController] logInCurrentUserAsyncWithAuthType:authType + authData:authData + revocableSession:[PFUser _isRevocableSessionEnabled]]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h new file mode 100644 index 0000000..d906dd1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const PFAnonymousUserAuthenticationType; + +@interface PFAnonymousAuthenticationProvider : NSObject + +/*! + Gets auth data with a fresh UUID. + */ +@property (nonatomic, copy, readonly) NSDictionary *authData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m new file mode 100644 index 0000000..e338151 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAnonymousAuthenticationProvider.h" + +#import + +NSString *const PFAnonymousUserAuthenticationType = @"anonymous"; + +@implementation PFAnonymousAuthenticationProvider + +///-------------------------------------- +#pragma mark - PFAnonymousAuthenticationProvider +///-------------------------------------- + +- (BOOL)restoreAuthenticationWithAuthData:(NSDictionary *)authData { + return YES; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (NSDictionary *)authData { + NSString *uuidString = [NSUUID UUID].UUIDString; + uuidString = [uuidString lowercaseString]; + return @{ @"id" : uuidString }; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h new file mode 100644 index 0000000..6d966f3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 PFAnonymousAuthenticationProvider; +@class PFUser; + +@interface PFAnonymousUtils (Private) + ++ (PFAnonymousAuthenticationProvider *)_authenticationProvider; ++ (void)_clearAuthenticationProvider; + ++ (PFUser *)_lazyLogIn; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h new file mode 100644 index 0000000..4ccbf77 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectFileCodingLogic.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFUserFileCodingLogic : PFObjectFileCodingLogic + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m new file mode 100644 index 0000000..d459bc2 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserFileCodingLogic.h" + +#import "PFDecoder.h" +#import "PFMutableUserState.h" +#import "PFObjectPrivate.h" +#import "PFUserConstants.h" +#import "PFUserPrivate.h" + +@interface PFUserFileCodingLogic () + +@end + +@implementation PFUserFileCodingLogic + +///-------------------------------------- +#pragma mark - Coding +///-------------------------------------- + +- (void)updateObject:(PFObject *)object fromDictionary:(NSDictionary *)dictionary usingDecoder:(PFDecoder *)decoder { + PFUser *user = (PFUser *)object; + + NSString *newSessionToken = dictionary[@"session_token"] ?: dictionary[PFUserSessionTokenRESTKey]; + if (newSessionToken) { + PFMutableUserState *state = [user._state mutableCopy]; + state.sessionToken = newSessionToken; + user._state = state; + } + + // Merge the linked service metadata + NSDictionary *newAuthData = dictionary[@"auth_data"] ?: dictionary[PFUserAuthDataRESTKey]; + newAuthData = [decoder decodeObject:newAuthData]; + if (newAuthData) { + [user.authData removeAllObjects]; + [user.linkedServiceNames removeAllObjects]; + [newAuthData enumerateKeysAndObjectsUsingBlock:^(id key, id linkData, BOOL *stop) { + if (linkData != [NSNull null]) { + user.authData[key] = linkData; + [user.linkedServiceNames addObject:key]; + [user synchronizeAuthDataWithAuthType:key]; + } else { + [user.authData removeObjectForKey:key]; + [user.linkedServiceNames removeObject:key]; + [user synchronizeAuthDataWithAuthType:key]; + } + }]; + } + + [super updateObject:user fromDictionary:dictionary usingDecoder:decoder]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.h new file mode 100644 index 0000000..f8da41e --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.h @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +extern NSString *const PFUserUsernameRESTKey; +extern NSString *const PFUserPasswordRESTKey; +extern NSString *const PFUserSessionTokenRESTKey; +extern NSString *const PFUserAuthDataRESTKey; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.m new file mode 100644 index 0000000..ecccaf1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Constants/PFUserConstants.m @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserConstants.h" + +NSString *const PFUserUsernameRESTKey = @"username"; +NSString *const PFUserPasswordRESTKey = @"password"; +NSString *const PFUserSessionTokenRESTKey = @"sessionToken"; +NSString *const PFUserAuthDataRESTKey = @"authData"; diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.h new file mode 100644 index 0000000..4ff2208 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFDataProvider.h" +#import "PFObjectControlling.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PFUserController : NSObject + +@property (nonatomic, weak, readonly) id commonDataSource; +@property (nonatomic, weak, readonly) id coreDataSource; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; ++ (instancetype)controllerWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; + +///-------------------------------------- +/// @name Log In +///-------------------------------------- + +- (BFTask *)logInCurrentUserAsyncWithSessionToken:(NSString *)sessionToken; +- (BFTask *)logInCurrentUserAsyncWithUsername:(NSString *)username + password:(NSString *)password + revocableSession:(BOOL)revocableSession; + +//TODO: (nlutsenko) Move this method into PFUserAuthenticationController after PFUser is decoupled further. +- (BFTask *)logInCurrentUserAsyncWithAuthType:(NSString *)authType + authData:(NSDictionary *)authData + revocableSession:(BOOL)revocableSession; + +///-------------------------------------- +/// @name Reset Password +///-------------------------------------- + +- (BFTask *)requestPasswordResetAsyncForEmail:(NSString *)email; + +///-------------------------------------- +/// @name Log Out +///-------------------------------------- + +- (BFTask *)logOutUserAsyncWithSessionToken:(NSString *)sessionToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.m new file mode 100644 index 0000000..cebeb52 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/Controller/PFUserController.m @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserController.h" + +#import "BFTask+Private.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFCurrentUserController.h" +#import "PFErrorUtilities.h" +#import "PFMacros.h" +#import "PFObjectPrivate.h" +#import "PFRESTUserCommand.h" +#import "PFUserPrivate.h" + +@implementation PFUserController + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + self = [super init]; + if (!self) return nil; + + _commonDataSource = commonDataSource; + _coreDataSource = coreDataSource; + + return self; +} + ++ (instancetype)controllerWithCommonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + return [[self alloc] initWithCommonDataSource:commonDataSource + coreDataSource:coreDataSource]; +} + +///-------------------------------------- +#pragma mark - Log In +///-------------------------------------- + +- (BFTask *)logInCurrentUserAsyncWithSessionToken:(NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTUserCommand getCurrentUserCommandWithSessionToken:sessionToken]; + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFCommandResult *result = task.result; + NSDictionary *dictionary = result.result; + + // We test for a null object, if it isn't, we can use the response to create a PFUser. + if ([dictionary isKindOfClass:[NSNull class]] || !dictionary) { + return [BFTask taskWithError:[PFErrorUtilities errorWithCode:kPFErrorObjectNotFound + message:@"Invalid Session Token."]]; + } + + PFUser *user = [PFUser _objectFromDictionary:dictionary + defaultClassName:[PFUser parseClassName] + completeData:YES]; + // Serialize the object to disk so we can later access it via currentUser + PFCurrentUserController *controller = self.coreDataSource.currentUserController; + return [[controller saveCurrentObjectAsync:user] continueWithBlock:^id(BFTask *task) { + return user; + }]; + }]; +} + +- (BFTask *)logInCurrentUserAsyncWithUsername:(NSString *)username + password:(NSString *)password + revocableSession:(BOOL)revocableSession { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + PFRESTCommand *command = [PFRESTUserCommand logInUserCommandWithUsername:username + password:password + revocableSession:revocableSession]; + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + PFCommandResult *result = task.result; + NSDictionary *dictionary = result.result; + + // We test for a null object, if it isn't, we can use the response to create a PFUser. + if ([dictionary isKindOfClass:[NSNull class]] || !dictionary) { + return [BFTask taskWithError:[PFErrorUtilities errorWithCode:kPFErrorObjectNotFound + message:@"Invalid login credentials."]]; + } + + PFUser *user = [PFUser _objectFromDictionary:dictionary + defaultClassName:[PFUser parseClassName] + completeData:YES]; + + // Serialize the object to disk so we can later access it via currentUser + PFCurrentUserController *controller = self.coreDataSource.currentUserController; + return [[controller saveCurrentObjectAsync:user] continueWithBlock:^id(BFTask *task) { + return user; + }]; + }]; +} + +- (BFTask *)logInCurrentUserAsyncWithAuthType:(NSString *)authType + authData:(NSDictionary *)authData + revocableSession:(BOOL)revocableSession { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTUserCommand serviceLoginUserCommandWithAuthenticationType:authType + authenticationData:authData + revocableSession:revocableSession]; + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + PFUser *user = [PFUser _objectFromDictionary:result.result + defaultClassName:[PFUser parseClassName] + completeData:YES]; + @synchronized ([user lock]) { + user.authData[authType] = authData; + [user.linkedServiceNames addObject:authType]; + [user startSave]; + return [user _handleServiceLoginCommandResult:result]; + } + }]; +} + +///-------------------------------------- +#pragma mark - Reset Password +///-------------------------------------- + +- (BFTask *)requestPasswordResetAsyncForEmail:(NSString *)email { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTUserCommand resetPasswordCommandForUserWithEmail:email]; + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessResult:nil]; +} + +///-------------------------------------- +#pragma mark - Log Out +///-------------------------------------- + +- (BFTask *)logOutUserAsyncWithSessionToken:(NSString *)sessionToken { + @weakify(self); + return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @strongify(self); + PFRESTCommand *command = [PFRESTUserCommand logOutUserCommandWithSessionToken:sessionToken]; + return [self.commonDataSource.commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithSuccessResult:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.h new file mode 100644 index 0000000..15b8e99 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCoreDataProvider.h" +#import "PFCurrentObjectControlling.h" +#import "PFDataProvider.h" +#import "PFMacros.h" + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFUser; + +typedef NS_OPTIONS(NSUInteger, PFCurrentUserLoadingOptions) { + PFCurrentUserLoadingOptionCreateLazyIfNotAvailable = 1 << 0, +}; + +@interface PFCurrentUserController : NSObject + +@property (nonatomic, weak, readonly) id commonDataSource; +@property (nonatomic, weak, readonly) id coreDataSource; + +@property (atomic, assign) BOOL automaticUsersEnabled; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithStorageType:(PFCurrentObjectStorageType)storageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource NS_DESIGNATED_INITIALIZER; ++ (instancetype)controllerWithStorageType:(PFCurrentObjectStorageType)storageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource; + +///-------------------------------------- +/// @name User +///-------------------------------------- + +- (BFTask *)getCurrentUserAsyncWithOptions:(PFCurrentUserLoadingOptions)options; + +- (BFTask *)logOutCurrentUserAsync; + +///-------------------------------------- +/// @name Session Token +///-------------------------------------- + +- (BFTask *)getCurrentUserSessionTokenAsync; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.m new file mode 100644 index 0000000..098b4e6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/CurrentUserController/PFCurrentUserController.m @@ -0,0 +1,364 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCurrentUserController.h" + +#import + +#import "BFTask+Private.h" +#import "PFAnonymousUtils_Private.h" +#import "PFAssert.h" +#import "PFAsyncTaskQueue.h" +#import "PFFileManager.h" +#import "PFKeychainStore.h" +#import "PFMutableUserState.h" +#import "PFObjectFilePersistenceController.h" +#import "PFObjectPrivate.h" +#import "PFQuery.h" +#import "PFUserConstants.h" +#import "PFUserPrivate.h" + +@interface PFCurrentUserController () { + dispatch_queue_t _dataQueue; + PFAsyncTaskQueue *_dataTaskQueue; + + PFUser *_currentUser; + BOOL _currentUserMatchesDisk; +} + +@end + +@implementation PFCurrentUserController + +@synthesize storageType = _storageType; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + PFNotDesignatedInitializer(); +} + +- (instancetype)initWithStorageType:(PFCurrentObjectStorageType)storageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + self = [super init]; + if (!self) return nil; + + _dataQueue = dispatch_queue_create("com.parse.currentUser.controller", DISPATCH_QUEUE_CONCURRENT); + _dataTaskQueue = [PFAsyncTaskQueue taskQueue]; + + _storageType = storageType; + _commonDataSource = commonDataSource; + _coreDataSource = coreDataSource; + + return self; +} + ++ (instancetype)controllerWithStorageType:(PFCurrentObjectStorageType)dataStorageType + commonDataSource:(id)commonDataSource + coreDataSource:(id)coreDataSource { + return [[self alloc] initWithStorageType:dataStorageType + commonDataSource:commonDataSource + coreDataSource:coreDataSource]; +} + +///-------------------------------------- +#pragma mark - PFCurrentObjectControlling +///-------------------------------------- + +- (BFTask *)getCurrentObjectAsync { + PFCurrentUserLoadingOptions options = 0; + if (self.automaticUsersEnabled) { + options |= PFCurrentUserLoadingOptionCreateLazyIfNotAvailable; + } + return [self getCurrentUserAsyncWithOptions:options]; +} + +- (BFTask *)saveCurrentObjectAsync:(PFUser *)object { + return [_dataTaskQueue enqueue:^id(BFTask *task) { + return [self _saveCurrentUserAsync:object]; + }]; +} + +///-------------------------------------- +#pragma mark - User +///-------------------------------------- + +- (BFTask *)getCurrentUserAsyncWithOptions:(PFCurrentUserLoadingOptions)options { + return [_dataTaskQueue enqueue:^id(BFTask *task) { + return [self _getCurrentUserAsyncWithOptions:options]; + }]; +} + +- (BFTask *)_getCurrentUserAsyncWithOptions:(PFCurrentUserLoadingOptions)options { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + __block BOOL matchesDisk = NO; + __block PFUser *currentUser = nil; + dispatch_sync(_dataQueue, ^{ + matchesDisk = _currentUserMatchesDisk; + currentUser = _currentUser; + }); + if (currentUser) { + return currentUser; + } + + if (matchesDisk) { + if (options & PFCurrentUserLoadingOptionCreateLazyIfNotAvailable) { + return [self _lazyLogInUser]; + } + return nil; + } + + return [[[[self _loadCurrentUserFromDiskAsync] continueWithSuccessBlock:^id(BFTask *task) { + PFUser *user = task.result; + // If the object was not yet saved, but is already linked with AnonymousUtils - it means it is lazy. + // So mark it's state as `isLazy` and make it `dirty` + if (!user.objectId && [PFAnonymousUtils isLinkedWithUser:user]) { + user.isLazy = YES; + [user _setDirty:YES]; + } + return user; + }] continueWithBlock:^id(BFTask *task) { + dispatch_barrier_sync(_dataQueue, ^{ + _currentUser = task.result; + _currentUserMatchesDisk = !task.faulted; + }); + return task; + }] continueWithBlock:^id(BFTask *task) { + // If there's no user and automatic user is enabled, do lazy login. + if (!task.result && (options & PFCurrentUserLoadingOptionCreateLazyIfNotAvailable)) { + return [self _lazyLogInUser]; + } + return task; + }]; + }]; +} + +- (BFTask *)_saveCurrentUserAsync:(PFUser *)user { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + __block PFUser *currentUser = nil; + dispatch_sync(_dataQueue, ^{ + currentUser = _currentUser; + }); + + BFTask *task = [BFTask taskWithResult:nil]; + // Check for objectId equality to not logout in case we are saving another instance of the same user. + if (currentUser != nil && currentUser != user && ![user.objectId isEqualToString:currentUser.objectId]) { + task = [task continueWithBlock:^id(BFTask *task) { + return [currentUser _logOutAsync]; + }]; + } + return [[task continueWithBlock:^id(BFTask *task) { + @synchronized (user.lock) { + [user setIsCurrentUser:YES]; + [user synchronizeAllAuthData]; + } + return [self _saveCurrentUserToDiskAsync:user]; + }] continueWithBlock:^id(BFTask *task) { + dispatch_barrier_sync(_dataQueue, ^{ + _currentUser = user; + _currentUserMatchesDisk = !task.faulted && !task.cancelled; + }); + return user; + }]; + }]; +} + +- (BFTask *)logOutCurrentUserAsync { + return [_dataTaskQueue enqueue:^id(BFTask *task) { + return [[self _getCurrentUserAsyncWithOptions:0] continueWithBlock:^id(BFTask *task) { + BFTask *userLogoutTask = nil; + + PFUser *user = task.result; + if (user) { + userLogoutTask = [user _logOutAsync]; + } else { + userLogoutTask = [BFTask taskWithResult:nil]; + } + + NSString *filePath = [self.commonDataSource.fileManager parseDataItemPathForPathComponent:PFUserCurrentUserFileName]; + BFTask *fileTask = [PFFileManager removeItemAtPathAsync:filePath]; + BFTask *unpinTask = nil; + + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + unpinTask = [PFObject unpinAllObjectsInBackgroundWithName:PFUserCurrentUserPinName]; + } else { + unpinTask = [BFTask taskWithResult:nil]; + } + + [self _deleteSensitiveUserDataFromKeychainWithItemName:PFUserCurrentUserFileName]; + + BFTask *logoutTask = [[BFTask taskForCompletionOfAllTasks:@[ fileTask, unpinTask ]] continueWithBlock:^id(BFTask *task) { + dispatch_barrier_sync(_dataQueue, ^{ + _currentUser = nil; + _currentUserMatchesDisk = YES; + }); + return nil; + }]; + return [BFTask taskForCompletionOfAllTasks:@[ userLogoutTask, logoutTask ]]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Data Storage +///-------------------------------------- + +- (BFTask *)_loadCurrentUserFromDiskAsync { + BFTask *task = nil; + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + // Try loading from OfflineStore + PFQuery *query = [[[PFQuery queryWithClassName:[PFUser parseClassName]] + fromPinWithName:PFUserCurrentUserPinName] + // We need to ignoreACLs here because right now we don't have currentUser. + ignoreACLs]; + + // Silence the warning if we are loading from LDS + task = [[query findObjectsInBackground] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *results = task.result; + if ([results count] == 1) { + return [BFTask taskWithResult:results.firstObject]; + } else if ([results count] != 0) { + return [[PFObject unpinAllObjectsInBackgroundWithName:PFUserCurrentUserPinName] + continueWithSuccessResult:nil]; + } + + // Backward compatibility if we previously have non-LDS currentUser. + return [PFObject _migrateObjectInBackgroundFromFile:PFUserCurrentUserFileName toPin:PFUserCurrentUserPinName usingMigrationBlock:^id(BFTask *task) { + PFUser *user = task.result; + // Only migrate session token to Keychain if it was loaded from Data File. + if (user.sessionToken) { + return [self _saveSensitiveUserDataAsync:user + toKeychainItemWithName:PFUserCurrentUserKeychainItemName]; + } + return nil; + }]; + }]; + } else { + PFObjectFilePersistenceController *controller = self.coreDataSource.objectFilePersistenceController; + task = [controller loadPersistentObjectAsyncForKey:PFUserCurrentUserFileName]; + } + return [task continueWithSuccessBlock:^id(BFTask *task) { + PFUser *user = task.result; + [user setIsCurrentUser:YES]; + return [[self _loadSensitiveUserDataAsync:user + fromKeychainItemWithName:PFUserCurrentUserKeychainItemName] continueWithSuccessResult:user]; + }]; +} + +- (BFTask *)_saveCurrentUserToDiskAsync:(PFUser *)user { + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + return [[[PFObject unpinAllObjectsInBackgroundWithName:PFUserCurrentUserPinName] continueWithSuccessBlock:^id(BFTask *task) { + return [self _saveSensitiveUserDataAsync:user toKeychainItemWithName:PFUserCurrentUserKeychainItemName]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // We don't want to include children of `currentUser` automatically. + return [user _pinInBackgroundWithName:PFUserCurrentUserPinName includeChildren:NO]; + }]; + } + + return [[self _saveSensitiveUserDataAsync:user + toKeychainItemWithName:PFUserCurrentUserKeychainItemName] continueWithBlock:^id(BFTask *task) { + PFObjectFilePersistenceController *controller = self.coreDataSource.objectFilePersistenceController; + return [controller persistObjectAsync:user forKey:PFUserCurrentUserFileName]; + }]; +} + +///-------------------------------------- +#pragma mark - Sensitive Data +///-------------------------------------- + +- (BFTask *)_loadSensitiveUserDataAsync:(PFUser *)user fromKeychainItemWithName:(NSString *)itemName { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSDictionary *userData = self.commonDataSource.keychainStore[itemName]; + @synchronized (user.lock) { + if (userData) { + PFMutableUserState *state = [user._state mutableCopy]; + + NSString *sessionToken = userData[PFUserSessionTokenRESTKey] ?: userData[@"session_token"]; + if (sessionToken) { + state.sessionToken = sessionToken; + } + + user._state = state; + + NSDictionary *newAuthData = userData[PFUserAuthDataRESTKey] ?: userData[@"auth_data"]; + [newAuthData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + user.authData[key] = obj; + if (obj != nil) { + [user.linkedServiceNames addObject:key]; + } + [user synchronizeAuthDataWithAuthType:key]; + }]; + } + } + return nil; + }]; +} + +- (BFTask *)_saveSensitiveUserDataAsync:(PFUser *)user toKeychainItemWithName:(NSString *)itemName { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + NSMutableDictionary *userData = [NSMutableDictionary dictionaryWithCapacity:2]; + @synchronized (user.lock) { + if (user.sessionToken) { + userData[PFUserSessionTokenRESTKey] = [user.sessionToken copy]; + } + if ([user.authData count]) { + userData[PFUserAuthDataRESTKey] = [user.authData copy]; + } + } + self.commonDataSource.keychainStore[itemName] = userData; + + return nil; + }]; +} + +- (void)_deleteSensitiveUserDataFromKeychainWithItemName:(NSString *)itemName { + [self.commonDataSource.keychainStore removeObjectForKey:itemName]; +} + +///-------------------------------------- +#pragma mark - Session Token +///-------------------------------------- + +- (BFTask *)getCurrentUserSessionTokenAsync { + return [[self getCurrentUserAsyncWithOptions:0] continueWithSuccessBlock:^id(BFTask *task) { + PFUser *user = task.result; + return user.sessionToken; + }]; +} + +///-------------------------------------- +#pragma mark - Lazy Login +///-------------------------------------- + +- (BFTask *)_lazyLogInUser { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + PFUser *user = [PFAnonymousUtils _lazyLogIn]; + + // When LDS is enabled, we will immediately save the anon user to LDS. When LDS is disabled, we + // will create the anon user, but will lazily save it to Parse on an object save that has this + // user in its ACL. + // The main differences here would be that non-LDS may have different anon users in different + // sessions until an object is saved and LDS will persist the same anon user. This shouldn't be a + // big deal... + if (self.storageType == PFCurrentObjectStorageTypeOfflineStore) { + return [[self _saveCurrentUserAsync:user] continueWithSuccessResult:user]; + } + + dispatch_barrier_sync(_dataQueue, ^{ + _currentUser = user; + _currentUserMatchesDisk = YES; + }); + return user; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/PFUserPrivate.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/PFUserPrivate.h new file mode 100644 index 0000000..4dfebd4 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/PFUserPrivate.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMacros.h" + +extern NSString *const PFUserCurrentUserFileName; +extern NSString *const PFUserCurrentUserPinName; +extern NSString *const PFUserCurrentUserKeychainItemName; + +@class BFTask PF_GENERIC(__covariant BFGenericType); +@class PFCommandResult; +@class PFUserController; + +@interface PFUser (Private) + +///-------------------------------------- +/// @name Current User +///-------------------------------------- ++ (BFTask *)_getCurrentUserSessionTokenAsync; ++ (NSString *)currentSessionToken; + +- (void)synchronizeAllAuthData; + +- (BFTask *)_handleServiceLoginCommandResult:(PFCommandResult *)result; + +- (void)synchronizeAuthDataWithAuthType:(NSString *)authType; + ++ (PFUser *)logInLazyUserWithAuthType:(NSString *)authType authData:(NSDictionary *)authData; +- (BFTask *)resolveLazinessAsync:(BFTask *)toAwait; +- (void)stripAnonymity; +- (void)restoreAnonymity:(id)data; + +///-------------------------------------- +/// @name Revocable Session +///-------------------------------------- ++ (BOOL)_isRevocableSessionEnabled; ++ (void)_setRevocableSessionEnabled:(BOOL)enabled; + ++ (PFUserController *)userController; + +@end + +// Private Properties +@interface PFUser () { + BOOL isCurrentUser; + NSMutableDictionary *authData; + NSMutableSet *linkedServiceNames; + BOOL isLazy; +} + +// This earmarks the user as being an "identity" user. This will make saves write through +// to the currentUser singleton and disk object +@property (nonatomic, assign) BOOL isCurrentUser; + +@property (nonatomic, strong, readonly) NSMutableDictionary *authData; +@property (nonatomic, strong, readonly) NSMutableSet *linkedServiceNames; +@property (nonatomic, assign) BOOL isLazy; + +- (BOOL)_isAuthenticatedWithCurrentUser:(PFUser *)currentUser; + +- (BFTask *)_logOutAsync; + +///-------------------------------------- +/// @name Third-party Authentication (Private) +///-------------------------------------- + ++ (void)_unregisterAuthenticationDelegateForAuthType:(NSString *)authType; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.h new file mode 100644 index 0000000..43e8f2d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.h @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserState.h" + +@interface PFMutableUserState : PFUserState + +@property (nonatomic, copy, readwrite) NSString *sessionToken; +@property (nonatomic, copy, readwrite) NSDictionary *authData; + +@property (nonatomic, assign, readwrite) BOOL isNew; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.m new file mode 100644 index 0000000..255265b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFMutableUserState.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFMutableUserState.h" + +#import "PFUserState_Private.h" + +@implementation PFMutableUserState + +@dynamic sessionToken; +@dynamic authData; +@dynamic isNew; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.h new file mode 100644 index 0000000..72fa098 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObjectState.h" + +@interface PFUserState : PFObjectState + +@property (nonatomic, copy, readonly) NSString *sessionToken; +@property (nonatomic, copy, readonly) NSDictionary *authData; + +@property (nonatomic, assign, readonly) BOOL isNew; + +///-------------------------------------- +/// @name Init +///-------------------------------------- + +- (instancetype)initWithState:(PFUserState *)state; ++ (instancetype)stateWithState:(PFUserState *)state; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.m b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.m new file mode 100644 index 0000000..2c50485 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState.m @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserState.h" +#import "PFUserState_Private.h" + +#import "PFMutableUserState.h" +#import "PFObjectState_Private.h" +#import "PFUserConstants.h" + +@implementation PFUserState + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithState:(PFUserState *)state { + self = [super initWithState:state]; + if (!self) return nil; + + _sessionToken = [state.sessionToken copy]; + _authData = [state.authData copy]; + _isNew = state.isNew; + + return self; +} + ++ (instancetype)stateWithState:(PFUserState *)state { + return [super stateWithState:state]; +} + +///-------------------------------------- +#pragma mark - Serialization +///-------------------------------------- + +- (NSDictionary *)dictionaryRepresentationWithObjectEncoder:(PFEncoder *)objectEncoder { + NSMutableDictionary *dictionary = [[super dictionaryRepresentationWithObjectEncoder:objectEncoder] mutableCopy]; + [dictionary removeObjectForKey:PFUserPasswordRESTKey]; + return dictionary; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (id)copyWithZone:(NSZone *)zone { + return [[PFUserState allocWithZone:zone] initWithState:self]; +} + +///-------------------------------------- +#pragma mark - NSMutableCopying +///-------------------------------------- + +- (id)mutableCopyWithZone:(NSZone *)zone { + return [[PFMutableUserState allocWithZone:zone] initWithState:self]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState_Private.h b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState_Private.h new file mode 100644 index 0000000..c305f76 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Internal/User/State/PFUserState_Private.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUserState.h" + +@interface PFUserState () { +@protected + NSString *_sessionToken; + NSDictionary *_authData; + + BOOL _isNew; +} + +@property (nonatomic, copy, readwrite) NSString *sessionToken; +@property (nonatomic, copy, readwrite) NSDictionary *authData; + +@property (nonatomic, assign, readwrite) BOOL isNew; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFACL.h b/Unit-2-Journal/Pods/Parse/Parse/PFACL.h new file mode 100644 index 0000000..a952585 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFACL.h @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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`. + */ ++ (instancetype)ACL; + +/*! + @abstract Creates an ACL where only the provided user has access. + + @param user The user to assign access. + */ ++ (instancetype)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/Unit-2-Journal/Pods/Parse/Parse/PFACL.m b/Unit-2-Journal/Pods/Parse/Parse/PFACL.m new file mode 100644 index 0000000..59190f9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFACL.m @@ -0,0 +1,363 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFACL.h" +#import "PFACLPrivate.h" + +#import "BFTask+Private.h" +#import "PFACLState.h" +#import "PFAssert.h" +#import "PFDefaultACLController.h" +#import "PFMacros.h" +#import "PFMutableACLState.h" +#import "PFObjectPrivate.h" +#import "PFObjectUtilities.h" +#import "PFRole.h" +#import "PFUser.h" +#import "PFUserPrivate.h" + +static NSString *const PFACLPublicKey_ = @"*"; +static NSString *const PFACLUnresolvedKey_ = @"*unresolved"; +static NSString *const PFACLCodingDataKey_ = @"ACL"; + +@interface PFACL () + +@property (atomic, strong, readwrite) PFACLState *state; + +@end + +@implementation PFACL { + PFUser *unresolvedUser; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _state = [[PFACLState alloc] init]; + + return self; +} + +///-------------------------------------- +#pragma mark - Default ACL +///-------------------------------------- + ++ (instancetype)ACL { + return [[self alloc] init]; +} + ++ (instancetype)ACLWithUser:(PFUser *)user { + PFACL *acl = [self ACL]; + [acl setReadAccess:YES forUser:user]; + [acl setWriteAccess:YES forUser:user]; + return acl; +} + ++ (instancetype)ACLWithDictionary:(NSDictionary *)dictionary { + return [[self alloc] initWithDictionary:dictionary]; +} + ++ (PFACL *)defaultACL { + return [[[PFDefaultACLController defaultController] getDefaultACLAsync] waitForResult:NULL + withMainThreadWarning:NO]; +} + ++ (void)setDefaultACL:(PFACL *)acl withAccessForCurrentUser:(BOOL)currentUserAccess { + [[PFDefaultACLController defaultController] setDefaultACLAsync:acl withCurrentUserAccess:currentUserAccess]; +} + +- (void)setShared:(BOOL)newShared { + self.state = [self.state copyByMutatingWithBlock:^(PFMutableACLState *newState) { + newState.shared = newShared; + }]; +} + +- (BOOL)isShared { + return self.state.shared; +} + +- (instancetype)createUnsharedCopy { + PFACL *newACL = [[self class] ACLWithDictionary:self.state.permissions]; + if (unresolvedUser) { + [newACL setReadAccess:[self getReadAccessForUser:unresolvedUser] forUser:unresolvedUser]; + [newACL setWriteAccess:[self getWriteAccessForUser:unresolvedUser] forUser:unresolvedUser]; + } + return newACL; +} + +- (void)resolveUser:(PFUser *)user { + if (user != unresolvedUser) { + return; + } + NSMutableDictionary *unresolvedPermissions = self.state.permissions[PFACLUnresolvedKey_]; + if (unresolvedPermissions) { + self.state = [self.state copyByMutatingWithBlock:^(PFMutableACLState *newState) { + newState.permissions[user.objectId] = unresolvedPermissions; + [newState.permissions removeObjectForKey:PFACLUnresolvedKey_]; + }]; + } + unresolvedUser = nil; +} + +- (BOOL)hasUnresolvedUser { + return unresolvedUser != nil; +} + +- (void)setAccess:(NSString *)accessType to:(BOOL)allowed forUserId:(NSString *)userId { + NSDictionary *permissions = self.state.permissions[userId]; + + // No change needed. + if ([permissions[accessType] boolValue] == allowed) { + return; + } + + NSMutableDictionary *newPermissions = [NSMutableDictionary dictionaryWithDictionary:permissions]; + if (allowed) { + newPermissions[accessType] = @YES; + } else { + [newPermissions removeObjectForKey:accessType]; + } + + self.state = [self.state copyByMutatingWithBlock:^(PFMutableACLState *newState) { + if (newPermissions.count) { + newState.permissions[userId] = [newPermissions copy]; + } else { + [newState.permissions removeObjectForKey:userId]; + } + }]; +} + +- (BOOL)getAccess:(NSString *)accessType forUserId:(NSString *)userId { + return [self.state.permissions[userId][accessType] boolValue]; +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [self init]; + if (!self) return nil; + + // We iterate over the input ACL rather than just copying to + // permissionsById so that we can ensure it is the right format. + [dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *userId, NSDictionary *permissions, BOOL *stop) { + [permissions enumerateKeysAndObjectsUsingBlock:^(NSString *accessType, id obj, BOOL *stop) { + [self setAccess:accessType to:[obj boolValue] forUserId:userId]; + }]; + }]; + + return self; +} + +- (void)setReadAccess:(BOOL)allowed forUserId:(NSString *)userId { + PFParameterAssert(userId, @"Can't setReadAccess for nil userId."); + [self setAccess:@"read" to:allowed forUserId:userId]; +} + +- (BOOL)getReadAccessForUserId:(NSString *)userId { + PFParameterAssert(userId, @"Can't getReadAccessForUserId for nil userId."); + return [self getAccess:@"read" forUserId:userId]; +} + +- (void)setWriteAccess:(BOOL)allowed forUserId:(NSString *)userId { + PFParameterAssert(userId, @"Can't setWriteAccess for nil userId."); + [self setAccess:@"write" to:allowed forUserId:userId]; +} + +- (BOOL)getWriteAccessForUserId:(NSString *)userId { + PFParameterAssert(userId, @"Can't getWriteAccessForUserId for nil userId."); + return [self getAccess:@"write" forUserId:userId]; +} + +- (void)setPublicReadAccess:(BOOL)allowed { + [self setReadAccess:allowed forUserId:PFACLPublicKey_]; +} + +- (BOOL)getPublicReadAccess { + return [self getReadAccessForUserId:PFACLPublicKey_]; +} + +- (void)setPublicWriteAccess:(BOOL)allowed { + [self setWriteAccess:allowed forUserId:PFACLPublicKey_]; +} + +- (BOOL)getPublicWriteAccess { + return [self getWriteAccessForUserId:PFACLPublicKey_]; +} + +- (BOOL)getReadAccessForRoleWithName:(NSString *)name { + PFParameterAssert(name, @"Can't get read access for nil role name."); + return [self getReadAccessForUserId:[@"role:" stringByAppendingString:name]]; +} + +- (void)setReadAccess:(BOOL)allowed forRoleWithName:(NSString *)name { + PFParameterAssert(name, @"Can't set read access for nil role name."); + [self setReadAccess:allowed forUserId:[@"role:" stringByAppendingString:name]]; +} + +- (BOOL)getWriteAccessForRoleWithName:(NSString *)name { + PFParameterAssert(name, @"Can't get write access for nil role name."); + return [self getWriteAccessForUserId:[@"role:" stringByAppendingString:name]]; +} + +- (void)setWriteAccess:(BOOL)allowed forRoleWithName:(NSString *)name { + PFParameterAssert(name, @"Can't set write access for nil role name."); + [self setWriteAccess:allowed forUserId:[@"role:" stringByAppendingString:name]]; +} + +- (void)validateRoleState:(PFRole *)role { + // Validates that a role has already been saved to the server, and thus can be used in an ACL. + PFParameterAssert(role.objectId, @"Roles must be saved to the server before they can be used in an ACL."); +} + +- (BOOL)getReadAccessForRole:(PFRole *)role { + [self validateRoleState:role]; + return [self getReadAccessForRoleWithName:role.name]; +} + +- (void)setReadAccess:(BOOL)allowed forRole:(PFRole *)role { + [self validateRoleState:role]; + [self setReadAccess:allowed forRoleWithName:role.name]; +} + +- (BOOL)getWriteAccessForRole:(PFRole *)role { + [self validateRoleState:role]; + return [self getWriteAccessForRoleWithName:role.name]; +} + +- (void)setWriteAccess:(BOOL)allowed forRole:(PFRole *)role { + [self validateRoleState:role]; + [self setWriteAccess:allowed forRoleWithName:role.name]; +} + +- (void)prepareUnresolvedUser:(PFUser *)user { + // TODO: (nlutsenko) Consider making @synchronized. + if (unresolvedUser != user) { + // If the unresolved user changed, register the save listener on the new user. This listener + // will call resolveUser with the user. + self.state = [self.state copyByMutatingWithBlock:^(PFMutableACLState *newState) { + [newState.permissions removeObjectForKey:PFACLUnresolvedKey_]; + }]; + + unresolvedUser = user; + + // Note: callback is a reference back to the same block so that it can unregister itself. + @weakify(self); + __weak __block void (^weakCallback)(id result, NSError *error) = nil; + __block void (^callback)(id result, NSError *error) = [^(id result, NSError *error) { + @strongify(self); + [self resolveUser:result]; + [result unregisterSaveListener:weakCallback]; + } copy]; + weakCallback = callback; + [user registerSaveListener:callback]; + } +} + +- (void)setUnresolvedReadAccess:(BOOL)allowed forUser:(PFUser *)user { + [self prepareUnresolvedUser:user]; + [self setReadAccess:allowed forUserId:PFACLUnresolvedKey_]; +} + +- (void)setReadAccess:(BOOL)allowed forUser:(PFUser *)user { + NSString *objectId = user.objectId; + if (!objectId) { + if ([user isLazy]) { + [self setUnresolvedReadAccess:allowed forUser:user]; + return; + } + PFParameterAssert(objectId, @"Can't setReadAcccess for unsaved user."); + } + [self setReadAccess:allowed forUserId:objectId]; +} + +- (BOOL)getReadAccessForUser:(PFUser *)user { + if (user == unresolvedUser) { + return [self getReadAccessForUserId:PFACLUnresolvedKey_]; + } + NSString *objectId = user.objectId; + PFParameterAssert(objectId, @"Can't getReadAccessForUser who isn't saved."); + return [self getReadAccessForUserId:objectId]; +} + +- (void)setUnresolvedWriteAccess:(BOOL)allowed forUser:(PFUser *)user { + [self prepareUnresolvedUser:user]; + [self setWriteAccess:allowed forUserId:PFACLUnresolvedKey_]; +} + +- (void)setWriteAccess:(BOOL)allowed forUser:(PFUser *)user { + NSString *objectId = user.objectId; + if (!objectId) { + if ([user isLazy]) { + [self setUnresolvedWriteAccess:allowed forUser:user]; + return; + } + PFParameterAssert(objectId, @"Can't setWriteAccess for unsaved user."); + } + [self setWriteAccess:allowed forUserId:objectId]; +} + +- (BOOL)getWriteAccessForUser:(PFUser *)user { + if (user == unresolvedUser) { + return [self getWriteAccessForUserId:PFACLUnresolvedKey_]; + } + NSString *objectId = user.objectId; + PFParameterAssert(objectId, @"Can't getWriteAccessForUser who isn't saved."); + return [self getWriteAccessForUserId:objectId]; +} + +- (NSDictionary *)encodeIntoDictionary { + return self.state.permissions; +} + +///-------------------------------------- +#pragma mark - NSObject +///-------------------------------------- + +- (BOOL)isEqual:(id)object { + if (object == self) { + return YES; + } + if (![object isKindOfClass:[PFACL class]]) { + return NO; + } + + PFACL *acl = (PFACL *)object; + return [self.state isEqual:acl.state] && [PFObjectUtilities isObject:self->unresolvedUser + equalToObject:acl->unresolvedUser]; +} + +- (NSUInteger)hash { + return [self.state hash] ^ [unresolvedUser hash]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[PFACL allocWithZone:zone] initWithDictionary:self.state.permissions]; +} + +///-------------------------------------- +#pragma mark - NSCoding +///-------------------------------------- + +- (instancetype)initWithCoder:(NSCoder *)coder { + NSDictionary *dictionary = [coder decodeObjectForKey:PFACLCodingDataKey_]; + return [self initWithDictionary:dictionary]; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:[self encodeIntoDictionary] forKey:PFACLCodingDataKey_]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.h b/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.h new file mode 100644 index 0000000..7655e8f --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.h @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + `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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)trackEvent:(NSString *)name + dimensions:(PF_NULLABLE NSDictionary PF_GENERIC(NSString *, NSString *)*)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 PF_GENERIC(NSString *, NSString *)*)dimensions + block:(PF_NULLABLE PFBooleanResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.m b/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.m new file mode 100644 index 0000000..514095a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFAnalytics.m @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAnalytics.h" +#import "PFAnalytics_Private.h" + +#import "BFTask+Private.h" +#import "PFAnalyticsController.h" +#import "PFAssert.h" +#import "PFEncoder.h" +#import "PFEventuallyQueue.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +@implementation PFAnalytics + +///-------------------------------------- +#pragma mark - App-Open / Push Analytics +///-------------------------------------- + ++ (BFTask PF_GENERIC(NSNumber *)*)trackAppOpenedWithLaunchOptions:(PF_NULLABLE NSDictionary *)launchOptions { +#if TARGET_OS_WATCH + NSDictionary *userInfo = nil; +#elif TARGET_OS_IOS + NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; +#elif PF_TARGET_OS_OSX + NSDictionary *userInfo = launchOptions[NSApplicationLaunchUserNotificationKey]; +#endif + + return [self trackAppOpenedWithRemoteNotificationPayload:userInfo]; +} + ++ (void)trackAppOpenedWithLaunchOptionsInBackground:(PF_NULLABLE NSDictionary *)launchOptions + block:(PF_NULLABLE PFBooleanResultBlock)block { + [[self trackAppOpenedWithLaunchOptions:launchOptions] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BFTask PF_GENERIC(NSNumber *)*)trackAppOpenedWithRemoteNotificationPayload:(PF_NULLABLE NSDictionary *)userInfo { + return [[[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + PFAnalyticsController *controller = [Parse _currentManager].analyticsController; + return [controller trackAppOpenedEventAsyncWithRemoteNotificationPayload:userInfo sessionToken:sessionToken]; + }] continueWithSuccessResult:@YES]; +} + ++ (void)trackAppOpenedWithRemoteNotificationPayloadInBackground:(PF_NULLABLE NSDictionary *)userInfo + block:(PF_NULLABLE PFBooleanResultBlock)block { + [[self trackAppOpenedWithRemoteNotificationPayload:userInfo] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Custom Analytics +///-------------------------------------- + ++ (BFTask PF_GENERIC(NSNumber *)*)trackEvent:(NSString *)name { + return [self trackEvent:name dimensions:nil]; +} + ++ (void)trackEventInBackground:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block { + [self trackEventInBackground:name dimensions:nil block:block]; +} + ++ (BFTask PF_GENERIC(NSNumber *)*)trackEvent:(NSString *)name + dimensions:(PF_NULLABLE NSDictionary PF_GENERIC(NSString *, NSString *) *)dimensions { + PFParameterAssert([[name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length], + @"A name for the custom event must be provided."); + [dimensions enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + PFParameterAssert([key isKindOfClass:[NSString class]] && [obj isKindOfClass:[NSString class]], + @"trackEvent dimensions expect keys and values of type NSString."); + }]; + + return [[[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + PFAnalyticsController *controller = [Parse _currentManager].analyticsController; + return [controller trackEventAsyncWithName:name dimensions:dimensions sessionToken:sessionToken]; + }] continueWithSuccessResult:@YES]; +} + ++ (void)trackEventInBackground:(NSString *)name + dimensions:(PF_NULLABLE NSDictionary PF_GENERIC(NSString *, NSString *) *)dimensions + block:(PF_NULLABLE PFBooleanResultBlock)block { + [[self trackEvent:name dimensions:dimensions] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.h b/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.h new file mode 100644 index 0000000..ff9ed8b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.h @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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 PF_GENERIC(PFUser *)*)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/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.m b/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.m new file mode 100644 index 0000000..073e525 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFAnonymousUtils.m @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFAnonymousUtils.h" +#import "PFAnonymousUtils_Private.h" + +#import "BFTask+Private.h" +#import "PFAnonymousAuthenticationProvider.h" +#import "PFInternalUtils.h" +#import "PFUserPrivate.h" + +@implementation PFAnonymousUtils + +///-------------------------------------- +#pragma mark - Log In +///-------------------------------------- + ++ (BFTask *)logInInBackground { + PFAnonymousAuthenticationProvider *provider = [self _authenticationProvider]; + return [PFUser logInWithAuthTypeInBackground:PFAnonymousUserAuthenticationType authData:provider.authData]; +} + ++ (void)logInWithBlock:(PFUserResultBlock)block { + [[self logInInBackground] thenCallBackOnMainThreadAsync:block]; +} + ++ (void)logInWithTarget:(id)target selector:(SEL)selector { + [self logInWithBlock:^(PFUser *user, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:user object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Link +///-------------------------------------- + ++ (BOOL)isLinkedWithUser:(PFUser *)user { + return [user isLinkedWithAuthType:PFAnonymousUserAuthenticationType]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +static PFAnonymousAuthenticationProvider *authenticationProvider_; + ++ (dispatch_queue_t)_providerAccessQueue { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.parse.anonymousUtils.provider.access", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + ++ (PFAnonymousAuthenticationProvider *)_authenticationProvider { + __block PFAnonymousAuthenticationProvider *provider = nil; + dispatch_sync([self _providerAccessQueue], ^{ + provider = authenticationProvider_; + if (!provider) { + provider = [[PFAnonymousAuthenticationProvider alloc] init]; + [PFUser registerAuthenticationDelegate:provider forAuthType:PFAnonymousUserAuthenticationType]; + authenticationProvider_ = provider; + } + }); + return provider; +} + ++ (void)_clearAuthenticationProvider { + [PFUser _unregisterAuthenticationDelegateForAuthType:PFAnonymousUserAuthenticationType]; + dispatch_sync([self _providerAccessQueue], ^{ + authenticationProvider_ = nil; + }); +} + +///-------------------------------------- +#pragma mark - Lazy Login +///-------------------------------------- + ++ (PFUser *)_lazyLogIn { + PFAnonymousAuthenticationProvider *provider = [self _authenticationProvider]; + return [PFUser logInLazyUserWithAuthType:PFAnonymousUserAuthenticationType authData:provider.authData]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFCloud.h b/Unit-2-Journal/Pods/Parse/Parse/PFCloud.h new file mode 100644 index 0000000..b807b75 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFCloud.h @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + 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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(id) *)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/Unit-2-Journal/Pods/Parse/Parse/PFCloud.m b/Unit-2-Journal/Pods/Parse/Parse/PFCloud.m new file mode 100644 index 0000000..bb019ae --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFCloud.m @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFCloud.h" + +#import "BFTask+Private.h" +#import "PFCloudCodeController.h" +#import "PFCommandResult.h" +#import "PFCoreManager.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +@implementation PFCloud + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + ++ (id)callFunction:(NSString *)function withParameters:(NSDictionary *)parameters { + return [self callFunction:function withParameters:parameters error:nil]; +} + ++ (id)callFunction:(NSString *)function withParameters:(NSDictionary *)parameters error:(NSError **)error { + return [[self callFunctionInBackground:function withParameters:parameters] waitForResult:error]; +} + ++ (BFTask *)callFunctionInBackground:(NSString *)functionName withParameters:(NSDictionary *)parameters { + return [[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + PFCloudCodeController *controller = [Parse _currentManager].coreManager.cloudCodeController; + return [controller callCloudCodeFunctionAsync:functionName + withParameters:parameters + sessionToken:sessionToken]; + }]; +} + ++ (void)callFunctionInBackground:(NSString *)function + withParameters:(NSDictionary *)parameters + target:(id)target + selector:(SEL)selector { + [self callFunctionInBackground:function withParameters:parameters block:^(id results, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:results object:error]; + }]; +} + ++ (void)callFunctionInBackground:(NSString *)function + withParameters:(NSDictionary *)parameters + block:(PFIdResultBlock)block { + [[self callFunctionInBackground:function withParameters:parameters] thenCallBackOnMainThreadAsync:block]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFConfig.h b/Unit-2-Journal/Pods/Parse/Parse/PFConfig.h new file mode 100644 index 0000000..7420692 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFConfig.h @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +@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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFConfig *)*)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/Unit-2-Journal/Pods/Parse/Parse/PFConfig.m b/Unit-2-Journal/Pods/Parse/Parse/PFConfig.m new file mode 100644 index 0000000..b4d1655 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFConfig.m @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFConfig.h" + +#import "BFTask+Private.h" +#import "PFConfigController.h" +#import "PFCoreManager.h" +#import "PFCurrentConfigController.h" +#import "PFCurrentUserController.h" +#import "PFInternalUtils.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +NSString *const PFConfigParametersRESTKey = @"params"; + +@interface PFConfig () + +@property (atomic, copy, readwrite) NSDictionary *parametersDictionary; + +@end + +@implementation PFConfig + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (PFConfigController *)_configController { + return [Parse _currentManager].coreManager.configController; +} + +#pragma mark Public + ++ (PFConfig *)currentConfig { + return [[[self _configController].currentConfigController getCurrentConfigAsync] waitForResult:nil + withMainThreadWarning:NO]; +} + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithFetchedConfig:(NSDictionary *)resultDictionary { + self = [self init]; + if (!self) return nil; + + _parametersDictionary = resultDictionary[PFConfigParametersRESTKey]; + + return self; +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + ++ (PFConfig *)getConfig { + return [self getConfig:nil]; +} + ++ (PFConfig *)getConfig:(NSError **)error { + return [[self getConfigInBackground] waitForResult:error]; +} + ++ (BFTask *)getConfigInBackground { + PFCurrentUserController *controller = [Parse _currentManager].coreManager.currentUserController; + return [[controller getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [[self _configController] fetchConfigAsyncWithSessionToken:sessionToken]; + }]; +} + ++ (void)getConfigInBackgroundWithBlock:(PFConfigResultBlock)block { + [[self getConfigInBackground] thenCallBackOnMainThreadAsync:block]; +} + +///-------------------------------------- +#pragma mark - Getting Values +///-------------------------------------- + +- (id)objectForKey:(NSString *)key { + return _parametersDictionary[key]; +} + +- (id)objectForKeyedSubscript:(NSString *)keyedSubscript { + return _parametersDictionary[keyedSubscript]; +} + +#pragma mark Equality Testing + +- (NSUInteger)hash { + return [_parametersDictionary hash]; +} + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[PFConfig class]]) { + PFConfig *other = object; + + // Compare pointers first, to account for nil dictionary + return self.parametersDictionary == other.parametersDictionary || + [self.parametersDictionary isEqual:other.parametersDictionary]; + } + + return NO; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFConstants.h b/Unit-2-Journal/Pods/Parse/Parse/PFConstants.h new file mode 100644 index 0000000..c46eab0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFConstants.h @@ -0,0 +1,509 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFObject; +@class PFUser; + +///-------------------------------------- +/// @name Version +///-------------------------------------- + +#define PARSE_VERSION @"1.9.0" + +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 +#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 (^PFFilePathResultBlock)(NSString *PF_NULLABLE_S filePath, 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 Network Notifications +///-------------------------------------- + +/*! + @abstract The name of the notification that is going to be sent before any URL request is sent. + */ +extern NSString *const PF_NONNULL_S PFNetworkWillSendURLRequestNotification; + +/*! + @abstract The name of the notification that is going to be sent after any URL response is received. + */ +extern NSString *const PF_NONNULL_S PFNetworkDidReceiveURLResponseNotification; + +/*! + @abstract The key of request(NSURLRequest) in the userInfo dictionary of a notification. + @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`. + */ +extern NSString *const PF_NONNULL_S PFNetworkNotificationURLRequestUserInfoKey; + +/*! + @abstract The key of response(NSHTTPURLResponse) in the userInfo dictionary of a notification. + @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`. + */ +extern NSString *const PF_NONNULL_S PFNetworkNotificationURLResponseUserInfoKey; + +/*! + @abstract The key of repsonse body (usually `NSString` with JSON) in the userInfo dictionary of a notification. + @note This key is populated in userInfo, only if `PFLogLevel` on `Parse` is set to `PFLogLevelDebug`. + */ +extern NSString *const PF_NONNULL_S PFNetworkNotificationURLResponseBodyUserInfoKey; + + +///-------------------------------------- +/// @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 + +///-------------------------------------- +/// @name Swift Macros +///-------------------------------------- + +#ifndef PF_SWIFT_UNAVAILABLE +# ifdef NS_SWIFT_UNAVAILABLE +# define PF_SWIFT_UNAVAILABLE NS_SWIFT_UNAVAILABLE("") +# else +# define PF_SWIFT_UNAVAILABLE +# endif +#endif + +///-------------------------------------- +/// @name Obj-C Generics Macros +///-------------------------------------- + +#if __has_feature(objc_generics) || __has_extension(objc_generics) +# define PF_GENERIC(...) <__VA_ARGS__> +#else +# define PF_GENERIC(...) +# define PFGenericObject PFObject * +#endif + +///-------------------------------------- +/// @name Platform Availability Defines +///-------------------------------------- + +#ifndef TARGET_OS_IOS +# define TARGET_OS_IOS TARGET_OS_IPHONE +#endif +#ifndef TARGET_OS_WATCH +# define TARGET_OS_WATCH 0 +#endif +#ifndef TARGET_OS_TV +# define TARGET_OS_TV 0 +#endif + +#ifndef PF_TARGET_OS_OSX +# define PF_TARGET_OS_OSX TARGET_OS_MAC && !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV +#endif + +///-------------------------------------- +/// @name Avaiability Macros +///-------------------------------------- + +#ifndef PF_WATCH_UNAVAILABLE +# ifdef __WATCHOS_UNAVAILABLE +# define PF_WATCH_UNAVAILABLE __WATCHOS_UNAVAILABLE +# else +# define PF_WATCH_UNAVAILABLE +# endif +#endif diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFConstants.m b/Unit-2-Journal/Pods/Parse/Parse/PFConstants.m new file mode 100644 index 0000000..174b5a7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFConstants.m @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFConstants.h" + +NSInteger const PARSE_API_VERSION = 2; + +#if PARSE_IOS_ONLY +NSString *const kPFDeviceType = @"ios"; +#else +NSString *const kPFDeviceType = @"osx"; +#endif + +NSString *const kPFParseServer = @"https://api.parse.com"; + +NSString *const PFParseErrorDomain = @"Parse"; + +///-------------------------------------- +#pragma mark - Network Notifications +///-------------------------------------- + +NSString *const PFNetworkWillSendURLRequestNotification = @"PFNetworkWillSendURLRequestNotification"; +NSString *const PFNetworkDidReceiveURLResponseNotification = @"PFNetworkDidReceiveURLResponseNotification"; +NSString *const PFNetworkNotificationURLRequestUserInfoKey = @"PFNetworkNotificationURLRequestUserInfoKey"; +NSString *const PFNetworkNotificationURLResponseUserInfoKey = @"PFNetworkNotificationURLResponseUserInfoKey"; +NSString *const PFNetworkNotificationURLResponseBodyUserInfoKey = @"PFNetworkNotificationURLResponseBodyUserInfoKey"; diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFFile.h b/Unit-2-Journal/Pods/Parse/Parse/PFFile.h new file mode 100644 index 0000000..c2313cc --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFFile.h @@ -0,0 +1,446 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + `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 +///-------------------------------------- + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/*! + @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`. + */ ++ (PF_NULLABLE 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. + */ ++ (PF_NULLABLE 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. + */ ++ (PF_NULLABLE instancetype)fileWithName:(PF_NULLABLE NSString *)name + contentsAtPath:(NSString *)path PF_SWIFT_UNAVAILABLE; + +/*! + @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. + */ ++ (PF_NULLABLE 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. + */ ++ (PF_NULLABLE instancetype)fileWithName:(PF_NULLABLE NSString *)name + data:(NSData *)data + contentType:(PF_NULLABLE NSString *)contentType PF_SWIFT_UNAVAILABLE; + +/*! + @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. + */ ++ (PF_NULLABLE 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; + +///-------------------------------------- +/// @name File Properties +///-------------------------------------- + +/*! + @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; + +/*! + @abstract Whether the file has been uploaded for the first time. + */ +@property (nonatomic, assign, readonly) BOOL isDirty; + +///-------------------------------------- +/// @name Storing Data with Parse +///-------------------------------------- + +/*! + @abstract Saves the file *synchronously*. + + @returns Returns whether the save succeeded. + */ +- (BOOL)save PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSData *)*)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 PF_GENERIC(NSData *)*)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 PF_GENERIC(NSInputStream *)*)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 PF_GENERIC(NSInputStream *)*)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 PF_GENERIC(NSInputStream *)*)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 PF_GENERIC(NSInputStream *)*)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; + +/*! + @abstract *Asynchronously* gets the file path for file from cache if available or fetches its contents from the network. + + @note The file path may change between versions of SDK. + @note If you overwrite the contents of the file at returned path it will persist those change + until the file cache is cleared. + + @returns The task, with the result set to `NSString` representation of a file path. + */ +- (BFTask PF_GENERIC(NSString *)*)getFilePathInBackground; + +/*! + @abstract *Asynchronously* gets the file path for file from cache if available or fetches its contents from the network. + + @note The file path may change between versions of SDK. + @note If you overwrite the contents of the file at returned path it will persist those change + until the file cache is cleared. + + @param progressBlock The block should have the following argument signature: `^(int percentDone)`. + + @returns The task, with the result set to `NSString` representation of a file path. + */ +- (BFTask PF_GENERIC(NSString *)*)getFilePathInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract *Asynchronously* gets the file path for file from cache if available or fetches its contents from the network. + + @note The file path may change between versions of SDK. + @note If you overwrite the contents of the file at returned path it will persist those change + until the file cache is cleared. + + @param block The block should have the following argument signature: `^(NSString *filePath, NSError *error)`. + */ +- (void)getFilePathInBackgroundWithBlock:(PF_NULLABLE PFFilePathResultBlock)block; + +/*! + @abstract *Asynchronously* gets the file path for file from cache if available or fetches its contents from the network. + + @note The file path may change between versions of SDK. + @note If you overwrite the contents of the file at returned path it will persist those change + until the file cache is cleared. + + @param block The block should have the following argument signature: `^(NSString *filePath, NSError *error)`. + @param progressBlock The block should have the following argument signature: `^(int percentDone)`. + */ +- (void)getFilePathInBackgroundWithBlock:(PF_NULLABLE PFFilePathResultBlock)block + progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +///-------------------------------------- +/// @name Interrupting a Transfer +///-------------------------------------- + +/*! + @abstract Cancels the current request (upload or download of file). + */ +- (void)cancel; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFFile.m b/Unit-2-Journal/Pods/Parse/Parse/PFFile.m new file mode 100644 index 0000000..26fcda3 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFFile.m @@ -0,0 +1,546 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFFile.h" +#import "PFFile_Private.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFAsyncTaskQueue.h" +#import "PFCommandResult.h" +#import "PFCoreManager.h" +#import "PFErrorUtilities.h" +#import "PFFileController.h" +#import "PFFileManager.h" +#import "PFFileStagingController.h" +#import "PFInternalUtils.h" +#import "PFMacros.h" +#import "PFMutableFileState.h" +#import "PFRESTFileCommand.h" +#import "PFThreadsafety.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +static const unsigned long long PFFileMaxFileSize = 10 * 1024 * 1024; // 10 MB + +@interface PFFile () { + dispatch_queue_t _synchronizationQueue; +} + +@property (nonatomic, strong, readwrite) PFFileState *state; +@property (nonatomic, copy, readonly) NSString *stagedFilePath; +@property (nonatomic, assign, readonly, getter=isDirty) BOOL dirty; + +// +// Private +@property (nonatomic, strong) PFAsyncTaskQueue *taskQueue; +@property (nonatomic, strong) BFCancellationTokenSource *cancellationTokenSource; + +@end + +@implementation PFFile + +@synthesize stagedFilePath = _stagedFilePath; + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + +#pragma mark Init + ++ (instancetype)fileWithData:(NSData *)data { + return [self fileWithName:nil data:data contentType:nil]; +} + ++ (instancetype)fileWithName:(NSString *)name data:(NSData *)data { + return [self fileWithName:name data:data contentType:nil]; +} + ++ (instancetype)fileWithName:(NSString *)name contentsAtPath:(NSString *)path { + NSError *error = nil; + PFFile *file = [self fileWithName:name contentsAtPath:path error:&error]; + PFParameterAssert(!error, @"Could not access file at %@: %@", path, error); + return file; +} + ++ (instancetype)fileWithName:(NSString *)name contentsAtPath:(NSString *)path error:(NSError **)error { + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL directory = NO; + + if (![fileManager fileExistsAtPath:path isDirectory:&directory] || directory) { + NSString *message = [NSString stringWithFormat:@"Failed to create PFFile at path '%@': " + "file does not exist.", path]; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSFileNoSuchFileError + userInfo:@{ NSLocalizedDescriptionKey: message }]; + } + return nil; + } + + NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:nil]; + unsigned long long length = [attributes[NSFileSize] unsignedLongValue]; + if (length > PFFileMaxFileSize) { + NSString *message = [NSString stringWithFormat:@"Failed to create PFFile at path '%@': " + "file is larger than %lluMB.", path, (PFFileMaxFileSize >> 20)]; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSFileReadTooLargeError + userInfo:@{ NSLocalizedDescriptionKey: message }]; + } + return nil; + } + + PFFile *file = [self fileWithName:name url:nil]; + if (![file _stageWithPath:path error:error]) { + return nil; + } + return file; +} + ++ (instancetype)fileWithName:(NSString *)name + data:(NSData *)data + contentType:(NSString *)contentType { + NSError *error = nil; + PFFile *file = [self fileWithName:name data:data contentType:contentType error:&error]; + PFConsistencyAssert(!error, @"Could not save file data for %@ : %@", name, error); + return file; +} + ++ (instancetype)fileWithName:(NSString *)name + data:(NSData *)data + contentType:(NSString *)contentType + error:(NSError **)error { + if (!data) { + NSString *message = @"Cannot create a PFFile with nil data."; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSFileNoSuchFileError + userInfo:@{ NSLocalizedDescriptionKey: message }]; + } + return nil; + } + + if ([data length] > PFFileMaxFileSize) { + NSString *message = [NSString stringWithFormat:@"Failed to create PFFile with data: " + "data is larger than %lluMB.", (PFFileMaxFileSize >> 20)]; + if (error) { + *error = [NSError errorWithDomain:NSCocoaErrorDomain + code:NSFileReadTooLargeError + userInfo:@{ NSLocalizedDescriptionKey: message }]; + } + return nil; + } + + PFFile *file = [[self alloc] initWithName:name urlString:nil mimeType:contentType]; + if (![file _stageWithData:data error:error]) { + return nil; + } + return file; +} + ++ (instancetype)fileWithData:(NSData *)data contentType:(NSString *)contentType { + return [self fileWithName:nil data:data contentType:contentType]; +} + +#pragma mark Uploading + +- (BOOL)save { + return [self save:nil]; +} + +- (BOOL)save:(NSError **)error { + return [[[self saveInBackground] waitForResult:error] boolValue]; +} + +- (BFTask *)saveInBackground { + return [self _uploadAsyncWithProgressBlock:nil]; +} + +- (BFTask *)saveInBackgroundWithProgressBlock:(PFProgressBlock)progressBlock { + return [self _uploadAsyncWithProgressBlock:progressBlock]; +} + +- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self saveInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block + progressBlock:(PFProgressBlock)progressBlock { + [[self _uploadAsyncWithProgressBlock:progressBlock] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (void)saveInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +#pragma mark Downloading + +- (NSData *)getData { + return [self getData:nil]; +} + +- (NSInputStream *)getDataStream { + return [self getDataStream:nil]; +} + +- (NSData *)getData:(NSError **)error { + return [[self getDataInBackground] waitForResult:error]; +} + +- (NSInputStream *)getDataStream:(NSError **)error { + return [[self getDataStreamInBackground] waitForResult:error]; +} + +- (BFTask *)getDataInBackground { + return [self _getDataAsyncWithProgressBlock:nil]; +} + +- (BFTask *)getDataInBackgroundWithProgressBlock:(PFProgressBlock)progressBlock { + return [self _getDataAsyncWithProgressBlock:progressBlock]; +} + +- (BFTask *)getDataStreamInBackground { + return [self _getDataStreamAsyncWithProgressBlock:nil]; +} + +- (BFTask *)getDataStreamInBackgroundWithProgressBlock:(PFProgressBlock)progressBlock { + return [self _getDataStreamAsyncWithProgressBlock:progressBlock]; +} + +- (BFTask *)getDataDownloadStreamInBackground { + return [self getDataDownloadStreamInBackgroundWithProgressBlock:nil]; +} + +- (BFTask *)getDataDownloadStreamInBackgroundWithProgressBlock:(PFProgressBlock)progressBlock { + return [self _downloadStreamAsyncWithProgressBlock:progressBlock]; +} + +- (void)getDataInBackgroundWithBlock:(PFDataResultBlock)block { + [self getDataInBackgroundWithBlock:block progressBlock:nil]; +} + +- (void)getDataStreamInBackgroundWithBlock:(PFDataStreamResultBlock)block { + [self getDataStreamInBackgroundWithBlock:block progressBlock:nil]; +} + +- (void)getDataInBackgroundWithBlock:(PFDataResultBlock)resultBlock + progressBlock:(PFProgressBlock)progressBlock { + [[self _getDataAsyncWithProgressBlock:progressBlock] thenCallBackOnMainThreadAsync:resultBlock]; +} + +- (void)getDataStreamInBackgroundWithBlock:(PFDataStreamResultBlock)resultBlock + progressBlock:(PFProgressBlock)progressBlock { + [[self _getDataStreamAsyncWithProgressBlock:progressBlock] thenCallBackOnMainThreadAsync:resultBlock]; +} + +- (void)getDataInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self getDataInBackgroundWithBlock:^(NSData *data, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:data object:error]; + }]; +} + +- (BFTask PF_GENERIC(NSString *) *)getFilePathInBackground { + return [self getFilePathInBackgroundWithProgressBlock:nil]; +} + +- (BFTask PF_GENERIC(NSString *)*)getFilePathInBackgroundWithProgressBlock:(PFProgressBlock)progressBlock { + return [[self _downloadAsyncWithProgressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask *task) { + if (self.dirty) { + return self.stagedFilePath; + } + return [[[self class] fileController] cachedFilePathForFileState:self.state]; + }]; +} + +- (void)getFilePathInBackgroundWithBlock:(PF_NULLABLE PFFilePathResultBlock)block { + [[self getFilePathInBackground] thenCallBackOnMainThreadAsync:block]; +} + +- (void)getFilePathInBackgroundWithBlock:(PF_NULLABLE PFFilePathResultBlock)block + progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock { + [[self getFilePathInBackgroundWithProgressBlock:progressBlock] thenCallBackOnMainThreadAsync:block]; +} + +#pragma mark Interrupting + +- (void)cancel { + [self _performDataAccessBlock:^{ + [self.cancellationTokenSource cancel]; + self.cancellationTokenSource = nil; + }]; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +#pragma mark Init + +- (instancetype)initWithName:(NSString *)name urlString:(NSString *)url mimeType:(NSString *)mimeType { + self = [super init]; + if (!self) return nil; + + _taskQueue = [[PFAsyncTaskQueue alloc] init]; + _synchronizationQueue = PFThreadsafetyCreateQueueForObject(self); + + _state = [[PFFileState alloc] initWithName:name urlString:url mimeType:mimeType]; + + return self; +} + ++ (instancetype)fileWithName:(NSString *)name url:(NSString *)url { + return [[self alloc] initWithName:name urlString:url mimeType:nil]; +} + +#pragma mark Upload + +- (BFTask *)_uploadAsyncWithProgressBlock:(PFProgressBlock)progressBlock { + @weakify(self); + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id { + @strongify(self); + + __block BFCancellationToken *cancellationToken = nil; + [self _performDataAccessBlock:^{ + if (!self.cancellationTokenSource || self.cancellationTokenSource.cancellationRequested) { + self.cancellationTokenSource = [BFCancellationTokenSource cancellationTokenSource]; + } + cancellationToken = self.cancellationTokenSource.token; + }]; + + return [[[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [self.taskQueue enqueue:^id(BFTask *task) { + if (!self.dirty) { + [self _performProgressBlockAsync:progressBlock withProgress:100]; + return [BFTask taskWithResult:nil]; + } + + return [self _uploadFileAsyncWithSessionToken:sessionToken + cancellationToken:cancellationToken + progressBlock:progressBlock]; + }]; + }] continueWithSuccessResult:@YES]; + }]; +} + +- (BFTask *)_uploadFileAsyncWithSessionToken:(NSString *)sessionToken + cancellationToken:(BFCancellationToken *)cancellationToken + progressBlock:(PFProgressBlock)progressBlock { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + PFFileController *controller = [[self class] fileController]; + NSString *sourceFilePath = self.stagedFilePath; + @weakify(self); + return [[[controller uploadFileAsyncWithState:[self _fileState] + sourceFilePath:sourceFilePath + sessionToken:sessionToken + cancellationToken:cancellationToken + progressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask *task) { + @strongify(self); + [self _performDataAccessBlock:^{ + self.state = [task.result copy]; + }]; + return nil; + } cancellationToken:cancellationToken] continueWithBlock:^id(BFTask *task) { + @strongify(self); + [self _performDataAccessBlock:^{ + self.cancellationTokenSource = nil; + }]; + return task; + }]; +} + +#pragma mark Download + +- (BFTask *)_getDataAsyncWithProgressBlock:(PFProgressBlock)progressBlock { + return [[self _downloadAsyncWithProgressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask *task) { + return [self _cachedData]; + }]; +} + +- (BFTask *)_getDataStreamAsyncWithProgressBlock:(PFProgressBlock)progressBlock { + return [[self _downloadAsyncWithProgressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask *task) { + return [self _cachedDataStream]; + }]; +} + +- (BFTask *)_downloadAsyncWithProgressBlock:(PFProgressBlock)progressBlock { + __block BFCancellationToken *cancellationToken = nil; + [self _performDataAccessBlock:^{ + if (!self.cancellationTokenSource || self.cancellationTokenSource.cancellationRequested) { + self.cancellationTokenSource = [BFCancellationTokenSource cancellationTokenSource]; + } + cancellationToken = self.cancellationTokenSource.token; + }]; + + @weakify(self); + return [self.taskQueue enqueue:^id(BFTask *task) { + @strongify(self); + if (self.isDataAvailable) { + [self _performProgressBlockAsync:progressBlock withProgress:100]; + return [BFTask taskWithResult:nil]; + } + + PFFileController *controller = [[self class] fileController]; + return [[controller downloadFileAsyncWithState:[self _fileState] + cancellationToken:cancellationToken + progressBlock:progressBlock] continueWithBlock:^id(BFTask *task) { + [self _performDataAccessBlock:^{ + self.cancellationTokenSource = nil; + }]; + return task; + }]; + }]; +} + +- (BFTask *)_downloadStreamAsyncWithProgressBlock:(PFProgressBlock)progressBlock { + __block BFCancellationToken *cancellationToken = nil; + [self _performDataAccessBlock:^{ + if (!self.cancellationTokenSource || self.cancellationTokenSource.cancellationRequested) { + self.cancellationTokenSource = [BFCancellationTokenSource cancellationTokenSource]; + } + cancellationToken = self.cancellationTokenSource.token; + }]; + + @weakify(self); + return [self.taskQueue enqueue:^id(BFTask *task) { + @strongify(self); + if (self.isDataAvailable) { + [self _performProgressBlockAsync:progressBlock withProgress:100]; + return [self _cachedDataStream]; + } + + PFFileController *controller = [[self class] fileController]; + return [[controller downloadFileStreamAsyncWithState:[self _fileState] + cancellationToken:cancellationToken + progressBlock:progressBlock] continueWithBlock:^id(BFTask *task) { + [self _performDataAccessBlock:^{ + self.cancellationTokenSource = nil; + }]; + return task; + }]; + }]; +} + +#pragma mark Caching + +- (NSString *)_cachedFilePath { + return [[[self class] fileController] cachedFilePathForFileState:self.state]; +} + +- (NSData *)_cachedData { + NSString *filePath = (self.dirty ? self.stagedFilePath : [self _cachedFilePath]); + return [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:NULL]; +} + +- (NSInputStream *)_cachedDataStream { + NSString *filePath = (self.dirty ? self.stagedFilePath : [[[self class] fileController] cachedFilePathForFileState:self.state]); + return [NSInputStream inputStreamWithFileAtPath:filePath]; +} + +///-------------------------------------- +#pragma mark - Staging +///-------------------------------------- + +- (BOOL)_stageWithData:(NSData *)data error:(NSError **)error { + __block BOOL result = NO; + [self _performDataAccessBlock:^{ + _stagedFilePath = [[[[self class] fileController].fileStagingController stageFileAsyncWithData:data + name:self.state.name + uniqueId:(uintptr_t)self] + waitForResult:error withMainThreadWarning:NO]; + + result = (_stagedFilePath != nil); + }]; + return result; +} + +- (BOOL)_stageWithPath:(NSString *)path error:(NSError **)error { + __block BOOL result = NO; + [self _performDataAccessBlock:^{ + _stagedFilePath = [[[[self class] fileController].fileStagingController stageFileAsyncAtPath:path + name:self.state.name + uniqueId:(uintptr_t)self] + waitForResult:error withMainThreadWarning:NO]; + + result = (_stagedFilePath != nil); + }]; + return result; +} + +#pragma mark Data Access + +- (NSString *)name { + __block NSString *name = nil; + [self _performDataAccessBlock:^{ + name = self.state.name; + }]; + return name; +} + +- (NSString *)url { + __block NSString *url = nil; + [self _performDataAccessBlock:^{ + url = self.state.secureURLString; + }]; + return url; +} + +- (BOOL)isDirty { + return !self.url; +} + +- (BOOL)isDataAvailable { + __block BOOL available = NO; + [self _performDataAccessBlock:^{ + available = self.dirty || [[NSFileManager defaultManager] fileExistsAtPath:[self _cachedFilePath]]; + }]; + return available; +} + +- (void)_performDataAccessBlock:(dispatch_block_t)block { + PFThreadsafetySafeDispatchSync(_synchronizationQueue, block); +} + +- (PFFileState *)_fileState { + __block PFFileState *state = nil; + [self _performDataAccessBlock:^{ + state = self.state; + }]; + return state; +} + +#pragma mark Progress + +- (void)_performProgressBlockAsync:(PFProgressBlock)block withProgress:(int)progress { + if (!block) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + block(progress); + }); +} + +///-------------------------------------- +#pragma mark - FileController +///-------------------------------------- + ++ (PFFileController *)fileController { + return [Parse _currentManager].coreManager.fileController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.h b/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.h new file mode 100644 index 0000000..37d3bb0 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.h @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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`. + */ ++ (instancetype)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. + */ ++ (instancetype)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. + */ ++ (instancetype)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/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.m b/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.m new file mode 100644 index 0000000..5912bff --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFGeoPoint.m @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFGeoPoint.h" + +#import + +#import "PFAssert.h" +#import "PFCoreManager.h" +#import "PFHash.h" +#import "PFLocationManager.h" +#import "Parse_Private.h" + +const double EARTH_RADIUS_MILES = 3958.8; +const double EARTH_RADIUS_KILOMETERS = 6371.0; + +@implementation PFGeoPoint + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)geoPoint { + return [[self alloc] init]; +} + ++ (instancetype)geoPointWithLocation:(CLLocation *)location { + return [self geoPointWithLatitude:location.coordinate.latitude + longitude:location.coordinate.longitude]; +} + ++ (instancetype)geoPointWithLatitude:(double)latitude longitude:(double)longitude { + PFGeoPoint *gpt = [self geoPoint]; + gpt.latitude = latitude; + gpt.longitude = longitude; + return gpt; +} + ++ (void)geoPointForCurrentLocationInBackground:(PFGeoPointResultBlock)resultBlock { + if (!resultBlock) { + return; + } + + void(^locationHandler)(CLLocation *, NSError *) = ^(CLLocation *location, NSError *error) { + PFGeoPoint *newGeoPoint = [PFGeoPoint geoPointWithLocation:location]; + resultBlock(newGeoPoint, error); + }; + [[Parse _currentManager].coreManager.locationManager addBlockForCurrentLocation:locationHandler]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setLatitude:(double)latitude { + PFParameterAssert(latitude >= -90.0 && latitude <= 90.0, + @"`latitude` is out of range [-90.0, 90.0]: %f", latitude); + _latitude = latitude; +} + +- (void)setLongitude:(double)longitude { + PFParameterAssert(longitude >= -180.0 && longitude <= 180.0, + @"`longitude` is out of range [-180.0, 180.0]: %f", longitude); + _longitude = longitude; +} + +- (double)distanceInRadiansTo:(PFGeoPoint *)point { + double d2r = M_PI / 180.0; // radian conversion factor + double lat1rad = self.latitude * d2r; + double long1rad = self.longitude * d2r; + double lat2rad = [point latitude] * d2r; + double long2rad = [point longitude] * d2r; + double deltaLat = lat1rad - lat2rad; + double deltaLong = long1rad - long2rad; + double sinDeltaLatDiv2 = sin(deltaLat / 2.); + double sinDeltaLongDiv2 = sin(deltaLong / 2.); + // Square of half the straight line chord distance between both points. [0.0, 1.0] + double a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + + cos(lat1rad) * cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; + a = fmin(1.0, a); + return 2. * asin(sqrt(a)); +} + +- (double)distanceInMilesTo:(PFGeoPoint *)point { + return [self distanceInRadiansTo:point] * EARTH_RADIUS_MILES; +} + +- (double)distanceInKilometersTo:(PFGeoPoint *)point { + return [self distanceInRadiansTo:point] * EARTH_RADIUS_KILOMETERS; +} + +///-------------------------------------- +#pragma mark - Encoding +///-------------------------------------- + +static NSString *const PFGeoPointCodingTypeKey = @"__type"; +static NSString *const PFGeoPointCodingLatitudeKey = @"latitude"; +static NSString *const PFGeoPointCodingLongitudeKey = @"longitude"; + +- (NSDictionary *)encodeIntoDictionary { + return @{ + PFGeoPointCodingTypeKey : @"GeoPoint", + PFGeoPointCodingLatitudeKey : @(self.latitude), + PFGeoPointCodingLongitudeKey : @(self.longitude) + }; +} + ++ (instancetype)geoPointWithDictionary:(NSDictionary *)dictionary { + return [[self alloc] initWithEncodedDictionary:dictionary]; +} + +- (instancetype)initWithEncodedDictionary:(NSDictionary *)dictionary { + self = [self init]; + if (!self) return nil; + + id latObj = dictionary[PFGeoPointCodingLatitudeKey]; + PFParameterAssert([latObj isKindOfClass:[NSNumber class]], @"Invalid latitude type passed: %@", latObj); + + id longObj = dictionary[PFGeoPointCodingLongitudeKey]; + PFParameterAssert([longObj isKindOfClass:[NSNumber class]], @"Invalid longitude type passed: %@", longObj); + + _latitude = [latObj doubleValue]; + _longitude = [longObj doubleValue]; + + return self; +} + +///-------------------------------------- +#pragma mark - NSObject +///-------------------------------------- + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[PFGeoPoint class]]) { + return NO; + } + + PFGeoPoint *geoPoint = object; + + return (self.latitude == geoPoint.latitude && + self.longitude == geoPoint.longitude); +} + +- (NSUInteger)hash { + return PFDoublePairHash(self.latitude, self.longitude); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, latitude: %f, longitude: %f>", + [self class], + self, + self.latitude, + self.longitude]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + PFGeoPoint *geoPoint = [[self class] geoPointWithLatitude:self.latitude longitude:self.longitude]; + return geoPoint; +} + +///-------------------------------------- +#pragma mark - NSCoding +///-------------------------------------- + +- (instancetype)initWithCoder:(NSCoder *)coder { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[PFGeoPointCodingTypeKey] = [coder decodeObjectForKey:PFGeoPointCodingTypeKey]; + dictionary[PFGeoPointCodingLatitudeKey] = [coder decodeObjectForKey:PFGeoPointCodingLatitudeKey]; + dictionary[PFGeoPointCodingLongitudeKey] = [coder decodeObjectForKey:PFGeoPointCodingLongitudeKey]; + return [self initWithEncodedDictionary:dictionary]; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + NSDictionary *dictionary = [self encodeIntoDictionary]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [coder encodeObject:obj forKey:key]; + }]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.h b/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.h new file mode 100644 index 0000000..3b1c042 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.h @@ -0,0 +1,113 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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. + */ + +PF_WATCH_UNAVAILABLE @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, copy, readonly) NSString *deviceType; + +/*! + @abstract The installationId for the `PFInstallation`. + */ +@property (nonatomic, copy, readonly) NSString *installationId; + +/*! + @abstract The device token for the `PFInstallation`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) 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, copy, readonly) NSString *timeZone; + +/*! + @abstract The channels for the `PFInstallation`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) 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/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.m b/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.m new file mode 100644 index 0000000..2536d64 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFInstallation.m @@ -0,0 +1,342 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFInstallation.h" +#import "PFInstallationPrivate.h" + +#import "BFTask+Private.h" +#import "PFApplication.h" +#import "PFAssert.h" +#import "PFCoreManager.h" +#import "PFCurrentInstallationController.h" +#import "PFFileManager.h" +#import "PFInstallationConstants.h" +#import "PFInstallationController.h" +#import "PFInstallationIdentifierStore.h" +#import "PFInternalUtils.h" +#import "PFObject+Subclass.h" +#import "PFObjectEstimatedData.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFPushPrivate.h" +#import "PFQueryPrivate.h" +#import "Parse_Private.h" +#import "PFErrorUtilities.h" + +@implementation PFInstallation (Private) + +static NSSet *protectedKeys; + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + protectedKeys = PF_SET(PFInstallationKeyDeviceType, + PFInstallationKeyInstallationId, + PFInstallationKeyTimeZone, + PFInstallationKeyLocaleIdentifier, + PFInstallationKeyParseVersion, + PFInstallationKeyAppVersion, + PFInstallationKeyAppName, + PFInstallationKeyAppIdentifier); + }); +} + +// Clear device token. Used for testing. +- (void)_clearDeviceToken { + [super removeObjectForKey:PFInstallationKeyDeviceToken]; +} + +- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync { + return [[super _validateDeleteAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorCommandUnavailable + message:@"Installation cannot be deleted"]; + return [BFTask taskWithError:error]; + }]; +} + +// Validates a class name. We override this to only allow the installation class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[PFInstallation parseClassName]], + @"Cannot initialize a PFInstallation with a custom class name."); +} + +- (BOOL)_isCurrentInstallation { + return (self == [[self class] _currentInstallationController].memoryCachedCurrentInstallation); +} + +- (void)_markAllFieldsDirty { + @synchronized(self.lock) { + NSDictionary *estimatedData = self._estimatedData.dictionaryRepresentation; + [estimatedData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [super setObject:obj forKey:key]; + }]; + } +} + +- (NSString *)displayClassName { + return NSStringFromClass([PFInstallation class]); +} + +///-------------------------------------- +#pragma mark - Command Handlers +///-------------------------------------- + +- (BFTask *)handleSaveResultAsync:(NSDictionary *)result { + @weakify(self); + return [[super handleSaveResultAsync:result] continueWithBlock:^id(BFTask *task) { + @strongify(self); + BFTask *saveTask = [[[self class] _currentInstallationController] saveCurrentObjectAsync:self]; + return [saveTask continueWithResult:task]; + }]; +} + +///-------------------------------------- +#pragma mark - Current Installation Controller +///-------------------------------------- + ++ (PFCurrentInstallationController *)_currentInstallationController { + return [Parse _currentManager].coreManager.currentInstallationController; +} + +@end + +@implementation PFInstallation + +@dynamic deviceType; +@dynamic installationId; +@dynamic deviceToken; +@dynamic timeZone; +@dynamic channels; +@dynamic badge; + +///-------------------------------------- +#pragma mark - PFSubclassing +///-------------------------------------- + ++ (NSString *)parseClassName { + return @"_Installation"; +} + ++ (PFQuery *)query { + return [super query]; +} + +///-------------------------------------- +#pragma mark - Current Installation +///-------------------------------------- + ++ (instancetype)currentInstallation { + BFTask *task = [[self _currentInstallationController] getCurrentObjectAsync]; + return [task waitForResult:nil withMainThreadWarning:NO]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (id)objectForKey:(NSString *)key { + if ([key isEqualToString:PFInstallationKeyBadge] && [self _isCurrentInstallation]) { + // Update the data dictionary badge value from the device. + [self _updateBadgeFromDevice]; + } + + return [super objectForKey:key]; +} + +- (void)setObject:(id)object forKey:(NSString *)key { + PFParameterAssert(![protectedKeys containsObject:key], + @"Can't change the '%@' field of a PFInstallation.", key); + + if ([key isEqualToString:PFInstallationKeyBadge]) { + // Set the application badge and update the badge value in the data dictionary. + NSInteger badge = [object integerValue]; + PFParameterAssert(badge >= 0, @"Can't set the badge to less than zero."); + + [PFApplication currentApplication].iconBadgeNumber = badge; + [super setObject:@(badge) forKey:PFInstallationKeyBadge]; + } + + [super setObject:object forKey:key]; +} + +- (void)incrementKey:(NSString *)key byAmount:(NSNumber *)amount { + PFParameterAssert(![key isEqualToString:PFInstallationKeyBadge], + @"Can't atomically increment the 'badge' field of a PFInstallation."); + + [super incrementKey:key byAmount:amount]; +} + +- (void)removeObjectForKey:(NSString *)key { + PFParameterAssert(![protectedKeys containsObject:key], + @"Can't remove the '%@' field of a PFInstallation.", key); + PFParameterAssert(![key isEqualToString:PFInstallationKeyBadge], + @"Can't remove the 'badge' field of a PFInstallation."); + [super removeObjectForKey:key]; +} + +// Internal mutators override the dynamic accessor and use super to avoid +// read-only checks on automatic fields. +- (void)setDeviceType:(NSString *)deviceType { + [self _setObject:deviceType forKey:PFInstallationKeyDeviceType onlyIfDifferent:YES]; +} + +- (void)setInstallationId:(NSString *)installationId { + [self _setObject:installationId forKey:PFInstallationKeyInstallationId onlyIfDifferent:YES]; +} + +- (void)setDeviceToken:(NSString *)deviceToken { + [self _setObject:deviceToken forKey:PFInstallationKeyDeviceToken onlyIfDifferent:YES]; +} + +- (void)setDeviceTokenFromData:(NSData *)deviceTokenData { + [self _setObject:[[PFPush pushInternalUtilClass] convertDeviceTokenToString:deviceTokenData] + forKey:PFInstallationKeyDeviceToken + onlyIfDifferent:YES]; +} + +- (void)setTimeZone:(NSString *)timeZone { + [self _setObject:timeZone forKey:PFInstallationKeyTimeZone onlyIfDifferent:YES]; +} + +- (void)setLocaleIdentifier:(NSString *)localeIdentifier { + [self _setObject:localeIdentifier + forKey:PFInstallationKeyLocaleIdentifier + onlyIfDifferent:YES]; +} + +- (void)setChannels:(NSArray *)channels { + [self _setObject:channels forKey:PFInstallationKeyChannels onlyIfDifferent:YES]; +} + +///-------------------------------------- +#pragma mark - PFObject +///-------------------------------------- + +- (BFTask *)saveAsync:(BFTask *)toAwait { + return [[super saveAsync:toAwait] continueWithBlock:^id(BFTask *task) { + // Do not attempt to resave an object if LDS is enabled, since changing objectId is not allowed. + if ([Parse _currentManager].offlineStoreLoaded) { + return task; + } + + if (task.error.code == kPFErrorObjectNotFound) { + @synchronized (self.lock) { + // Retry the fetch as a save operation because this Installation was deleted on the server. + // We always want [currentInstallation save] to succeed. + self.objectId = nil; + [self _markAllFieldsDirty]; + return [super saveAsync:nil]; + } + } + return task; + }]; +} + +- (BOOL)needsDefaultACL { + return NO; +} + +///-------------------------------------- +#pragma mark - Automatic Info +///-------------------------------------- + +- (void)_objectWillSave { + if ([self _isCurrentInstallation]) { + @synchronized(self.lock) { + [self _updateTimeZoneFromDevice]; + [self _updateBadgeFromDevice]; + [self _updateVersionInfoFromDevice]; + [self _updateLocaleIdentifierFromDevice]; + } + } +} + +- (void)_updateTimeZoneFromDevice { + // Get the system time zone (after clearing the cached value) and update + // the installation if necessary. + NSString *systemTimeZoneName = [PFInternalUtils currentSystemTimeZoneName]; + if (![systemTimeZoneName isEqualToString:self.timeZone]) { + self.timeZone = systemTimeZoneName; + } +} + +- (void)_updateBadgeFromDevice { + // Get the application icon and update the installation if necessary. + NSNumber *applicationBadge = @([PFApplication currentApplication].iconBadgeNumber); + NSNumber *installationBadge = [super objectForKey:PFInstallationKeyBadge]; + if (installationBadge == nil || ![applicationBadge isEqualToNumber:installationBadge]) { + [super setObject:applicationBadge forKey:PFInstallationKeyBadge]; + } +} + +- (void)_updateVersionInfoFromDevice { + NSDictionary *appInfo = [[NSBundle mainBundle] infoDictionary]; + NSString *appName = appInfo[(__bridge NSString *)kCFBundleNameKey]; + NSString *appVersion = appInfo[(__bridge NSString *)kCFBundleVersionKey]; + NSString *appIdentifier = appInfo[(__bridge NSString *)kCFBundleIdentifierKey]; + // It's possible that the app was created without an info.plist and we just + // cannot get the data we need. + // Note: it's important to make the possibly nil string the message receptor for + // nil propegation instead of a BAD_ACCESS + if (appName && ![self[PFInstallationKeyAppName] isEqualToString:appName]) { + [super setObject:appName forKey:PFInstallationKeyAppName]; + } + if (appVersion && ![self[PFInstallationKeyAppVersion] isEqualToString:appVersion]) { + [super setObject:appVersion forKey:PFInstallationKeyAppVersion]; + } + if (appIdentifier && ![self[PFInstallationKeyAppIdentifier] isEqualToString:appIdentifier]) { + [super setObject:appIdentifier forKey:PFInstallationKeyAppIdentifier]; + } + if (![self[PFInstallationKeyParseVersion] isEqualToString:PARSE_VERSION]) { + [super setObject:PARSE_VERSION forKey:PFInstallationKeyParseVersion]; + } +} + +/*! + @abstract Save localeIdentifier in the following format: [language code]-[COUNTRY CODE]. + + @discussion The language codes are two-letter lowercase ISO language codes (such as "en") as defined by + ISO 639-1. + The country codes are two-letter uppercase ISO country codes (such as "US") as defined by + ISO 3166-1. + + Many iOS locale identifiers don't contain the country code -> inconsistencies with Android/Windows Phone. + */ +- (void)_updateLocaleIdentifierFromDevice { + NSLocale *currentLocale = [NSLocale currentLocale]; + NSString *language = [currentLocale objectForKey:NSLocaleLanguageCode]; + NSString *countryCode = [currentLocale objectForKey:NSLocaleCountryCode]; + + if (language.length == 0) { + return; + } + + NSString *localeIdentifier = nil; + if (countryCode.length > 0) { + localeIdentifier = [NSString stringWithFormat:@"%@-%@", language, countryCode]; + } else { + localeIdentifier = language; + } + + NSString *currentLocaleIdentifier = self[PFInstallationKeyLocaleIdentifier]; + if (localeIdentifier.length > 0 && ![localeIdentifier isEqualToString:currentLocaleIdentifier]) { + // Call into super to avoid checking on protected keys. + [super setObject:localeIdentifier forKey:PFInstallationKeyLocaleIdentifier]; + } +} + +///-------------------------------------- +#pragma mark - Data Source +///-------------------------------------- + ++ (id)objectController { + return [Parse _currentManager].coreManager.installationController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.h b/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.h new file mode 100644 index 0000000..d5b376a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.m b/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.m new file mode 100644 index 0000000..c8d9e6a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFNetworkActivityIndicatorManager.m @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFNetworkActivityIndicatorManager.h" + +#import + +#import "PFApplication.h" +#import "PFCommandRunningConstants.h" + +static NSTimeInterval const PFNetworkActivityIndicatorVisibilityDelay = 0.17; + +@interface PFNetworkActivityIndicatorManager () { + dispatch_queue_t _networkActivityAccessQueue; +} + +@property (nonatomic, assign, readwrite) NSUInteger networkActivityCount; + +@property (nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer; + +@end + +@implementation PFNetworkActivityIndicatorManager + +@synthesize enabled = _enabled; +@synthesize networkActivityCount = _networkActivityCount; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + ++ (instancetype)sharedManager { + static PFNetworkActivityIndicatorManager *manager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[self alloc] init]; + manager.enabled = YES; + }); + return manager; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _networkActivityAccessQueue = dispatch_queue_create("com.parse.networkActivityIndicatorManager", + DISPATCH_QUEUE_SERIAL); + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_handleWillSendURLRequestNotification:) + name:PFNetworkWillSendURLRequestNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_handleDidReceiveURLResponseNotification:) + name:PFNetworkDidReceiveURLResponseNotification + object:nil]; + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [_activityIndicatorVisibilityTimer invalidate]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setNetworkActivityCount:(NSUInteger)networkActivityCount { + dispatch_sync(_networkActivityAccessQueue, ^{ + _networkActivityCount = networkActivityCount; + }); + dispatch_async(dispatch_get_main_queue(), ^{ + [self _updateNetworkActivityIndicatorVisibilityAfterDelay]; + }); +} + +- (NSUInteger)networkActivityCount { + __block NSUInteger count = 0; + dispatch_sync(_networkActivityAccessQueue, ^{ + count = _networkActivityCount; + }); + return count; +} + +- (BOOL)isNetworkActivityIndicatorVisible { + return self.networkActivityCount > 0; +} + +///-------------------------------------- +#pragma mark - Counts +///-------------------------------------- + +- (void)incrementActivityCount { + dispatch_sync(_networkActivityAccessQueue, ^{ + _networkActivityCount++; + }); + dispatch_async(dispatch_get_main_queue(), ^{ + [self _updateNetworkActivityIndicatorVisibilityAfterDelay]; + }); +} + +- (void)decrementActivityCount { + dispatch_sync(_networkActivityAccessQueue, ^{ + _networkActivityCount = MAX(_networkActivityCount - 1, 0); + }); + dispatch_async(dispatch_get_main_queue(), ^{ + [self _updateNetworkActivityIndicatorVisibilityAfterDelay]; + }); +} + +///-------------------------------------- +#pragma mark - Network Activity Indicator +///-------------------------------------- + +- (void)_updateNetworkActivityIndicatorVisibilityAfterDelay { + if (self.enabled) { + // Delay hiding of activity indicator for a short interval, to avoid flickering + if (![self isNetworkActivityIndicatorVisible]) { + [self.activityIndicatorVisibilityTimer invalidate]; + + NSTimeInterval timeInterval = PFNetworkActivityIndicatorVisibilityDelay; + SEL selector = @selector(_updateNetworkActivityIndicatorVisibility); + self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:timeInterval + target:self + selector:selector + userInfo:nil + repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer + forMode:NSRunLoopCommonModes]; + } else { + [self performSelectorOnMainThread:@selector(_updateNetworkActivityIndicatorVisibility) + withObject:nil + waitUntilDone:NO + modes:@[ NSRunLoopCommonModes ]]; + } + } +} + +- (void)_updateNetworkActivityIndicatorVisibility NS_EXTENSION_UNAVAILABLE_IOS("") { + if (![PFApplication currentApplication].extensionEnvironment) { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:self.networkActivityIndicatorVisible]; + } +} + +///-------------------------------------- +#pragma mark - Command Running +///-------------------------------------- + +- (void)_handleWillSendURLRequestNotification:(NSNotification *)notification { + [self incrementActivityCount]; +} + +- (void)_handleDidReceiveURLResponseNotification:(NSNotification *)notification { + [self decrementActivityCount]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFNullability.h b/Unit-2-Journal/Pods/Parse/Parse/PFNullability.h new file mode 100644 index 0000000..8c1b958 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFNullability.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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. + */ + +#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/Unit-2-Journal/Pods/Parse/Parse/PFObject+Subclass.h b/Unit-2-Journal/Pods/Parse/Parse/PFObject+Subclass.h new file mode 100644 index 0000000..585d5c1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFObject+Subclass.h @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFQuery PF_GENERIC(PFGenericObject : PFObject *); + +PF_ASSUME_NONNULL_BEGIN + +/*! + ### 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, copy) 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/Unit-2-Journal/Pods/Parse/Parse/PFObject.h b/Unit-2-Journal/Pods/Parse/Parse/PFObject.h new file mode 100644 index 0000000..aeb51c7 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFObject.h @@ -0,0 +1,1429 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +@protocol PFSubclassing; +@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; +} + +///-------------------------------------- +/// @name Creating a PFObject +///-------------------------------------- + +/*! + @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; + +/*! + @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 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. + */ ++ (instancetype)objectWithClassName:(NSString *)className dictionary:(PF_NULLABLE NSDictionary PF_GENERIC(NSString *, id)*)dictionary; + +/*! + @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; + +///-------------------------------------- +/// @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 PF_GENERIC(NSString *)*)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 maintained 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 maintained 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:(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."); + +/*! + @abstract Clears any changes to this object made since the last call to save and sets it back to the server state. + */ +- (void)revert; + +/*! + @abstract Clears any changes to this object's key that were done after last successful save and sets it back to the + server state. + + @param key The key to revert changes for. + */ +- (void)revertObjectForKey:(NSString *)key; + +///-------------------------------------- +/// @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)saveEventually PF_WATCH_UNAVAILABLE; + +/*! + @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 PF_WATCH_UNAVAILABLE; + +///-------------------------------------- +/// @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 PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)saveAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)deleteAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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. + */ +- (PF_NULLABLE instancetype)refresh PF_SWIFT_UNAVAILABLE 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. + */ +- (PF_NULLABLE instancetype)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. + */ +- (PF_NULLABLE instancetype)fetch PF_SWIFT_UNAVAILABLE; +/*! + @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. + */ +- (PF_NULLABLE instancetype)fetch:(NSError **)error; + +/*! + @abstract *Synchronously* fetches the `PFObject` data from the server if is `NO`. + */ +- (PF_NULLABLE instancetype)fetchIfNeeded PF_SWIFT_UNAVAILABLE; + +/*! + @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 instancetype)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 PF_GENERIC(__kindof PFObject *)*)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 PF_GENERIC(__kindof PFObject *)*)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. + */ ++ (PF_NULLABLE NSArray PF_GENERIC(__kindof PFObject *)*)fetchAll:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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. + */ ++ (PF_NULLABLE NSArray PF_GENERIC(__kindof PFObject *)*)fetchAll:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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. + */ ++ (PF_NULLABLE NSArray PF_GENERIC(__kindof PFObject *)*)fetchAllIfNeeded:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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. + */ ++ (PF_NULLABLE NSArray PF_GENERIC(__kindof PFObject *)*)fetchAllIfNeeded:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSArray<__kindof PFObject *> *)*)fetchAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSArray<__kindof PFObject *> *)*)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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. + */ +- (PF_NULLABLE instancetype)fetchFromLocalDatastore PF_SWIFT_UNAVAILABLE; + +/*! + @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. + */ +- (PF_NULLABLE instancetype)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 PF_GENERIC(__kindof PFObject *)*)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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)deleteEventually PF_WATCH_UNAVAILABLE; + +///-------------------------------------- +/// @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)objects withName:(NSString *)name PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)pinAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)pinAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(NSNumber *)*)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 PF_GENERIC(PFObject *)*)objects PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)objects withName:(NSString *)name PF_SWIFT_UNAVAILABLE; + +/*! + @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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)unpinAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)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 PF_GENERIC(NSNumber *)*)unpinAllInBackground:(PF_NULLABLE NSArray PF_GENERIC(PFObject *)*)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 PF_GENERIC(PFObject *)*)objects + withName:(NSString *)name + block:(PF_NULLABLE PFBooleanResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFObject.m b/Unit-2-Journal/Pods/Parse/Parse/PFObject.m new file mode 100644 index 0000000..b403694 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFObject.m @@ -0,0 +1,2770 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFObject.h" +#import "PFObject+Subclass.h" +#import "PFObjectSubclassingController.h" + +#import +#import +#import + +#import + +#import "BFTask+Private.h" +#import "PFACLPrivate.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFConstants.h" +#import "PFCoreManager.h" +#import "PFCurrentUserController.h" +#import "PFDateFormatter.h" +#import "PFDecoder.h" +#import "PFEncoder.h" +#import "PFErrorUtilities.h" +#import "PFEventuallyQueue_Private.h" +#import "PFFileManager.h" +#import "PFFile_Private.h" +#import "PFJSONSerialization.h" +#import "PFLogging.h" +#import "PFMacros.h" +#import "PFMultiProcessFileLockController.h" +#import "PFMutableObjectState.h" +#import "PFObjectBatchController.h" +#import "PFObjectConstants.h" +#import "PFObjectController.h" +#import "PFObjectEstimatedData.h" +#import "PFObjectFileCodingLogic.h" +#import "PFObjectFilePersistenceController.h" +#import "PFObjectLocalIdStore.h" +#import "PFObjectUtilities.h" +#import "PFOfflineStore.h" +#import "PFOperationSet.h" +#import "PFPin.h" +#import "PFPinningObjectStore.h" +#import "PFQueryPrivate.h" +#import "PFRESTObjectBatchCommand.h" +#import "PFRESTObjectCommand.h" +#import "PFRelation.h" +#import "PFRelationPrivate.h" +#import "PFSubclassing.h" +#import "PFTaskQueue.h" +#import "ParseInternal.h" +#import "Parse_Private.h" + +/*! + Checks if an object can be used as a value for PFObject. + */ +static void PFObjectAssertValueIsKindOfValidClass(id object) { + static NSArray *classes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + classes = @[ [NSDictionary class], [NSArray class], + [NSString class], [NSNumber class], [NSNull class], [NSDate class], [NSData class], + [PFObject class], [PFFile class], [PFACL class], [PFGeoPoint class] ]; + }); + + for (Class class in classes) { + if ([object isKindOfClass:class]) { + return; + } + } + + PFParameterAssert(NO, @"PFObject values may not have class: %@", [object class]); +} + +/*! + Checks if a class is a of container kind to be used as a value for PFObject. + */ +static BOOL PFObjectValueIsKindOfMutableContainerClass(id object) { + static NSArray *classes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + classes = @[ [NSDictionary class], [NSArray class], [PFACL class], [PFGeoPoint class] ]; + }); + + for (Class class in classes) { + if ([object isKindOfClass:class]) { + return YES; + } + } + + return NO; +} + +@interface PFObject () { + // A lock for accessing any of the internal state of this object. + // Guards basically all of the variables below. + NSObject *lock; + + PFObjectState *_pfinternal_state; + + PFObjectEstimatedData *_estimatedData; + NSMutableSet *_availableKeys; // TODO: (nlutsenko) Maybe decouple this further. + + // TODO (grantland): Derive this off the EventuallyPins as opposed to +/- count. + int _deletingEventually; + + // A dictionary that maps id (objects) => PFJSONCache + NSMutableDictionary *hashedObjectsCache; + + NSString *localId; + + // This queue is used to guarantee the order of *Eventually commands + // and offload all the work to the background thread + PFTaskQueue *_eventuallyTaskQueue; +} + +@property (nonatomic, strong, readwrite) NSString *localId; + +@property (nonatomic, strong, readwrite) PFTaskQueue *taskQueue; + ++ (void)assertSubclassIsRegistered:(Class)subclass; + +@end + +@implementation PFObject (Private) + ++ (void)unregisterSubclass:(Class)subclass { + [[self subclassingController] unregisterSubclass:subclass]; +} + +/*! + Returns the object that should be used to synchronize all internal data access. + */ +- (NSObject *)lock { + return lock; +} + +/*! + Blocks until all outstanding operations have completed. + */ +- (void)waitUntilFinished { + [[self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return toAwait; + }] waitForResult:nil]; +} + +/*! + For operations that need to be put into multiple objects queues, like saveAll + and fetchAll, this method does the nasty work. + @param taskStart - A block that is called when all of the objects are ready. + It can return a promise that all of the queues will then wait on. + @param objects - The objects that this operation affects. + @returns - Returns a promise that is fulfilled once the promise returned by the + block is fulfilled. + */ ++ (BFTask *)_enqueue:(BFTask *(^)(BFTask *toAwait))taskStart forObjects:(NSArray *)objects { + // The task that will be complete when all of the child queues indicate they're ready to start. + BFTaskCompletionSource *readyToStart = [BFTaskCompletionSource taskCompletionSource]; + + // First, we need to lock the mutex for the queue for every object. We have to hold this + // from at least when taskStart() is called to when obj.taskQueue enqueue is called, so + // that saves actually get executed in the order they were setup by taskStart(). + // The locks have to be sorted so that we always acquire them in the same order. + // Otherwise, there's some risk of deadlock. + NSMutableArray *mutexes = [NSMutableArray array]; + for (PFObject *obj in objects) { + [mutexes addObject:obj.taskQueue.mutex]; + } + [mutexes sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { + void *lock1 = (__bridge void *)obj1; + void *lock2 = (__bridge void *)obj2; + return lock1 - lock2; + }]; + for (NSObject *lock in mutexes) { + objc_sync_enter(lock); + } + + @try { + // The task produced by taskStart. By running this immediately, we allow everything prior + // to toAwait to run before waiting for all of the queues on all of the objects. + BFTask *fullTask = taskStart(readyToStart.task); + + // Add fullTask to each of the objects' queues. + NSMutableArray *childTasks = [NSMutableArray array]; + for (PFObject *obj in objects) { + [obj.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + [childTasks addObject:toAwait]; + return fullTask; + }]; + } + + // When all of the objects' queues are ready, signal fullTask that it's ready to go on. + [[BFTask taskForCompletionOfAllTasks:childTasks] continueWithBlock:^id(BFTask *task) { + readyToStart.result = nil; + return nil; + }]; + + return fullTask; + + } @finally { + for (NSObject *lock in mutexes) { + objc_sync_exit(lock); + } + } +} + +///-------------------------------------- +#pragma mark - Children helpers +///-------------------------------------- + +/*! + Finds all of the objects that are reachable from child, including child itself, + and adds them to the given mutable array. It traverses arrays and json objects. + @param node An kind object to search for children. + @param dirtyChildren The array to collect the result into. + @param seen The set of all objects that have already been seen. + @param seenNew The set of new objects that have already been seen since the + last existing object. + */ ++ (void)collectDirtyChildren:(id)node + children:(NSMutableSet *)dirtyChildren + files:(NSMutableSet *)dirtyFiles + seen:(NSSet *)seen + seenNew:(NSSet *)seenNew + currentUser:(PFUser *)currentUser { + if ([node isKindOfClass:[NSArray class]]) { + for (id elem in node) { + @autoreleasepool { + [self collectDirtyChildren:elem + children:dirtyChildren + files:dirtyFiles + seen:seen + seenNew:seenNew + currentUser:currentUser]; + } + } + } else if ([node isKindOfClass:[NSDictionary class]]) { + [node enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [self collectDirtyChildren:obj + children:dirtyChildren + files:dirtyFiles + seen:seen + seenNew:seenNew + currentUser:currentUser]; + }]; + } else if ([node isKindOfClass:[PFACL class]]) { + PFACL *acl = (PFACL *)node; + if ([acl hasUnresolvedUser]) { + [self collectDirtyChildren:currentUser + children:dirtyChildren + files:dirtyFiles + seen:seen + seenNew:seenNew + currentUser:currentUser]; + } + + } else if ([node isKindOfClass:[PFObject class]]) { + PFObject *object = (PFObject *)node; + NSDictionary *toSearch = nil; + + @synchronized ([object lock]) { + // Check for cycles of new objects. Any such cycle means it will be + // impossible to save this collection of objects, so throw an exception. + if (object.objectId) { + seenNew = [NSSet set]; + } else { + if ([seenNew containsObject:object]) { + [NSException raise:NSInternalInconsistencyException + format:@"Found a circular dependency when saving."]; + } + seenNew = [seenNew setByAddingObject:object]; + } + + // Check for cycles of any object. If this occurs, then there's no + // problem, but we shouldn't recurse any deeper, because it would be + // an infinite recursion. + if ([seen containsObject:object]) { + return; + } + seen = [seen setByAddingObject:object]; + + // Recurse into this object's children looking for dirty children. + // We only need to look at the child object's current estimated data, + // because that's the only data that might need to be saved now. + toSearch = [object->_estimatedData.dictionaryRepresentation copy]; + } + + [self collectDirtyChildren:toSearch + children:dirtyChildren + files:dirtyFiles + seen:seen + seenNew:seenNew + currentUser:currentUser]; + + if ([object isDirty:NO]) { + [dirtyChildren addObject:object]; + } + } else if ([node isKindOfClass:[PFFile class]]) { + PFFile *file = (PFFile *)node; + if (!file.url) { + [dirtyFiles addObject:node]; + } + } +} + +// Helper version of collectDirtyChildren:children:seen:seenNew so that callers +// don't have to add the internally used parameters. ++ (void)collectDirtyChildren:(id)child + children:(NSMutableSet *)dirtyChildren + files:(NSMutableSet *)dirtyFiles + currentUser:(PFUser *)currentUser { + [self collectDirtyChildren:child + children:dirtyChildren + files:dirtyFiles + seen:[NSSet set] + seenNew:[NSSet set] + currentUser:currentUser]; +} + +// Returns YES if the given object can be serialized for saving as a value +// that is pointed to by a PFObject. +// @param value The object we want to serialize as a value. +// @param saved The set of all objects we can assume will be saved before this one. +// @param error The reason why it can't be serialized. ++ (BOOL)canBeSerializedAsValue:(id)value + afterSaving:(NSMutableArray *)saved + error:(NSError **)error { + if ([value isKindOfClass:[PFObject class]]) { + PFObject *object = (PFObject *)value; + if (!object.objectId && ![saved containsObject:object]) { + if (error) { + *error = [PFErrorUtilities errorWithCode:kPFErrorInvalidPointer + message:@"Pointer to an unsaved object."]; + } + return NO; + } + + } else if ([value isKindOfClass:[NSDictionary class]]) { + __block BOOL retValue = YES; + [value enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if (![[self class] canBeSerializedAsValue:obj + afterSaving:saved + error:error]) { + retValue = NO; + *stop = YES; + } + }]; + return retValue; + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = (NSArray *)value; + for (NSString *item in array) { + if (![[self class] canBeSerializedAsValue:item + afterSaving:saved + error:error]) { + return NO; + } + } + } + + return YES; +} + +// Returns YES if this object can be serialized for saving. +// @param saved A set of objects that we can assume will have been saved. +// @param error The reason why it can't be serialized. +- (BOOL)canBeSerializedAfterSaving:(NSMutableArray *)saved withCurrentUser:(PFUser *)user error:(NSError **)error { + @synchronized (lock) { + // This method is only used for batching sets of objects for saveAll + // and when saving children automatically. Since it's only used to + // determine whether or not save should be called on them, it only + // needs to examine their current values, so we use estimatedData. + if (![[self class] canBeSerializedAsValue:_estimatedData.dictionaryRepresentation + afterSaving:saved + error:error]) { + return NO; + } + + if ([self isDataAvailableForKey:@"ACL"] && + [[self ACLWithoutCopying] hasUnresolvedUser] && + ![saved containsObject:user]) { + if (error) { + *error = [PFErrorUtilities errorWithCode:kPFErrorInvalidACL + message:@"User associated with ACL must be signed up."]; + } + return NO; + } + + return YES; + } +} + +// This saves all of the objects and files reachable from the given object. +// It does its work in multiple waves, saving as many as possible in each wave. +// If there's ever an error, it just gives up, sets error, and returns NO; ++ (BFTask *)_deepSaveAsync:(id)object withCurrentUser:(PFUser *)currentUser sessionToken:(NSString *)sessionToken { + BFTask *task = [BFTask taskWithResult:@YES]; + + NSMutableSet *uniqueObjects = [NSMutableSet set]; + NSMutableSet *uniqueFiles = [NSMutableSet set]; + [self collectDirtyChildren:object children:uniqueObjects files:uniqueFiles currentUser:currentUser]; + for (PFFile *file in uniqueFiles) { + task = [task continueAsyncWithSuccessBlock:^id(BFTask *task) { + return [[file saveInBackground] continueAsyncWithBlock:^id(BFTask *task) { + // This is a stupid hack because our current behavior is to fail file + // saves with an error when a file save inside it is cancelled. + if (task.isCancelled) { + NSError *newError = [PFErrorUtilities errorWithCode:kPFErrorUnsavedFile + message:@"A file save was cancelled."]; + return [BFTask taskWithError:newError]; + } + return task; + }]; + }]; + } + + // TODO: (nlutsenko) Get rid of this once we allow localIds in batches. + NSArray *remaining = [uniqueObjects allObjects]; + NSMutableArray *finished = [NSMutableArray array]; + while ([remaining count] > 0) { + // Partition the objects into two sets: those that can be save immediately, + // and those that rely on other objects to be created first. + NSMutableArray *current = [NSMutableArray array]; + NSMutableArray *nextBatch = [NSMutableArray array]; + for (PFObject *object in remaining) { + if ([object canBeSerializedAfterSaving:finished withCurrentUser:currentUser error:nil]) { + [current addObject:object]; + } else { + [nextBatch addObject:object]; + } + } + remaining = nextBatch; + + if (current.count == 0) { + // We do cycle-detection when building the list of objects passed to this + // function, so this should never get called. But we should check for it + // anyway, so that we get an exception instead of an infinite loop. + [NSException raise:NSInternalInconsistencyException + format:@"Unable to save a PFObject with a relation to a cycle."]; + } + + // If a lazy user is one of the objects in the array, resolve its laziness now and + // remove it from the list of things to save. + // + // This has to happen separately from everything else because there [PFUser save] + // is special-cased to work for lazy users, but new users can't be created by + // PFMultiCommand's regular save. + if ([currentUser isLazy] && [current containsObject:currentUser]) { + task = [task continueAsyncWithSuccessBlock:^id(BFTask *task) { + return [currentUser saveInBackground]; + }]; + + [finished addObject:currentUser]; + [current removeObject:currentUser]; + if (current.count == 0) { + continue; + } + } + + task = [task continueAsyncWithSuccessBlock:^id(BFTask *task) { + // Batch requests have currently a limit of 50 packaged requests per single request + // This splitting will split the overall array into segments of upto 50 requests + // and execute them concurrently with a wrapper task for all of them. + NSArray *objectBatches = [PFInternalUtils arrayBySplittingArray:current + withMaximumComponentsPerSegment:PFRESTObjectBatchCommandSubcommandsLimit]; + NSMutableArray *tasks = [NSMutableArray arrayWithCapacity:[objectBatches count]]; + + for (NSArray *objectBatch in objectBatches) { + BFTask *batchTask = [self _enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + NSMutableArray *commands = [NSMutableArray arrayWithCapacity:[objectBatch count]]; + for (PFObject *object in objectBatch) { + PFRESTCommand *command = nil; + @synchronized ([object lock]) { + [object _objectWillSave]; + [object _checkSaveParametersWithCurrentUser:currentUser]; + command = [object _constructSaveCommandForChanges:[object unsavedChanges] + sessionToken:sessionToken + objectEncoder:[PFPointerObjectEncoder objectEncoder]]; + [object startSave]; + } + [commands addObject:command]; + } + + PFRESTCommand *batchCommand = [PFRESTObjectBatchCommand batchCommandWithCommands:commands + sessionToken:sessionToken]; + return [[[Parse _currentManager].commandRunner runCommandAsync:batchCommand withOptions:0] + continueAsyncWithBlock:^id(BFTask *commandRunnerTask) { + NSArray *results = [commandRunnerTask.result result]; + + NSMutableArray *handleSaveTasks = [NSMutableArray arrayWithCapacity:[objectBatch count]]; + + __block NSError *error = task.error; + [objectBatch enumerateObjectsUsingBlock:^(PFObject *object, NSUInteger idx, BOOL *stop) { + // If the task resulted in an error - don't even bother looking into + // the result of the command, just roll the error further + + BFTask *task = nil; + if (commandRunnerTask.error) { + task = [object handleSaveResultAsync:nil]; + } else { + NSDictionary *commandResult = results[idx]; + + NSDictionary *errorResult = commandResult[@"error"]; + if (errorResult) { + error = [PFErrorUtilities errorFromResult:errorResult]; + task = [[object handleSaveResultAsync:nil] continueWithBlock:^id(BFTask *task) { + return [BFTask taskWithError:error]; + }]; + } else { + NSDictionary *successfulResult = commandResult[@"success"]; + task = [object handleSaveResultAsync:successfulResult]; + } + } + [handleSaveTasks addObject:task]; + }]; + + return [[BFTask taskForCompletionOfAllTasks:handleSaveTasks] continueAsyncWithBlock:^id(BFTask *task) { + if (commandRunnerTask.error || commandRunnerTask.cancelled || commandRunnerTask.exception) { + return commandRunnerTask; + } + + // Reiterate saveAll tasks, return first error. + for (BFTask *handleSaveTask in handleSaveTasks) { + if (handleSaveTask.error || handleSaveTask.exception) { + return handleSaveTask; + } + } + + return @YES; + }]; + }]; + }]; + } forObjects:objectBatch]; + [tasks addObject:batchTask]; + } + + return [[BFTask taskForCompletionOfAllTasks:tasks] continueWithBlock:^id(BFTask *task) { + // Return the first exception, instead of the aggregated one + // for the sake of compatability with old versions + + if ([task.exception.name isEqualToString:BFTaskMultipleExceptionsException]) { + NSException *firstException = [task.exception.userInfo[@"exceptions"] firstObject]; + if (firstException) { + return [BFTask taskWithException:firstException]; + } + } + + if (task.error || task.cancelled || task.exception) { + return task; + } + + return @YES; + }]; + }]; + + [finished addObjectsFromArray:current]; + } + + return task; +} + +// Just like deepSaveAsync, but uses saveEventually instead of saveAsync. +// Because you shouldn't wait for saveEventually calls to complete, this +// does not return any operation. ++ (BFTask *)_enqueueSaveEventuallyChildrenOfObject:(PFObject *)object + currentUser:(PFUser *)currentUser { + return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + NSMutableSet *uniqueObjects = [NSMutableSet set]; + NSMutableSet *uniqueFiles = [NSMutableSet set]; + [self collectDirtyChildren:object children:uniqueObjects files:uniqueFiles currentUser:currentUser]; + for (PFFile *file in uniqueFiles) { + if (!file.url) { + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"Unable to saveEventually a PFObject with a relation to a new, unsaved PFFile." + userInfo:nil]; + return [BFTask taskWithException:exception]; + } + } + + // Remove object from the queue of objects to save as this method should only save children. + [uniqueObjects removeObject:object]; + + NSArray *remaining = [uniqueObjects allObjects]; + NSMutableArray *finished = [NSMutableArray array]; + NSMutableArray *enqueueTasks = [NSMutableArray array]; + while ([remaining count] > 0) { + // Partition the objects into two sets: those that can be save immediately, + // and those that rely on other objects to be created first. + NSMutableArray *current = [NSMutableArray array]; + NSMutableArray *nextBatch = [NSMutableArray array]; + for (PFObject *object in remaining) { + if ([object canBeSerializedAfterSaving:finished withCurrentUser:currentUser error:nil]) { + [current addObject:object]; + } else { + [nextBatch addObject:object]; + } + } + remaining = nextBatch; + + if (current.count == 0) { + // We do cycle-detection when building the list of objects passed to this + // function, so this should never get called. But we should check for it + // anyway, so that we get an exception instead of an infinite loop. + [NSException raise:NSInternalInconsistencyException + format:@"Unable to save a PFObject with a relation to a cycle."]; + } + + // If a lazy user is one of the objects in the array, resolve its laziness now and + // remove it from the list of things to save. + // + // This has to happen separately from everything else because there [PFUser save] + // is special-cased to work for lazy users, but new users can't be created by + // PFMultiCommand's regular save. + // + // Unfortunately, ACLs with lazy users still cannot be saved, because the ACL does + // does not get updated after the user save completes. + // TODO: (nlutsenko) Make the ACL update after the user is saved. + if ([currentUser isLazy] && [current containsObject:currentUser]) { + [enqueueTasks addObject:[currentUser _enqueueSaveEventuallyWithChildren:NO]]; + [finished addObject:currentUser]; + [current removeObject:currentUser]; + if (current.count == 0) { + continue; + } + } + + // TODO: (nlutsenko) Allow batching with saveEventually. + for (PFObject *object in current) { + [enqueueTasks addObject:[object _enqueueSaveEventuallyWithChildren:NO]]; + } + + [finished addObjectsFromArray:current]; + } + return [BFTask taskForCompletionOfAllTasks:enqueueTasks]; + }]; +} + +- (BFTask *)_saveChildrenInBackgroundWithCurrentUser:(PFUser *)currentUser sessionToken:(NSString *)sessionToken { + @synchronized (lock) { + return [[self class] _deepSaveAsync:_estimatedData.dictionaryRepresentation + withCurrentUser:currentUser + sessionToken:sessionToken]; + } +} + +///-------------------------------------- +#pragma mark - Dirtiness helper +///-------------------------------------- + +- (BOOL)isDirty:(BOOL)considerChildren { + @synchronized (lock) { + [self checkForChangesToMutableContainers]; + if (self._state.deleted || dirty || [self _hasChanges]) { + return YES; + } + + if (considerChildren) { + NSMutableSet *seen = [NSMutableSet set]; + return [self _areChildrenDirty:seen]; + } + + return NO; + } +} + +- (void)_setDirty:(BOOL)aDirty { + @synchronized (lock) { + dirty = aDirty; + } +} + +- (BOOL)_areChildrenDirty:(NSMutableSet *)seenObjects { + if ([seenObjects containsObject:self]) { + return NO; + } + [seenObjects addObject:self]; + + @synchronized(lock) { + [self checkpointAllMutableContainers]; + if (self._state.deleted || dirty || [self _hasChanges]) { + return YES; + } + + // We only need to consider the currently estimated children here, + // because they're the only ones that might need to be saved in a + // subsequent call to save, which is the meaning of "dirtiness". + __block BOOL retValue = NO; + [_estimatedData enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + if ([obj isKindOfClass:[PFObject class]] && [obj _areChildrenDirty:seenObjects]) { + retValue = YES; + *stop = YES; + } + }]; + return retValue; + } +} + +///-------------------------------------- +#pragma mark - Mutable container management +///-------------------------------------- + +- (void)checkpointAllMutableContainers { + @synchronized (lock) { + [_estimatedData enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { + [self checkpointMutableContainer:obj]; + }]; + } +} + +- (void)checkpointMutableContainer:(id)object { + @synchronized (lock) { + if (PFObjectValueIsKindOfMutableContainerClass(object)) { + [hashedObjectsCache setObject:[PFJSONCacheItem cacheFromObject:object] + forKey:[NSValue valueWithNonretainedObject:object]]; + } + } +} + +- (void)checkForChangesToMutableContainer:(id)object forKey:(NSString *)key { + @synchronized (lock) { + // If this is a mutable container, we should check its contents. + if (PFObjectValueIsKindOfMutableContainerClass(object)) { + PFJSONCacheItem *oldCacheItem = [hashedObjectsCache objectForKey:[NSValue valueWithNonretainedObject:object]]; + if (!oldCacheItem) { + [NSException raise:NSInternalInconsistencyException + format:@"PFObject contains container item that isn't cached."]; + } else { + PFJSONCacheItem *newCacheItem = [PFJSONCacheItem cacheFromObject:object]; + if (![oldCacheItem isEqual:newCacheItem]) { + // A mutable container changed out from under us. Treat it as a set operation. + [self setObject:object forKey:key]; + } + } + } else { + [hashedObjectsCache removeObjectForKey:[NSValue valueWithNonretainedObject:object]]; + } + } +} + +- (void)checkForChangesToMutableContainers { + @synchronized (lock) { + NSMutableArray *unexaminedCacheKeys = [[hashedObjectsCache allKeys] mutableCopy]; + NSDictionary *reachableData = _estimatedData.dictionaryRepresentation; + [reachableData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [unexaminedCacheKeys removeObject:[NSValue valueWithNonretainedObject:obj]]; + [self checkForChangesToMutableContainer:obj forKey:key]; + }]; + + // Remove unchecked cache entries. + [hashedObjectsCache removeObjectsForKeys:unexaminedCacheKeys]; + } +} + +///-------------------------------------- +#pragma mark - Data Availability +///-------------------------------------- + +// TODO: (nlutsenko) Remove this when rest of PFObject is decoupled. +- (void)setHasBeenFetched:(BOOL)fetched { + @synchronized (lock) { + if (self._state.complete != fetched) { + PFMutableObjectState *state = [_pfinternal_state mutableCopy]; + state.complete = fetched; + self._state = state; + } + } +} + +- (void)_setDeleted:(BOOL)deleted { + @synchronized (lock) { + if (self._state.deleted != deleted) { + PFMutableObjectState *state = [_pfinternal_state mutableCopy]; + state.deleted = deleted; + self._state = state; + } + } +} + +- (BOOL)isDataAvailableForKey:(NSString *)key { + if (!key) { + return NO; + } + + @synchronized (lock) { + if ([self isDataAvailable]) { + return YES; + } + return [_availableKeys containsObject:key]; + } +} + +///-------------------------------------- +#pragma mark - Validations +///-------------------------------------- + +// Validations that are done on save. For now, there is nothing. +- (void)_checkSaveParametersWithCurrentUser:(PFUser *)currentUser { + return; +} + +/*! + Checks if Parse class name could be used to initialize a given instance of PFObject or it's subclass. + */ ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert(className, @"Class name can't be 'nil'."); + PFParameterAssert(![className hasPrefix:@"_"], @"Invalid class name. Class names cannot start with an underscore."); +} + +///-------------------------------------- +#pragma mark - Serialization helpers +///-------------------------------------- + +- (NSString *)getOrCreateLocalId { + @synchronized(lock) { + if (!self.localId) { + PFConsistencyAssert(!self._state.objectId, + @"A localId should not be created for an object with an objectId."); + self.localId = [[Parse _currentManager].coreManager.objectLocalIdStore createLocalId]; + } + } + return self.localId; +} + +- (void)resolveLocalId { + @synchronized (lock) { + PFConsistencyAssert(self.localId, @"Tried to resolve a localId for an object with no localId."); + NSString *newObjectId = [[Parse _currentManager].coreManager.objectLocalIdStore objectIdForLocalId:self.localId]; + + // If we are resolving local ids, then this object is about to go over the network. + // But if it has local ids that haven't been resolved yet, then that's not going to + // be possible. + if (!newObjectId) { + [NSException raise:NSInternalInconsistencyException + format:@"Tried to save an object with a pointer to a new, unsaved object."]; + } + + // Nil out the localId so that the new objectId won't be saved back to the PFObjectLocalIdStore. + self.localId = nil; + self.objectId = newObjectId; + } +} + ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + completeData:(BOOL)completeData { + return [self _objectFromDictionary:dictionary + defaultClassName:defaultClassName + completeData:completeData + decoder:[PFDecoder objectDecoder]]; +} + +// When merging results from a query, ensure that any supplied `selectedKeys` are marked as available. This special +// handling is necessary because keys with an `undefined` value are not guaranteed to be included in the server's +// response data. +// +// See T3336562 ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + selectedKeys:(NSArray *)selectedKeys { + PFObject *result = [self _objectFromDictionary:dictionary + defaultClassName:defaultClassName + completeData:(selectedKeys == nil) + decoder:[PFDecoder objectDecoder]]; + [result->_availableKeys addObjectsFromArray:selectedKeys]; + return result; +} + +/*! + Creates a PFObject from a dictionary object. + + @param dictionary Undecoded dictionary. + @param defaultClassName The className of the resulting object if none is given by the dictionary. + @param completeData Whether to use complete data. + @param decoder Decoder used to decode the dictionary. + */ ++ (id)_objectFromDictionary:(NSDictionary *)dictionary + defaultClassName:(NSString *)defaultClassName + completeData:(BOOL)completeData + decoder:(PFDecoder *)decoder { + NSString *objectId = nil; + NSString *className = nil; + if (dictionary != nil) { + objectId = dictionary[@"objectId"]; + className = dictionary[@"className"] ?: defaultClassName; + } + PFObject *object = [PFObject objectWithoutDataWithClassName:className objectId:objectId]; + [object _mergeAfterFetchWithResult:dictionary decoder:decoder completeData:completeData]; + return object; +} + +/*! + When the app was previously a non-LDS app and want to enable LDS, currentUser and currentInstallation + will be discarded if we don't migrate them. This is a helper method to migrate user/installation + from disk to pin. + + @param fileName the file in which the object was saved. + @param pinName the name of the pin in which the object should be stored. + */ ++ (BFTask *)_migrateObjectInBackgroundFromFile:(NSString *)fileName + toPin:(NSString *)pinName { + return [self _migrateObjectInBackgroundFromFile:fileName toPin:pinName usingMigrationBlock:nil]; +} + +/*! + When the app was previously a non-LDS app and want to enable LDS, currentUser and currentInstallation + will be discarded if we don't migrate them. This is a helper method to migrate user/installation + from disk to pin. + + @param fileName the file in which the object was saved. + @param pinName the name of the pin in which the object should be stored. + @param migrationBlock The block that will be called if there is an object on disk and before the object is pinned. + */ ++ (BFTask *)_migrateObjectInBackgroundFromFile:(NSString *)fileName + toPin:(NSString *)pinName + usingMigrationBlock:(BFContinuationBlock)migrationBlock { + PFObjectFilePersistenceController *controller = [Parse _currentManager].coreManager.objectFilePersistenceController; + BFTask *task = [controller loadPersistentObjectAsyncForKey:fileName]; + if (migrationBlock) { + task = [task continueWithSuccessBlock:^id(BFTask *task) { + PFObject *object = task.result; + if (object) { + return [[task continueWithBlock:migrationBlock] continueWithResult:object]; + } + return task; + }]; + } + return [task continueWithSuccessBlock:^id(BFTask *task) { + PFObject *object = task.result; + return [[object _pinInBackgroundWithName:pinName includeChildren:NO] continueWithBlock:^id(BFTask *task) { + BFTask *resultTask = [BFTask taskWithResult:object]; + + // Only delete if we successfully pin it so that it retries the migration next time. + if (!task.error && !task.exception && !task.cancelled) { + NSString *path = [[Parse _currentManager].fileManager parseDataItemPathForPathComponent:fileName]; + return [[PFFileManager removeItemAtPathAsync:path] continueWithBlock:^id(BFTask *task) { + // We don't care if it fails to delete the file, so return the + return resultTask; + }]; + } + return resultTask; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - REST operations +///-------------------------------------- + +/*! + Encodes parse object into NSDictionary suitable for persisting into LDS. + */ +- (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs { + @synchronized (lock) { + [self checkForChangesToMutableContainers]; + PFObjectState *state = self._state; + return [self RESTDictionaryWithObjectEncoder:objectEncoder + operationSetUUIDs:operationSetUUIDs + state:state + operationSetQueue:operationSetQueue]; + } +} + +- (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs + state:(PFObjectState *)state + operationSetQueue:(NSArray *)queue { + NSMutableDictionary *result = [[state dictionaryRepresentationWithObjectEncoder:objectEncoder] mutableCopy]; + result[PFObjectClassNameRESTKey] = state.parseClassName; + result[PFObjectCompleteRESTKey] = @(state.complete); + + result[PFObjectIsDeletingEventuallyRESTKey] = @(_deletingEventually); + + // TODO (hallucinogen): based on some note from Android's toRest, we'll need to put this + // stuff somewhere else + NSMutableArray *operations = [NSMutableArray array]; + NSMutableArray *mutableOperationSetUUIDs = [NSMutableArray array]; + for (PFOperationSet *operation in queue) { + NSArray *ooSetUUIDs = nil; + [operations addObject:[operation RESTDictionaryUsingObjectEncoder:objectEncoder + operationSetUUIDs:&ooSetUUIDs]]; + [mutableOperationSetUUIDs addObjectsFromArray:ooSetUUIDs]; + } + + *operationSetUUIDs = mutableOperationSetUUIDs; + + result[PFObjectOperationsRESTKey] = operations; + return result; +} + +- (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *)decoder { + @synchronized (lock) { + BOOL mergeServerData = NO; + + PFMutableObjectState *state = [self._state mutableCopy]; + + // If LDS has `updatedAt` and we have it - compare, then if stuff is newer - merge. + // If LDS doesn't have `updatedAt` and we don't have it - merge anyway. + NSString *updatedAtString = object[PFObjectUpdatedAtRESTKey]; + if (updatedAtString) { + NSDate *updatedDate = [[PFDateFormatter sharedFormatter] dateFromString:updatedAtString]; + mergeServerData = ([state.updatedAt compare:updatedDate] != NSOrderedDescending); + } else if (!state.updatedAt) { + mergeServerData = YES; + } + [object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([key isEqualToString:PFObjectOperationsRESTKey]) { + PFOperationSet *remoteOperationSet = nil; + NSArray *operations = (NSArray *)obj; + if ([operations count] > 0) { + // Add and enqueue any saveEventually operations, roll forward any other + // operations sets (operations sets here are generally failed/incomplete saves). + PFOperationSet *current = nil; + for (id rawOperationSet in operations) { + PFOperationSet *operationSet = [PFOperationSet operationSetFromRESTDictionary:rawOperationSet + usingDecoder:decoder]; + if (operationSet.saveEventually) { + if (current != nil) { + [[self unsavedChanges] mergeOperationSet:current]; + current = nil; + } + + // Check if queue already contains this operation set and discard it if does + if (![self _containsOperationSet:operationSet]) { + // Insert the `saveEventually` operationSet before the last operation set at all times. + NSUInteger index = ([operationSetQueue count] == 0 ? 0 : [operationSetQueue count] - 1); + [operationSetQueue insertObject:operationSet atIndex:index]; + [self _enqueueSaveEventuallyOperationAsync:operationSet]; + } + + continue; + } + + if (current != nil) { + [operationSet mergeOperationSet:current]; + } + current = operationSet; + } + if (current != nil) { + remoteOperationSet = current; + } + } + + PFOperationSet *localOperationSet = [self unsavedChanges]; + if (localOperationSet.updatedAt != nil && + [localOperationSet.updatedAt compare:remoteOperationSet.updatedAt] != NSOrderedAscending) { + [localOperationSet mergeOperationSet:remoteOperationSet]; + } else { + PFConsistencyAssert(remoteOperationSet, @"'remoteOperationSet' should not be nil."); + NSUInteger index = [operationSetQueue indexOfObject:localOperationSet]; + [remoteOperationSet mergeOperationSet:localOperationSet]; + [operationSetQueue replaceObjectAtIndex:index withObject:remoteOperationSet]; + } + + return; + } + + if ([key isEqualToString:PFObjectCompleteRESTKey]) { + // If server data is complete, consider this object to be fetched + state.complete = state.complete || [obj boolValue]; + return; + } + if ([key isEqualToString:PFObjectIsDeletingEventuallyRESTKey]) { + _deletingEventually = [obj intValue]; + return; + } + + [_availableKeys addObject:key]; + + // If server data in dictionary is older - don't merge it. + if (!mergeServerData) { + return; + } + + if ([key isEqualToString:PFObjectTypeRESTKey] || [key isEqualToString:PFObjectClassNameRESTKey]) { + return; + } + if ([key isEqualToString:PFObjectObjectIdRESTKey]) { + state.objectId = obj; + return; + } + if ([key isEqualToString:PFObjectCreatedAtRESTKey]) { + [state setCreatedAtFromString:obj]; + return; + } + if ([key isEqualToString:PFObjectUpdatedAtRESTKey]) { + [state setUpdatedAtFromString:obj]; + return; + } + + if ([key isEqualToString:PFObjectACLRESTKey]) { + PFACL *acl = [PFACL ACLWithDictionary:obj]; + [state setServerDataObject:acl forKey:PFObjectACLRESTKey]; + [self checkpointMutableContainer:acl]; + return; + } + + // Should be decoded + id decodedObject = [decoder decodeObject:obj]; + if (PFObjectValueIsKindOfMutableContainerClass(decodedObject)) { + [self checkpointMutableContainer:decodedObject]; + } + [state setServerDataObject:decodedObject forKey:key]; + }]; + if (state.updatedAt == nil && state.createdAt != nil) { + state.updatedAt = state.createdAt; + } + BOOL previousDirtyState = dirty; + self._state = state; + dirty = previousDirtyState; + + if (mergeServerData) { + if ([object[PFObjectCompleteRESTKey] boolValue]) { + [self removeOldKeysAfterFetch:object]; + } else { + // Unmark the object as fetched, because we merged from incomplete new data. + [self setHasBeenFetched:NO]; + } + } + [self rebuildEstimatedData]; + [self checkpointAllMutableContainers]; + } +} + +///-------------------------------------- +#pragma mark - Eventually Helper +///-------------------------------------- + +/*! + Enqueues saveEventually operation asynchronously. + + @returns A task which result is a saveEventually task. + */ +- (BFTask *)_enqueueSaveEventuallyWithChildren:(BOOL)saveChildren { + return [_eventuallyTaskQueue enqueue:^BFTask *(BFTask *toAwait) { + PFUser *currentUser = [PFUser currentUser]; + NSString *sessionToken = currentUser.sessionToken; + return [[toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [self _validateSaveEventuallyAsync]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @synchronized (lock) { + [self _objectWillSave]; + if (![self isDirty:NO]) { + return [BFTask taskWithResult:@YES]; + } + } + + BFTask *saveChildrenTask = nil; + if (saveChildren) { + saveChildrenTask = [[self class] _enqueueSaveEventuallyChildrenOfObject:self currentUser:currentUser]; + } else { + saveChildrenTask = [BFTask taskWithResult:nil]; + } + + return [saveChildrenTask continueWithSuccessBlock:^id(BFTask *task) { + BFTask *saveTask = nil; + @synchronized (lock) { + // Snapshot the current set of changes, and push a new changeset into the queue. + PFOperationSet *changes = [self unsavedChanges]; + changes.saveEventually = YES; + [self startSave]; + [self _checkSaveParametersWithCurrentUser:currentUser]; + PFRESTCommand *command = [self _constructSaveCommandForChanges:changes + sessionToken:sessionToken + objectEncoder:[PFPointerOrLocalIdObjectEncoder objectEncoder]]; + + // Enqueue the eventually operation! + saveTask = [[Parse _currentManager].eventuallyQueue enqueueCommandInBackground:command withObject:self]; + [self _enqueueSaveEventuallyOperationAsync:changes]; + } + saveTask = [saveTask continueWithBlock:^id(BFTask *task) { + @try { + if (!task.isCancelled && !task.exception && !task.error) { + PFCommandResult *result = task.result; + // PFPinningEventuallyQueue handle save result directly. + if (![Parse _currentManager].offlineStoreLoaded) { + return [self handleSaveResultAsync:result.result]; + } + } + return task; + } @finally { + [[Parse _currentManager].eventuallyQueue _notifyTestHelperObjectUpdated]; + } + }]; + return [BFTask taskWithResult:saveTask]; + }]; + }]; + }]; +} + + +/*! + Enqueues the saveEventually PFOperationSet in PFObject taskQueue + */ +- (BFTask *)_enqueueSaveEventuallyOperationAsync:(PFOperationSet *)operationSet { + if (!operationSet.isSaveEventually) { + NSString *message = @"This should only be used to enqueue saveEventually operation sets"; + NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException + reason:message + userInfo:nil]; + return [BFTask taskWithException:exception]; + } + + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + // Use default priority background to break a chain and make sure this operation is truly asynchronous + return [toAwait continueWithExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id(BFTask *task) { + PFEventuallyQueue *queue = [Parse _currentManager].eventuallyQueue; + id queueSubClass = (id)queue; + return [queueSubClass _waitForOperationSet:operationSet eventuallyPin:nil]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Data model manipulation +///-------------------------------------- + +- (NSMutableDictionary *)_convertToDictionaryForSaving:(PFOperationSet *)changes + withObjectEncoder:(PFEncoder *)encoder { + @synchronized (lock) { + [self checkForChangesToMutableContainers]; + + NSMutableDictionary *serialized = [NSMutableDictionary dictionary]; + [changes enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + serialized[key] = obj; + }]; + return [encoder encodeObject:serialized]; + } +} + +/*! + performOperation:forKey: is like setObject:forKey, but instead of just taking a + new value, it takes a PFFieldOperation that modifies the value. + */ +- (void)performOperation:(PFFieldOperation *)operation forKey:(NSString *)key { + @synchronized (lock) { + id newValue = [_estimatedData applyFieldOperation:operation forKey:key]; + + PFFieldOperation *oldOperation = [[self unsavedChanges] objectForKey:key]; + PFFieldOperation *newOperation = [operation mergeWithPrevious:oldOperation]; + [[self unsavedChanges] setObject:newOperation forKey:key]; + [self checkpointMutableContainer:newValue]; + [_availableKeys addObject:key]; + } +} + +- (BOOL)_containsOperationSet:(PFOperationSet *)operationSet { + @synchronized (lock) { + for (PFOperationSet *existingOperationSet in operationSetQueue) { + if (existingOperationSet == operationSet || + [existingOperationSet.uuid isEqualToString:operationSet.uuid]) { + return YES; + } + } + } + return NO; +} + +/*! + Returns the set of PFFieldOperations that will be sent in the next save. + */ +- (PFOperationSet *)unsavedChanges { + @synchronized (lock) { + return [operationSetQueue lastObject]; + } +} + +/*! + @returns YES if there's unsaved changes in this object. This complements ivar `dirty` for `isDirty` check. + */ +- (BOOL)_hasChanges { + @synchronized (lock) { + return [[self unsavedChanges] count] > 0; + } +} + +/*! + @returns YES if this PFObject has operations in operationSetQueue that haven't been completed yet, + NO if there are no operations in the operationSetQueue. + */ +- (BOOL)_hasOutstandingOperations { + @synchronized (lock) { + // > 1 since 1 is unsaved changes. + return [operationSetQueue count] > 1; + } +} + +- (void)rebuildEstimatedData { + @synchronized (lock) { + _estimatedData = [PFObjectEstimatedData estimatedDataFromServerData:self._state.serverData + operationSetQueue:operationSetQueue]; + } +} + +- (PFObject *)mergeFromObject:(PFObject *)other { + @synchronized (lock) { + if (self == other) { + // If they point to the same instance, then don't merge. + return self; + } + + PFMutableObjectState *state = [self._state mutableCopy]; + state.objectId = other.objectId; + state.createdAt = other.createdAt; + state.updatedAt = other.updatedAt; + state.serverData = [other._state.serverData mutableCopy]; + self._state = state; + [self checkpointAllMutableContainers]; + + dirty = NO; + + [self rebuildEstimatedData]; + return self; + } +} + +- (void)_mergeAfterFetchWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData { + @synchronized (lock) { + [self checkForChangesToMutableContainers]; + [self _mergeFromServerWithResult:result decoder:decoder completeData:completeData]; + if (completeData) { + [self removeOldKeysAfterFetch:result]; + } + [self rebuildEstimatedData]; + [self checkpointAllMutableContainers]; + } +} + +- (void)removeOldKeysAfterFetch:(NSDictionary *)result { + @synchronized (lock) { + PFMutableObjectState *state = [self._state mutableCopy]; + + NSMutableDictionary *removedDictionary = [NSMutableDictionary dictionaryWithDictionary:state.serverData]; + [removedDictionary removeObjectsForKeys:[result allKeys]]; + + NSArray *removedKeys = [removedDictionary allKeys]; + [state removeServerDataObjectsForKeys:removedKeys]; + [_availableKeys minusSet:[NSSet setWithArray:removedKeys]]; + + self._state = state; + } +} + +- (void)_mergeAfterSaveWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder { + @synchronized (lock) { + PFOperationSet *operationsBeforeSave = operationSetQueue[0]; + [operationSetQueue removeObjectAtIndex:0]; + + if (!result) { + // Merge the data from the failed save into the next save. + PFOperationSet *operationsForNextSave = operationSetQueue[0]; + [operationsForNextSave mergeOperationSet:operationsBeforeSave]; + } else { + // Merge the data from the save and the data from the server into serverData. + [self checkForChangesToMutableContainers]; + + PFMutableObjectState *state = [self._state mutableCopy]; + [state applyOperationSet:operationsBeforeSave]; + self._state = state; + + [self _mergeFromServerWithResult:result decoder:decoder completeData:NO]; + [self rebuildEstimatedData]; + [self checkpointAllMutableContainers]; + } + } +} + +- (void)_mergeFromServerWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData { + @synchronized (lock) { + PFMutableObjectState *state = [self._state mutableCopy]; + + // If the server's data is complete, consider this object to be fetched. + state.complete |= completeData; + + [result enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if ([key isEqualToString:PFObjectObjectIdRESTKey]) { + state.objectId = obj; + } else if ([key isEqualToString:PFObjectCreatedAtRESTKey]) { + // These dates can be passed in as NSDate or as NSString, + // depending on whether they were wrapped inside JSONObject with __type: Date or not. + if ([obj isKindOfClass:[NSDate class]]) { + state.createdAt = obj; + } else { + [state setCreatedAtFromString:obj]; + } + } else if ([key isEqualToString:PFObjectUpdatedAtRESTKey]) { + // These dates can be passed in as NSDate or as NSString, + // depending on whether they were wrapped inside JSONObject with __type: Date or not. + if ([obj isKindOfClass:[NSDate class]]) { + state.updatedAt = obj; + } else { + [state setUpdatedAtFromString:obj]; + } + } else if ([key isEqualToString:PFObjectACLRESTKey]) { + PFACL *acl = [PFACL ACLWithDictionary:obj]; + [state setServerDataObject:acl forKey:key]; + [self checkpointMutableContainer:acl]; + } else { + [state setServerDataObject:[decoder decodeObject:obj] forKey:key]; + } + }]; + if (state.updatedAt == nil && state.createdAt != nil) { + state.updatedAt = state.createdAt; + } + self._state = state; + [_availableKeys addObjectsFromArray:[result allKeys]]; + + dirty = NO; + } +} + +///-------------------------------------- +#pragma mark - Command handlers +///-------------------------------------- + +// We can't get rid of these handlers, because subclasses override them +// to add special actions after operations. + +- (BFTask *)handleSaveResultAsync:(NSDictionary *)result { + BFTask *task = [BFTask taskWithResult:nil]; + + NSDictionary *fetchedObjects = [self _collectFetchedObjects]; + + [task continueWithBlock:^id(BFTask *task) { + PFKnownParseObjectDecoder *decoder = [PFKnownParseObjectDecoder decoderWithFetchedObjects:fetchedObjects]; + @synchronized (self.lock) { + // TODO (hallucinogen): t5611821 we need to make mergeAfterSave that accepts decoder and operationBeforeSave + [self _mergeAfterSaveWithResult:result decoder:decoder]; + } + return nil; + }]; + + PFOfflineStore *store = [Parse _currentManager].offlineStore; + if (store != nil) { + task = [task continueWithBlock:^id(BFTask *task) { + return [store updateDataForObjectAsync:self]; + }]; + } + + return [task continueWithBlock:^id(BFTask *task) { + @synchronized (lock) { + if (self.saveDelegate) { + [self.saveDelegate invoke:self error:nil]; + } + return [BFTask taskWithResult:@(!!result)]; + } + }]; +} + +///-------------------------------------- +#pragma mark - Asynchronous operations +///-------------------------------------- + +- (void)startSave { + @synchronized (lock) { + [operationSetQueue addObject:[[PFOperationSet alloc] init]]; + } +} + +- (BFTask *)saveAsync:(BFTask *)toAwait { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentObjectAsync] continueWithBlock:^id(BFTask *task) { + PFUser *currentUser = task.result; + NSString *sessionToken = currentUser.sessionToken; + + BFTask *await = toAwait ?: [BFTask taskWithResult:nil]; + return [[await continueAsyncWithBlock:^id(BFTask *task) { + PFOfflineStore *offlineStore = [Parse _currentManager].offlineStore; + if (offlineStore != nil) { + return [offlineStore fetchObjectLocallyAsync:self]; + } + return nil; + }] continueWithBlock:^id(BFTask *task) { + @synchronized (lock) { + if (![self isDirty:YES]) { + return [BFTask taskWithResult:@YES]; + } + + [self _objectWillSave]; + + // Snapshot the current set of changes, and push a new changeset into the queue. + PFOperationSet *changes = [self unsavedChanges]; + + [self startSave]; + BFTask *childrenTask = [self _saveChildrenInBackgroundWithCurrentUser:currentUser + sessionToken:sessionToken]; + if (!dirty && ![changes count]) { + return childrenTask; + } + return [[childrenTask continueWithSuccessBlock:^id(BFTask *task) { + [self _checkSaveParametersWithCurrentUser:currentUser]; + PFRESTCommand *command = [self _constructSaveCommandForChanges:changes + sessionToken:sessionToken + objectEncoder:[PFPointerObjectEncoder objectEncoder]]; + return [[Parse _currentManager].commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueAsyncWithBlock:^id(BFTask *task) { + if (task.isCancelled || task.exception || task.error) { + // If there was an error, we want to roll forward the save changes before rethrowing. + BFTask *commandRunnerTask = task; + return [[self handleSaveResultAsync:nil] continueWithBlock:^id(BFTask *task) { + return commandRunnerTask; + }]; + } + PFCommandResult *result = task.result; + return [self handleSaveResultAsync:result.result]; + }]; + } + }]; + }]; +} + +- (BFTask *)fetchAsync:(BFTask *)toAwait { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[[self class] objectController] fetchObjectAsync:self withSessionToken:sessionToken]; + }]; + }]; +} + +- (BFTask *)deleteAsync:(BFTask *)toAwait { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[[self class] objectController] deleteObjectAsync:self withSessionToken:sessionToken]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Command constructors +///-------------------------------------- + +- (PFRESTCommand *)_constructSaveCommandForChanges:(PFOperationSet *)changes + sessionToken:(NSString *)sessionToken + objectEncoder:(PFEncoder *)encoder { + @synchronized (lock) { + NSDictionary *parameters = [self _convertToDictionaryForSaving:changes withObjectEncoder:encoder]; + + if (self._state.objectId) { + return [PFRESTObjectCommand updateObjectCommandForObjectState:self._state + changes:parameters + operationSetUUID:changes.uuid + sessionToken:sessionToken]; + } + + return [PFRESTObjectCommand createObjectCommandForObjectState:self._state + changes:parameters + operationSetUUID:changes.uuid + sessionToken:sessionToken]; + + } +} + +- (PFRESTCommand *)_currentDeleteCommandWithSessionToken:(NSString *)sessionToken { + return [PFRESTObjectCommand deleteObjectCommandForObjectState:self._state withSessionToken:sessionToken]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)_setObject:(id)object forKey:(NSString *)key onlyIfDifferent:(BOOL)onlyIfDifferent { + PFParameterAssert(object != nil && key != nil, + @"Can't use nil for keys or values on PFObject. Use NSNull for values."); + PFParameterAssert([key isKindOfClass:[NSString class]], @"PFObject keys must be NSStrings."); + + if (onlyIfDifferent) { + id currentObject = self[key]; + if (currentObject == object || + [currentObject isEqual:object]) { + return; + } + } + + @synchronized (lock) { + if ([object isKindOfClass:[PFFieldOperation class]]) { + [self performOperation:object forKey:key]; + return; + } + + PFObjectAssertValueIsKindOfValidClass(object); + [self performOperation:[PFSetOperation setWithValue:object] forKey:key]; + } +} + +///-------------------------------------- +#pragma mark - Misc helpers +///-------------------------------------- + +- (NSString *)displayObjectId { + return self._state.objectId ?: @"new"; +} + +- (NSString *)displayClassName { + return self._state.parseClassName; +} + +- (void)registerSaveListener:(void (^)(id result, NSError *error))callback { + @synchronized (lock) { + if (!self.saveDelegate) { + self.saveDelegate = [[PFMulticastDelegate alloc] init]; + } + [self.saveDelegate subscribe:callback]; + } +} + +- (void)unregisterSaveListener:(void (^)(id result, NSError *error))callback { + @synchronized (lock) { + if (!self.saveDelegate) { + self.saveDelegate = [[PFMulticastDelegate alloc] init]; + } + [self.saveDelegate unsubscribe:callback]; + } +} + +- (PFACL *)ACLWithoutCopying { + @synchronized (lock) { + return _estimatedData[@"ACL"]; + } +} + +// Overriden by classes which want to ignore the default ACL. +- (void)setDefaultValues { + if ([self needsDefaultACL]) { + PFACL *defaultACL = [PFACL defaultACL]; + if (defaultACL) { + self.ACL = defaultACL; + } + } +} + +- (BOOL)needsDefaultACL { + return YES; +} + +- (NSDictionary *)_collectFetchedObjects { + NSMutableDictionary *fetchedObjects = [NSMutableDictionary dictionary]; + @synchronized (lock) { + NSDictionary *dictionary = _estimatedData.dictionaryRepresentation; + [PFInternalUtils traverseObject:dictionary usingBlock:^id(id obj) { + if ([obj isKindOfClass:[PFObject class]]) { + PFObject *object = obj; + NSString *objectId = object.objectId; + if (objectId && [object isDataAvailable]) { + fetchedObjects[objectId] = object; + } + } + return obj; + }]; + } + return fetchedObjects; +} + +@end + +@implementation PFObject + +@synthesize _availableKeys = _availableKeys; + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + if (!_pfinternal_state) { + PFConsistencyAssert([self conformsToProtocol:@protocol(PFSubclassing)], + @"Can only call -[PFObject init] on subclasses conforming to PFSubclassing."); + [PFObject assertSubclassIsRegistered:[self class]]; + _pfinternal_state = [[self class] _newObjectStateWithParseClassName:[[self class] parseClassName] + objectId:nil + isComplete:YES]; + } + [[self class] _assertValidInstanceClassName:_pfinternal_state.parseClassName]; + + lock = [[NSObject alloc] init]; + operationSetQueue = [NSMutableArray arrayWithObject:[[PFOperationSet alloc] init]]; + _estimatedData = [PFObjectEstimatedData estimatedDataFromServerData:_pfinternal_state.serverData + operationSetQueue:operationSetQueue]; + _availableKeys = [NSMutableSet set]; + hashedObjectsCache = [[NSMutableDictionary alloc] init]; + self.taskQueue = [[PFTaskQueue alloc] init]; + _eventuallyTaskQueue = [[PFTaskQueue alloc] init]; + + if (_pfinternal_state.complete) { + dirty = YES; + [self setDefaultValues]; + } + + return self; +} + +- (instancetype)initWithClassName:(NSString *)className { + PFObjectState *state = [[self class] _newObjectStateWithParseClassName:className objectId:nil isComplete:YES]; + return [self initWithObjectState:state]; +} + +- (instancetype)initWithObjectState:(PFObjectState *)state { + _pfinternal_state = state; + return [self init]; +} + ++ (instancetype)objectWithClassName:(NSString *)className + objectId:(NSString *)objectId + completeData:(BOOL)completeData { + Class class = [[[self class] subclassingController] subclassForParseClassName:className] ?: [PFObject class]; + PFObjectState *state = [class _newObjectStateWithParseClassName:className objectId:objectId isComplete:completeData]; + PFObject *object = [[class alloc] initWithObjectState:state]; + if (!completeData) { + PFConsistencyAssert(![object _hasChanges], + @"The init method of %@ set values on the object, which is not allowed.", class); + } + return object; +} + ++ (instancetype)objectWithClassName:(NSString *)className { + return [self objectWithClassName:className objectId:nil completeData:YES]; +} + ++ (instancetype)objectWithClassName:(NSString *)className dictionary:(NSDictionary *)dictionary { + PFObject *object = [self objectWithClassName:className]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + object[key] = obj; + }]; + return object; +} + ++ (instancetype)objectWithoutDataWithClassName:(NSString *)className objectId:(NSString *)objectId { + // Try get single instance from OfflineStore + PFOfflineStore *store = [Parse _currentManager].offlineStore; + if (store != nil && objectId != nil) { + PFObject *singleObject = [store getOrCreateObjectWithoutDataWithClassName:className objectId:objectId]; + if (singleObject) { + return singleObject; + } + } + + // Local Datastore is not enabled or cannot found the single instance using objectId, let's use the old way + return [self objectWithClassName:className objectId:objectId completeData:NO]; +} + +#pragma mark Subclassing + ++ (instancetype)object { + PFConsistencyAssert([self conformsToProtocol:@protocol(PFSubclassing)], + @"Can only call +object on subclasses conforming to PFSubclassing"); + NSString *className = [(id)self parseClassName]; + Class class = [[self subclassingController] subclassForParseClassName:className] ?: [PFObject class]; + return [class objectWithClassName:className]; +} + ++ (instancetype)objectWithoutDataWithObjectId:(NSString *)objectId { + PFConsistencyAssert([self conformsToProtocol:@protocol(PFSubclassing)], + @"Can only call objectWithoutDataWithObjectId: on subclasses conforming to PFSubclassing"); + return [self objectWithoutDataWithClassName:[(id)self parseClassName] objectId:objectId]; +} + +#pragma mark Private + ++ (instancetype)objectWithoutDataWithClassName:(NSString *)className localId:(NSString *)localId { + PFObject *object = [self objectWithoutDataWithClassName:className objectId:nil]; + object.localId = localId; + return object; +} + +///-------------------------------------- +#pragma mark - PFObjectPrivateSubclass +///-------------------------------------- + +#pragma mark State + ++ (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className + objectId:(NSString *)objectId + isComplete:(BOOL)complete { + return [PFObjectState stateWithParseClassName:className objectId:objectId isComplete:complete]; +} + +///-------------------------------------- +#pragma mark - Validation +///-------------------------------------- + +- (BFTask PF_GENERIC(PFVoid) *)_validateFetchAsync { + if (!self._state.objectId) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId + message:@"Can't fetch an object that hasn't been saved to the server."]; + return [BFTask taskWithError:error]; + } + return [BFTask taskWithResult:nil]; +} + +- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync { + return [BFTask taskWithResult:nil]; +} + +- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync { + return [BFTask taskWithResult:nil]; +} + +#pragma mark Object Will Save + +- (void)_objectWillSave { + // Do nothing. +} + +///-------------------------------------- +#pragma mark - Properties +///-------------------------------------- + +- (void)set_state:(PFObjectState *)state { + @synchronized(lock) { + NSString *oldObjectId = _pfinternal_state.objectId; + if (self._state != state) { + _pfinternal_state = [state copy]; + } + + NSString *newObjectId = _pfinternal_state.objectId; + if (![PFObjectUtilities isObject:oldObjectId equalToObject:newObjectId]) { + [self _notifyObjectIdChangedFrom:oldObjectId toObjectId:newObjectId]; + } + } +} + +- (PFObjectState *)_state { + @synchronized(lock) { + return _pfinternal_state; + } +} + +- (PFObjectEstimatedData *)_estimatedData { + @synchronized (lock) { + return _estimatedData; + } +} + +- (void)setObjectId:(NSString *)objectId { + @synchronized (lock) { + NSString *oldObjectId = self._state.objectId; + if ([PFObjectUtilities isObject:oldObjectId equalToObject:objectId]) { + return; + } + + dirty = YES; + + PFMutableObjectState *state = [self._state mutableCopy]; + state.objectId = objectId; + _pfinternal_state = state; + + [self _notifyObjectIdChangedFrom:oldObjectId toObjectId:objectId]; + } +} + +- (NSString *)objectId { + return self._state.objectId; +} + +- (void)_notifyObjectIdChangedFrom:(NSString *)fromObjectId toObjectId:(NSString *)toObjectId { + @synchronized (self.lock) { + // The OfflineStore might raise exception if this object already had a different objectId. + PFOfflineStore *store = [Parse _currentManager].offlineStore; + if (store != nil) { + [store updateObjectIdForObject:self oldObjectId:fromObjectId newObjectId:toObjectId]; + } + if (self.localId) { + [[Parse _currentManager].coreManager.objectLocalIdStore setObjectId:toObjectId forLocalId:self.localId]; + self.localId = nil; + } + } +} + +- (NSString *)parseClassName { + return self._state.parseClassName; +} + +- (NSDate *)updatedAt { + return self._state.updatedAt; +} + +- (NSDate *)createdAt { + return self._state.createdAt; +} + +- (PFACL *)ACL { + return self[@"ACL"]; +} + +- (void)setACL:(PFACL *)ACL { + if (!ACL) { + [self removeObjectForKey:@"ACL"]; + } else { + self[@"ACL"] = ACL; + } +} + +// PFObject(): +@synthesize localId; +@synthesize taskQueue; + +// PFObject(Private): +@synthesize saveDelegate; + +///-------------------------------------- +#pragma mark - PFObject factory methods for Subclassing +///-------------------------------------- + +// Reverse compatibility note: many people may have built PFObject subclasses before +// we officially supported them. Our implementation can do cool stuff, but requires +// the parseClassName class method. ++ (void)registerSubclass { + [[self subclassingController] registerSubclass:self]; +} + ++ (PFQuery *)query { + PFConsistencyAssert([self conformsToProtocol:@protocol(PFSubclassing)], + @"+[PFObject query] can only be called on subclasses conforming to PFSubclassing."); + [PFObject assertSubclassIsRegistered:self]; + return [PFQuery queryWithClassName:[(id)self parseClassName]]; +} + ++ (PFQuery *)queryWithPredicate:(NSPredicate *)predicate { + PFConsistencyAssert([self conformsToProtocol:@protocol(PFSubclassing)], + @"+[PFObject queryWithPredicate:] can only be called on subclasses conforming to PFSubclassing."); + [PFObject assertSubclassIsRegistered:[self class]]; + return [PFQuery queryWithClassName:[(id)self parseClassName] predicate:predicate]; +} + ++ (void)assertSubclassIsRegistered:(Class)subclass { + // If people hacked their own subclass together before we supported it officially, we shouldn't break their app. + if ([subclass conformsToProtocol:@protocol(PFSubclassing)]) { + Class registration = [[self subclassingController] subclassForParseClassName:[subclass parseClassName]]; + + // It's OK to subclass a subclass (i.e. custom PFUser implementation) + PFConsistencyAssert(registration && (registration == subclass || [registration isSubclassOfClass:subclass]), + @"The class %@ must be registered with registerSubclass before using Parse.", subclass); + } +} + +///-------------------------------------- +#pragma mark - Delete commands +///-------------------------------------- + +- (BOOL)delete { + return [self delete:nil]; +} + +- (BOOL)delete:(NSError **)error { + return [[[self deleteInBackground] waitForResult:error] boolValue]; +} + +- (BFTask *)deleteInBackground { + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [[self deleteAsync:toAwait] continueWithSuccessResult:@YES]; + }]; +} + +- (void)deleteInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +- (void)deleteInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self deleteInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Save commands +///-------------------------------------- + +- (BOOL)save { + return [self save:nil]; +} + +- (BOOL)save:(NSError **)error { + return [[[self saveInBackground] waitForResult:error] boolValue]; +} + +- (BFTask *)saveInBackground { + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [self saveAsync:toAwait]; + }]; +} + +- (void)saveInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self saveInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (BFTask *)saveEventually { + return [[self _enqueueSaveEventuallyWithChildren:YES] continueWithSuccessBlock:^id(BFTask *task) { + // The result of the previous task will be an instance of BFTask. + // Returning it here will trigger the whole task stack become an actual save task. + return task.result; + }]; +} + +- (void)saveEventually:(PFBooleanResultBlock)block { + [[self saveEventually] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (BFTask *)deleteEventually { + return [[[_eventuallyTaskQueue enqueue:^BFTask *(BFTask *toAwait) { + NSString *sessionToken = [PFUser currentSessionToken]; + return [[toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [self _validateDeleteAsync]; + }] continueWithSuccessBlock:^id(BFTask *task) { + @synchronized (lock) { + _deletingEventually += 1; + + PFOfflineStore *store = [Parse _currentManager].offlineStore; + BFTask *updateDataTask = store ? [store updateDataForObjectAsync:self] : [BFTask taskWithResult:nil]; + + PFRESTCommand *command = [self _currentDeleteCommandWithSessionToken:sessionToken]; + BFTask *deleteTask = [updateDataTask continueWithBlock:^id(BFTask *task) { + return [[Parse _currentManager].eventuallyQueue enqueueCommandInBackground:command withObject:self]; + }]; + deleteTask = [deleteTask continueWithSuccessBlock:^id(BFTask *task) { + // PFPinningEventuallyQueue handles delete result directly. + if (![Parse _currentManager].offlineStoreLoaded) { + PFCommandResult *result = task.result; + return [[[self class] objectController] processDeleteResultAsync:result.result forObject:self]; + } + return task; + }]; + return deleteTask; + } + }]; + }] continueWithSuccessBlock:^id(BFTask *task) { + // The result of the previous task will be an instance of BFTask. + // Returning it here will trigger the whole task stack become an actual save task. + return task.result; + }] continueWithSuccessResult:@YES]; +} + +///-------------------------------------- +#pragma mark - Dirtiness +///-------------------------------------- + +- (BOOL)isDirty { + return [self isDirty:YES]; +} + +- (BOOL)isDirtyForKey:(NSString *)key { + @synchronized (lock) { + [self checkForChangesToMutableContainer:_estimatedData[key] forKey:key]; + return !![[self unsavedChanges] objectForKey:key]; + } +} + +///-------------------------------------- +#pragma mark - Fetch +///-------------------------------------- + +- (BOOL)isDataAvailable { + return self._state.complete; +} + +- (instancetype)refresh { + return [self fetch]; +} + +- (instancetype)refresh:(NSError **)error { + return [self fetch:error]; +} + +- (void)refreshInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self fetchInBackgroundWithTarget:target selector:selector]; +} + +- (void)refreshInBackgroundWithBlock:(PFObjectResultBlock)block { + [self fetchInBackgroundWithBlock:block]; +} + +- (instancetype)fetch { + return [self fetch:nil]; +} + +- (instancetype)fetch:(NSError **)error { + return [[self fetchInBackground] waitForResult:error]; +} + +- (BFTask *)fetchInBackground { + if (!self._state.objectId) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorMissingObjectId + message:@"Can't refresh an object that hasn't been saved to the server."]; + return [BFTask taskWithError:error]; + } + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [self fetchAsync:toAwait]; + }]; +} + +- (void)fetchInBackgroundWithBlock:(PFObjectResultBlock)block { + [[self fetchInBackground] thenCallBackOnMainThreadAsync:block]; +} + +- (void)fetchInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:object object:error]; + }]; +} + +- (instancetype)fetchIfNeeded { + return [self fetchIfNeeded:nil]; +} + +- (instancetype)fetchIfNeeded:(NSError **)error { + return [[self fetchIfNeededInBackground] waitForResult:error]; +} + +- (BFTask *)fetchIfNeededInBackground { + if ([self isDataAvailable]) { + return [BFTask taskWithResult:self]; + } + return [self fetchInBackground]; +} + +- (void)fetchIfNeededInBackgroundWithBlock:(PFObjectResultBlock)block { + [[self fetchIfNeededInBackground] thenCallBackOnMainThreadAsync:block]; +} + +- (void)fetchIfNeededInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:object object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Fetching Many Objects +///-------------------------------------- + ++ (NSArray *)fetchAll:(NSArray *)objects { + return [self fetchAll:objects error:nil]; +} + ++ (NSArray *)fetchAllIfNeeded:(NSArray *)objects { + return [self fetchAllIfNeeded:objects error:nil]; +} + ++ (NSArray *)fetchAll:(NSArray *)objects error:(NSError **)error { + return [[self fetchAllInBackground:objects] waitForResult:error]; +} + ++ (NSArray *)fetchAllIfNeeded:(NSArray *)objects error:(NSError **)error { + return [[self fetchAllIfNeededInBackground:objects] waitForResult:error]; +} + ++ (BFTask *)fetchAllInBackground:(NSArray *)objects { + // Snapshot the objects array. + NSArray *fetchObjects = [objects copy]; + + if (fetchObjects.count == 0) { + return [BFTask taskWithResult:fetchObjects]; + } + NSArray *uniqueObjects = [PFObjectBatchController uniqueObjectsArrayFromArray:fetchObjects omitObjectsWithData:NO]; + return [[[[self currentUserController] getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [PFObject _enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[self objectBatchController] fetchObjectsAsync:uniqueObjects withSessionToken:sessionToken]; + }]; + } forObjects:uniqueObjects]; + }] continueWithSuccessResult:fetchObjects]; +} + ++ (void)fetchAllInBackground:(NSArray *)objects target:(id)target selector:(SEL)selector { + [self fetchAllInBackground:objects block:^(NSArray *objects, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:objects object:error]; + }]; +} + ++ (void)fetchAllInBackground:(NSArray *)objects block:(PFArrayResultBlock)block { + [[self fetchAllInBackground:objects] thenCallBackOnMainThreadAsync:block]; +} + ++ (BFTask *)fetchAllIfNeededInBackground:(NSArray *)objects { + NSArray *fetchObjects = [objects copy]; + if (fetchObjects.count == 0) { + return [BFTask taskWithResult:fetchObjects]; + } + NSArray *uniqueObjects = [PFObjectBatchController uniqueObjectsArrayFromArray:fetchObjects omitObjectsWithData:YES]; + return [[[[self currentUserController] getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [PFObject _enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[self objectBatchController] fetchObjectsAsync:uniqueObjects withSessionToken:sessionToken]; + }]; + } forObjects:uniqueObjects]; + }] continueWithSuccessResult:fetchObjects]; +} + ++ (void)fetchAllIfNeededInBackground:(NSArray *)objects target:(id)target selector:(SEL)selector { + [self fetchAllIfNeededInBackground:objects block:^(NSArray *objects, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:objects object:error]; + }]; +} + ++ (void)fetchAllIfNeededInBackground:(NSArray *)objects block:(PFArrayResultBlock)block { + [[self fetchAllIfNeededInBackground:objects] thenCallBackOnMainThreadAsync:block]; +} + +///-------------------------------------- +#pragma mark - Fetch From Local Datastore +///-------------------------------------- + +- (instancetype)fetchFromLocalDatastore { + return [self fetchFromLocalDatastore:nil]; +} + +- (instancetype)fetchFromLocalDatastore:(NSError **)error { + return [[self fetchFromLocalDatastoreInBackground] waitForResult:error]; +} + +- (void)fetchFromLocalDatastoreInBackgroundWithBlock:(PFObjectResultBlock)block { + [[self fetchFromLocalDatastoreInBackground] thenCallBackOnMainThreadAsync:block]; +} + +- (BFTask *)fetchFromLocalDatastoreInBackground { + PFOfflineStore *store = [Parse _currentManager].offlineStore; + PFConsistencyAssert(store != nil, @"You must enable the local datastore before calling fetchFromLocalDatastore()."); + return [store fetchObjectLocallyAsync:self]; +} + +///-------------------------------------- +#pragma mark - Key/Value Accessors +///-------------------------------------- + +- (void)setObject:(id)object forKey:(NSString *)key { + [self _setObject:object forKey:key onlyIfDifferent:NO]; +} + +- (void)setObject:(id)object forKeyedSubscript:(NSString *)key { + [self setObject:object forKey:key]; +} + +- (id)objectForKey:(NSString *)key { + @synchronized (lock) { + PFConsistencyAssert([self isDataAvailableForKey:key], + @"Key \"%@\" has no data. Call fetchIfNeeded before getting its value.", key); + + id result = _estimatedData[key]; + if ([key isEqualToString:PFObjectACLRESTKey] && [result isKindOfClass:[PFACL class]]) { + PFACL *acl = result; + if ([acl isShared]) { + PFACL *copy = [acl createUnsharedCopy]; + self[PFObjectACLRESTKey] = copy; + return copy; + } + } + + // A relation may be deserialized without a parent or key. Either way, make sure it's consistent. + // TODO: (nlutsenko) This should be removable after we clean up the serialization code. + if ([result isKindOfClass:[PFRelation class]]) { + [result ensureParentIs:self andKeyIs:key]; + } + + return result; + } +} + +- (id)objectForKeyedSubscript:(NSString *)key { + return [self objectForKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key { + @synchronized (lock) { + if ([self objectForKey:key]) { + PFDeleteOperation *operation = [[PFDeleteOperation alloc] init]; + [self performOperation:operation forKey:key]; + } + } +} + +- (void)revert { + @synchronized (self.lock) { + if ([self isDirty]) { + NSMutableSet *persistentKeys = [NSMutableSet setWithArray:[self._state.serverData allKeys]]; + + PFOperationSet *unsavedChanges = [self unsavedChanges]; + for (PFOperationSet *operationSet in operationSetQueue) { + if (operationSet != unsavedChanges) { + [persistentKeys addObjectsFromArray:[operationSet.keyEnumerator allObjects]]; + } + } + + [unsavedChanges removeAllObjects]; + [_availableKeys intersectSet:persistentKeys]; + + [self rebuildEstimatedData]; + [self checkpointAllMutableContainers]; + } + } +} + +- (void)revertObjectForKey:(NSString *)key { + @synchronized (self.lock) { + if ([self isDirtyForKey:key]) { + [[self unsavedChanges] removeObjectForKey:key]; + [self rebuildEstimatedData]; + [_availableKeys removeObject:key]; + [self checkpointAllMutableContainers]; + } + } +} + +#pragma mark Relations + +- (PFRelation *)relationforKey:(NSString *)key { + return [self relationForKey:key]; +} + +- (PFRelation *)relationForKey:(NSString *)key { + @synchronized (lock) { + // All the sanity checking is done when addObject or + // removeObject is called on the relation. + PFRelation *relation = [PFRelation relationForObject:self forKey:key]; + + id object = _estimatedData[key]; + if ([object isKindOfClass:[PFRelation class]]) { + relation.targetClass = ((PFRelation *)object).targetClass; + } + return relation; + } +} + +#pragma mark Array + +- (void)addObject:(id)object forKey:(NSString *)key { + [self addObjectsFromArray:@[ object ] forKey:key]; +} + +- (void)addObjectsFromArray:(NSArray *)objects forKey:(NSString *)key { + [self performOperation:[PFAddOperation addWithObjects:objects] forKey:key]; +} + +- (void)addUniqueObject:(id)object forKey:(NSString *)key { + [self addUniqueObjectsFromArray:@[ object ] forKey:key]; +} + +- (void)addUniqueObjectsFromArray:(NSArray *)objects forKey:(NSString *)key { + [self performOperation:[PFAddUniqueOperation addUniqueWithObjects:objects] forKey:key]; +} + +- (void)removeObject:(id)object forKey:(NSString *)key { + [self removeObjectsInArray:@[ object ] forKey:key]; +} + +- (void)removeObjectsInArray:(NSArray *)objects forKey:(NSString *)key { + [self performOperation:[PFRemoveOperation removeWithObjects:objects] forKey:key]; +} + +#pragma mark Increment + +- (void)incrementKey:(NSString *)key { + [self incrementKey:key byAmount:@1]; +} + +- (void)incrementKey:(NSString *)key byAmount:(NSNumber *)amount { + [self performOperation:[PFIncrementOperation incrementWithAmount:amount] forKey:key]; +} + +///-------------------------------------- +#pragma mark - Key Value Coding +///-------------------------------------- + +- (id)valueForUndefinedKey:(NSString *)key { + return self[key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + self[key] = value; +} + +///-------------------------------------- +#pragma mark - Misc +///-------------------------------------- + +- (NSArray *)allKeys { + @synchronized (lock) { + return [_estimatedData allKeys]; + } +} + +- (NSString *)description { + static NSString *descriptionKey = @"PFObject-PrintingDescription"; + + NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary; + if ([threadDictionary[descriptionKey] boolValue]) { + return [self _flatDescription]; + } + threadDictionary[descriptionKey] = @YES; + NSString *description = [self _recursiveDescription]; + [threadDictionary removeObjectForKey:descriptionKey]; + return description; +} + +- (NSString *)_recursiveDescription { + @synchronized (lock) { + return [NSString stringWithFormat:@"%@ %@", + [self _flatDescription], [_estimatedData.dictionaryRepresentation description]]; + } +} + +- (NSString *)_flatDescription { + @synchronized (lock) { + return [NSString stringWithFormat:@"<%@: %p, objectId: %@, localId: %@>", + self.displayClassName, self, [self displayObjectId], localId]; + } +} + +///-------------------------------------- +#pragma mark - Save all +///-------------------------------------- + ++ (BOOL)saveAll:(NSArray *)objects { + return [PFObject saveAll:objects error:nil]; +} + ++ (BOOL)saveAll:(NSArray *)objects error:(NSError **)error { + return [[[self saveAllInBackground:objects] waitForResult:error] boolValue]; +} + ++ (BFTask *)saveAllInBackground:(NSArray *)objects { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentObjectAsync] continueWithBlock:^id(BFTask *task) { + PFUser *currentUser = task.result; + NSString *sessionToken = currentUser.sessionToken; + return [PFObject _deepSaveAsync:objects withCurrentUser:currentUser sessionToken:sessionToken]; + }]; +} + ++ (void)saveAllInBackground:(NSArray *)objects target:(id)target selector:(SEL)selector { + [PFObject saveAllInBackground:objects block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + ++ (void)saveAllInBackground:(NSArray *)objects block:(PFBooleanResultBlock)block { + [[PFObject saveAllInBackground:objects] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Delete all +///-------------------------------------- + ++ (BOOL)deleteAll:(NSArray *)objects { + return [PFObject deleteAll:objects error:nil]; +} + ++ (BOOL)deleteAll:(NSArray *)objects error:(NSError **)error { + return [[[self deleteAllInBackground:objects] waitForResult:error] boolValue]; +} + ++ (BFTask PF_GENERIC(NSNumber *) *)deleteAllInBackground:(NSArray *)objects { + NSArray *deleteObjects = [objects copy]; // Snapshot the objects. + if (deleteObjects.count == 0) { + return [BFTask PF_GENERIC(NSNumber *) taskWithResult:@YES]; + } + return [[[[self currentUserController] getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + + NSArray *uniqueObjects = [PFObjectBatchController uniqueObjectsArrayFromArray:deleteObjects usingFilter:^BOOL(PFObject *object) { + return (object.objectId != nil); + }]; + NSMutableArray PF_GENERIC(BFTask *) *validationTasks = [NSMutableArray array]; + for (PFObject *object in uniqueObjects) { + [validationTasks addObject:[object _validateDeleteAsync]]; + } + return [[BFTask taskForCompletionOfAllTasks:validationTasks] continueWithSuccessBlock:^id(BFTask *task) { + return [self _enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[self objectBatchController] deleteObjectsAsync:uniqueObjects + withSessionToken:sessionToken]; + }]; + } forObjects:uniqueObjects]; + }]; + }] continueWithSuccessResult:@YES]; +} + ++ (void)deleteAllInBackground:(NSArray *)objects target:(id)target selector:(SEL)selector { + [PFObject deleteAllInBackground:objects block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + ++ (void)deleteAllInBackground:(NSArray *)objects block:(PFBooleanResultBlock)block { + [[self deleteAllInBackground:objects] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Dynamic synthesizers +///-------------------------------------- + +// NOTE: The ONLY reason this needs to exist is to support mocking PFObject subclasses. +// +// The reason mocking doesn't work is because OCMClassMock looks for methods that exist on the class already, and will +// not be able to use our dynamic instance-level method resolving. By implementing this, we give this method a signature +// once, and then tell the runtime to forward that message on from there. +// +// Note that by implementing it this way, we no longer need to implement -methodSignatureForSelector: or +// -respondsToSelector:, as the method will be dynamically resolved by the runtime when either of those methods is +// invoked. ++ (BOOL)resolveInstanceMethod:(SEL)sel { + if (self == [PFObject class]) { + return NO; + } + + NSMethodSignature *signature = [[self subclassingController] forwardingMethodSignatureForSelector:sel ofClass:self]; + if (!signature) { + return NO; + } + + // Convert the method signature *back* into a objc type string (sidenote, why isn't this a built in?). + NSMutableString *typeString = [NSMutableString stringWithFormat:@"%s", [signature methodReturnType]]; + for (NSUInteger argumentIndex = 0; argumentIndex < [signature numberOfArguments]; argumentIndex++) { + [typeString appendFormat:@"%s", [signature getArgumentTypeAtIndex:argumentIndex]]; + } + + // TODO: (richardross) Support stret return here (will need to introspect the method signature to do so). + class_addMethod(self, sel, _objc_msgForward, [typeString UTF8String]); + + return YES; +} + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + if (![[[self class] subclassingController] forwardObjectInvocation:anInvocation + withObject:(PFObject *)self]) { + [self doesNotRecognizeSelector:anInvocation.selector]; + } +} + +///-------------------------------------- +#pragma mark - Pinning +///-------------------------------------- + +- (BOOL)pin { + return [self pin:nil]; +} + +- (BOOL)pin:(NSError **)error { + return [self pinWithName:PFObjectDefaultPin error:error]; +} + +- (BFTask *)pinInBackground { + return [self pinInBackgroundWithName:PFObjectDefaultPin]; +} + +- (void)pinInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self pinInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (BOOL)pinWithName:(NSString *)name { + return [self pinWithName:name error:nil]; +} + +- (BOOL)pinWithName:(NSString *)name error:(NSError **)error { + return [[[self pinInBackgroundWithName:name] waitForResult:error] boolValue]; +} + +- (void)pinInBackgroundWithName:(NSString *)name block:(PFBooleanResultBlock)block { + [[self pinInBackgroundWithName:name] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (BFTask *)pinInBackgroundWithName:(NSString *)name { + return [self _pinInBackgroundWithName:name includeChildren:YES]; +} + +- (BFTask *)_pinInBackgroundWithName:(NSString *)name includeChildren:(BOOL)includeChildren { + return [[self class] _pinAllInBackground:@[ self ] withName:name includeChildren:includeChildren]; +} + +///-------------------------------------- +#pragma mark - Pinning Many Objects +///-------------------------------------- + ++ (BOOL)pinAll:(NSArray *)objects { + return [self pinAll:objects error:nil]; +} + ++ (BOOL)pinAll:(NSArray *)objects error:(NSError **)error { + return [self pinAll:objects withName:PFObjectDefaultPin error:error]; +} + ++ (BFTask *)pinAllInBackground:(NSArray *)objects { + return [self pinAllInBackground:objects withName:PFObjectDefaultPin]; +} + ++ (void)pinAllInBackground:(NSArray *)objects + block:(PFBooleanResultBlock)block { + [[self pinAllInBackground:objects] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BOOL)pinAll:(NSArray *)objects withName:(NSString *)name { + return [self pinAll:objects withName:name error:nil]; +} + ++ (BOOL)pinAll:(NSArray *)objects withName:(NSString *)name error:(NSError **)error { + return [[[self pinAllInBackground:objects withName:name] waitForResult:error] boolValue]; +} + ++ (BFTask *)pinAllInBackground:(NSArray *)objects withName:(NSString *)name { + return [self _pinAllInBackground:objects withName:name includeChildren:YES]; +} + ++ (void)pinAllInBackground:(NSArray *)objects + withName:(NSString *)name + block:(PFBooleanResultBlock)block { + [[self pinAllInBackground:objects withName:name] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BFTask *)_pinAllInBackground:(NSArray *)objects + withName:(NSString *)name + includeChildren:(BOOL)includeChildren { + return [[self pinningObjectStore] pinObjectsAsync:objects + withPinName:name + includeChildren:includeChildren]; +} + +///-------------------------------------- +#pragma mark - Unpinning +///-------------------------------------- + +- (BOOL)unpin { + return [self unpinWithName:PFObjectDefaultPin]; +} + +- (BOOL)unpin:(NSError **)error { + return [self unpinWithName:PFObjectDefaultPin error:error]; +} + +- (BFTask *)unpinInBackground { + return [self unpinInBackgroundWithName:PFObjectDefaultPin]; +} + +- (void)unpinInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self unpinInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +- (BOOL)unpinWithName:(NSString *)name { + return [self unpinWithName:name error:nil]; +} + +- (BOOL)unpinWithName:(NSString *)name error:(NSError **)error { + return [[[self unpinInBackgroundWithName:name] waitForResult:error] boolValue]; +} + +- (BFTask *)unpinInBackgroundWithName:(NSString *)name { + return [[self class] unpinAllInBackground:@[ self ] withName:name]; +} + +- (void)unpinInBackgroundWithName:(NSString *)name block:(PFBooleanResultBlock)block { + [[self unpinInBackgroundWithName:name] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Unpinning Many Objects +///-------------------------------------- + ++ (BOOL)unpinAllObjects { + return [self unpinAllObjects:nil]; +} + ++ (BOOL)unpinAllObjects:(NSError **)error { + return [self unpinAllObjectsWithName:PFObjectDefaultPin error:error]; +} + ++ (BFTask *)unpinAllObjectsInBackground { + return [self unpinAllObjectsInBackgroundWithName:PFObjectDefaultPin]; +} + ++ (void)unpinAllObjectsInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self unpinAllObjectsInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BOOL)unpinAllObjectsWithName:(NSString *)name { + return [self unpinAllObjectsWithName:name error:nil]; +} + ++ (BOOL)unpinAllObjectsWithName:(NSString *)name error:(NSError **)error { + return [[[self unpinAllObjectsInBackgroundWithName:name] waitForResult:error] boolValue]; +} + ++ (void)unpinAllObjectsInBackgroundWithName:(NSString *)name block:(PFBooleanResultBlock)block { + [[self unpinAllObjectsInBackgroundWithName:name] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BFTask *)unpinAllObjectsInBackgroundWithName:(NSString *)name { + return [[self pinningObjectStore] unpinAllObjectsAsyncWithPinName:name]; +} + ++ (BOOL)unpinAll:(NSArray *)objects { + return [self unpinAll:objects error:nil]; +} + ++ (BOOL)unpinAll:(NSArray *)objects error:(NSError **)error { + return [self unpinAll:objects withName:PFObjectDefaultPin error:error]; +} + ++ (BFTask *)unpinAllInBackground:(NSArray *)objects { + return [self unpinAllInBackground:objects withName:PFObjectDefaultPin]; +} + ++ (void)unpinAllInBackground:(NSArray *)objects block:(PFBooleanResultBlock)block { + [[self unpinAllInBackground:objects] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (BOOL)unpinAll:(NSArray *)objects withName:(NSString *)name { + return [self unpinAll:objects withName:name error:nil]; +} + ++ (BOOL)unpinAll:(NSArray *)objects withName:(NSString *)name error:(NSError **)error { + return [[[self unpinAllInBackground:objects withName:name] waitForResult:error] boolValue]; +} + ++ (BFTask *)unpinAllInBackground:(NSArray *)objects withName:(NSString *)name { + return [[self pinningObjectStore] unpinObjectsAsync:objects withPinName:name]; +} + ++ (void)unpinAllInBackground:(NSArray *)objects + withName:(NSString *)name + block:(PFBooleanResultBlock)block { + [[self unpinAllInBackground:objects withName:name] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +///-------------------------------------- +#pragma mark - Data Source +///-------------------------------------- + ++ (id)objectController { + return [Parse _currentManager].coreManager.objectController; +} + ++ (PFObjectFileCodingLogic *)objectFileCodingLogic { + return [PFObjectFileCodingLogic codingLogic]; +} + ++ (PFObjectBatchController *)objectBatchController { + return [Parse _currentManager].coreManager.objectBatchController; +} + ++ (PFPinningObjectStore *)pinningObjectStore { + return [Parse _currentManager].coreManager.pinningObjectStore; +} + ++ (PFCurrentUserController *)currentUserController { + return [Parse _currentManager].coreManager.currentUserController; +} + ++ (PFObjectSubclassingController *)subclassingController { + return [PFObjectSubclassingController defaultController]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFProduct.h b/Unit-2-Journal/Pods/Parse/Parse/PFProduct.h new file mode 100644 index 0000000..e895d6b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFProduct.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +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. + */ +PF_WATCH_UNAVAILABLE @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/Unit-2-Journal/Pods/Parse/Parse/PFProduct.m b/Unit-2-Journal/Pods/Parse/Parse/PFProduct.m new file mode 100644 index 0000000..4eb2f2b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFProduct.m @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFProduct.h" +#import "PFProduct+Private.h" + +#import "PFAssert.h" +#import "PFObject+Subclass.h" + +@implementation PFProduct + +@dynamic productIdentifier; +@dynamic icon; +@dynamic title; +@dynamic subtitle; +@dynamic order; +@dynamic downloadName; + +///-------------------------------------- +#pragma mark - PFSubclassing +///-------------------------------------- + +// Validates a class name. We override this to only allow the product class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[PFProduct parseClassName]], + @"Cannot initialize a PFProduct with a custom class name."); +} + ++ (NSString *)parseClassName { + return @"_Product"; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + +@dynamic price; +@dynamic priceLocale; +@dynamic contentPath; +@dynamic progress; + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.h b/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.h new file mode 100644 index 0000000..b681cc1 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.h @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFProduct; + +PF_ASSUME_NONNULL_BEGIN + +typedef void (^PFPurchaseProductObservationBlock)(SKPaymentTransaction *transaction); +typedef void (^PFPurchaseBuyProductResultBlock)(NSError *PF_NULLABLE_S error); +typedef void (^PFPurchaseDownloadAssetResultBlock)(NSString *PF_NULLABLE_S filePath, NSError *PF_NULLABLE_S error); + +/*! + `PFPurchase` provides a set of APIs for working with in-app purchases. + + This class is currently for iOS only. + */ +@interface PFPurchase : NSObject + +/*! + @abstract Add application logic block which is run when buying a product. + + @discussion This method should be called once for each product, and should be called before + calling . All invocations to should happen within + the same method, and on the main thread. It is recommended to place all invocations of this method + in `application:didFinishLaunchingWithOptions:`. + + @param productIdentifier the product identifier + @param block The block to be run when buying a product. + */ ++ (void)addObserverForProduct:(NSString *)productIdentifier block:(PFPurchaseProductObservationBlock)block; + +/*! + @abstract *Asynchronously* initiates the purchase for the product. + + @param productIdentifier the product identifier + @param block the completion block. + */ ++ (void)buyProduct:(NSString *)productIdentifier block:(PFPurchaseBuyProductResultBlock)block; + +/*! + @abstract *Asynchronously* download the purchased asset, which is stored on Parse's server. + + @discussion Parse verifies the receipt with Apple and delivers the content only if the receipt is valid. + + @param transaction the transaction, which contains the receipt. + @param completion the completion block. + */ ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(PFPurchaseDownloadAssetResultBlock)completion; + +/*! + @abstract *Asynchronously* download the purchased asset, which is stored on Parse's server. + + @discussion Parse verifies the receipt with Apple and delivers the content only if the receipt is valid. + + @param transaction the transaction, which contains the receipt. + @param completion the completion block. + @param progress the progress block, which is called multiple times to reveal progress of the download. + */ ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(PFPurchaseDownloadAssetResultBlock)completion + progress:(PF_NULLABLE PFProgressBlock)progress; + +/*! + @abstract *Asynchronously* restore completed transactions for the current user. + + @discussion Only nonconsumable purchases are restored. If observers for the products have been added before + calling this method, invoking the method reruns the application logic associated with the purchase. + + @warning This method is only important to developers who want to preserve purchase states across + different installations of the same app. + */ ++ (void)restore; + +/*! + @abstract Returns a content path of the asset of a product, if it was purchased and downloaded. + + @discussion To download and verify purchases use . + + @warning This method will return `nil`, if the purchase wasn't verified or if the asset was not downloaded. + */ ++ (PF_NULLABLE NSString *)assetContentPathForProduct:(PFProduct *)product; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.m b/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.m new file mode 100644 index 0000000..52ee0f8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFPurchase.m @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPurchase.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFConstants.h" +#import "PFPaymentTransactionObserver.h" +#import "PFProduct.h" +#import "PFPurchaseController.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +@implementation PFPurchase + +///-------------------------------------- +#pragma mark - Public +///-------------------------------------- + ++ (void)addObserverForProduct:(NSString *)productIdentifier block:(PFPurchaseProductObservationBlock)block { + // We require the following method to run on the main thread because we want to add the observer + // *after* all products handlers have been added. Developers might be calling this method multiple + // times; and if the observer is added after the first call, the observer might not know how to + // handle some purchases. + + PFConsistencyAssert([NSThread isMainThread], @"%@ must be called on the main thread.", NSStringFromSelector(_cmd)); + PFParameterAssert(productIdentifier, @"You must pass in a valid product identifier."); + PFParameterAssert(block, @"You must pass in a valid block for the product."); + + [[Parse _currentManager].purchaseController.transactionObserver handle:productIdentifier block:block]; +} + ++ (void)buyProduct:(NSString *)productIdentifier block:(PFPurchaseBuyProductResultBlock)completion { + [[[self _purchaseController] buyProductAsyncWithIdentifier:productIdentifier] continueWithBlock:^id(BFTask *task) { + if (completion) { + completion(task.error); + } + return nil; + }]; +} + ++ (void)restore { + [[self _purchaseController].paymentQueue restoreCompletedTransactions]; +} + ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(PFPurchaseDownloadAssetResultBlock)completion { + [self downloadAssetForTransaction:transaction completion:completion progress:nil]; +} + ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(PFPurchaseDownloadAssetResultBlock)completion + progress:(PFProgressBlock)progress { + @weakify(self); + [[[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + @strongify(self); + NSString *sessionToken = task.result; + return [[self _purchaseController] downloadAssetAsyncForTransaction:transaction + withProgressBlock:progress + sessionToken:sessionToken]; + }] continueWithMainThreadResultBlock:completion executeIfCancelled:YES]; +} + ++ (NSString *)assetContentPathForProduct:(PFProduct *)product { + NSString *path = [[self _purchaseController] assetContentPathForProductWithIdentifier:product.productIdentifier + fileName:product.downloadName]; + if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { + return path; + } + + return nil; +} + +///-------------------------------------- +#pragma mark - Purchase Controller +///-------------------------------------- + ++ (PFPurchaseController *)_purchaseController { + return [Parse _currentManager].purchaseController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFPush.h b/Unit-2-Journal/Pods/Parse/Parse/PFPush.h new file mode 100644 index 0000000..6cff85b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFPush.h @@ -0,0 +1,532 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFQuery PF_GENERIC(PFGenericObject : PFObject *); + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFPush` class defines a push notification that can be sent from a client device. + + The preferred way of modifying or retrieving channel subscriptions is to use + the class, instead of the class methods in `PFPush`. + */ +@interface PFPush : NSObject + +///-------------------------------------- +/// @name Creating a Push Notification +///-------------------------------------- + ++ (instancetype)push; + +///-------------------------------------- +/// @name Configuring a Push Notification +///-------------------------------------- + +/*! + @abstract Sets the channel on which this push notification will be sent. + + @param channel The channel to set for this push. + The channel name must start with a letter and contain only letters, numbers, dashes, and underscores. + */ +- (void)setChannel:(PF_NULLABLE NSString *)channel; + +/*! + @abstract Sets the array of channels on which this push notification will be sent. + + @param channels The array of channels to set for this push. + Each channel name must start with a letter and contain only letters, numbers, dashes, and underscores. + */ +- (void)setChannels:(PF_NULLABLE NSArray PF_GENERIC(NSString *) *)channels; + +/*! + @abstract Sets an installation query to which this push notification will be sent. + + @discussion The query should be created via <[PFInstallation query]> and should not specify a skip, limit, or order. + + @param query The installation query to set for this push. + */ +- (void)setQuery:(PF_NULLABLE PFQuery PF_GENERIC(PFInstallation *) *)query; + +/*! + @abstract Sets an alert message for this push notification. + + @warning This will overwrite any data specified in setData. + + @param message The message to send in this push. + */ +- (void)setMessage:(PF_NULLABLE NSString *)message; + +/*! + @abstract Sets an arbitrary data payload for this push notification. + + @discussion See the guide for information about the dictionary structure. + + @warning This will overwrite any data specified in setMessage. + + @param data The data to send in this push. + */ +- (void)setData:(PF_NULLABLE NSDictionary *)data; + +/*! + @abstract Sets whether this push will go to Android devices. + + @param pushToAndroid Whether this push will go to Android devices. + + @deprecated Please use a `[PFInstallation query]` with a constraint on deviceType instead. + */ +- (void)setPushToAndroid:(BOOL)pushToAndroid PARSE_DEPRECATED("Please use a [PFInstallation query] with a constraint on deviceType. This method is deprecated and won't do anything."); + +/*! + @abstract Sets whether this push will go to iOS devices. + + @param pushToIOS Whether this push will go to iOS devices. + + @deprecated Please use a `[PFInstallation query]` with a constraint on deviceType instead. + */ +- (void)setPushToIOS:(BOOL)pushToIOS PARSE_DEPRECATED("Please use a [PFInstallation query] with a constraint on deviceType. This method is deprecated and won't do anything."); + +/*! + @abstract Sets the expiration time for this notification. + + @discussion The notification will be sent to devices which are either online + at the time the notification is sent, or which come online before the expiration time is reached. + Because device clocks are not guaranteed to be accurate, + most applications should instead use . + + @see expireAfterTimeInterval: + + @param date The time at which the notification should expire. + */ +- (void)expireAtDate:(PF_NULLABLE NSDate *)date; + +/*! + @abstract Sets the time interval after which this notification should expire. + + @discussion This notification will be sent to devices which are either online at + the time the notification is sent, or which come online within the given + time interval of the notification being received by Parse's server. + An interval which is less than or equal to zero indicates that the + message should only be sent to devices which are currently online. + + @param timeInterval The interval after which the notification should expire. + */ +- (void)expireAfterTimeInterval:(NSTimeInterval)timeInterval; + +/*! + @abstract Clears both expiration values, indicating that the notification should never expire. + */ +- (void)clearExpiration; + +///-------------------------------------- +/// @name Sending Push Notifications +///-------------------------------------- + +/*! + @abstract *Synchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushMessageToChannel:(NSString *)channel + withMessage:(NSString *)message + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message; + +/*! + @abstract *Asynchronously* sends a push message to a channel and calls the given block. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @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)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Send a push message to a query. + + @param query The query to send to. The query must be a query created with <[PFInstallation query]>. + @param message The message to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushMessageToQuery:(PFQuery PF_GENERIC(PFInstallation *) *)query + withMessage:(NSString *)message + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message to a query. + + @param query The query to send to. The query must be a query created with <[PFInstallation query]>. + @param message The message to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)sendPushMessageToQueryInBackground:(PFQuery PF_GENERIC(PFInstallation *) *)query + withMessage:(NSString *)message; + +/*! + @abstract *Asynchronously* sends a push message to a query and calls the given block. + + @param query The query to send to. The query must be a PFInstallation query + created with [PFInstallation query]. + @param message The message to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)sendPushMessageToQueryInBackground:(PFQuery PF_GENERIC(PFInstallation *) *)query + withMessage:(NSString *)message + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Synchronously* send this push message. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the send succeeded. + */ +- (BOOL)sendPush:(NSError **)error; + +/*! + @abstract *Asynchronously* send this push message. + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(NSNumber *)*)sendPushInBackground; + +/*! + @abstract *Asynchronously* send this push message and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)sendPushInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send this push message 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)sendPushInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract *Synchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushDataToChannel:(NSString *)channel + withData:(NSDictionary *)data + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data; + +/*! + @abstract Asynchronously sends a push message with arbitrary data to a channel and calls the given block. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @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)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract *Synchronously* send a push message with arbitrary data to a query. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushDataToQuery:(PFQuery PF_GENERIC(PFInstallation *) *)query + withData:(NSDictionary *)data + error:(NSError **)error; + +/*! + @abstract Asynchronously send a push message with arbitrary data to a query. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)sendPushDataToQueryInBackground:(PFQuery PF_GENERIC(PFInstallation *) *)query + withData:(NSDictionary *)data; + +/*! + @abstract *Asynchronously* sends a push message with arbitrary data to a query and calls the given block. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)sendPushDataToQueryInBackground:(PFQuery PF_GENERIC(PFInstallation *) *)query + withData:(NSDictionary *)data + block:(PF_NULLABLE PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Handling Notifications +///-------------------------------------- + +/*! + @abstract A default handler for push notifications while the app is active that + could be used to mimic the behavior of iOS push notifications while the app is backgrounded or not running. + + @discussion Call this from `application:didReceiveRemoteNotification:`. + If push has a dictionary containing loc-key and loc-args in the alert, + we support up to 10 items in loc-args (`NSRangeException` if limit exceeded). + + @warning This method is available only on iOS. + + @param userInfo The userInfo dictionary you get in `appplication:didReceiveRemoteNotification:`. + */ ++ (void)handlePush:(PF_NULLABLE NSDictionary *)userInfo NS_AVAILABLE_IOS(3_0) PF_EXTENSION_UNAVAILABLE(""); + +///-------------------------------------- +/// @name Managing Channel Subscriptions +///-------------------------------------- + +/*! + @abstract Store the device token locally for push notifications. + + @discussion Usually called from you main app delegate's `didRegisterForRemoteNotificationsWithDeviceToken:`. + + @param deviceToken Either as an `NSData` straight from `application:didRegisterForRemoteNotificationsWithDeviceToken:` + or as an `NSString` if you converted it yourself. + */ ++ (void)storeDeviceToken:(id)deviceToken; + +/*! + @abstract *Synchronously* get all the channels that this device is subscribed to. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns an `NSSet` containing all the channel names this device is subscribed to. + */ ++ (PF_NULLABLE NSSet *)getSubscribedChannels:(NSError **)error; + +/*! + @abstract *Asynchronously* get all the channels that this device is subscribed to. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSSet *)*)getSubscribedChannelsInBackground; + +/*! + @abstract *Asynchronously* get all the channels that this device is subscribed to. + @param block The block to execute. + It should have the following argument signature: `^(NSSet *channels, NSError *error)`. + */ ++ (void)getSubscribedChannelsInBackgroundWithBlock:(PFSetResultBlock)block; + +/* + @abstract *Asynchronously* get all the channels that this device is subscribed to. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSSet *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + */ ++ (void)getSubscribedChannelsInBackgroundWithTarget:(id)target + selector:(SEL)selector; + +/*! + @abstract *Synchrnously* subscribes the device to a channel of push notifications. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the subscribe succeeded. + */ ++ (BOOL)subscribeToChannel:(NSString *)channel error:(NSError **)error; + +/*! + @abstract *Asynchronously* subscribes the device to a channel of push notifications. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)subscribeToChannelInBackground:(NSString *)channel; + +/*! + @abstract *Asynchronously* subscribes the device to a channel of push notifications and calls the given block. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)subscribeToChannelInBackground:(NSString *)channel + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* subscribes the device to a channel of push notifications and calls the given callback. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @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)subscribeToChannelInBackground:(NSString *)channel + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract *Synchronously* unsubscribes the device to a channel of push notifications. + + @param channel The channel to unsubscribe from. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unsubscribe succeeded. + */ ++ (BOOL)unsubscribeFromChannel:(NSString *)channel error:(NSError **)error; + +/*! + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications. + + @param channel The channel to unsubscribe from. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)unsubscribeFromChannelInBackground:(NSString *)channel; + +/*! + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications and calls the given block. + + @param channel The channel to unsubscribe from. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)unsubscribeFromChannelInBackground:(NSString *)channel + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications and calls the given callback. + + @param channel The channel to unsubscribe from. + @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)unsubscribeFromChannelInBackground:(NSString *)channel + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFPush.m b/Unit-2-Journal/Pods/Parse/Parse/PFPush.m new file mode 100644 index 0000000..e5101dd --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFPush.m @@ -0,0 +1,464 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFPush.h" +#import "PFPushPrivate.h" + +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFEncoder.h" +#import "PFHash.h" +#import "PFInstallationPrivate.h" +#import "PFKeychainStore.h" +#import "PFMacros.h" +#import "PFMutablePushState.h" +#import "PFMutableQueryState.h" +#import "PFPushChannelsController.h" +#import "PFPushController.h" +#import "PFPushManager.h" +#import "PFPushUtilities.h" +#import "PFQueryPrivate.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +static Class _pushInternalUtilClass = nil; + +@interface PFPush () + +@property (nonatomic, strong) PFMutablePushState *state; +@property (nonatomic, strong) PFQuery PF_GENERIC(PFInstallation *) *query; + +@end + +@implementation PFPush (Private) + ++ (Class)pushInternalUtilClass { + return _pushInternalUtilClass ?: [PFPushUtilities class]; +} + ++ (void)setPushInternalUtilClass:(Class)utilClass { + if (utilClass) { + PFParameterAssert([utilClass conformsToProtocol:@protocol(PFPushInternalUtils)], + @"utilClass must conform to PFPushInternalUtils protocol"); + } + _pushInternalUtilClass = utilClass; +} + +@end + +@implementation PFPush + +///-------------------------------------- +#pragma mark - Instance +///-------------------------------------- + +#pragma mark Init + ++ (instancetype)push { + return [[self alloc] init]; +} + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _state = [[PFMutablePushState alloc] init]; + + return self; +} + +#pragma mark Accessors + +- (void)setQuery:(PFQuery *)query { + PFParameterAssert(!self.state.channels || !query, @"Can't set both the query and channel(s) properties."); + _query = query; +} + +- (void)setChannelSet:(NSSet *)channelSet { + PFParameterAssert(!self.query || !channelSet, @"Can't set both the query and channel(s) properties."); + self.state.channels = channelSet; +} + +- (void)setChannel:(NSString *)channel { + self.channelSet = PF_SET(channel); +} + +- (void)setChannels:(NSArray *)channels { + self.channelSet = [NSSet setWithArray:channels]; +} + +- (void)setMessage:(NSString *)message { + [self.state setPayloadWithMessage:message]; +} + +- (void)expireAtDate:(NSDate *)date { + self.state.expirationDate = date; + self.state.expirationTimeInterval = nil; +} + +- (void)expireAfterTimeInterval:(NSTimeInterval)timeInterval { + self.state.expirationDate = nil; + self.state.expirationTimeInterval = @(timeInterval); +} + +- (void)clearExpiration { + self.state.expirationDate = nil; + self.state.expirationTimeInterval = nil; +} + +- (void)setData:(NSDictionary *)data { + self.state.payload = data; +} + +#pragma mark Sending + +- (BOOL)sendPush:(NSError **)error { + return [[[self sendPushInBackground] waitForResult:error] boolValue]; +} + +- (BFTask *)sendPushInBackground { + if (self.query) { + PFParameterAssert(!self.query.state.sortKeys, @"Cannot send push notifications to an ordered query."); + PFParameterAssert(self.query.state.limit == -1, @"Cannot send push notifications to a limit query."); + PFParameterAssert(self.query.state.skip == 0, @"Cannot send push notifications to a skip query."); + } + + // Capture state first. + PFPushController *pushController = [[self class] pushController]; + PFPushState *state = [self _currentStateCopy]; + return [[PFUser _getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [pushController sendPushNotificationAsyncWithState:state sessionToken:sessionToken]; + }]; +} + +- (void)sendPushInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self sendPushInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +- (void)sendPushInBackgroundWithBlock:(PFBooleanResultBlock)block { + [[self sendPushInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + +#pragma mark Command + +- (PFPushState *)_currentStateCopy { + if (self.query) { + PFMutablePushState *state = [self.state mutableCopy]; + state.queryState = self.query.state; + return [state copy]; + } + return [self.state copy]; +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + PFPush *push = [[PFPush allocWithZone:zone] init]; + push.state = [self.state mutableCopy]; + return push; +} + +///-------------------------------------- +#pragma mark - NSObject +///-------------------------------------- + +- (NSUInteger)hash { + return PFIntegerPairHash([self.query hash], [self.state hash]); +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[PFPush class]]) { + return NO; + } + + PFPush *push = (PFPush *)object; + return (((self.query == nil && push.query == nil) || + [self.query isEqual:push.query]) && + [self.state isEqual:push.state]); +} + +///-------------------------------------- +#pragma mark - Sending Push Notifications +///-------------------------------------- + +#pragma mark To Channel + ++ (BOOL)sendPushMessageToChannel:(NSString *)channel + withMessage:(NSString *)message + error:(NSError **)error { + return [[[self sendPushMessageToChannelInBackground:channel withMessage:message] waitForResult:error] boolValue]; +} + ++ (BFTask *)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message { + NSDictionary *data = @{ @"alert" : message }; + return [self sendPushDataToChannelInBackground:channel withData:data]; +} + ++ (void)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + block:(PFBooleanResultBlock)block { + [[self sendPushMessageToChannelInBackground:channel + withMessage:message] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (void)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + target:(id)target + selector:(SEL)selector { + [self sendPushMessageToChannelInBackground:channel withMessage:message block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + ++ (BOOL)sendPushDataToChannel:(NSString *)channel + withData:(NSDictionary *)data + error:(NSError **)error { + return [[[PFPush sendPushDataToChannelInBackground:channel withData:data] waitForResult:error] boolValue]; +} + ++ (BFTask *)sendPushDataToChannelInBackground:(NSString *)channel withData:(NSDictionary *)data { + PFPush *push = [self push]; + [push setChannel:channel]; + [push setData:data]; + return [push sendPushInBackground]; +} + ++ (void)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + block:(PFBooleanResultBlock)block { + [[self sendPushDataToChannelInBackground:channel withData:data] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (void)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + target:(id)target + selector:(SEL)selector { + [self sendPushDataToChannelInBackground:channel withData:data block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +#pragma mark To Query + ++ (BOOL)sendPushMessageToQuery:(PFQuery *)query + withMessage:(NSString *)message + error:(NSError **)error { + PFPush *push = [PFPush push]; + push.query = query; + push.message = message; + return [push sendPush:error]; +} + ++ (BFTask *)sendPushMessageToQueryInBackground:(PFQuery *)query + withMessage:(NSString *)message { + PFPush *push = [PFPush push]; + push.query = query; + push.message = message; + return [push sendPushInBackground]; +} + ++ (void)sendPushMessageToQueryInBackground:(PFQuery *)query + withMessage:(NSString *)message + block:(PFBooleanResultBlock)block { + PFPush *push = [PFPush push]; + push.query = query; + push.message = message; + [push sendPushInBackgroundWithBlock:block]; +} + + ++ (BOOL)sendPushDataToQuery:(PFQuery *)query + withData:(NSDictionary *)data + error:(NSError **)error { + PFPush *push = [PFPush push]; + push.query = query; + push.data = data; + return [push sendPush:error]; +} + ++ (BFTask *)sendPushDataToQueryInBackground:(PFQuery *)query + withData:(NSDictionary *)data { + PFPush *push = [PFPush push]; + push.query = query; + push.data = data; + return [push sendPushInBackground]; +} + ++ (void)sendPushDataToQueryInBackground:(PFQuery *)query + withData:(NSDictionary *)data + block:(PFBooleanResultBlock)block { + PFPush *push = [PFPush push]; + push.query = query; + push.data = data; + [push sendPushInBackgroundWithBlock:block]; +} + +///-------------------------------------- +#pragma mark - Channels +///-------------------------------------- + +#pragma mark Get + ++ (NSSet *)getSubscribedChannels:(NSError **)error { + return [[self getSubscribedChannelsInBackground] waitForResult:error]; +} + ++ (BFTask *)getSubscribedChannelsInBackground { + return [[self channelsController] getSubscribedChannelsAsync]; +} + ++ (void)getSubscribedChannelsInBackgroundWithBlock:(PFSetResultBlock)block { + [[self getSubscribedChannelsInBackground] thenCallBackOnMainThreadAsync:block]; +} + ++ (void)getSubscribedChannelsInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self getSubscribedChannelsInBackgroundWithBlock:^(NSSet *channels, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:channels object:error]; + }]; +} + +#pragma mark Subscribe + ++ (BOOL)subscribeToChannel:(NSString *)channel error:(NSError **)error { + return [[[self subscribeToChannelInBackground:channel] waitForResult:error] boolValue]; +} + ++ (BFTask *)subscribeToChannelInBackground:(NSString *)channel { + return [[self channelsController] subscribeToChannelAsyncWithName:channel]; +} + ++ (void)subscribeToChannelInBackground:(NSString *)channel block:(PFBooleanResultBlock)block { + [[self subscribeToChannelInBackground:channel] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (void)subscribeToChannelInBackground:(NSString *)channel target:(id)target selector:(SEL)selector { + [self subscribeToChannelInBackground:channel block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +#pragma mark Unsubscribe + ++ (BOOL)unsubscribeFromChannel:(NSString *)channel error:(NSError **)error { + return [[[self unsubscribeFromChannelInBackground:channel] waitForResult:error] boolValue]; +} + ++ (BFTask *)unsubscribeFromChannelInBackground:(NSString *)channel { + return [[self channelsController] unsubscribeFromChannelAsyncWithName:channel]; +} + ++ (void)unsubscribeFromChannelInBackground:(NSString *)channel block:(PFBooleanResultBlock)block { + [[self unsubscribeFromChannelInBackground:channel] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (void)unsubscribeFromChannelInBackground:(NSString *)channel target:(id)target selector:(SEL)selector { + [self unsubscribeFromChannelInBackground:channel block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Handling Notifications +///-------------------------------------- + +#if PARSE_IOS_ONLY ++ (void)handlePush:(NSDictionary *)userInfo { + UIApplication *application = [UIApplication sharedApplication]; + if ([application applicationState] != UIApplicationStateActive) { + return; + } + + NSDictionary *aps = userInfo[@"aps"]; + id alert = aps[@"alert"]; + + if (alert) { + NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:(__bridge NSString *)kCFBundleNameKey]; + NSString *message = nil; + if ([alert isKindOfClass:[NSString class]]) { + message = alert; + } else if ([alert isKindOfClass:[NSDictionary class]]) { + NSDictionary *alertDict = alert; + NSString *locKey = alertDict[@"loc-key"]; + if (locKey) { + NSString *format = [[NSBundle mainBundle] localizedStringForKey:locKey value:@"" table:nil]; + message = [PFInternalUtils _stringWithFormat:format arguments:alertDict[@"loc-args"]]; + } + } + if (message) { + [[self pushInternalUtilClass] showAlertViewWithTitle:appName message:message]; + } + } + + NSNumber *badgeNumber = aps[@"badge"]; + if (badgeNumber) { + NSInteger number = [aps[@"badge"] integerValue]; + [application setApplicationIconBadgeNumber:number]; + } + + NSString *soundName = aps[@"sound"]; + + // Vibrate or play sound only if `sound` is specified. + if ([soundName isKindOfClass:[NSString class]] && soundName.length != 0) { + // Vibrate if the sound is `default`, otherwise - play the sound name. + if ([soundName isEqualToString:@"default"]) { + [[self pushInternalUtilClass] playVibrate]; + } else { + [[self pushInternalUtilClass] playAudioWithName:soundName]; + } + } +} +#endif + +///-------------------------------------- +#pragma mark - Store Token +///-------------------------------------- + ++ (void)storeDeviceToken:(id)deviceToken { + NSString *deviceTokenString = [[self pushInternalUtilClass] convertDeviceTokenToString:deviceToken]; + [PFInstallation currentInstallation].deviceToken = deviceTokenString; +} + +///-------------------------------------- +#pragma mark - Deprecated +///-------------------------------------- + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +- (void)setPushToIOS:(BOOL)pushToIOS { +} + +- (void)setPushToAndroid:(BOOL)pushToAndroid { +} +#pragma clang diagnostic pop + +///-------------------------------------- +#pragma mark - Push Manager +///-------------------------------------- + ++ (PFPushController *)pushController { + return [Parse _currentManager].pushManager.pushController; +} + ++ (PFPushChannelsController *)channelsController { + return [Parse _currentManager].pushManager.channelsController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFQuery.h b/Unit-2-Journal/Pods/Parse/Parse/PFQuery.h new file mode 100644 index 0000000..661399a --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFQuery.h @@ -0,0 +1,892 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFQuery` class defines a query that is used to query for s. + */ +@interface PFQuery PF_GENERIC(PFGenericObject : PFObject *) : NSObject + +///-------------------------------------- +/// @name Blocks +///-------------------------------------- + +typedef void (^PFQueryArrayResultBlock)(NSArray PF_GENERIC(PFGenericObject) * PF_NULLABLE_S objects, NSError * PF_NULLABLE_S error); + +///-------------------------------------- +/// @name Creating a Query for a Class +///-------------------------------------- + +/*! + @abstract Initializes the query with a class name. + + @param className The class name. + */ +- (instancetype)initWithClassName:(NSString *)className; + +/*! + @abstract Returns a `PFQuery` for a given class. + + @param className The class to query on. + + @returns A `PFQuery` object. + */ ++ (instancetype)queryWithClassName:(NSString *)className; + +/*! + @abstract Creates a PFQuery with the constraints given by predicate. + + @discussion The following types of predicates are supported: + + - Simple comparisons such as `=`, `!=`, `<`, `>`, `<=`, `>=`, and `BETWEEN` with a key and a constant. + - Containment predicates, such as `x IN {1, 2, 3}`. + - Key-existence predicates, such as `x IN SELF`. + - BEGINSWITH expressions. + - Compound predicates with `AND`, `OR`, and `NOT`. + - SubQueries with `key IN %@`, subquery. + + The following types of predicates are NOT supported: + + - Aggregate operations, such as `ANY`, `SOME`, `ALL`, or `NONE`. + - Regular expressions, such as `LIKE`, `MATCHES`, `CONTAINS`, or `ENDSWITH`. + - Predicates comparing one key to another. + - Complex predicates with many ORed clauses. + + @param className The class to query on. + @param predicate The predicate to create conditions from. + */ ++ (instancetype)queryWithClassName:(NSString *)className predicate:(PF_NULLABLE NSPredicate *)predicate; + +/*! + The class name to query for. + */ +@property (nonatomic, strong) NSString *parseClassName; + +///-------------------------------------- +/// @name Adding Basic Constraints +///-------------------------------------- + +/*! + @abstract Make the query include PFObjects that have a reference stored at the provided key. + + @discussion This has an effect similar to a join. You can use dot notation to specify which fields in + the included object are also fetch. + + @param key The key to load child s for. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)includeKey:(NSString *)key; + +/*! + @abstract Make the query restrict the fields of the returned s to include only the provided keys. + + @discussion If this is called multiple times, then all of the keys specified in each of the calls will be included. + + @param keys The keys to include in the result. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)selectKeys:(NSArray PF_GENERIC(NSString *) *)keys; + +/*! + @abstract Add a constraint that requires a particular key exists. + + @param key The key that should exist. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKeyExists:(NSString *)key; + +/*! + @abstract Add a constraint that requires a key not exist. + + @param key The key that should not exist. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKeyDoesNotExist:(NSString *)key; + +/*! + @abstract Add a constraint to the query that requires a particular key's object to be equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key equalTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object to be less than the provided object. + + @param key The key to be constrained. + @param object The object that provides an upper bound. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key lessThan:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be less than or equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key lessThanOrEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be greater than the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key greaterThan:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's + object to be greater than or equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key greaterThanOrEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be not equal to the provided object. + + @param key The key to be constrained. + @param object The object that must not be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key notEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be contained in the provided array. + + @param key The key to be constrained. + @param array The possible values for the key's object. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containedIn:(NSArray *)array; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + not be contained in the provided array. + + @param key The key to be constrained. + @param array The list of values the key's object should not be. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key notContainedIn:(NSArray *)array; + +/*! + @abstract Add a constraint to the query that requires a particular key's array + contains every element of the provided array. + + @param key The key to be constrained. + @param array The array of values to search for. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containsAllObjectsInArray:(NSArray *)array; + +///-------------------------------------- +/// @name Adding Location Constraints +///-------------------------------------- + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point. + + @discussion Distance is calculated based on angular distance on a sphere. Results will be sorted by distance + from reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point and within the maximum distance specified (in miles). + + @discussion Distance is calculated based on a spherical coordinate system. + Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + @param maxDistance Maximum distance in miles. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinMiles:(double)maxDistance; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point and within the maximum distance specified (in kilometers). + + @discussion Distance is calculated based on a spherical coordinate system. + Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + @param maxDistance Maximum distance in kilometers. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinKilometers:(double)maxDistance; + +/*! + Add a constraint to the query that requires a particular key's coordinates (specified via ) be near + a reference point and within the maximum distance specified (in radians). Distance is calculated based on + angular distance on a sphere. Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point as a . + @param maxDistance Maximum distance in radians. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinRadians:(double)maxDistance; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) be + contained within a given rectangular geographic bounding box. + + @param key The key to be constrained. + @param southwest The lower-left inclusive corner of the box. + @param northeast The upper-right inclusive corner of the box. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key withinGeoBoxFromSouthwest:(PFGeoPoint *)southwest toNortheast:(PFGeoPoint *)northeast; + +///-------------------------------------- +/// @name Adding String Constraints +///-------------------------------------- + +/*! + @abstract Add a regular expression constraint for finding string values that match the provided regular expression. + + @warning This may be slow for large datasets. + + @param key The key that the string to match is stored in. + @param regex The regular expression pattern to match. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key matchesRegex:(NSString *)regex; + +/*! + @abstract Add a regular expression constraint for finding string values that match the provided regular expression. + + @warning This may be slow for large datasets. + + @param key The key that the string to match is stored in. + @param regex The regular expression pattern to match. + @param modifiers Any of the following supported PCRE modifiers: + - `i` - Case insensitive search + - `m` - Search across multiple lines of input + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + matchesRegex:(NSString *)regex + modifiers:(PF_NULLABLE NSString *)modifiers; + +/*! + @abstract Add a constraint for finding string values that contain a provided substring. + + @warning This will be slow for large datasets. + + @param key The key that the string to match is stored in. + @param substring The substring that the value must contain. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containsString:(PF_NULLABLE NSString *)substring; + +/*! + @abstract Add a constraint for finding string values that start with a provided prefix. + + @discussion This will use smart indexing, so it will be fast for large datasets. + + @param key The key that the string to match is stored in. + @param prefix The substring that the value must start with. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key hasPrefix:(PF_NULLABLE NSString *)prefix; + +/*! + @abstract Add a constraint for finding string values that end with a provided suffix. + + @warning This will be slow for large datasets. + + @param key The key that the string to match is stored in. + @param suffix The substring that the value must end with. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key hasSuffix:(PF_NULLABLE NSString *)suffix; + +///-------------------------------------- +/// @name Adding Subqueries +///-------------------------------------- + +/*! + Returns a `PFQuery` that is the `or` of the passed in queries. + + @param queries The list of queries to or together. + + @returns An instance of `PFQuery` that is the `or` of the passed in queries. + */ ++ (instancetype)orQueryWithSubqueries:(NSArray PF_GENERIC(PFQuery *) *)queries; + +/*! + @abstract Adds a constraint that requires that a key's value matches a value in another key + in objects returned by a sub query. + + @param key The key that the value is stored. + @param otherKey The key in objects in the returned by the sub query whose value should match. + @param query The query to run. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + matchesKey:(NSString *)otherKey + inQuery:(PFQuery *)query; + +/*! + @abstract Adds a constraint that requires that a key's value `NOT` match a value in another key + in objects returned by a sub query. + + @param key The key that the value is stored. + @param otherKey The key in objects in the returned by the sub query whose value should match. + @param query The query to run. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + doesNotMatchKey:(NSString *)otherKey + inQuery:(PFQuery *)query; + +/*! + @abstract Add a constraint that requires that a key's value matches a `PFQuery` constraint. + + @warning This only works where the key's values are s or arrays of s. + + @param key The key that the value is stored in + @param query The query the value should match + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key matchesQuery:(PFQuery *)query; + +/*! + @abstract Add a constraint that requires that a key's value to not match a `PFQuery` constraint. + + @warning This only works where the key's values are s or arrays of s. + + @param key The key that the value is stored in + @param query The query the value should not match + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key doesNotMatchQuery:(PFQuery *)query; + +///-------------------------------------- +/// @name Sorting +///-------------------------------------- + +/*! + @abstract Sort the results in *ascending* order with the given key. + + @param key The key to order by. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderByAscending:(NSString *)key; + +/*! + @abstract Additionally sort in *ascending* order by the given key. + + @discussion The previous keys provided will precedence over this key. + + @param key The key to order by. + */ +- (instancetype)addAscendingOrder:(NSString *)key; + +/*! + @abstract Sort the results in *descending* order with the given key. + + @param key The key to order by. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderByDescending:(NSString *)key; + +/*! + @abstract Additionally sort in *descending* order by the given key. + + @discussion The previous keys provided will precedence over this key. + + @param key The key to order by. + */ +- (instancetype)addDescendingOrder:(NSString *)key; + +/*! + @abstract Sort the results using a given sort descriptor. + + @warning If a `sortDescriptor` has custom `selector` or `comparator` - they aren't going to be used. + + @param sortDescriptor The `NSSortDescriptor` to use to sort the results of the query. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderBySortDescriptor:(NSSortDescriptor *)sortDescriptor; + +/*! + @abstract Sort the results using a given array of sort descriptors. + + @warning If a `sortDescriptor` has custom `selector` or `comparator` - they aren't going to be used. + + @param sortDescriptors An array of `NSSortDescriptor` objects to use to sort the results of the query. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderBySortDescriptors:(PF_NULLABLE NSArray PF_GENERIC(NSSortDescriptor *) *)sortDescriptors; + +///-------------------------------------- +/// @name Getting Objects by ID +///-------------------------------------- + +/*! + @abstract Returns a with a given class and id. + + @param objectClass The class name for the object that is being requested. + @param objectId The id of the object that is being requested. + + @returns The if found. Returns `nil` if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFGenericObject)getObjectOfClass:(NSString *)objectClass + objectId:(NSString *)objectId PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Returns a with a given class and id and sets an error if necessary. + + @param objectClass The class name for the object that is being requested. + @param objectId The id of the object that is being requested. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The if found. Returns `nil` if the object isn't found, or if there was an `error`. + */ ++ (PF_NULLABLE PFGenericObject)getObjectOfClass:(NSString *)objectClass + objectId:(NSString *)objectId + error:(NSError **)error; + +/*! + @abstract Returns a with the given id. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + + @returns The if found. Returns nil if the object isn't found, or if there was an error. + */ +- (PF_NULLABLE PFGenericObject)getObjectWithId:(NSString *)objectId PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Returns a with the given id and sets an error if necessary. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The if found. Returns nil if the object isn't found, or if there was an error. + */ +- (PF_NULLABLE PFGenericObject)getObjectWithId:(NSString *)objectId error:(NSError **)error; + +/*! + @abstract Gets a asynchronously and calls the given block with the result. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(PFGenericObject) *)getObjectInBackgroundWithId:(NSString *)objectId; + +/*! + @abstract Gets a asynchronously and calls the given block with the result. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + @param block The block to execute. + The block should have the following argument signature: `^(NSArray *object, NSError *error)` + */ +- (void)getObjectInBackgroundWithId:(NSString *)objectId + block:(PF_NULLABLE void(^)(PFGenericObject PF_NULLABLE_S object, NSError *PF_NULLABLE_S error))block; + +/* + @abstract Gets a asynchronously. + + This mutates the PFQuery. It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object being requested. + @param target The target for the callback selector. + @param selector The selector for the callback. + 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)getObjectInBackgroundWithId:(NSString *)objectId + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting User Objects +///-------------------------------------- + +/*! + @abstract Returns a with a given id. + + @param objectId The id of the object that is being requested. + + @returns The PFUser if found. Returns nil if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFUser *)getUserObjectWithId:(NSString *)objectId PF_SWIFT_UNAVAILABLE; + +/*! + Returns a PFUser with a given class and id and sets an error if necessary. + @param objectId The id of the object that is being requested. + @param error Pointer to an NSError that will be set if necessary. + @result The PFUser if found. Returns nil if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFUser *)getUserObjectWithId:(NSString *)objectId error:(NSError **)error; + +/*! + @deprecated Please use [PFUser query] instead. + */ ++ (instancetype)queryForUser PARSE_DEPRECATED("Use [PFUser query] instead."); + +///-------------------------------------- +/// @name Getting all Matches for a Query +///-------------------------------------- + +/*! + @abstract Finds objects *synchronously* based on the constructed query. + + @returns Returns an array of objects that were found. + */ +- (PF_NULLABLE NSArray PF_GENERIC(PFGenericObject) *)findObjects PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Finds objects *synchronously* based on the constructed query and sets an error if there was one. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns an array of objects that were found. + */ +- (PF_NULLABLE NSArray PF_GENERIC(PFGenericObject) *)findObjects:(NSError **)error; + +/*! + @abstract Finds objects *asynchronously* and sets the `NSArray` of objects as a result of the task. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(NSArray *)*)findObjectsInBackground; + +/*! + @abstract Finds objects *asynchronously* and calls the given block with the results. + + @param block The block to execute. + It should have the following argument signature: `^(NSArray *objects, NSError *error)` + */ +- (void)findObjectsInBackgroundWithBlock:(PF_NULLABLE PFQueryArrayResultBlock)block; + +/* + @abstract Finds objects *asynchronously* and calls the given callback with the results. + + @param target The object to call the selector on. + @param selector The selector to call. + 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)findObjectsInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting the First Match in a Query +///-------------------------------------- + +/*! + @abstract Gets an object *synchronously* based on the constructed query. + + @warning This method mutates the query. It will reset the limit to `1`. + + @returns Returns a , or `nil` if none was found. + */ +- (PF_NULLABLE PFGenericObject)getFirstObject PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Gets an object *synchronously* based on the constructed query and sets an error if any occurred. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns a , or `nil` if none was found. + */ +- (PF_NULLABLE PFGenericObject)getFirstObject:(NSError **)error; + +/*! + @abstract Gets an object *asynchronously* and sets it as a result of the task. + + @warning This method mutates the query. It will reset the limit to `1`. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(PFGenericObject) *)getFirstObjectInBackground; + +/*! + @abstract Gets an object *asynchronously* and calls the given block with the result. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param block The block to execute. + It should have the following argument signature: `^(PFObject *object, NSError *error)`. + `result` will be `nil` if `error` is set OR no object was found matching the query. + `error` will be `nil` if `result` is set OR if the query succeeded, but found no results. + */ +- (void)getFirstObjectInBackgroundWithBlock:(PF_NULLABLE void(^)(PFGenericObject PF_NULLABLE_S object, NSError *PF_NULLABLE_S error))block; + +/* + @abstract Gets an object *asynchronously* and calls the given callback with the results. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param target The object to call the selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(PFObject *)result error:(NSError *)error`. + `result` will be `nil` if `error` is set OR no object was found matching the query. + `error` will be `nil` if `result` is set OR if the query succeeded, but found no results. + */ +- (void)getFirstObjectInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Counting the Matches in a Query +///-------------------------------------- + +/*! + @abstract Counts objects *synchronously* based on the constructed query. + + @returns Returns the number of objects that match the query, or `-1` if there is an error. + */ +- (NSInteger)countObjects PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Counts objects *synchronously* based on the constructed query and sets an error if there was one. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns the number of objects that match the query, or `-1` if there is an error. + */ +- (NSInteger)countObjects:(NSError **)error; + +/*! + @abstract Counts objects *asynchronously* and sets `NSNumber` with count as a result of the task. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(NSNumber *)*)countObjectsInBackground; + +/*! + @abstract Counts objects *asynchronously* and calls the given block with the counts. + + @param block The block to execute. + It should have the following argument signature: `^(int count, NSError *error)` + */ +- (void)countObjectsInBackgroundWithBlock:(PF_NULLABLE PFIntegerResultBlock)block; + +/* + @abstract Counts objects *asynchronously* and calls the given callback with the count. + + @param target The object to call the selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + */ +- (void)countObjectsInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Cancelling a Query +///-------------------------------------- + +/*! + @abstract Cancels the current network request (if any). Ensures that callbacks won't be called. + */ +- (void)cancel; + +///-------------------------------------- +/// @name Paginating Results +///-------------------------------------- + +/*! + @abstract A limit on the number of objects to return. The default limit is `100`, with a + maximum of 1000 results being returned at a time. + + @warning If you are calling `findObjects` with `limit = 1`, you may find it easier to use `getFirst` instead. + */ +@property (nonatomic, assign) NSInteger limit; + +/*! + @abstract The number of objects to skip before returning any. + */ +@property (nonatomic, assign) NSInteger skip; + +///-------------------------------------- +/// @name Controlling Caching Behavior +///-------------------------------------- + +/*! + @abstract The cache policy to use for requests. + + Not allowed when Pinning is enabled. + + @see fromLocalDatastore + @see fromPin + @see fromPinWithName: + */ +@property (assign, readwrite) PFCachePolicy cachePolicy; + +/*! + @abstract The age after which a cached value will be ignored + */ +@property (assign, readwrite) NSTimeInterval maxCacheAge; + +/*! + @abstract Returns whether there is a cached result for this query. + + @result `YES` if there is a cached result for this query, otherwise `NO`. + */ +- (BOOL)hasCachedResult; + +/*! + @abstract Clears the cached result for this query. If there is no cached result, this is a noop. + */ +- (void)clearCachedResult; + +/*! + @abstract Clears the cached results for all queries. + */ ++ (void)clearAllCachedResults; + +///-------------------------------------- +/// @name Query Source +///-------------------------------------- + +/*! + @abstract Change the source of this query to all pinned objects. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see cachePolicy + */ +- (instancetype)fromLocalDatastore; + +/*! + @abstract Change the source of this query to the default group of pinned objects. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see PFObjectDefaultPin + @see cachePolicy + */ +- (instancetype)fromPin; + +/*! + @abstract Change the source of this query to a specific group of pinned objects. + + @warning Requires Local Datastore to be enabled. + + @param name The pinned group. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see PFObjectDefaultPin + @see cachePolicy + */ +- (instancetype)fromPinWithName:(PF_NULLABLE NSString *)name; + +/*! + @abstract Ignore ACLs when querying from the Local Datastore. + + @discussion This is particularly useful when querying for objects with Role based ACLs set on them. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)ignoreACLs; + +///-------------------------------------- +/// @name Advanced Settings +///-------------------------------------- + +/*! + @abstract Whether or not performance tracing should be done on the query. + + @warning This should not be set to `YES` in most cases. + */ +@property (nonatomic, assign) BOOL trace; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFQuery.m b/Unit-2-Journal/Pods/Parse/Parse/PFQuery.m new file mode 100644 index 0000000..0fb3995 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFQuery.m @@ -0,0 +1,1136 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFQuery.h" + +#import +#import + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCoreManager.h" +#import "PFCurrentUserController.h" +#import "PFGeoPointPrivate.h" +#import "PFInternalUtils.h" +#import "PFKeyValueCache.h" +#import "PFMutableQueryState.h" +#import "PFObject.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFPin.h" +#import "PFQueryController.h" +#import "PFQueryUtilities.h" +#import "PFRESTQueryCommand.h" +#import "PFUserPrivate.h" +#import "ParseInternal.h" +#import "Parse_Private.h" + +NSString *const PFQueryKeyNotEqualTo = @"$ne"; +NSString *const PFQueryKeyLessThan = @"$lt"; +NSString *const PFQueryKeyLessThanEqualTo = @"$lte"; +NSString *const PFQueryKeyGreaterThan = @"$gt"; +NSString *const PFQueryKeyGreaterThanOrEqualTo = @"$gte"; +NSString *const PFQueryKeyContainedIn = @"$in"; +NSString *const PFQueryKeyNotContainedIn = @"$nin"; +NSString *const PFQueryKeyContainsAll = @"$all"; +NSString *const PFQueryKeyNearSphere = @"$nearSphere"; +NSString *const PFQueryKeyWithin = @"$within"; +NSString *const PFQueryKeyRegex = @"$regex"; +NSString *const PFQueryKeyExists = @"$exists"; +NSString *const PFQueryKeyInQuery = @"$inQuery"; +NSString *const PFQueryKeyNotInQuery = @"$notInQuery"; +NSString *const PFQueryKeySelect = @"$select"; +NSString *const PFQueryKeyDontSelect = @"$dontSelect"; +NSString *const PFQueryKeyRelatedTo = @"$relatedTo"; +NSString *const PFQueryKeyOr = @"$or"; +NSString *const PFQueryKeyQuery = @"query"; +NSString *const PFQueryKeyKey = @"key"; +NSString *const PFQueryKeyObject = @"object"; + +NSString *const PFQueryOptionKeyMaxDistance = @"$maxDistance"; +NSString *const PFQueryOptionKeyBox = @"$box"; +NSString *const PFQueryOptionKeyRegexOptions = @"$options"; + +/*! + Checks if an object can be used as value for query equality clauses. + */ +static void PFQueryAssertValidEqualityClauseClass(id object) { + static NSArray *classes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + classes = @[ [NSString class], [NSNumber class], [NSDate class], [NSNull class], + [PFObject class], [PFGeoPoint class] ]; + }); + + for (Class class in classes) { + if ([object isKindOfClass:class]) { + return; + } + } + + PFParameterAssert(NO, @"Cannot do a comparison query for type: %@", [object class]); +} + +/*! + Checks if an object can be used as value for query ordering clauses. + */ +static void PFQueryAssertValidOrderingClauseClass(id object) { + static NSArray *classes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + classes = @[ [NSString class], [NSNumber class], [NSDate class] ]; + }); + + for (Class class in classes) { + if ([object isKindOfClass:class]) { + return; + } + } + + PFParameterAssert(NO, @"Cannot do a query that requires ordering for type: %@", [object class]); +} + +@interface PFQuery () { + BFCancellationTokenSource *_cancellationTokenSource; +} + +@property (nonatomic, strong, readwrite) PFMutableQueryState *state; + +@end + +@implementation PFQuery + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithState:(PFQueryState *)state { + self = [super init]; + if (!self) return nil; + + _state = [state mutableCopy]; + + return self; +} + +- (instancetype)initWithClassName:(NSString *)className { + self = [super init]; + if (!self) return nil; + + _state = [PFMutableQueryState stateWithParseClassName:className]; + + return self; +} + +///-------------------------------------- +#pragma mark - Public Accessors +///-------------------------------------- + +#pragma mark Basic + +- (NSString *)parseClassName { + return self.state.parseClassName; +} + +- (void)setParseClassName:(NSString *)parseClassName { + [self checkIfCommandIsRunning]; + self.state.parseClassName = parseClassName; +} + +#pragma mark Limit + +- (void)setLimit:(NSInteger)limit { + self.state.limit = limit; +} + +- (NSInteger)limit { + return self.state.limit; +} + +#pragma mark Skip + +- (void)setSkip:(NSInteger)skip { + self.state.skip = skip; +} + +- (NSInteger)skip { + return self.state.skip; +} + +#pragma mark Cache Policy + +- (void)setCachePolicy:(PFCachePolicy)cachePolicy { + [self _checkPinningEnabled:NO]; + [self checkIfCommandIsRunning]; + + self.state.cachePolicy = cachePolicy; +} + +- (PFCachePolicy)cachePolicy { + [self _checkPinningEnabled:NO]; + [self checkIfCommandIsRunning]; + + return self.state.cachePolicy; +} + +#pragma mark Cache Policy + +- (void)setMaxCacheAge:(NSTimeInterval)maxCacheAge { + self.state.maxCacheAge = maxCacheAge; +} + +- (NSTimeInterval)maxCacheAge { + return self.state.maxCacheAge; +} + +#pragma mark Trace + +- (void)setTrace:(BOOL)trace { + self.state.trace = trace; +} + +- (BOOL)trace { + return self.state.trace; +} + +///-------------------------------------- +#pragma mark - Order +///-------------------------------------- + +- (instancetype)orderByAscending:(NSString *)key { + [self checkIfCommandIsRunning]; + [self.state sortByKey:key ascending:YES]; + return self; +} + +- (instancetype)addAscendingOrder:(NSString *)key { + [self checkIfCommandIsRunning]; + [self.state addSortKey:key ascending:YES]; + return self; +} + +- (instancetype)orderByDescending:(NSString *)key { + [self checkIfCommandIsRunning]; + [self.state sortByKey:key ascending:NO]; + return self; +} + +- (instancetype)addDescendingOrder:(NSString *)key { + [self checkIfCommandIsRunning]; + [self.state addSortKey:key ascending:NO]; + return self; +} + +- (instancetype)orderBySortDescriptor:(NSSortDescriptor *)sortDescriptor { + NSString *key = sortDescriptor.key; + if (key) { + if (sortDescriptor.ascending) { + [self orderByAscending:key]; + } else { + [self orderByDescending:key]; + } + } + return self; +} + +- (instancetype)orderBySortDescriptors:(NSArray *)sortDescriptors { + [self.state addSortKeysFromSortDescriptors:sortDescriptors]; + return self; +} + +///-------------------------------------- +#pragma mark - Conditions +///-------------------------------------- + +// Helper for condition queries. +- (instancetype)whereKey:(NSString *)key condition:(NSString *)condition object:(id)object { + [self checkIfCommandIsRunning]; + [self.state setConditionType:condition withObject:object forKey:key]; + return self; +} + +- (instancetype)whereKey:(NSString *)key equalTo:(id)object { + [self checkIfCommandIsRunning]; + PFQueryAssertValidEqualityClauseClass(object); + [self.state setEqualityConditionWithObject:object forKey:key]; + return self; +} + +- (instancetype)whereKey:(NSString *)key greaterThan:(id)object { + PFQueryAssertValidOrderingClauseClass(object); + return [self whereKey:key condition:PFQueryKeyGreaterThan object:object]; +} + +- (instancetype)whereKey:(NSString *)key greaterThanOrEqualTo:(id)object { + PFQueryAssertValidOrderingClauseClass(object); + return [self whereKey:key condition:PFQueryKeyGreaterThanOrEqualTo object:object]; +} + +- (instancetype)whereKey:(NSString *)key lessThan:(id)object { + PFQueryAssertValidOrderingClauseClass(object); + return [self whereKey:key condition:PFQueryKeyLessThan object:object]; +} + +- (instancetype)whereKey:(NSString *)key lessThanOrEqualTo:(id)object { + PFQueryAssertValidOrderingClauseClass(object); + return [self whereKey:key condition:PFQueryKeyLessThanEqualTo object:object]; +} + +- (instancetype)whereKey:(NSString *)key notEqualTo:(id)object { + PFQueryAssertValidEqualityClauseClass(object); + return [self whereKey:key condition:PFQueryKeyNotEqualTo object:object]; +} + +- (instancetype)whereKey:(NSString *)key containedIn:(NSArray *)inArray { + return [self whereKey:key condition:PFQueryKeyContainedIn object:inArray]; +} + +- (instancetype)whereKey:(NSString *)key notContainedIn:(NSArray *)inArray { + return [self whereKey:key condition:PFQueryKeyNotContainedIn object:inArray]; +} + +- (instancetype)whereKey:(NSString *)key containsAllObjectsInArray:(NSArray *)array { + return [self whereKey:key condition:PFQueryKeyContainsAll object:array]; +} + +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint { + return [self whereKey:key condition:PFQueryKeyNearSphere object:geopoint]; +} + +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint withinRadians:(double)maxDistance { + return [[self whereKey:key condition:PFQueryKeyNearSphere object:geopoint] + whereKey:key condition:PFQueryOptionKeyMaxDistance object:@(maxDistance)]; +} + +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint withinMiles:(double)maxDistance { + return [self whereKey:key nearGeoPoint:geopoint withinRadians:(maxDistance/EARTH_RADIUS_MILES)]; +} + +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint withinKilometers:(double)maxDistance { + return [self whereKey:key nearGeoPoint:geopoint withinRadians:(maxDistance/EARTH_RADIUS_KILOMETERS)]; +} + +- (instancetype)whereKey:(NSString *)key withinGeoBoxFromSouthwest:(PFGeoPoint *)southwest toNortheast:(PFGeoPoint *)northeast { + NSArray *array = @[ southwest, northeast ]; + NSDictionary *dictionary = @{ PFQueryOptionKeyBox : array }; + return [self whereKey:key condition:PFQueryKeyWithin object:dictionary]; +} + +- (instancetype)whereKey:(NSString *)key matchesRegex:(NSString *)regex { + return [self whereKey:key condition:PFQueryKeyRegex object:regex]; +} + +- (instancetype)whereKey:(NSString *)key matchesRegex:(NSString *)regex modifiers:(NSString *)modifiers { + [self checkIfCommandIsRunning]; + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:2]; + dictionary[PFQueryKeyRegex] = regex; + if ([modifiers length]) { + dictionary[PFQueryOptionKeyRegexOptions] = modifiers; + } + [self.state setEqualityConditionWithObject:dictionary forKey:key]; + return self; +} + +- (instancetype)whereKey:(NSString *)key containsString:(NSString *)substring { + NSString *regex = [PFQueryUtilities regexStringForString:substring]; + return [self whereKey:key matchesRegex:regex]; +} + +- (instancetype)whereKey:(NSString *)key hasPrefix:(NSString *)prefix { + NSString *regex = [NSString stringWithFormat:@"^%@", [PFQueryUtilities regexStringForString:prefix]]; + return [self whereKey:key matchesRegex:regex]; +} + +- (instancetype)whereKey:(NSString *)key hasSuffix:(NSString *)suffix { + NSString *regex = [NSString stringWithFormat:@"%@$", [PFQueryUtilities regexStringForString:suffix]]; + return [self whereKey:key matchesRegex:regex]; +} + +- (instancetype)whereKeyExists:(NSString *)key { + return [self whereKey:key condition:PFQueryKeyExists object:@YES]; +} + +- (instancetype)whereKeyDoesNotExist:(NSString *)key { + return [self whereKey:key condition:PFQueryKeyExists object:@NO]; +} + +- (instancetype)whereKey:(NSString *)key matchesQuery:(PFQuery *)query { + return [self whereKey:key condition:PFQueryKeyInQuery object:query]; +} + +- (instancetype)whereKey:(NSString *)key doesNotMatchQuery:(PFQuery *)query { + return [self whereKey:key condition:PFQueryKeyNotInQuery object:query]; +} + +- (instancetype)whereKey:(NSString *)key matchesKey:(NSString *)otherKey inQuery:(PFQuery *)query { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:2]; + dict[PFQueryKeyQuery] = query; + dict[PFQueryKeyKey] = otherKey; + return [self whereKey:key condition:PFQueryKeySelect object:dict]; +} + +- (instancetype)whereKey:(NSString *)key doesNotMatchKey:(NSString *)otherKey inQuery:(PFQuery *)query { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:2]; + dict[PFQueryKeyQuery] = query; + dict[PFQueryKeyKey] = otherKey; + return [self whereKey:key condition:PFQueryKeyDontSelect object:dict]; +} + +- (instancetype)whereRelatedToObject:(PFObject *)parent fromKey:(NSString *)key { + [self.state setRelationConditionWithObject:parent forKey:key]; + return self; +} + +- (void)redirectClassNameForKey:(NSString *)key { + [self.state redirectClassNameForKey:key]; +} + +///-------------------------------------- +#pragma mark - Include +///-------------------------------------- + +- (instancetype)includeKey:(NSString *)key { + [self checkIfCommandIsRunning]; + [self.state includeKey:key]; + return self; +} + +///-------------------------------------- +#pragma mark - Select +///-------------------------------------- + +- (instancetype)selectKeys:(NSArray *)keys { + [self checkIfCommandIsRunning]; + [self.state selectKeys:keys]; + return self; +} + +///-------------------------------------- +#pragma mark - NSPredicate helper methods +///-------------------------------------- + ++ (void)assertKeyPathConstant:(NSComparisonPredicate *)predicate { + PFConsistencyAssert(predicate.leftExpression.expressionType == NSKeyPathExpressionType && + predicate.rightExpression.expressionType == NSConstantValueExpressionType, + @"This predicate must have a key path and a constant. %@", predicate); +} + +// Adds the conditions from an NSComparisonPredicate to a PFQuery. +- (void)whereComparisonPredicate:(NSComparisonPredicate *)predicate { + NSExpression *left = predicate.leftExpression; + NSExpression *right = predicate.rightExpression; + + switch (predicate.predicateOperatorType) { + case NSEqualToPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath equalTo:(right.constantValue ?: [NSNull null])]; + return; + } + case NSNotEqualToPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath notEqualTo:(right.constantValue ?: [NSNull null])]; + return; + } + case NSLessThanPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath lessThan:right.constantValue]; + return; + } + case NSLessThanOrEqualToPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath lessThanOrEqualTo:right.constantValue]; + return; + } + case NSGreaterThanPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath greaterThan:right.constantValue]; + return; + } + case NSGreaterThanOrEqualToPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath greaterThanOrEqualTo:right.constantValue]; + return; + } + case NSInPredicateOperatorType: { + if (left.expressionType == NSKeyPathExpressionType && + right.expressionType == NSConstantValueExpressionType) { + if ([right.constantValue isKindOfClass:[PFQuery class]]) { + // Like "value IN subquery + [self whereKey:left.keyPath matchesQuery:right.constantValue]; + } else { + // Like "value IN %@", @{@1, @2, @3, @4} + [self whereKey:left.keyPath containedIn:right.constantValue]; + } + } else if (left.expressionType == NSKeyPathExpressionType && + right.expressionType == NSAggregateExpressionType && + [right.constantValue isKindOfClass:[NSArray class]]) { + // Like "value IN {1, 2, 3, 4}" + NSArray *constants = right.constantValue; + NSMutableArray *values = [NSMutableArray arrayWithCapacity:constants.count]; + for (NSExpression *expression in constants) { + [values addObject:expression.constantValue]; + } + [self whereKey:left.keyPath containedIn:values]; + } else if (right.expressionType == NSEvaluatedObjectExpressionType && + left.expressionType == NSKeyPathExpressionType) { + // Like "value IN SELF" + [self whereKeyExists:left.keyPath]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"An IN predicate must have a key path and a constant."]; + } + return; + } + case NSCustomSelectorPredicateOperatorType: { + if (predicate.customSelector != NSSelectorFromString(@"notContainedIn:")) { + [NSException raise:NSInternalInconsistencyException + format:@"Predicates with custom selectors are not supported."]; + } + + if (right.expressionType == NSConstantValueExpressionType && + left.expressionType == NSKeyPathExpressionType) { + if ([right.constantValue isKindOfClass:[PFQuery class]]) { + // Like "NOT (value IN subquery)" + [self whereKey:left.keyPath doesNotMatchQuery:right.constantValue]; + } else { + // Like "NOT (value in %@)", @{@1, @2, @3} + [self whereKey:left.keyPath notContainedIn:right.constantValue]; + } + } else if (left.expressionType == NSKeyPathExpressionType && + right.expressionType == NSAggregateExpressionType && + [right.constantValue isKindOfClass:[NSArray class]]) { + // Like "NOT (value IN {1, 2, 3, 4})" + NSArray *constants = right.constantValue; + NSMutableArray *values = [NSMutableArray arrayWithCapacity:constants.count]; + for (NSExpression *expression in constants) { + [values addObject:expression.constantValue]; + } + [self whereKey:left.keyPath notContainedIn:values]; + } else if (right.expressionType == NSEvaluatedObjectExpressionType && + left.expressionType == NSKeyPathExpressionType) { + // Like "NOT (value IN SELF)" + [self whereKeyDoesNotExist:left.keyPath]; + } else { + [NSException raise:NSInternalInconsistencyException + format:@"A NOT IN predicate must have a key path and a constant array."]; + } + return; + } + case NSBeginsWithPredicateOperatorType: { + [[self class] assertKeyPathConstant:predicate]; + [self whereKey:left.keyPath hasPrefix:right.constantValue]; + return; + } + case NSContainsPredicateOperatorType: { + [NSException raise:NSInternalInconsistencyException + format:@"Regex queries are not supported with " + "[PFQuery queryWithClassName:predicate:]. Please try to structure your " + "data so that you can use an equalTo or containedIn query."]; + } + case NSEndsWithPredicateOperatorType: { + [NSException raise:NSInternalInconsistencyException + format:@"Regex queries are not supported with " + "[PFQuery queryWithClassName:predicate:]. Please try to structure your " + "data so that you can use an equalTo or containedIn query."]; + } + case NSMatchesPredicateOperatorType: { + [NSException raise:NSInternalInconsistencyException + format:@"Regex queries are not supported with " + "[PFQuery queryWithClassName:predicate:]. Please try to structure your " + "data so that you can use an equalTo or containedIn query."]; + } + case NSLikePredicateOperatorType: { + [NSException raise:NSInternalInconsistencyException + format:@"LIKE is not supported by PFQuery."]; + } + default: { + [NSException raise:NSInternalInconsistencyException + format:@"This comparison predicate is not supported. (%zd)", predicate.predicateOperatorType]; + } + } +} + +/*! + Creates a PFQuery with the constraints given by predicate. + This method assumes the predicate has already been normalized. + */ ++ (instancetype)queryWithClassName:(NSString *)className normalizedPredicate:(NSPredicate *)predicate { + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + PFQuery *query = [self queryWithClassName:className]; + [query whereComparisonPredicate:(NSComparisonPredicate *)predicate]; + return query; + } else if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate; + switch (compound.compoundPredicateType) { + case NSAndPredicateType: { + PFQuery *query = nil; + NSMutableArray *subpredicates = [NSMutableArray array]; + // If there's an OR query in here, we'll start with it. + for (NSPredicate *subpredicate in compound.subpredicates) { + if ([subpredicate isKindOfClass:[NSCompoundPredicate class]] && + ((NSCompoundPredicate *)subpredicate).compoundPredicateType == NSOrPredicateType) { + if (query) { + [NSException raise:NSInternalInconsistencyException + format:@"A query had 2 ORs in an AND after normalization. %@", + predicate]; + } + query = [self queryWithClassName:className normalizedPredicate:subpredicate]; + } else { + [subpredicates addObject:subpredicate]; + } + } + // If there was no OR query, then start with an empty query. + if (!query) { + query = [self queryWithClassName:className]; + } + for (NSPredicate *subpredicate in subpredicates) { + if (![subpredicate isKindOfClass:[NSComparisonPredicate class]]) { + // This should never happen. + [NSException raise:NSInternalInconsistencyException + format:@"A predicate had a non-comparison predicate inside an AND " + "after normalization. %@", predicate]; + } + NSComparisonPredicate *comparison = (NSComparisonPredicate *)subpredicate; + [query whereComparisonPredicate:comparison]; + } + return query; + } + case NSOrPredicateType: { + NSMutableArray *subqueries = [NSMutableArray arrayWithCapacity:compound.subpredicates.count]; + if (compound.subpredicates.count > 4) { + [NSException raise:NSInternalInconsistencyException + format:@"This query is too complex. It had an OR with >4 subpredicates " + "after normalization."]; + } + for (NSPredicate *subpredicate in compound.subpredicates) { + [subqueries addObject:[self queryWithClassName:className normalizedPredicate:subpredicate]]; + } + return [self orQueryWithSubqueries:subqueries]; + } + default: { + // This should never happen. + [NSException raise:NSInternalInconsistencyException + format:@"A predicate had a NOT after normalization. %@", predicate]; + return nil; + } + } + } else { + [NSException raise:NSInternalInconsistencyException format:@"Unknown predicate type."]; + return nil; + } +} + +///-------------------------------------- +#pragma mark - Helpers +///-------------------------------------- + +- (void)checkIfCommandIsRunning { + @synchronized (self) { + if (_cancellationTokenSource) { + [NSException raise:NSInternalInconsistencyException + format:@"This query has an outstanding network connection. You have to wait until it's done."]; + } + } +} + +- (void)markAsRunning:(BFCancellationTokenSource *)source { + [self checkIfCommandIsRunning]; + @synchronized (self) { + _cancellationTokenSource = source; + } +} + +///-------------------------------------- +#pragma mark - Constructors +///-------------------------------------- + ++ (instancetype)queryWithClassName:(NSString *)className { + return [[self alloc] initWithClassName:className]; +} + ++ (instancetype)queryWithClassName:(NSString *)className predicate:(NSPredicate *)predicate { + if (!predicate) { + return [self queryWithClassName:className]; + } + + NSPredicate *normalizedPredicate = [PFQueryUtilities predicateByNormalizingPredicate:predicate]; + return [self queryWithClassName:className normalizedPredicate:normalizedPredicate]; +} + ++ (instancetype)orQueryWithSubqueries:(NSArray *)queries { + NSMutableArray *array = [NSMutableArray array]; + NSString *className = nil; + for (id object in queries) { + PFParameterAssert([object isKindOfClass:[PFQuery class]], + @"All elements should be instances of `PFQuery` class."); + + PFQuery *query = (PFQuery *)object; + if (!className) { + className = query.parseClassName; + } else { + PFParameterAssert([query.parseClassName isEqualToString:className], + @"All sub queries of an `or` query should be on the same class."); + } + + [array addObject:query]; + } + PFQuery *query = [self queryWithClassName:className]; + [query.state setEqualityConditionWithObject:array forKey:PFQueryKeyOr]; + return query; +} + +///-------------------------------------- +#pragma mark - Get with objectId +///-------------------------------------- + ++ (PFObject *)getObjectOfClass:(NSString *)objectClass objectId:(NSString *)objectId { + return [self getObjectOfClass:objectClass objectId:objectId error:nil]; +} + ++ (PFObject *)getObjectOfClass:(NSString *)objectClass + objectId:(NSString *)objectId + error:(NSError **)error { + PFQuery *query = [self queryWithClassName:objectClass]; + return [query getObjectWithId:objectId error:error]; +} + +// TODO (hallucinogen): we may want to remove this in 2.0 since we can just use the static counterpart +- (PFObject *)getObjectWithId:(NSString *)objectId { + return [self getObjectWithId:objectId error:nil]; +} + +- (PFObject *)getObjectWithId:(NSString *)objectId error:(NSError **)error { + return [[self getObjectInBackgroundWithId:objectId] waitForResult:error]; +} + +- (BFTask *)getObjectInBackgroundWithId:(NSString *)objectId { + if ([objectId length] == 0) { + return [BFTask taskWithResult:nil]; + } + + PFConsistencyAssert(self.state.cachePolicy != kPFCachePolicyCacheThenNetwork, + @"kPFCachePolicyCacheThenNetwork can only be used with methods that have a callback."); + return [self _getObjectWithIdAsync:objectId cachePolicy:self.state.cachePolicy after:nil]; +} + +- (void)getObjectInBackgroundWithId:(NSString *)objectId block:(PFObjectResultBlock)block { + @synchronized (self) { + if (!self.state.queriesLocalDatastore && self.state.cachePolicy == kPFCachePolicyCacheThenNetwork) { + BFTask *cacheTask = [[self _getObjectWithIdAsync:objectId + cachePolicy:kPFCachePolicyCacheOnly + after:nil] thenCallBackOnMainThreadAsync:block]; + [[self _getObjectWithIdAsync:objectId + cachePolicy:kPFCachePolicyNetworkOnly + after:cacheTask] thenCallBackOnMainThreadAsync:block]; + } else { + [[self getObjectInBackgroundWithId:objectId] thenCallBackOnMainThreadAsync:block]; + } + } +} + +- (void)getObjectInBackgroundWithId:(NSString *)objectId target:(id)target selector:(SEL)selector { + [self getObjectInBackgroundWithId:objectId block:^(PFObject *object, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:object object:error]; + }]; +} + +- (BFTask *)_getObjectWithIdAsync:(NSString *)objectId cachePolicy:(PFCachePolicy)cachePolicy after:(BFTask *)task { + self.limit = 1; + self.skip = 0; + [self.state removeAllConditions]; + [self.state setEqualityConditionWithObject:objectId forKey:@"objectId"]; + + PFQueryState *state = [self _queryStateCopyWithCachePolicy:cachePolicy]; + return [[self _findObjectsAsyncForQueryState:state + after:task] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *objects = task.result; + if (objects.count == 0) { + return [BFTask taskWithError:[PFQueryUtilities objectNotFoundError]]; + } + + return [BFTask taskWithResult:objects.lastObject]; + }]; +} + +///-------------------------------------- +#pragma mark - Get Users (Deprecated) +///-------------------------------------- + ++ (PFUser *)getUserObjectWithId:(NSString *)objectId { + return [self getUserObjectWithId:objectId error:nil]; +} + ++ (PFUser *)getUserObjectWithId:(NSString *)objectId error:(NSError **)error { + PFQuery *query = [PFUser query]; + PFUser *object = (PFUser *)[query getObjectWithId:objectId error:error]; + + return object; +} + ++ (instancetype)queryForUser { + return [PFUser query]; +} + +///-------------------------------------- +#pragma mark - Find Objects +///-------------------------------------- + +- (NSArray *)findObjects { + return [self findObjects:nil]; +} + +- (NSArray *)findObjects:(NSError **)error { + return [[self findObjectsInBackground] waitForResult:error]; +} + +- (BFTask *)findObjectsInBackground { + PFQueryState *state = [self _queryStateCopy]; + + PFConsistencyAssert(state.cachePolicy != kPFCachePolicyCacheThenNetwork, + @"kPFCachePolicyCacheThenNetwork can only be used with methods that have a callback."); + return [self _findObjectsAsyncForQueryState:state after:nil]; +} + +- (void)findObjectsInBackgroundWithBlock:(PFQueryArrayResultBlock)block { + @synchronized (self) { + if (!self.state.queriesLocalDatastore && self.state.cachePolicy == kPFCachePolicyCacheThenNetwork) { + PFQueryState *cacheQueryState = [self _queryStateCopyWithCachePolicy:kPFCachePolicyCacheOnly]; + BFTask *cacheTask = [[self _findObjectsAsyncForQueryState:cacheQueryState + after:nil] thenCallBackOnMainThreadAsync:block]; + + PFQueryState *remoteQueryState = [self _queryStateCopyWithCachePolicy:kPFCachePolicyNetworkOnly]; + [[self _findObjectsAsyncForQueryState:remoteQueryState + after:cacheTask] thenCallBackOnMainThreadAsync:block]; + } else { + [[self findObjectsInBackground] thenCallBackOnMainThreadAsync:block]; + } + } +} + +- (void)findObjectsInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:objects object:error]; + }]; +} + +- (BFTask *)_findObjectsAsyncForQueryState:(PFQueryState *)queryState after:(BFTask *)previous { + BFCancellationTokenSource *cancellationTokenSource = _cancellationTokenSource; + if (!previous) { + cancellationTokenSource = [BFCancellationTokenSource cancellationTokenSource]; + [self markAsRunning:cancellationTokenSource]; + } + + BFTask *start = (previous ?: [BFTask taskWithResult:nil]); + + [self _validateQueryState]; + @weakify(self); + return [[[start continueWithBlock:^id(BFTask *task) { + @strongify(self); + return [[self class] _getCurrentUserForQueryState:queryState]; + }] continueWithBlock:^id(BFTask *task) { + @strongify(self); + PFUser *user = task.result; + return [[[self class] queryController] findObjectsAsyncForQueryState:queryState + withCancellationToken:cancellationTokenSource.token + user:user]; + }] continueWithBlock:^id(BFTask *task) { + @strongify(self); + if (!self) { + return task; + } + @synchronized (self) { + if (_cancellationTokenSource == cancellationTokenSource) { + _cancellationTokenSource = nil; + } + } + return task; + }]; +} + +///-------------------------------------- +#pragma mark - Get Object +///-------------------------------------- + +- (PFObject *)getFirstObject { + return [self getFirstObject:nil]; +} + +- (PFObject *)getFirstObject:(NSError **)error { + return [[self getFirstObjectInBackground] waitForResult:error]; +} + +- (BFTask *)getFirstObjectInBackground { + PFConsistencyAssert(self.state.cachePolicy != kPFCachePolicyCacheThenNetwork, + @"kPFCachePolicyCacheThenNetwork can only be used with methods that have a callback."); + return [self _getFirstObjectAsyncWithCachePolicy:self.state.cachePolicy after:nil]; +} + +- (void)getFirstObjectInBackgroundWithBlock:(PFObjectResultBlock)block { + @synchronized (self) { + if (!self.state.queriesLocalDatastore && self.state.cachePolicy == kPFCachePolicyCacheThenNetwork) { + BFTask *cacheTask = [[self _getFirstObjectAsyncWithCachePolicy:kPFCachePolicyCacheOnly + after:nil] thenCallBackOnMainThreadAsync:block]; + [[self _getFirstObjectAsyncWithCachePolicy:kPFCachePolicyNetworkOnly + after:cacheTask] thenCallBackOnMainThreadAsync:block]; + } else { + [[self getFirstObjectInBackground] thenCallBackOnMainThreadAsync:block]; + } + } +} + +- (void)getFirstObjectInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self getFirstObjectInBackgroundWithBlock:^(PFObject *result, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:result object:error]; + }]; +} + +- (BFTask *)_getFirstObjectAsyncWithCachePolicy:(PFCachePolicy)cachePolicy after:(BFTask *)task { + self.limit = 1; + + PFQueryState *state = [self _queryStateCopyWithCachePolicy:cachePolicy]; + return [[self _findObjectsAsyncForQueryState:state after:task] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *objects = task.result; + if (objects.count == 0) { + return [BFTask taskWithError:[PFQueryUtilities objectNotFoundError]]; + } + + return [BFTask taskWithResult:objects.lastObject]; + }]; +} + +///-------------------------------------- +#pragma mark - Count Objects +///-------------------------------------- + +- (NSInteger)countObjects { + return [self countObjects:nil]; +} + +- (NSInteger)countObjects:(NSError **)error { + NSNumber *count = [[self countObjectsInBackground] waitForResult:error]; + if (!count) { + // TODO: (nlutsenko) It's really weird that we are inconsistent in sync vs async methods. + // Leaving for now since some devs might be relying on this. + return -1; + } + + return [count integerValue]; +} + +- (BFTask *)countObjectsInBackground { + PFConsistencyAssert(self.state.cachePolicy != kPFCachePolicyCacheThenNetwork, + @"kPFCachePolicyCacheThenNetwork can only be used with methods that have a callback."); + return [self _countObjectsAsyncForQueryState:[self _queryStateCopy] after:nil]; +} + +- (void)countObjectsInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self countObjectsInBackgroundWithBlock:^(int number, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(number) object:error]; + }]; +} + +- (void)countObjectsInBackgroundWithBlock:(PFIntegerResultBlock)block { + PFIdResultBlock callback = nil; + if (block) { + callback = ^(id result, NSError *error) { + block([result intValue], error); + }; + } + + @synchronized (self) { + if (!self.state.queriesLocalDatastore && self.state.cachePolicy == kPFCachePolicyCacheThenNetwork) { + PFQueryState *cacheQueryState = [self _queryStateCopyWithCachePolicy:kPFCachePolicyCacheOnly]; + BFTask *cacheTask = [[self _countObjectsAsyncForQueryState:cacheQueryState + after:nil] thenCallBackOnMainThreadAsync:callback]; + + PFQueryState *remoteQueryState = [self _queryStateCopyWithCachePolicy:kPFCachePolicyNetworkOnly]; + [[self _countObjectsAsyncForQueryState:remoteQueryState + after:cacheTask] thenCallBackOnMainThreadAsync:callback]; + } else { + [[self countObjectsInBackground] thenCallBackOnMainThreadAsync:callback]; + } + } +} + +- (BFTask *)_countObjectsAsyncForQueryState:(PFQueryState *)queryState after:(BFTask *)previousTask { + BFCancellationTokenSource *cancellationTokenSource = _cancellationTokenSource; + if (!previousTask) { + cancellationTokenSource = [BFCancellationTokenSource cancellationTokenSource]; + [self markAsRunning:cancellationTokenSource]; + } + + BFTask *start = (previousTask ?: [BFTask taskWithResult:nil]); + + [self _validateQueryState]; + @weakify(self); + return [[[start continueWithBlock:^id(BFTask *task) { + return [[self class] _getCurrentUserForQueryState:queryState]; + }] continueWithBlock:^id(BFTask *task) { + @strongify(self); + PFUser *user = task.result; + return [[[self class] queryController] countObjectsAsyncForQueryState:queryState + withCancellationToken:cancellationTokenSource.token + user:user]; + }] continueWithBlock:^id(BFTask *task) { + @synchronized(self) { + if (_cancellationTokenSource == cancellationTokenSource) { + _cancellationTokenSource = nil; + } + } + return task; + }]; +} + +///-------------------------------------- +#pragma mark - Cancel +///-------------------------------------- + +- (void)cancel { + @synchronized (self) { + if (_cancellationTokenSource) { + [_cancellationTokenSource cancel]; + _cancellationTokenSource = nil; + } + } +} + +///-------------------------------------- +#pragma mark - NSCopying +///-------------------------------------- + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[[self class] allocWithZone:zone] initWithState:self.state]; +} + +///-------------------------------------- +#pragma mark NSObject +///-------------------------------------- + +- (NSUInteger)hash { + return [self.state hash]; +} + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[PFQuery class]]) { + return NO; + } + + return [self.state isEqual:((PFQuery *)object).state]; +} + +///-------------------------------------- +#pragma mark - Caching +///-------------------------------------- + +- (BOOL)hasCachedResult { + return [[[self class] queryController] hasCachedResultForQueryState:self.state + sessionToken:[PFUser currentSessionToken]]; +} + +- (void)clearCachedResult { + [[[self class] queryController] clearCachedResultForQueryState:self.state + sessionToken:[PFUser currentSessionToken]]; +} + ++ (void)clearAllCachedResults { + [[self queryController] clearAllCachedResults]; +} + +///-------------------------------------- +#pragma mark - Check Pinning Status +///-------------------------------------- + +/*! + If `enabled` is YES, raise an exception if OfflineStore is not enabled. If `enabled` is NO, raise + an exception if OfflineStore is enabled. + */ +- (void)_checkPinningEnabled:(BOOL)enabled { + BOOL loaded = [Parse _currentManager].offlineStoreLoaded; + if (enabled) { + PFConsistencyAssert(loaded, @"Method requires Pinning enabled."); + } else { + PFConsistencyAssert(!loaded, @"Method not allowed when Pinning is enabled."); + } +} + +///-------------------------------------- +#pragma mark - Query Source +///-------------------------------------- + +- (instancetype)fromLocalDatastore { + return [self fromPinWithName:nil]; +} + +- (instancetype)fromPin { + return [self fromPinWithName:PFObjectDefaultPin]; +} + +- (instancetype)fromPinWithName:(NSString *)name { + [self _checkPinningEnabled:YES]; + [self checkIfCommandIsRunning]; + + self.state.queriesLocalDatastore = YES; + self.state.localDatastorePinName = [name copy]; + + return self; +} + +- (instancetype)ignoreACLs { + [self _checkPinningEnabled:YES]; + [self checkIfCommandIsRunning]; + + self.state.shouldIgnoreACLs = YES; + + return self; +} + +///-------------------------------------- +#pragma mark - Query State +///-------------------------------------- + +- (PFQueryState *)_queryStateCopy { + return [self.state copy]; +} + +- (PFQueryState *)_queryStateCopyWithCachePolicy:(PFCachePolicy)cachePolicy { + PFMutableQueryState *state = [self.state mutableCopy]; + state.cachePolicy = cachePolicy; + return state; +} + +- (void)_validateQueryState { + PFConsistencyAssert(self.state.queriesLocalDatastore || !self.state.shouldIgnoreACLs, + @"`ignoreACLs` can only be used with Local Datastore queries."); +} + +///-------------------------------------- +#pragma mark - Query Controller +///-------------------------------------- + ++ (PFQueryController *)queryController { + return [Parse _currentManager].coreManager.queryController; +} + +///-------------------------------------- +#pragma mark - User +///-------------------------------------- + ++ (BFTask *)_getCurrentUserForQueryState:(PFQueryState *)state { + if (state.shouldIgnoreACLs) { + return [BFTask taskWithResult:nil]; + } + return [[Parse _currentManager].coreManager.currentUserController getCurrentObjectAsync]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFRelation.h b/Unit-2-Journal/Pods/Parse/Parse/PFRelation.h new file mode 100644 index 0000000..af64ff9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFRelation.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFRelation` class that is used to access all of the children of a many-to-many relationship. + Each instance of `PFRelation` is associated with a particular parent object and key. + */ +@interface PFRelation : NSObject + +/*! + @abstract The name of the class of the target child objects. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *targetClass; + +///-------------------------------------- +/// @name Accessing Objects +///-------------------------------------- + +/*! + @abstract Returns a object that can be used to get objects in this relation. + */ +- (PF_NULLABLE PFQuery *)query; + +///-------------------------------------- +/// @name Modifying Relations +///-------------------------------------- + +/*! + @abstract Adds a relation to the passed in object. + + @param object A object to add relation to. + */ +- (void)addObject:(PFObject *)object; + +/*! + @abstract Removes a relation to the passed in object. + + @param object A object to add relation to. + */ +- (void)removeObject:(PFObject *)object; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFRelation.m b/Unit-2-Journal/Pods/Parse/Parse/PFRelation.m new file mode 100644 index 0000000..a6fdb68 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFRelation.m @@ -0,0 +1,236 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRelation.h" +#import "PFRelationPrivate.h" + +#import + +#import "PFAssert.h" +#import "PFFieldOperation.h" +#import "PFInternalUtils.h" +#import "PFMacros.h" +#import "PFMutableRelationState.h" +#import "PFObjectPrivate.h" +#import "PFQueryPrivate.h" + +NSString *const PFRelationKeyClassName = @"className"; +NSString *const PFRelationKeyType = @"__type"; +NSString *const PFRelationKeyObjects = @"objects"; + +@interface PFRelation () { + // + // Use this queue as follows: + // Because state is defined as an atomic property, there's no need to use the queue if you're only reading from + // self.state once during the method. + // + // If you ever need to use self.state more than once, either take a copy at the top of the function, or use a + // dispatch_sync block. + // + // If you are ever changing the state variable, you should use dispatch_sync. + // + dispatch_queue_t _stateAccessQueue; +} + +@property (atomic, copy) PFMutableRelationState *state; + +@end + +@implementation PFRelation + +@dynamic targetClass; + +- (instancetype)init { + self = [super init]; + if (!self) return nil; + + _stateAccessQueue = dispatch_queue_create("com.parse.relation.state.access", DISPATCH_QUEUE_SERIAL); + _state = [[PFMutableRelationState alloc] init]; + + return self; +} + +- (instancetype)initWithParent:(PFObject *)newParent key:(NSString *)newKey { + self = [self init]; + if (!self) return nil; + + _state.parent = newParent; + _state.key = newKey; + + return self; +} + +- (instancetype)initWithTargetClass:(NSString *)newTargetClass { + self = [self init]; + if (!self) return nil; + + _state.targetClass = newTargetClass; + + return self; +} + +- (instancetype)initFromDictionary:(NSDictionary *)dictionary withDecoder:(PFDecoder *)decoder { + self = [self init]; + if (!self) return nil; + + NSArray *array = dictionary[PFRelationKeyObjects]; + NSMutableSet *known = [[NSMutableSet alloc] initWithCapacity:array.count]; + + // Decode the result + for (id encodedObject in array) { + [known addObject:[decoder decodeObject:encodedObject]]; + } + + _state.targetClass = dictionary[PFRelationKeyClassName]; + [_state.knownObjects setSet:known]; + + return self; +} + ++ (PFRelation *)relationForObject:(PFObject *)parent forKey:(NSString *)key { + return [[PFRelation alloc] initWithParent:parent key:key]; +} + ++ (PFRelation *)relationWithTargetClass:(NSString *)targetClass { + return [[PFRelation alloc] initWithTargetClass:targetClass]; +} + ++ (PFRelation *)relationFromDictionary:(NSDictionary *)dictionary withDecoder:(PFDecoder *)decoder { + return [[PFRelation alloc] initFromDictionary:dictionary withDecoder:decoder]; +} + +- (void)ensureParentIs:(PFObject *)someParent andKeyIs:(NSString *)someKey { + pf_sync_with_throw(_stateAccessQueue, ^{ + __strong PFObject *sparent = self.state.parent; + + if (!sparent) { + sparent = self.state.parent = someParent; + } + + if (!self.state.key) { + self.state.key = someKey; + } + + PFConsistencyAssert(sparent == someParent, + @"Internal error. One PFRelation retrieved from two different PFObjects."); + + PFConsistencyAssert([self.state.key isEqualToString:someKey], + @"Internal error. One PFRelation retrieved from two different keys."); + }); +} + +- (NSString *)description { + PFRelationState *state = [self.state copy]; + + return [NSString stringWithFormat:@"<%@: %p, %p.%@ -> %@>", + [self class], + self, + state.parent, + state.key, + state.targetClass]; +} + +- (PFQuery *)query { + PFRelationState *state = [self.state copy]; + __strong PFObject *sparent = state.parent; + + PFQuery *query = nil; + if (state.targetClass) { + query = [PFQuery queryWithClassName:state.targetClass]; + } else { + query = [PFQuery queryWithClassName:state.parentClassName]; + [query redirectClassNameForKey:state.key]; + } + if (sparent) { + [query whereRelatedToObject:sparent fromKey:state.key]; + } else if (state.parentClassName) { + PFObject *object = [PFObject objectWithoutDataWithClassName:state.parentClassName + objectId:state.parentObjectId]; + [query whereRelatedToObject:object fromKey:state.key]; + } + + return query; +} + +- (NSString *)targetClass { + return self.state.targetClass; +} + +- (void)setTargetClass:(NSString *)targetClass { + dispatch_sync(_stateAccessQueue, ^{ + self.state.targetClass = targetClass; + }); +} + +- (void)addObject:(PFObject *)object { + pf_sync_with_throw(_stateAccessQueue, ^{ + PFRelationState *state = self.state; + + PFRelationOperation *op = [PFRelationOperation addRelationToObjects:@[ object ]]; + [state.parent performOperation:op forKey:state.key]; + + self.state.targetClass = op.targetClass; + [self.state.knownObjects addObject:object]; + }); +} + +- (void)removeObject:(PFObject *)object { + pf_sync_with_throw(_stateAccessQueue, ^{ + PFRelationState *state = self.state; + + PFRelationOperation *op = [PFRelationOperation removeRelationToObjects:@[ object ]]; + [state.parent performOperation:op forKey:state.key]; + + self.state.targetClass = op.targetClass; + [self.state.knownObjects removeObject:object]; + }); +} + +- (NSDictionary *)encodeIntoDictionary { + PFRelationState *state = [self.state copy]; + NSMutableArray *encodedObjects = [NSMutableArray arrayWithCapacity:state.knownObjects.count]; + + for (PFObject *knownObject in state.knownObjects) { + [encodedObjects addObject:[[PFPointerObjectEncoder objectEncoder] encodeObject:knownObject]]; + } + + return @{ + PFRelationKeyType : @"Relation", + PFRelationKeyClassName : state.targetClass, + PFRelationKeyObjects : encodedObjects + }; +} + +/*! + Returns true if and only if this object was ever known to be in the relation. + This is used for offline caching. + */ +- (BOOL)_hasKnownObject:(PFObject *)object { + __block BOOL results = NO; + + dispatch_sync(_stateAccessQueue, ^{ + results = [self.state.knownObjects containsObject:object]; + }); + + return results; +} + +- (void)_addKnownObject:(PFObject *)object { + dispatch_sync(_stateAccessQueue, ^{ + [self.state.knownObjects addObject:object]; + }); +} + +- (void)_removeKnownObject:(PFObject *)object { + dispatch_sync(_stateAccessQueue, ^{ + [self.state.knownObjects removeObject:object]; + }); +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFRole.h b/Unit-2-Journal/Pods/Parse/Parse/PFRole.h new file mode 100644 index 0000000..18d21c9 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFRole.h @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFRole` class represents a Role on the Parse server. + `PFRoles` represent groupings of objects for the purposes of granting permissions + (e.g. specifying a for a ). + Roles are specified by their sets of child users and child roles, + all of which are granted any permissions that the parent role has. + + Roles must have a name (which cannot be changed after creation of the role), and must specify an ACL. + */ +@interface PFRole : PFObject + +///-------------------------------------- +/// @name Creating a New Role +///-------------------------------------- + +/*! + @abstract Constructs a new `PFRole` with the given name. + If no default ACL has been specified, you must provide an ACL for the role. + + @param name The name of the Role to create. + */ +- (instancetype)initWithName:(NSString *)name; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @param name The name of the Role to create. + @param acl The ACL for this role. Roles must have an ACL. + */ +- (instancetype)initWithName:(NSString *)name acl:(PF_NULLABLE PFACL *)acl; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @discussion If no default ACL has been specified, you must provide an ACL for the role. + + @param name The name of the Role to create. + */ ++ (instancetype)roleWithName:(NSString *)name; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @param name The name of the Role to create. + @param acl The ACL for this role. Roles must have an ACL. + */ ++ (instancetype)roleWithName:(NSString *)name acl:(PF_NULLABLE PFACL *)acl; + +///-------------------------------------- +/// @name Role-specific Properties +///-------------------------------------- + +/*! + @abstract Gets or sets the name for a role. + + @discussion This value must be set before the role has been saved to the server, + and cannot be set once the role has been saved. + + @warning A role's name can only contain alphanumeric characters, `_`, `-`, and spaces. + */ +@property (nonatomic, copy) NSString *name; + +/*! + @abstract Gets the for the objects that are direct children of this role. + + @discussion These users are granted any privileges that this role has been granted + (e.g. read or write access through ACLs). You can add or remove users from + the role through this relation. + */ +@property (nonatomic, strong, readonly) PFRelation *users; + +/*! + @abstract Gets the for the `PFRole` objects that are direct children of this role. + + @discussion These roles' users are granted any privileges that this role has been granted + (e.g. read or write access through ACLs). You can add or remove child roles + from this role through this relation. + */ +@property (nonatomic, strong, readonly) PFRelation *roles; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFRole.m b/Unit-2-Journal/Pods/Parse/Parse/PFRole.m new file mode 100644 index 0000000..bceec77 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFRole.m @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFRole.h" + +#import + +#import "PFAssert.h" +#import "PFObject+Subclass.h" +#import "PFObjectPrivate.h" +#import "PFQuery.h" + +@implementation PFRole + +///-------------------------------------- +#pragma mark - Init +///-------------------------------------- + +- (instancetype)initWithName:(NSString *)name { + return [self initWithName:name acl:nil]; +} + +- (instancetype)initWithName:(NSString *)name acl:(PFACL *)acl { + self = [super init]; + if (!self) return nil; + + self.name = name; + self.ACL = acl; + + return self; +} + ++ (instancetype)roleWithName:(NSString *)name { + return [[self alloc] initWithName:name]; +} + ++ (instancetype)roleWithName:(NSString *)name acl:(PFACL *)acl { + return [[self alloc] initWithName:name acl:acl]; +} + +///-------------------------------------- +#pragma mark - Role-specific Properties +///-------------------------------------- + +@dynamic name; + +// Dynamic synthesizers would use objectForKey, not relationForKey +- (PFRelation *)roles { + return [self relationForKey:@keypath(PFRole, roles)]; +} + +- (PFRelation *)users { + return [self relationForKey:@keypath(PFRole, users)]; +} + +///-------------------------------------- +#pragma mark - PFObject Overrides +///-------------------------------------- + +- (void)setObject:(id)object forKey:(NSString *)key { + if ([key isEqualToString:@keypath(PFRole, name)]) { + PFConsistencyAssert(!self.objectId, @"A role's name can only be set before it has been saved."); + PFParameterAssert([object isKindOfClass:[NSString class]], @"A role's name must be an NSString."); + PFParameterAssert([object rangeOfString:@"^[0-9a-zA-Z_\\- ]+$" options:NSRegularExpressionSearch].location != NSNotFound, + @"A role's name can only contain alphanumeric characters, _, -, and spaces."); + } + [super setObject:object forKey:key]; +} + +- (BFTask *)saveInBackground { + PFConsistencyAssert(self.objectId || self.name, @"New roles must specify a name."); + return [super saveInBackground]; +} + +// Validates a class name. We override this to only allow the role class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[self parseClassName]], + @"Cannot initialize a PFRole with a custom class name."); +} + ++ (NSString *)parseClassName { + return @"_Role"; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFSession.h b/Unit-2-Journal/Pods/Parse/Parse/PFSession.h new file mode 100644 index 0000000..3b5c00c --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFSession.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +@class PFSession; + +typedef void(^PFSessionResultBlock)(PFSession *PF_NULLABLE_S session, NSError *PF_NULLABLE_S error); + +/*! + `PFSession` is a local representation of a session. + This class is a subclass of a , + and retains the same functionality as any other subclass of . + */ +@interface PFSession : PFObject + +/*! + @abstract The session token string for this session. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *sessionToken; + +/*! + *Asynchronously* fetches a `PFSession` object related to the current user. + + @returns A task that is `completed` with an instance of `PFSession` class or is `faulted` if the operation fails. + */ ++ (BFTask PF_GENERIC(PFSession *)*)getCurrentSessionInBackground; + +/*! + *Asynchronously* fetches a `PFSession` object related to the current user. + + @param block The block to execute when the operation completes. + It should have the following argument signature: `^(PFSession *session, NSError *error)`. + */ ++ (void)getCurrentSessionInBackgroundWithBlock:(PF_NULLABLE PFSessionResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFSession.m b/Unit-2-Journal/Pods/Parse/Parse/PFSession.m new file mode 100644 index 0000000..a4af8e8 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFSession.m @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFSession.h" + +#import "BFTask+Private.h" +#import "PFAssert.h" +#import "PFCoreManager.h" +#import "PFCurrentUserController.h" +#import "PFObject+Subclass.h" +#import "PFObjectPrivate.h" +#import "PFSessionController.h" +#import "PFUserPrivate.h" +#import "Parse_Private.h" + +static BOOL _PFSessionIsWritablePropertyForKey(NSString *key) { + static NSSet *protectedKeys; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + protectedKeys = [NSSet setWithObjects: + @"sessionToken", + @"restricted", + @"createdWith", + @"installationId", + @"user", + @"expiresAt", nil]; + }); + return ![protectedKeys containsObject:key]; +} + +@implementation PFSession + +@dynamic sessionToken; + +///-------------------------------------- +#pragma mark - PFSubclassing +///-------------------------------------- + ++ (NSString *)parseClassName { + return @"_Session"; +} + +- (BOOL)needsDefaultACL { + return NO; +} + +///-------------------------------------- +#pragma mark - Class +///-------------------------------------- + ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[PFSession parseClassName]], + @"Cannot initialize a PFSession with a custom class name."); +} + +#pragma mark Get Current Session + ++ (BFTask *)getCurrentSessionInBackground { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentUserSessionTokenAsync] continueWithBlock:^id(BFTask *task) { + NSString *sessionToken = task.result; + return [[self sessionController] getCurrentSessionAsyncWithSessionToken:sessionToken]; + }]; +} + ++ (void)getCurrentSessionInBackgroundWithBlock:(PFSessionResultBlock)block { + [[self getCurrentSessionInBackground] thenCallBackOnMainThreadAsync:block]; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setObject:(id)object forKey:(NSString *)key { + PFParameterAssert(_PFSessionIsWritablePropertyForKey(key), + @"Can't change the '%@' field of a PFSession.", key); + [super setObject:object forKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key { + PFParameterAssert(_PFSessionIsWritablePropertyForKey(key), + @"Can't remove the '%@' field of a PFSession.", key); + [super removeObjectForKey:key]; +} + +- (void)removeObjectsInArray:(NSArray *)objects forKey:(NSString *)key { + PFParameterAssert(_PFSessionIsWritablePropertyForKey(key), + @"Can't remove any object from '%@' field of a PFSession.", key); + [super removeObjectsInArray:objects forKey:key]; +} + +///-------------------------------------- +#pragma mark - Session Controller +///-------------------------------------- + ++ (PFSessionController *)sessionController { + return [Parse _currentManager].coreManager.sessionController; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFSubclassing.h b/Unit-2-Journal/Pods/Parse/Parse/PFSubclassing.h new file mode 100644 index 0000000..c07743d --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFSubclassing.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +@class PFQuery PF_GENERIC(PFGenericObject : PFObject *); + +PF_ASSUME_NONNULL_BEGIN + +/*! + If a subclass of conforms to `PFSubclassing` and calls , + Parse framework will be able to use that class as the native class for a Parse cloud object. + + Classes conforming to this protocol should subclass and + include `PFObject+Subclass.h` in their implementation file. + This ensures the methods in the Subclass category of are exposed in its subclasses only. + */ +@protocol PFSubclassing + +/*! + @abstract Constructs an object of the most specific class known to implement . + + @discussion This method takes care to help subclasses be subclassed themselves. + For example, `[PFUser object]` returns a by default but will return an + object of a registered subclass instead if one is known. + A default implementation is provided by which should always be sufficient. + + @returns Returns the object that is instantiated. + */ ++ (instancetype)object; + +/*! + @abstract Creates a reference to an existing PFObject for use in creating associations between PFObjects. + + @discussion Calling <[PFObject isDataAvailable]> on this object will return `NO` + until <[PFObject fetchIfNeeded]> has been called. No network request will be made. + A default implementation is provided by PFObject which should always be sufficient. + + @param objectId The object id for the referenced object. + + @returns A new without data. + */ ++ (instancetype)objectWithoutDataWithObjectId:(PF_NULLABLE NSString *)objectId; + +/*! + @abstract The name of the class as seen in the REST API. + */ ++ (NSString *)parseClassName; + +/*! + @abstract Create a query which returns objects of this type. + + @discussion A default implementation is provided by which should always be sufficient. + */ ++ (PF_NULLABLE PFQuery *)query; + +/*! + @abstract Returns a query for objects of this type with a given predicate. + + @discussion A default implementation is provided by which should always be sufficient. + + @param predicate The predicate to create conditions from. + + @returns An instance of . + + @see [PFQuery queryWithClassName:predicate:] + */ ++ (PF_NULLABLE PFQuery *)queryWithPredicate:(PF_NULLABLE NSPredicate *)predicate; + +/*! + @abstract Lets Parse know this class should be used to instantiate all objects with class type . + + @warning This method must be called before <[Parse setApplicationId:clientKey:]> + */ ++ (void)registerSubclass; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFUser.h b/Unit-2-Journal/Pods/Parse/Parse/PFUser.h new file mode 100644 index 0000000..3ae63f6 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFUser.h @@ -0,0 +1,519 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +typedef void(^PFUserSessionUpgradeResultBlock)(NSError *PF_NULLABLE_S error); +typedef void(^PFUserLogoutResultBlock)(NSError *PF_NULLABLE_S error); + +@class PFQuery PF_GENERIC(PFGenericObject : PFObject *); +@protocol PFUserAuthenticationDelegate; + +/*! + The `PFUser` class is a local representation of a user persisted to the Parse Data. + This class is a subclass of a , and retains the same functionality of a , + but also extends it with various user specific methods, like authentication, signing up, and validation uniqueness. + + Many APIs responsible for linking a `PFUser` with Facebook or Twitter have been deprecated in favor of dedicated + utilities for each social network. See , and for more information. + */ + +@interface PFUser : PFObject + +///-------------------------------------- +/// @name Accessing the Current User +///-------------------------------------- + +/*! + @abstract Gets the currently logged in user from disk and returns an instance of it. + + @returns Returns a `PFUser` that is the currently logged in user. If there is none, returns `nil`. + */ ++ (PF_NULLABLE instancetype)currentUser; + +/*! + @abstract The session token for the `PFUser`. + + @discussion This is set by the server upon successful authentication. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *sessionToken; + +/*! + @abstract Whether the `PFUser` was just created from a request. + + @discussion This is only set after a Facebook or Twitter login. + */ +@property (assign, readonly) BOOL isNew; + +/*! + @abstract Whether the user is an authenticated object for the device. + + @discussion An authenticated `PFUser` is one that is obtained via a or method. + An authenticated object is required in order to save (with altered values) or delete it. + + @returns Returns whether the user is authenticated. + */ +- (BOOL)isAuthenticated; + +///-------------------------------------- +/// @name Creating a New User +///-------------------------------------- + +/*! + @abstract Creates a new `PFUser` object. + + @returns Returns a new `PFUser` object. + */ ++ (instancetype)user; + +/*! + @abstract Enables automatic creation of anonymous users. + + @discussion After calling this method, will always have a value. + The user will only be created on the server once the user has been saved, + or once an object with a relation to that user or an ACL that refers to the user has been saved. + + @warning <[PFObject saveEventually]> will not work on if an item being saved has a relation + to an automatic user that has never been saved. + */ ++ (void)enableAutomaticUser; + +/*! + @abstract The username for the `PFUser`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *username; + +/**! + @abstract The password for the `PFUser`. + + @discussion This will not be filled in from the server with the password. + It is only meant to be set. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *password; + +/*! + @abstract The email for the `PFUser`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *email; + +/*! + @abstract Signs up the user *synchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @returns Returns `YES` if the sign up was successful, otherwise `NO`. + */ +- (BOOL)signUp PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Signs up the user *synchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param error Error object to set on error. + + @returns Returns whether the sign up was successful. + */ +- (BOOL)signUp:(NSError **)error; + +/*! + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask PF_GENERIC(NSNumber *)*)signUpInBackground; + +/*! + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)signUpInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + 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)signUpInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Logging In +///-------------------------------------- + +/*! + @abstract Makes a *synchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + + @returns Returns an instance of the `PFUser` on success. + If login failed for either wrong password or wrong username, returns `nil`. + */ ++ (PF_NULLABLE instancetype)logInWithUsername:(NSString *)username + password:(NSString *)password PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Makes a *synchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param error The error object to set on error. + + @returns Returns an instance of the `PFUser` on success. + If login failed for either wrong password or wrong username, returns `nil`. + */ ++ (PF_NULLABLE instancetype)logInWithUsername:(NSString *)username + password:(NSString *)password + error:(NSError **)error; + +/*! + @abstract Makes an *asynchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(__kindof PFUser *)*)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password; + +/*! + @abstract Makes an *asynchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Makes an *asynchronous* request to log in a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param block The block to execute. + It should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + block:(PF_NULLABLE PFUserResultBlock)block; + +///-------------------------------------- +/// @name Becoming a User +///-------------------------------------- + +/*! + @abstract Makes a *synchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + + @returns Returns an instance of the `PFUser` on success. + If becoming a user fails due to incorrect token, it returns `nil`. + */ ++ (PF_NULLABLE instancetype)become:(NSString *)sessionToken PF_SWIFT_UNAVAILABLE; + +/*! + @abstract Makes a *synchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This will also cache the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param error The error object to set on error. + + @returns Returns an instance of the `PFUser` on success. + If becoming a user fails due to incorrect token, it returns `nil`. + */ ++ (PF_NULLABLE instancetype)become:(NSString *)sessionToken error:(NSError **)error; + +/*! + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(__kindof PFUser *)*)becomeInBackground:(NSString *)sessionToken; + +/*! + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. This also caches the user locally + so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param block The block to execute. + The block should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)becomeInBackground:(NSString *)sessionToken block:(PF_NULLABLE PFUserResultBlock)block; + +/*! + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. This also caches the user locally + so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)becomeInBackground:(NSString *)sessionToken + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Revocable Session +///-------------------------------------- + +/*! + @abstract Enables revocable sessions and migrates the currentUser session token to use revocable session if needed. + + @discussion This method is required if you want to use APIs + and you application's 'Require Revocable Session' setting is turned off on `http://parse.com` app settings. + After returned `BFTask` completes - class and APIs will be available for use. + + @returns An instance of `BFTask` that is completed when revocable + sessions are enabled and currentUser token is migrated. + */ ++ (BFTask *)enableRevocableSessionInBackground; + +/*! + @abstract Enables revocable sessions and upgrades the currentUser session token to use revocable session if needed. + + @discussion This method is required if you want to use APIs + and legacy sessions are enabled in your application settings on `http://parse.com/`. + After returned `BFTask` completes - class and APIs will be available for use. + + @param block Block that will be called when revocable sessions are enabled and currentUser token is migrated. + */ ++ (void)enableRevocableSessionInBackgroundWithBlock:(PF_NULLABLE PFUserSessionUpgradeResultBlock)block; + +///-------------------------------------- +/// @name Logging Out +///-------------------------------------- + +/*! + @abstract *Synchronously* logs out the currently logged in user on disk. + */ ++ (void)logOut; + +/*! + @abstract *Asynchronously* logs out the currently logged in user. + + @discussion This will also remove the session from disk, log out of linked services + and all future calls to will return `nil`. This is preferrable to using , + unless your code is already running from a background thread. + + @returns An instance of `BFTask`, that is resolved with `nil` result when logging out completes. + */ ++ (BFTask *)logOutInBackground; + +/*! + @abstract *Asynchronously* logs out the currently logged in user. + + @discussion This will also remove the session from disk, log out of linked services + and all future calls to will return `nil`. This is preferrable to using , + unless your code is already running from a background thread. + + @param block A block that will be called when logging out completes or fails. + */ ++ (void)logOutInBackgroundWithBlock:(PF_NULLABLE PFUserLogoutResultBlock)block; + +///-------------------------------------- +/// @name Requesting a Password Reset +///-------------------------------------- + +/*! + @abstract *Synchronously* Send a password reset request for a specified email. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + + @returns Returns `YES` if the reset email request is successful. `NO` - if no account was found for the email address. + */ ++ (BOOL)requestPasswordResetForEmail:(NSString *)email PF_SWIFT_UNAVAILABLE; + +/*! + @abstract *Synchronously* send a password reset request for a specified email and sets an error object. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @param error Error object to set on error. + @returns Returns `YES` if the reset email request is successful. `NO` - if no account was found for the email address. + */ ++ (BOOL)requestPasswordResetForEmail:(NSString *)email error:(NSError **)error; + +/*! + @abstract Send a password reset request asynchronously for a specified email and sets an + error object. If a user account exists with that email, an email will be sent to + that address with instructions on how to reset their password. + @param email Email of the account to send a reset password request. + @returns The task, that encapsulates the work being done. + */ ++ (BFTask PF_GENERIC(NSNumber *)*)requestPasswordResetForEmailInBackground:(NSString *)email; + +/*! + @abstract Send a password reset request *asynchronously* for a specified email. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)requestPasswordResetForEmailInBackground:(NSString *)email + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract Send a password reset request *asynchronously* for a specified email and sets an error object. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @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)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)requestPasswordResetForEmailInBackground:(NSString *)email + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Third-party Authentication +///-------------------------------------- + +/*! + @abstract Registers a third party authentication delegate. + + @note This method shouldn't be invoked directly unless developing a third party authentication library. + @see PFUserAuthenticationDelegate + + @param delegate The third party authenticaiton delegate to be registered. + @param authType The name of the type of third party authentication source. + */ ++ (void)registerAuthenticationDelegate:(id)delegate forAuthType:(NSString *)authType; + +/*! + @abstract Logs in a user with third party authentication credentials. + + @note This method shouldn't be invoked directly unless developing a third party authentication library. + @see PFUserAuthenticationDelegate + + @param authType The name of the type of third party authentication source. + @param authData The user credentials of the third party authentication source. + + @returns A `BFTask` that is resolved to `PFUser` when logging in completes. + */ ++ (BFTask PF_GENERIC(PFUser *) *)logInWithAuthTypeInBackground:(NSString *)authType authData:(NSDictionary *)authData; + +/*! + @abstract Links this user to a third party authentication library. + + @note This method shouldn't be invoked directly unless developing a third party authentication library. + @see PFUserAuthenticationDelegate + + @param authType The name of the type of third party authentication source. + @param authData The user credentials of the third party authentication source. + + @returns A `BFTask` that is resolved to `@YES` if linking succeeds. + */ +- (BFTask PF_GENERIC(NSNumber *) *)linkWithAuthTypeInBackground:(NSString *)authType authData:(NSDictionary *)authData; + +/*! + @abstract Unlinks this user from a third party authentication library. + + @note This method shouldn't be invoked directly unless developing a third party authentication library. + @see PFUserAuthenticationDelegate + + @param authType The name of the type of third party authentication source. + + @returns A `BFTask` that is resolved to `@YES` if unlinking succeeds. + */ +- (BFTask PF_GENERIC(NSNumber *) *)unlinkWithAuthTypeInBackground:(NSString *)authType; + +/*! + @abstract Indicates whether this user is linked with a third party authentication library of a specific type. + + @note This method shouldn't be invoked directly unless developing a third party authentication library. + @see PFUserAuthenticationDelegate + + @param authType The name of the type of third party authentication source. + + @returns `YES` if the user is linked with a provider, otherwise `NO`. + */ +- (BOOL)isLinkedWithAuthType:(NSString *)authType; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFUser.m b/Unit-2-Journal/Pods/Parse/Parse/PFUser.m new file mode 100644 index 0000000..d7a6eac --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFUser.m @@ -0,0 +1,1225 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 "PFUser.h" +#import "PFUserPrivate.h" + +#import +#import + +#import "BFTask+Private.h" +#import "PFACLPrivate.h" +#import "PFAnonymousAuthenticationProvider.h" +#import "PFAnonymousUtils_Private.h" +#import "PFAssert.h" +#import "PFCommandResult.h" +#import "PFCommandRunning.h" +#import "PFCoreManager.h" +#import "PFCurrentUserController.h" +#import "PFDecoder.h" +#import "PFErrorUtilities.h" +#import "PFFileManager.h" +#import "PFKeychainStore.h" +#import "PFMultiProcessFileLockController.h" +#import "PFMutableUserState.h" +#import "PFObject+Subclass.h" +#import "PFObjectConstants.h" +#import "PFObjectFilePersistenceController.h" +#import "PFObjectPrivate.h" +#import "PFOfflineStore.h" +#import "PFOperationSet.h" +#import "PFQueryPrivate.h" +#import "PFRESTUserCommand.h" +#import "PFSessionUtilities.h" +#import "PFTaskQueue.h" +#import "PFUserAuthenticationController.h" +#import "PFUserConstants.h" +#import "PFUserController.h" +#import "PFUserFileCodingLogic.h" +#import "Parse_Private.h" + +NSString *const PFUserCurrentUserFileName = @"currentUser"; +NSString *const PFUserCurrentUserPinName = @"_currentUser"; +NSString *const PFUserCurrentUserKeychainItemName = @"currentUser"; + +static BOOL _PFUserIsWritablePropertyForKey(NSString *key) { + return ![PFUserSessionTokenRESTKey isEqualToString:key]; +} + +static BOOL _PFUserIsRemovablePropertyForKey(NSString *key) { + return _PFUserIsWritablePropertyForKey(key) && ![PFUserUsernameRESTKey isEqualToString:key]; +} + +@interface PFUser () + +@property (nonatomic, copy) PFUserState *_state; + +@end + +@implementation PFUser (Private) + +static BOOL revocableSessionEnabled_; + +- (void)setDefaultValues { + [super setDefaultValues]; + self.isCurrentUser = NO; +} + +- (BOOL)needsDefaultACL { + return NO; +} + +///-------------------------------------- +#pragma mark - Current User +///-------------------------------------- + +// Returns the session token for the current user. ++ (NSString *)currentSessionToken { + return [[self _getCurrentUserSessionTokenAsync] waitForResult:nil withMainThreadWarning:NO]; +} + ++ (BFTask *)_getCurrentUserSessionTokenAsync { + return [[self currentUserController] getCurrentUserSessionTokenAsync]; +} + +///-------------------------------------- +#pragma mark - PFObject +///-------------------------------------- + +#pragma mark Validation + +- (BFTask PF_GENERIC(PFVoid) *)_validateDeleteAsync { + return [[super _validateDeleteAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) { + if (!self.isAuthenticated) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorUserCannotBeAlteredWithoutSession + message:@"User cannot be deleted unless they have been authenticated."]; + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + +- (BFTask PF_GENERIC(PFVoid) *)_validateSaveEventuallyAsync { + return [[super _validateSaveEventuallyAsync] continueWithSuccessBlock:^id(BFTask PF_GENERIC(PFVoid) *task) { + if ([self isDirtyForKey:PFUserPasswordRESTKey]) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorOperationForbidden + message:@"Unable to saveEventually a PFUser with dirty password."]; + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + +#pragma mark Else + +- (NSString *)displayClassName { + if ([self isMemberOfClass:[PFUser class]]) { + return @"PFUser"; + } + return NSStringFromClass([self class]); +} + +// Validates a class name. We override this to only allow the user class name. ++ (void)_assertValidInstanceClassName:(NSString *)className { + PFParameterAssert([className isEqualToString:[PFUser parseClassName]], + @"Cannot initialize a PFUser with a custom class name."); +} + +// Checks the properties on the object before saving. +- (void)_checkSaveParametersWithCurrentUser:(PFUser *)currentUser { + @synchronized ([self lock]) { + PFConsistencyAssert(self.objectId || self.isLazy, + @"User cannot be saved unless they are already signed up. Call signUp first."); + + PFConsistencyAssert([self _isAuthenticatedWithCurrentUser:currentUser] || + [self.objectId isEqualToString:currentUser.objectId], + @"User cannot be saved unless they have been authenticated via logIn or signUp", nil); + } +} + +// Checks the properties on the object before signUp. +- (BFTask *)_validateSignUpAsync { + return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + NSError *error = nil; + @synchronized (self.lock) { + if (!self.username) { + error = [PFErrorUtilities errorWithCode:kPFErrorUsernameMissing + message:@"Cannot sign up without a username."]; + } else if (!self.password) { + error = [PFErrorUtilities errorWithCode:kPFErrorUserPasswordMissing + message:@"Cannot sign up without a password."]; + } else if (![self isDirty:NO] || self.objectId) { + error = [PFErrorUtilities errorWithCode:kPFErrorUsernameTaken + message:@"Cannot sign up an existing user."]; + } + } + if (error) { + return [BFTask taskWithError:error]; + } + return nil; + }]; +} + +- (NSMutableDictionary *)_convertToDictionaryForSaving:(PFOperationSet *)changes + withObjectEncoder:(PFEncoder *)encoder { + @synchronized ([self lock]) { + NSMutableDictionary *serialized = [super _convertToDictionaryForSaving:changes withObjectEncoder:encoder]; + if ([self.authData count] > 0) { + serialized[PFUserAuthDataRESTKey] = [self.authData copy]; + } + return serialized; + } +} + +- (BFTask *)handleSaveResultAsync:(NSDictionary *)result { + return [[super handleSaveResultAsync:result] continueWithSuccessBlock:^id(BFTask *saveTask) { + if (self.isCurrentUser) { + [self cleanUpAuthData]; + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller saveCurrentObjectAsync:self] continueWithBlock:^id(BFTask *task) { + return saveTask.result; + }]; + } + return saveTask; + }]; +} + +///-------------------------------------- +#pragma mark - Sign Up +///-------------------------------------- + +- (PFRESTCommand *)_currentSignUpCommandForChanges:(PFOperationSet *)changes { + @synchronized ([self lock]) { + NSDictionary *parameters = [self _convertToDictionaryForSaving:changes + withObjectEncoder:[PFPointerObjectEncoder objectEncoder]]; + return [PFRESTUserCommand signUpUserCommandWithParameters:parameters + revocableSession:[[self class] _isRevocableSessionEnabled] + sessionToken:self.sessionToken]; + } +} + +///-------------------------------------- +#pragma mark - Service Login +///-------------------------------------- + +// Constructs the command for user_signup_or_login. This is used for Facebook, Twitter, and other linking services. +- (PFRESTCommand *)_currentServiceLoginCommandForChanges:(PFOperationSet *)changes { + @synchronized ([self lock]) { + NSDictionary *parameters = [self _convertToDictionaryForSaving:changes + withObjectEncoder:[PFPointerObjectEncoder objectEncoder]]; + return [PFRESTUserCommand serviceLoginUserCommandWithParameters:parameters + revocableSession:[[self class] _isRevocableSessionEnabled] + sessionToken:self.sessionToken]; + } +} + +- (BFTask *)_handleServiceLoginCommandResult:(PFCommandResult *)result { + return [BFTask taskFromExecutor:[BFExecutor defaultExecutor] withBlock:^id{ + NSDictionary *resultDictionary = result.result; + return [[self handleSaveResultAsync:resultDictionary] continueWithBlock:^id(BFTask *task) { + BOOL new = (result.httpResponse.statusCode == 201); // 201 means Created + @synchronized (self.lock) { + if (self._state.isNew != new) { + PFMutableUserState *state = [self._state mutableCopy]; + state.isNew = new; + self._state = state; + } + if (resultDictionary) { + self.isLazy = NO; + + // Serialize the object to disk so we can later access it via currentUser + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller saveCurrentObjectAsync:self] continueAsyncWithBlock:^id(BFTask *task) { + [self.saveDelegate invoke:self error:nil]; + return self; + }]; + } + return [BFTask taskWithResult:self]; + } + }]; + }]; +} + +// Override the save result handling with custom user functionality +- (BFTask *)handleSignUpResultAsync:(BFTask *)task { + @synchronized ([self lock]) { + PFCommandResult *commandResult = task.result; + NSDictionary *result = commandResult.result; + BFTask *signUpTask = task; + + // Bail-out early, but still make sure that super class handled the result + if (task.error || task.cancelled || task.exception) { + return [[super handleSaveResultAsync:nil] continueWithBlock:^id(BFTask *task) { + return signUpTask; + }]; + } + __block BOOL saveResult = NO; + return [[[super handleSaveResultAsync:result] continueWithBlock:^id(BFTask *task) { + saveResult = [task.result boolValue]; + if (saveResult) { + @synchronized (self.lock) { + // Save the session information + PFMutableUserState *state = [self._state mutableCopy]; + state.sessionToken = result[PFUserSessionTokenRESTKey]; + state.isNew = YES; + self._state = state; + self.isLazy = NO; + } + } + return signUpTask; + }] continueWithBlock:^id(BFTask *task) { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller saveCurrentObjectAsync:self] continueWithResult:@(saveResult)]; + }]; + } +} + +- (void)cleanUpAuthData { + @synchronized ([self lock]) { + for (NSString *key in [self.authData copy]) { + id linkData = [self.authData objectForKey:key]; + if (!linkData || linkData == [NSNull null]) { + [self.authData removeObjectForKey:key]; + [self.linkedServiceNames removeObject:key]; + + [[[[self class] authenticationController] restoreAuthenticationAsyncWithAuthData:nil + forAuthType:key] waitForResult:nil withMainThreadWarning:NO]; + } + } + } +} + +/*! + Copies special PFUser fields from another user. + */ +- (PFObject *)mergeFromObject:(PFUser *)other { + @synchronized ([self lock]) { + [super mergeFromObject:other]; + + if (self == other) { + // If they point to the same instance, then don't merge. + return self; + } + + PFMutableUserState *state = [self._state mutableCopy]; + state.sessionToken = other.sessionToken; + state.isNew = other._state.isNew; + self._state = state; + + [self.authData removeAllObjects]; + [self.authData addEntriesFromDictionary:other.authData]; + + [self.linkedServiceNames removeAllObjects]; + [self.linkedServiceNames unionSet:other.linkedServiceNames]; + + return self; + } +} + +/* + Merges custom fields from JSON associated with a PFUser: + { + "session_token": string, + "is_new": boolean, + "auth_data": { + "facebook": { + "id": string, + "access_token": string, + "expiration_date": string (represents date) + } + } + } + */ +- (void)_mergeFromServerWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData { + @synchronized ([self lock]) { + // save the session token + + PFMutableUserState *state = [self._state mutableCopy]; + + NSString *newSessionToken = result[PFUserSessionTokenRESTKey]; + if (newSessionToken) { + // Save the session token + state.sessionToken = newSessionToken; + } + + self._state = state; + + // Merge the linked service metadata + NSDictionary *newAuthData = [decoder decodeObject:result[PFUserAuthDataRESTKey]]; + if (newAuthData) { + [self.authData removeAllObjects]; + [self.linkedServiceNames removeAllObjects]; + [newAuthData enumerateKeysAndObjectsUsingBlock:^(id key, id linkData, BOOL *stop) { + if (linkData != [NSNull null]) { + [self.authData setObject:linkData forKey:key]; + [self.linkedServiceNames addObject:key]; + [self synchronizeAuthDataWithAuthType:key]; + } else { + [self.authData removeObjectForKey:key]; + [self.linkedServiceNames removeObject:key]; + [self synchronizeAuthDataWithAuthType:key]; + } + }]; + } + + // Strip authData and sessionToken from the data, as those keys are saved in a custom way + NSMutableDictionary *serverData = [result mutableCopy]; + [serverData removeObjectForKey:PFUserSessionTokenRESTKey]; + [serverData removeObjectForKey:PFUserAuthDataRESTKey]; + + // The public fields are handled by the regular mergeFromServer + [super _mergeFromServerWithResult:serverData decoder:decoder completeData:completeData]; + } +} + +- (void)synchronizeAuthDataWithAuthType:(NSString *)authType { + @synchronized ([self lock]) { + if (!self.isCurrentUser) { + return; + } + + NSDictionary *data = self.authData[authType]; + BFTask *restoreTask = [[[self class] authenticationController] restoreAuthenticationAsyncWithAuthData:data + forAuthType:authType]; + [restoreTask waitForResult:nil withMainThreadWarning:NO]; + if (restoreTask.faulted || ![restoreTask.result boolValue]) { // TODO: (nlutsenko) Maybe chain this method? + [self unlinkWithAuthTypeInBackground:authType]; + } + } +} + +- (void)synchronizeAllAuthData { + @synchronized ([self lock]) { + // Ensures that all auth providers have auth data (e.g. access tokens, etc.) that matches this user. + if (self.authData) { + [self.authData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [self synchronizeAuthDataWithAuthType:key]; + }]; + } + } +} + +- (BFTask *)resolveLazinessAsync:(BFTask *)toAwait { + @synchronized ([self lock]) { + if (!self.isLazy) { + return [BFTask taskWithResult:self]; + } + if (self.linkedServiceNames.count == 0) { + // If there are no linked services, treat this like a sign-up. + return [[self signUpAsync:toAwait] continueAsyncWithSuccessBlock:^id(BFTask *task) { + self.isLazy = NO; + return self; + }]; + } + + // Otherwise, treat this as a SignUpOrLogIn + PFRESTCommand *command = [self _currentServiceLoginCommandForChanges:[self unsavedChanges]]; + [self startSave]; + + return [[toAwait continueAsyncWithBlock:^id(BFTask *task) { + return [[Parse _currentManager].commandRunner runCommandAsync:command withOptions:0]; + }] continueAsyncWithBlock:^id(BFTask *task) { + PFCommandResult *result = task.result; + + if (task.error || task.cancelled) { + // If there was an error, we want to roll forward the save changes, but return the original task. + return [[self _handleServiceLoginCommandResult:result] continueAsyncWithBlock:^id(BFTask *unused) { + // Return the original task, instead of the new one (in order to have a proper error) + return task; + }]; + } + + if ([result.httpResponse statusCode] == 201) { + return [self _handleServiceLoginCommandResult:result]; + } else { + // Otherwise, treat this as a fresh login, and switch the current user to the new user. + PFUser *newUser = [[self class] _objectFromDictionary:result.result + defaultClassName:[self parseClassName] + completeData:YES]; + @synchronized ([newUser lock]) { + [newUser startSave]; + return [newUser _handleServiceLoginCommandResult:result]; + } + } + }]; + } +} + +- (BFTask *)_logOutAsyncWithAuthType:(NSString *)authType { + return [[[self class] authenticationController] deauthenticateAsyncWithAuthType:authType]; +} + ++ (instancetype)logInLazyUserWithAuthType:(NSString *)authType authData:(NSDictionary *)authData { + PFUser *user = [self user]; + @synchronized ([user lock]) { + [user setIsCurrentUser:YES]; + user.isLazy = YES; + [user.authData setObject:authData forKey:authType]; + [user.linkedServiceNames addObject:authType]; + } + return user; +} + +- (BFTask *)signUpAsync:(BFTask *)toAwait { + PFUser *currentUser = [[self class] currentUser]; + NSString *token = currentUser.sessionToken; + @synchronized ([self lock]) { + if (self.objectId) { + // For anonymous users, there may be an objectId. Setting the userName + // will have removed the anonymous link and set the value in the authData + // object to [NSNull null], so we can just treat it like a save operation. + if (self.authData[PFAnonymousUserAuthenticationType] == [NSNull null]) { + return [self saveAsync:toAwait]; + } + + // Otherwise, return an error + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorUsernameTaken + message:@"Cannot sign up a user that has already signed up."]; + return [BFTask taskWithError:error]; + } + + // If the operationSetQueue is has operation sets in it, then a save or signUp is in progress. + // If there is a signUp or save already in progress, don't allow another one to start. + if ([self _hasOutstandingOperations]) { + NSError *error = [PFErrorUtilities errorWithCode:kPFErrorUsernameTaken + message:@"Cannot sign up a user that is already signing up."]; + return [BFTask taskWithError:error]; + } + + return [[self _validateSignUpAsync] continueWithSuccessBlock:^id(BFTask *task) { + if (currentUser && [PFAnonymousUtils isLinkedWithUser:currentUser]) { + // self doesn't have any outstanding saves, so we can safely merge its operations + // into the current user. + + PFConsistencyAssert(!isCurrentUser, @"Attempt to merge currentUser with itself."); + + [self checkForChangesToMutableContainers]; + @synchronized ([currentUser lock]) { + NSString *oldUsername = [currentUser.username copy]; + NSString *oldPassword = [currentUser.password copy]; + NSArray *oldAnonymousData = currentUser.authData[PFAnonymousUserAuthenticationType]; + + [currentUser checkForChangesToMutableContainers]; + + // Move the changes to this object over to the currentUser object. + PFOperationSet *selfOperations = operationSetQueue[0]; + [operationSetQueue removeAllObjects]; + [operationSetQueue addObject:[[PFOperationSet alloc] init]]; + for (NSString *key in selfOperations) { + [currentUser setObject:[selfOperations objectForKey:key] forKey:key]; + } + + currentUser->dirty = YES; + currentUser.password = self.password; + currentUser.username = self.username; + + [self rebuildEstimatedData]; + [currentUser rebuildEstimatedData]; + + return [[[[currentUser saveInBackground] continueWithBlock:^id(BFTask *task) { + if (task.error || task.cancelled || task.exception) { + @synchronized ([currentUser lock]) { + if (oldUsername) { + currentUser.username = oldUsername; + } + currentUser.password = oldPassword; + [currentUser restoreAnonymity:oldAnonymousData]; + } + + @synchronized(self.lock) { + [operationSetQueue replaceObjectAtIndex:0 withObject:selfOperations]; + [self rebuildEstimatedData]; + } + } + return task; + }] continueWithSuccessBlock:^id(BFTask *task) { + if ([Parse _currentManager].offlineStoreLoaded) { + return [[Parse _currentManager].offlineStore deleteDataForObjectAsync:currentUser]; + } + return nil; + }] continueWithSuccessBlock:^id(BFTask *task) { + [self mergeFromObject:currentUser]; + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller saveCurrentObjectAsync:self] continueWithResult:@YES]; + }]; + } + } + // Use a nil session token for objects saved during a signup. + BFTask *saveChildren = [self _saveChildrenInBackgroundWithCurrentUser:currentUser sessionToken:token]; + PFOperationSet *changes = [self unsavedChanges]; + [self startSave]; + + return [[[toAwait continueWithBlock:^id(BFTask *task) { + return saveChildren; + }] continueWithSuccessBlock:^id(BFTask *task) { + // We need to construct the signup command lazily, because saving the children + // may change the way the object itself is serialized. + PFRESTCommand *command = [self _currentSignUpCommandForChanges:changes]; + return [[Parse _currentManager].commandRunner runCommandAsync:command + withOptions:PFCommandRunningOptionRetryIfFailed]; + }] continueWithBlock:^id(BFTask *task) { + return [self handleSignUpResultAsync:task]; + }]; + }]; + } +} + +- (void)stripAnonymity { + @synchronized ([self lock]) { + if ([PFAnonymousUtils isLinkedWithUser:self]) { + NSString *authType = PFAnonymousUserAuthenticationType; + + [self.linkedServiceNames removeObject:authType]; + + if (self.objectId) { + self.authData[authType] = [NSNull null]; + } else { + [self.authData removeObjectForKey:authType]; + } + dirty = YES; + } + } +} + +- (void)restoreAnonymity:(id)anonymousData { + @synchronized ([self lock]) { + if (anonymousData && anonymousData != [NSNull null]) { + NSString *authType = PFAnonymousUserAuthenticationType; + [self.linkedServiceNames addObject:authType]; + self.authData[authType] = anonymousData; + } + } +} + +///-------------------------------------- +#pragma mark - Saving +///-------------------------------------- + +- (PFRESTCommand *)_constructSaveCommandForChanges:(PFOperationSet *)changes + sessionToken:(NSString *)token + objectEncoder:(PFEncoder *)encoder { + // If we are curent user - use the latest available session token, as it might have been changed since + // this command was enqueued. + if ([self isCurrentUser]) { + token = self.sessionToken; + } + return [super _constructSaveCommandForChanges:changes + sessionToken:token + objectEncoder:encoder]; +} + +///-------------------------------------- +#pragma mark - REST operations +///-------------------------------------- + +- (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *)decoder { + @synchronized ([self lock]) { + NSMutableDictionary *restDictionary = [object mutableCopy]; + + PFMutableUserState *state = [self._state mutableCopy]; + if (object[PFUserSessionTokenRESTKey] != nil) { + state.sessionToken = object[PFUserSessionTokenRESTKey]; + [restDictionary removeObjectForKey:PFUserSessionTokenRESTKey]; + } + + if (object[PFUserAuthDataRESTKey] != nil) { + NSDictionary *newAuthData = object[PFUserAuthDataRESTKey]; + [newAuthData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + self.authData[key] = obj; + if (obj != nil) { + [self.linkedServiceNames addObject:key]; + } + [self synchronizeAuthDataWithAuthType:key]; + }]; + + [restDictionary removeObjectForKey:PFUserAuthDataRESTKey]; + } + + self._state = state; + + [super mergeFromRESTDictionary:restDictionary withDecoder:decoder]; + } +} + +- (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder + operationSetUUIDs:(NSArray **)operationSetUUIDs + state:(PFObjectState *)state + operationSetQueue:(NSArray *)queue { + @synchronized (self.lock) { + NSMutableArray *cleanQueue = [queue mutableCopy]; + [queue enumerateObjectsUsingBlock:^(PFOperationSet *operationSet, NSUInteger idx, BOOL *stop) { + // Remove operations for `password` field, to not let it persist to LDS. + if (operationSet[PFUserPasswordRESTKey]) { + operationSet = [operationSet copy]; + [operationSet removeObjectForKey:PFUserPasswordRESTKey]; + + cleanQueue[idx] = operationSet; + } + }]; + return [super RESTDictionaryWithObjectEncoder:objectEncoder + operationSetUUIDs:operationSetUUIDs + state:state + operationSetQueue:cleanQueue]; + } +} + +///-------------------------------------- +#pragma mark - Revocable Session +///-------------------------------------- + ++ (dispatch_queue_t)_revocableSessionSynchronizationQueue { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.parse.user.revocableSession", DISPATCH_QUEUE_CONCURRENT); + }); + return queue; +} + ++ (BOOL)_isRevocableSessionEnabled { + __block BOOL value = NO; + dispatch_sync([self _revocableSessionSynchronizationQueue], ^{ + value = revocableSessionEnabled_; + }); + return value; +} + ++ (void)_setRevocableSessionEnabled:(BOOL)enabled { + dispatch_barrier_sync([self _revocableSessionSynchronizationQueue], ^{ + revocableSessionEnabled_ = enabled; + }); +} + ++ (BFTask *)_upgradeToRevocableSessionInBackground { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentUserAsyncWithOptions:0] continueWithSuccessBlock:^id(BFTask *task) { + PFUser *currentUser = task.result; + NSString *sessionToken = currentUser.sessionToken; + + // Bail-out early if session token is already revocable. + if ([PFSessionUtilities isSessionTokenRevocable:sessionToken]) { + return [BFTask taskWithResult:currentUser]; + } + return [currentUser _upgradeToRevocableSessionInBackground]; + }]; +} + +- (BFTask *)_upgradeToRevocableSessionInBackground { + @weakify(self); + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + @strongify(self); + + NSString *token = nil; + @synchronized(self.lock) { + token = self.sessionToken; + } + + // Check session token here as well, to make sure we didn't upgrade the token in between. + if ([PFSessionUtilities isSessionTokenRevocable:token]) { + return [BFTask taskWithResult:self]; + } + + PFRESTCommand *command = [PFRESTUserCommand upgradeToRevocableSessionCommandWithSessionToken:token]; + return [[[Parse _currentManager].commandRunner runCommandAsync:command + withOptions:0] continueWithSuccessBlock:^id(BFTask *task) { + NSDictionary *dictionary = [task.result result]; + PFSession *session = [PFSession _objectFromDictionary:dictionary + defaultClassName:[PFSession parseClassName] + completeData:YES]; + @synchronized(self.lock) { + PFMutableUserState *state = [self._state mutableCopy]; + state.sessionToken = session.sessionToken; + self._state = state; + } + PFCurrentUserController *controller = [[self class] currentUserController]; + return [controller saveCurrentObjectAsync:self]; + }]; + }]; + }]; +} + +///-------------------------------------- +#pragma mark - Data Source +///-------------------------------------- + ++ (PFObjectFileCodingLogic *)objectFileCodingLogic { + return [PFUserFileCodingLogic codingLogic]; +} + ++ (PFUserAuthenticationController *)authenticationController { + return [Parse _currentManager].coreManager.userAuthenticationController; +} + ++ (PFUserController *)userController { + return [Parse _currentManager].coreManager.userController; +} + +@end + +@implementation PFUser + +@dynamic _state; + +// PFUser: +@dynamic username; +@dynamic email; +@dynamic password; + +// PFUser (Private): +@dynamic authData; +@dynamic linkedServiceNames; +@dynamic isLazy; + ++ (NSString *)parseClassName { + return @"_User"; +} + ++ (instancetype)currentUser { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller getCurrentObjectAsync] waitForResult:nil withMainThreadWarning:NO]; +} + +- (BOOL)isCurrentUser { + @synchronized (self.lock) { + return isCurrentUser; + } +} + +- (void)setIsCurrentUser:(BOOL)aBool { + @synchronized (self.lock) { + isCurrentUser = aBool; + } +} + +///-------------------------------------- +#pragma mark - Log In +///-------------------------------------- + ++ (instancetype)logInWithUsername:(NSString *)username password:(NSString *)password { + return [self logInWithUsername:username password:password error:nil]; +} + ++ (instancetype)logInWithUsername:(NSString *)username password:(NSString *)password error:(NSError **)error { + return [[self logInWithUsernameInBackground:username password:password] waitForResult:error]; +} + ++ (BFTask *)logInWithUsernameInBackground:(NSString *)username password:(NSString *)password { + return [[self userController] logInCurrentUserAsyncWithUsername:username + password:password + revocableSession:[self _isRevocableSessionEnabled]]; +} + ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + block:(PFUserResultBlock)block { + [[self logInWithUsernameInBackground:username password:password] thenCallBackOnMainThreadAsync:block]; +} + ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + target:(id)target + selector:(SEL)selector { + [self logInWithUsernameInBackground:username password:password block:^(PFUser *user, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:user object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Third-party Authentication +///-------------------------------------- + ++ (void)registerAuthenticationDelegate:(id)delegate forAuthType:(NSString *)authType { + [[self authenticationController] registerAuthenticationDelegate:delegate forAuthType:authType]; +} + +#pragma mark Log In + ++ (BFTask *)logInWithAuthTypeInBackground:(NSString *)authType authData:(NSDictionary *)authData { + PFParameterAssert(authType, @"Can't log in without `authType`."); + PFParameterAssert(authData, @"Can't log in without `authData`."); + PFUserAuthenticationController *controller = [self authenticationController]; + PFConsistencyAssert([controller authenticationDelegateForAuthType:authType], + @"No registered authentication delegate found for `%@` authentication type. " + @"Register a delegate first via PFUser.registerAuthenticationDelegate(delegate, forAuthType:)", authType); + return [[self authenticationController] logInUserAsyncWithAuthType:authType authData:authData]; +} + +#pragma mark Link + +- (BFTask *)linkWithAuthTypeInBackground:(NSString *)authType authData:(NSDictionary *)newAuthData { + PFParameterAssert(authType, @"Can't link without `authType`."); + PFParameterAssert(authData, @"Can't link without `authData`."); + PFUserAuthenticationController *controller = [[self class] authenticationController]; + PFConsistencyAssert([controller authenticationDelegateForAuthType:authType], + @"No registered authentication delegate found for `%@` authentication type. " + @"Register a delegate first via PFUser.registerAuthenticationDelegate(delegate, forAuthType:)", authType); + + @weakify(self); + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [toAwait continueWithBlock:^id(BFTask *task) { + @strongify(self); + + NSDictionary *oldAnonymousData = nil; + + @synchronized (self.lock) { + self.authData[authType] = newAuthData; + [self.linkedServiceNames addObject:authType]; + + oldAnonymousData = self.authData[PFAnonymousUserAuthenticationType]; + [self stripAnonymity]; + + dirty = YES; + } + + return [[self saveAsync:nil] continueAsyncWithBlock:^id(BFTask *task) { + if (task.result) { + [self synchronizeAuthDataWithAuthType:authType]; + } else { + @synchronized (self.lock) { + [self.authData removeObjectForKey:authType]; + [self.linkedServiceNames removeObject:authType]; + [self restoreAnonymity:oldAnonymousData]; + } + } + return task; + }]; + }]; + }]; +} + +#pragma mark Unlink + +- (BFTask *)unlinkWithAuthTypeInBackground:(NSString *)authType { + return [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{ + @synchronized (self.lock) { + if (self.authData[authType]) { + self.authData[authType] = [NSNull null]; + dirty = YES; + return [self saveInBackground]; + } + } + return @YES; + }]; +} + +#pragma mark Linked + +- (BOOL)isLinkedWithAuthType:(NSString *)authType { + PFParameterAssert(authType, @"Authentication type can't be `nil`."); + @synchronized(self.lock) { + return [self.linkedServiceNames containsObject:authType]; + } +} + +#pragma mark Private + ++ (void)_unregisterAuthenticationDelegateForAuthType:(NSString *)authType { + [[[self class] authenticationController] unregisterAuthenticationDelegateForAuthType:authType]; +} + +///-------------------------------------- +#pragma mark - Become +///-------------------------------------- + ++ (instancetype)become:(NSString *)sessionToken { + return [self become:sessionToken error:nil]; +} + ++ (instancetype)become:(NSString *)sessionToken error:(NSError **)error { + return [[self becomeInBackground:sessionToken] waitForResult:error]; +} + ++ (BFTask *)becomeInBackground:(NSString *)sessionToken { + PFParameterAssert(sessionToken, @"Session Token must be provided for login."); + return [[self userController] logInCurrentUserAsyncWithSessionToken:sessionToken]; +} + ++ (void)becomeInBackground:(NSString *)sessionToken block:(PFUserResultBlock)block { + [[self becomeInBackground:sessionToken] thenCallBackOnMainThreadAsync:block]; +} + ++ (void)becomeInBackground:(NSString *)sessionToken target:(id)target selector:(SEL)selector { + [self becomeInBackground:sessionToken block:^(PFUser *user, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:user object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Revocable Sessions +///-------------------------------------- + ++ (BFTask *)enableRevocableSessionInBackground { + if ([self _isRevocableSessionEnabled]) { + return [BFTask taskWithResult:nil]; + } + [self _setRevocableSessionEnabled:YES]; + return [self _upgradeToRevocableSessionInBackground]; +} + ++ (void)enableRevocableSessionInBackgroundWithBlock:(PFUserSessionUpgradeResultBlock)block { + [[self enableRevocableSessionInBackground] continueWithBlock:^id(BFTask *task) { + block(task.error); + return nil; + }]; +} + +///-------------------------------------- +#pragma mark - Request Password Reset +///-------------------------------------- + ++ (BOOL)requestPasswordResetForEmail:(NSString *)email { + return [self requestPasswordResetForEmail:email error:nil]; +} + ++ (BOOL)requestPasswordResetForEmail:(NSString *)email error:(NSError **)error { + return [[[self requestPasswordResetForEmailInBackground:email] waitForResult:error] boolValue]; +} + ++ (BFTask *)requestPasswordResetForEmailInBackground:(NSString *)email { + PFParameterAssert(email, @"Email should be provided to request password reset."); + return [[[self userController] requestPasswordResetAsyncForEmail:email] continueWithSuccessResult:@YES]; +} + ++ (void)requestPasswordResetForEmailInBackground:(NSString *)email block:(PFBooleanResultBlock)block { + [[self requestPasswordResetForEmailInBackground:email] thenCallBackOnMainThreadWithBoolValueAsync:block]; +} + ++ (void)requestPasswordResetForEmailInBackground:(NSString *)email target:(id)target selector:(SEL)selector { + [self requestPasswordResetForEmailInBackground:email block:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +///-------------------------------------- +#pragma mark - Logging out +///-------------------------------------- + ++ (void)logOut { + [[self logOutInBackground] waitForResult:nil withMainThreadWarning:NO]; +} + ++ (BFTask *)logOutInBackground { + PFCurrentUserController *controller = [[self class] currentUserController]; + return [controller logOutCurrentUserAsync]; +} + ++ (void)logOutInBackgroundWithBlock:(PFUserLogoutResultBlock)block { + [[self logOutInBackground] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) { + block(task.error); + return nil; + }]; +} + +- (BFTask *)_logOutAsync { + //TODO: (nlutsenko) Maybe add this to `taskQueue`? + + NSString *token = nil; + NSMutableArray *tasks = [NSMutableArray array]; + @synchronized(self.lock) { + [self.authData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + BFTask *task = [self _logOutAsyncWithAuthType:key]; + [tasks addObject:task]; + }]; + + self.isCurrentUser = NO; + + token = [self.sessionToken copy]; + + PFMutableUserState *state = [self._state mutableCopy]; + state.sessionToken = nil; + self._state = state; + } + + BFTask *task = [BFTask taskForCompletionOfAllTasks:tasks]; + + if ([PFSessionUtilities isSessionTokenRevocable:token]) { + return [task continueWithExecutor:[BFExecutor defaultExecutor] withBlock:^id(BFTask *task) { + return [[[self class] userController] logOutUserAsyncWithSessionToken:token]; + }]; + } + return task; +} + +///-------------------------------------- +#pragma mark - Accessors +///-------------------------------------- + +- (void)setObject:(id)object forKey:(NSString *)key { + PFParameterAssert(_PFUserIsWritablePropertyForKey(key), + @"Can't remove the '%@' field of a PFUser.", key); + if ([key isEqualToString:PFUserUsernameRESTKey]) { + [self stripAnonymity]; + } + [super setObject:object forKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key { + PFParameterAssert(_PFUserIsRemovablePropertyForKey(key), + @"Can't remove the '%@' field of a PFUser.", key); + [super removeObjectForKey:key]; +} + +- (NSMutableDictionary *)authData { + @synchronized ([self lock]) { + if (!authData) { + authData = [[NSMutableDictionary alloc] init]; + } + } + return authData; +} + +- (NSMutableSet *)linkedServiceNames { + @synchronized ([self lock]) { + if (!linkedServiceNames) { + linkedServiceNames = [[NSMutableSet alloc] init]; + } + } + return linkedServiceNames; +} + ++ (instancetype)user { + return [self object]; +} + +- (BFTask *)saveAsync:(BFTask *)toAwait { + if (!toAwait) { + toAwait = [BFTask taskWithResult:nil]; + } + + // This breaks a rare deadlock scenario where on one thread, user.lock is acquired before taskQueue.lock sometimes, + // but not always. Using continueAsyncWithBlock unlocks from the taskQueue, and solves the proplem. + return [toAwait continueAsyncWithBlock:^id(BFTask *task) { + @synchronized ([self lock]) { + if (self.isLazy) { + return [[self resolveLazinessAsync:toAwait] continueAsyncWithSuccessBlock:^id(BFTask *task) { + return @(!!task.result); + }]; + } + } + + return [super saveAsync:toAwait]; + }]; +} + +- (BFTask *)fetchAsync:(BFTask *)toAwait { + if ([self isLazy]) { + return [BFTask taskWithResult:@YES]; + } + + return [[super fetchAsync:toAwait] continueAsyncWithSuccessBlock:^id(BFTask *fetchAsyncTask) { + if ([self isCurrentUser]) { + [self cleanUpAuthData]; + PFCurrentUserController *controller = [[self class] currentUserController]; + return [[controller saveCurrentObjectAsync:self] continueAsyncWithBlock:^id(BFTask *task) { + return fetchAsyncTask.result; + }]; + } + return fetchAsyncTask.result; + }]; +} + +- (instancetype)fetch:(NSError **)error { + if (self.isLazy) { + return self; + } + return [super fetch:error]; +} + +- (void)fetchInBackgroundWithBlock:(PFObjectResultBlock)block { + if (self.isLazy) { + if (block) { + block(self, nil); + return; + } + } + [super fetchInBackgroundWithBlock:^(PFObject *result, NSError *error) { + if (block) { + block(result, error); + } + }]; +} + +- (BOOL)signUp { + return [self signUp:nil]; +} + +- (BOOL)signUp:(NSError **)error { + return [[[self signUpInBackground] waitForResult:error] boolValue]; +} + +- (BFTask *)signUpInBackground { + return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) { + return [self signUpAsync:toAwait]; + }]; +} + +- (void)signUpInBackgroundWithTarget:(id)target selector:(SEL)selector { + [self signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { + [PFInternalUtils safePerformSelector:selector withTarget:target object:@(succeeded) object:error]; + }]; +} + +- (BOOL)isAuthenticated { + PFUser *currentUser = [[self class] currentUser]; + return [self _isAuthenticatedWithCurrentUser:currentUser]; +} + +- (BOOL)_isAuthenticatedWithCurrentUser:(PFUser *)currentUser { + @synchronized ([self lock]) { + BOOL authenticated = self.isLazy || self.sessionToken; + if (!authenticated && currentUser != nil) { + authenticated = [self.objectId isEqualToString:currentUser.objectId]; + } else { + authenticated = self.isCurrentUser; + } + return authenticated; + } +} + +- (BOOL)isNew { + return self._state.isNew; +} + +- (NSString *)sessionToken { + return self._state.sessionToken; +} + +- (void)signUpInBackgroundWithBlock:(PFBooleanResultBlock)block { + @synchronized ([self lock]) { + if (self.objectId) { + // For anonymous users, there may be an objectId. Setting the userName + // will have removed the anonymous link and set the value in the authData + // object to [NSNull null], so we can just treat it like a save operation. + if (authData[PFAnonymousUserAuthenticationType] == [NSNull null]) { + [self saveInBackgroundWithBlock:block]; + return; + } + } + [[self signUpInBackground] thenCallBackOnMainThreadWithBoolValueAsync:block]; + } +} + ++ (void)enableAutomaticUser { + [Parse _currentManager].coreManager.currentUserController.automaticUsersEnabled = YES; +} + +///-------------------------------------- +#pragma mark - PFObjectPrivateSubclass +///-------------------------------------- + +#pragma mark State + ++ (PFObjectState *)_newObjectStateWithParseClassName:(NSString *)className + objectId:(NSString *)objectId + isComplete:(BOOL)complete { + return [PFUserState stateWithParseClassName:className objectId:objectId isComplete:complete]; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/PFUserAuthenticationDelegate.h b/Unit-2-Journal/Pods/Parse/Parse/PFUserAuthenticationDelegate.h new file mode 100644 index 0000000..d51c107 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/PFUserAuthenticationDelegate.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 + +PF_ASSUME_NONNULL_BEGIN + +/*! + Provides a general interface for delegation of third party authentication with s. + */ +@protocol PFUserAuthenticationDelegate + +/*! + @abstract Called when restoring third party authentication credentials that have been serialized, + such as session keys, user id, etc. + + @note This method will be executed on a background thread. + + @param authData The auth data for the provider. This value may be `nil` when unlinking an account. + + @returns `YES` - if the `authData` was succesfully synchronized, + or `NO` if user should not longer be associated because of bad `authData`. + */ +- (BOOL)restoreAuthenticationWithAuthData:(PF_NULLABLE NSDictionary PF_GENERIC(NSString *, NSString *) *)authData; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Parse.h b/Unit-2-Journal/Pods/Parse/Parse/Parse.h new file mode 100644 index 0000000..52cd000 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Parse.h @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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 +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#if !TARGET_OS_WATCH + +#import +#import + +#endif + +#if TARGET_OS_IOS + +#import +#import +#import + +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `Parse` class contains static functions that handle global configuration for the Parse framework. + */ +@interface Parse : NSObject + +///-------------------------------------- +/// @name Connecting to Parse +///-------------------------------------- + +/*! + @abstract Sets the applicationId and clientKey of your application. + + @param applicationId The application id of your Parse application. + @param clientKey The client key of your Parse application. + */ ++ (void)setApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey; + +/*! + @abstract The current application id that was used to configure Parse framework. + */ ++ (NSString *)getApplicationId; + +/*! + @abstract The current client key that was used to configure Parse framework. + */ ++ (NSString *)getClientKey; + +///-------------------------------------- +/// @name Enabling Local Datastore +///-------------------------------------- + +/*! + @abstract Enable pinning in your application. This must be called before your application can use + pinning. The recommended way is to call this method before `setApplicationId:clientKey:`. + */ ++ (void)enableLocalDatastore; + +/*! + @abstract Flag that indicates whether Local Datastore is enabled. + + @returns `YES` if Local Datastore is enabled, otherwise `NO`. + */ ++ (BOOL)isLocalDatastoreEnabled; + +///-------------------------------------- +/// @name Enabling Extensions Data Sharing +///-------------------------------------- + +/*! + @abstract Enables data sharing with an application group identifier. + + @discussion After enabling - Local Datastore, `currentUser`, `currentInstallation` and all eventually commands + are going to be available to every application/extension in a group that have the same Parse applicationId. + + @warning This method is required to be called before . + + @param groupIdentifier Application Group Identifier to share data with. + */ ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier PF_EXTENSION_UNAVAILABLE("Use `enableDataSharingWithApplicationGroupIdentifier:containingApplication:`.") PF_WATCH_UNAVAILABLE; + +/*! + @abstract Enables data sharing with an application group identifier. + + @discussion After enabling - Local Datastore, `currentUser`, `currentInstallation` and all eventually commands + are going to be available to every application/extension in a group that have the same Parse applicationId. + + @warning This method is required to be called before . + This method can only be used by application extensions. + + @param groupIdentifier Application Group Identifier to share data with. + @param bundleIdentifier Bundle identifier of the containing application. + */ ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier + containingApplication:(NSString *)bundleIdentifier PF_WATCH_UNAVAILABLE; + +/*! + @abstract Application Group Identifier for Data Sharing + + @returns `NSString` value if data sharing is enabled, otherwise `nil`. + */ ++ (NSString *)applicationGroupIdentifierForDataSharing PF_WATCH_UNAVAILABLE; + +/*! + @abstract Containing application bundle identifier. + + @returns `NSString` value if data sharing is enabled, otherwise `nil`. + */ ++ (NSString *)containingApplicationBundleIdentifierForDataSharing PF_WATCH_UNAVAILABLE; + +#if PARSE_IOS_ONLY + +///-------------------------------------- +/// @name Configuring UI Settings +///-------------------------------------- + +/*! + @abstract Set whether to show offline messages when using a Parse view or view controller related classes. + + @param enabled Whether a `UIAlertView` should be shown when the device is offline + and network access is required from a view or view controller. + + @deprecated This method has no effect. + */ ++ (void)offlineMessagesEnabled:(BOOL)enabled PARSE_DEPRECATED("This method is deprecated and has no effect."); + +/*! + @abstract Set whether to show an error message when using a Parse view or view controller related classes + and a Parse error was generated via a query. + + @param enabled Whether a `UIAlertView` should be shown when an error occurs. + + @deprecated This method has no effect. + */ ++ (void)errorMessagesEnabled:(BOOL)enabled PARSE_DEPRECATED("This method is deprecated and has no effect."); + +#endif + +///-------------------------------------- +/// @name Logging +///-------------------------------------- + +/*! + @abstract Sets the level of logging to display. + + @discussion By default: + - If running inside an app that was downloaded from iOS App Store - it is set to + - All other cases - it is set to + + @param logLevel Log level to set. + @see PFLogLevel + */ ++ (void)setLogLevel:(PFLogLevel)logLevel; + +/*! + @abstract Log level that will be displayed. + + @discussion By default: + - If running inside an app that was downloaded from iOS App Store - it is set to + - All other cases - it is set to + + @returns A value. + @see PFLogLevel + */ ++ (PFLogLevel)logLevel; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Unit-2-Journal/Pods/Parse/Parse/Parse.m b/Unit-2-Journal/Pods/Parse/Parse/Parse.m new file mode 100644 index 0000000..4bafd45 --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/Parse/Parse.m @@ -0,0 +1,235 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * 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+Private.h" +#import "Parse.h" +#import "ParseInternal.h" +#import "ParseManager.h" +#import "PFEventuallyPin.h" +#import "PFObject+Subclass.h" +#import "PFOfflineStore.h" +#import "PFPin.h" +#import "PFPinningEventuallyQueue.h" +#import "PFUserPrivate.h" +#import "PFLogger.h" +#import "PFSession.h" +#import "PFFileManager.h" +#import "PFApplication.h" +#import "PFKeychainStore.h" +#import "PFLogging.h" +#import "PFObjectSubclassingController.h" + +#if !TARGET_OS_WATCH +#import "PFInstallationPrivate.h" +#if TARGET_OS_IOS +#import "PFProduct+Private.h" +#endif +#endif + +#import "PFCategoryLoader.h" + +@implementation Parse + +static ParseManager *currentParseManager_; + +static BOOL shouldEnableLocalDatastore_; + +static NSString *applicationGroupIdentifier_; +static NSString *containingApplicationBundleIdentifier_; + ++ (void)initialize { + if (self == [Parse class]) { + // Load all private categories, that we have... + // Without this call - private categories - will require `-ObjC` in linker flags. + // By explicitly calling empty method - we can avoid that. + [PFCategoryLoader loadPrivateCategories]; + } +} + +///-------------------------------------- +#pragma mark - Connect +///-------------------------------------- + ++ (void)setApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey { + PFConsistencyAssert([applicationId length], @"'applicationId' should not be nil."); + PFConsistencyAssert([clientKey length], @"'clientKey' should not be nil."); + + // Setup new manager first, so it's 100% ready whenever someone sends a request for anything. + ParseManager *manager = [[ParseManager alloc] initWithApplicationId:applicationId clientKey:clientKey]; + [manager configureWithApplicationGroupIdentifier:applicationGroupIdentifier_ + containingApplicationIdentifier:containingApplicationBundleIdentifier_ + enabledLocalDataStore:shouldEnableLocalDatastore_]; + currentParseManager_ = manager; + + shouldEnableLocalDatastore_ = NO; + + PFObjectSubclassingController *subclassingController = [PFObjectSubclassingController defaultController]; + // Register built-in subclasses of PFObject so they get used. + // We're forced to register subclasses directly this way, in order to prevent a deadlock. + // If we ever switch to bundle scanning, this code can go away. + [subclassingController registerSubclass:[PFUser class]]; + [subclassingController registerSubclass:[PFSession class]]; + [subclassingController registerSubclass:[PFRole class]]; + [subclassingController registerSubclass:[PFPin class]]; + [subclassingController registerSubclass:[PFEventuallyPin class]]; +#if !TARGET_OS_WATCH + [subclassingController registerSubclass:[PFInstallation class]]; +#if TARGET_OS_IOS + [subclassingController registerSubclass:[PFProduct class]]; +#endif +#endif + +#if TARGET_OS_IOS + [PFNetworkActivityIndicatorManager sharedManager].enabled = YES; +#endif + + [currentParseManager_ preloadDiskObjectsToMemoryAsync]; + + [[self parseModulesCollection] parseDidInitializeWithApplicationId:applicationId clientKey:clientKey]; +} + ++ (NSString *)getApplicationId { + PFConsistencyAssert(currentParseManager_, + @"You have to call setApplicationId:clientKey: on Parse to configure Parse."); + return currentParseManager_.applicationId; +} + ++ (NSString *)getClientKey { + PFConsistencyAssert(currentParseManager_, + @"You have to call setApplicationId:clientKey: on Parse to configure Parse."); + return currentParseManager_.clientKey; +} + +///-------------------------------------- +#pragma mark - Extensions Data Sharing +///-------------------------------------- + ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier { + PFConsistencyAssert(!currentParseManager_, + @"'enableDataSharingWithApplicationGroupIdentifier:' must be called before 'setApplicationId:clientKey'"); + PFParameterAssert([groupIdentifier length], @"'groupIdentifier' should not be nil."); + PFConsistencyAssert(![PFApplication currentApplication].extensionEnvironment, @"This method cannot be used in application extensions."); + PFConsistencyAssert([PFFileManager isApplicationGroupContainerReachableForGroupIdentifier:groupIdentifier], + @"ApplicationGroupContainer is unreachable. Please double check your Xcode project settings."); + applicationGroupIdentifier_ = [groupIdentifier copy]; +} + ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier + containingApplication:(NSString *)bundleIdentifier { + PFConsistencyAssert(!currentParseManager_, + @"'enableDataSharingWithApplicationGroupIdentifier:containingApplication:' must be called before 'setApplicationId:clientKey'"); + PFParameterAssert([groupIdentifier length], @"'groupIdentifier' should not be nil."); + PFParameterAssert([bundleIdentifier length], @"Containing application bundle identifier should not be nil."); + PFConsistencyAssert([PFApplication currentApplication].extensionEnvironment, @"This method can only be used in application extensions."); + PFConsistencyAssert([PFFileManager isApplicationGroupContainerReachableForGroupIdentifier:groupIdentifier], + @"ApplicationGroupContainer is unreachable. Please double check your Xcode project settings."); + + applicationGroupIdentifier_ = groupIdentifier; + containingApplicationBundleIdentifier_ = bundleIdentifier; +} + ++ (NSString *)applicationGroupIdentifierForDataSharing { + return applicationGroupIdentifier_; +} + ++ (NSString *)containingApplicationBundleIdentifierForDataSharing { + return containingApplicationBundleIdentifier_; +} + ++ (void)_resetDataSharingIdentifiers { + applicationGroupIdentifier_ = nil; + containingApplicationBundleIdentifier_ = nil; +} + +///-------------------------------------- +#pragma mark - Local Datastore +///-------------------------------------- + ++ (void)enableLocalDatastore { + PFConsistencyAssert(!currentParseManager_, + @"'enableLocalDataStore' must be called before 'setApplicationId:clientKey:'"); + + // Lazily enableLocalDatastore after init. We can't use ParseModule because + // ParseModule isn't processed in main thread and may cause race condition. + shouldEnableLocalDatastore_ = YES; +} + ++ (BOOL)isLocalDatastoreEnabled { + if (!currentParseManager_) { + return shouldEnableLocalDatastore_; + } + return currentParseManager_.offlineStoreLoaded; +} + +///-------------------------------------- +#pragma mark - User Interface +///-------------------------------------- + +#if PARSE_IOS_ONLY + ++ (void)offlineMessagesEnabled:(BOOL)enabled { + // Deprecated method - shouldn't do anything. +} + ++ (void)errorMessagesEnabled:(BOOL)enabled { + // Deprecated method - shouldn't do anything. +} + +#endif + +///-------------------------------------- +#pragma mark - Logging +///-------------------------------------- + ++ (void)setLogLevel:(PFLogLevel)logLevel { + [PFLogger sharedLogger].logLevel = logLevel; +} + ++ (PFLogLevel)logLevel { + return [PFLogger sharedLogger].logLevel; +} + +///-------------------------------------- +#pragma mark - Private +///-------------------------------------- + ++ (ParseManager *)_currentManager { + return currentParseManager_; +} + ++ (void)_clearCurrentManager { + currentParseManager_ = nil; +} + +///-------------------------------------- +#pragma mark - Modules +///-------------------------------------- + ++ (void)enableParseModule:(id)module { + [[self parseModulesCollection] addParseModule:module]; +} + ++ (void)disableParseModule:(id)module { + [[self parseModulesCollection] removeParseModule:module]; +} + ++ (BOOL)isModuleEnabled:(id)module { + return [[self parseModulesCollection] containsModule:module]; +} + ++ (ParseModuleCollection *)parseModulesCollection { + static ParseModuleCollection *collection; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + collection = [[ParseModuleCollection alloc] init]; + }); + return collection; +} + +@end diff --git a/Unit-2-Journal/Pods/Parse/Parse/Resources/en.lproj/Parse.strings b/Unit-2-Journal/Pods/Parse/Parse/Resources/en.lproj/Parse.strings new file mode 100644 index 0000000..c1c3414 Binary files /dev/null and b/Unit-2-Journal/Pods/Parse/Parse/Resources/en.lproj/Parse.strings differ diff --git a/Unit-2-Journal/Pods/Parse/README.md b/Unit-2-Journal/Pods/Parse/README.md new file mode 100644 index 0000000..c8e506b --- /dev/null +++ b/Unit-2-Journal/Pods/Parse/README.md @@ -0,0 +1,106 @@ +# Parse SDK for iOS/OS X + +[![Build Status][build-status-svg]][build-status-link] +[![Coverage Status][coverage-status-svg]][coverage-status-link] +[![Podspec][podspec-svg]][podspec-link] +[![License][license-svg]][license-link] +![Platforms][platforms-svg] +[![Dependencies][dependencies-svg]][dependencies-link] +[![References][references-svg]][references-link] + +A library that gives you access to the powerful Parse cloud platform from your iOS or OS X app. +For more information Parse and its features, see [the website][parse.com] and [getting started][docs]. + +## Other Parse Projects + + - [ParseUI for iOS][parseui-ios-link] + - [Parse SDK for Android][android-sdk-link] + +## Getting Started + +To use parse, head on over to the [releases][releases] page, and download the latest build. +And you're off! Take a look at the public [documentation][docs] and start building. + +**Other Installation Options** + + 1. **CocoaPods** + + Add the following line to your podfile: + + pod 'Parse' + + Run pod install, and you should now have the latest parse release. + + 2. **Compiling for yourself** + + If you want to manually compile the SDK, clone it locally, and run the following commands in the root directory of the repository: + + # To pull in extra dependencies (Bolts and OCMock) + git submodule update --init --recursive + + # To install all the gems + bundle install + + # Build & Package the Frameworks + rake package:frameworks + + Compiled frameworks will be in 2 archives: `Parse-iOS.zip` and `Parse-OSX.zip` inside the `build/release` folder, and you can link them as you'd please. + + 3. **Using Parse as a sub-project** + + You can also include parse as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the Parse.xcodeproj file into your workspace. Note that unit tests will be unavailable if you use Parse like this, as OCMock will be unable to be found. + +## How Do I Contribute? + +We want to make contributing to this project as easy and transparent as possible. Please refer to the [Contribution Guidelines][contributing]. + +## Dependencies + +We use the following libraries as dependencies inside of Parse: + + - [Bolts][bolts-framework], for task management. + - [OCMock][ocmock-framework], for unit testing. + +## License + +``` +Copyright (c) 2015-present, Parse, LLC. +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. +``` + + [parse.com]: https://www.parse.com/products/ios + [docs]: https://www.parse.com/docs/ios/guide + [blog]: https://blog.parse.com/ + + [parseui-ios-link]: https://github.com/ParsePlatform/ParseUI-iOS + [android-sdk-link]: https://github.com/ParsePlatform/Parse-SDK-Android + + [releases]: https://github.com/ParsePlatform/Parse-SDK-iOS-OSX/releases + [contributing]: https://github.com/ParsePlatform/Parse-SDK-iOS-OSX/blob/master/CONTRIBUTING.md + + [bolts-framework]: https://github.com/BoltsFramework/Bolts-iOS + [ocmock-framework]: http://ocmock.org + + [build-status-svg]: https://travis-ci.org/ParsePlatform/Parse-SDK-iOS-OSX.svg + [build-status-link]: https://travis-ci.org/ParsePlatform/Parse-SDK-iOS-OSX/branches + + [coverage-status-svg]: https://codecov.io/github/ParsePlatform/Parse-SDK-iOS-OSX/coverage.svg?branch=master + [coverage-status-link]: https://codecov.io/github/ParsePlatform/Parse-SDK-iOS-OSX?branch=master + + [license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg + [license-link]: https://github.com/ParsePlatform/Parse-SDK-iOS-OSX/blob/master/LICENSE + + [podspec-svg]: https://img.shields.io/cocoapods/v/Parse.svg + [podspec-link]: https://cocoapods.org/pods/Parse + + [platforms-svg]: https://img.shields.io/badge/platform-ios%20%7C%20osx-lightgrey.svg + + [dependencies-svg]: https://img.shields.io/badge/dependencies-2-yellowgreen.svg + [dependencies-link]: https://github.com/ParsePlatform/Parse-SDK-iOS-OSX/blob/master/Vendor + + [references-svg]: https://www.versioneye.com/objective-c/parse/reference_badge.svg + [references-link]: https://www.versioneye.com/objective-c/parse/references diff --git a/Unit-2-Journal/Pods/Pods.xcodeproj/project.pbxproj b/Unit-2-Journal/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ee44097 --- /dev/null +++ b/Unit-2-Journal/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,5678 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00163060B2D0C8870906DF0994834474 /* FBSDKBridgeAPIProtocolNativeV1.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CE70D7D33DCB5A7B77D431309FF7DED /* FBSDKBridgeAPIProtocolNativeV1.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0059AAF7BDA07F6056221CE7D55CFE28 /* RKTestConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A986FCBAFF66C34031E230F059A2DCF /* RKTestConstants.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 007D207B3BF73369E36B01A53A09538A /* lcl_config_extensions_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = 18811D86AFD569DE58C69DE2D674A00D /* lcl_config_extensions_RK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 00CC1284C4EC48A67C89030A464A8E22 /* PFBaseState.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB9F7182025D4FEB1027A192204588E /* PFBaseState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 00F8DED37CC833980AEAD7E7BD46C99E /* YALAnimatingTabBarConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 2870EF5BFCF54FA3B58A74A16C8DEA99 /* YALAnimatingTabBarConstants.m */; }; + 012374FC7BF3C42864F8A6D9790C7836 /* BFExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D63D25E0D4B1B1573FC3216A3041E64 /* BFExecutor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01A64680ACA654A0CAA6A98B76A2C015 /* PFProduct+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D18572FD7945CECB627B25FAFC28DF5 /* PFProduct+Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 01A9C95FB174BF00024C127D94FAE9F9 /* FBSDKApplicationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = D8B4BCA52E13031B048A091F56EDD1FE /* FBSDKApplicationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01CEDCC7CB1512AB0E0F3D84C2F12918 /* RKTestFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 530B742954AE4C60876DC3128D82F154 /* RKTestFactory.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 02437AFB910783C6BD25E492758C46D9 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEBA4E2BFC884C1F4B170F5BC7DE8B77 /* CoreGraphics.framework */; }; + 02551F124693A0300B457431E75E3AF0 /* PFUserState.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FAEDC2711A67FEFF48FE305A9A04C6 /* PFUserState.m */; }; + 0277D1C85C0C1E1358C7AAD044B40757 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 02A63183E1CD64A36C6C93A5A33A2CC8 /* PFObjectSubclassingController.m in Sources */ = {isa = PBXBuildFile; fileRef = F9E40B348CF74929CFC2ED015A0099CE /* PFObjectSubclassingController.m */; }; + 0301C8C6C03DB444A51A086E29571535 /* PFRelation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25EF987A717711C8CEAE29DFF3C12EA0 /* PFRelation.m */; }; + 03FB2588038E1FF08053127B70281205 /* RKAttributeMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 776A46D7EBDABB85B1A452ED93BEFBF9 /* RKAttributeMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04562DEDFEB5549638FFF3A71A940FF3 /* FBSDKLoginManagerLoginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5D256457EA109A0FD3C2B7F2AFFFD8 /* FBSDKLoginManagerLoginResult.m */; }; + 04885DFC809E60B33C73D0262CCD3D7B /* RestKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D169B7683E9DA4DE1D139D6CD10D190 /* RestKit-dummy.m */; }; + 04C21C0C58DD5EF39D9E5A7C9E060F3C /* PFMutableUserState.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D052546B61C8CA0E3EB34475BFB60D0 /* PFMutableUserState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 04CF8AD033C179325590EA52685AE224 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 733D51F628A8649F5A0790296BA3E42A /* CFNetwork.framework */; }; + 0524E3768D3DFCF2E4E232DCF896DC2D /* FBSDKLoginKit+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B3362FF57BC5AE2D2552F6F4C4ACD2C9 /* FBSDKLoginKit+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 05606336B17E8DE7AFBE9B0AD554763D /* PFRESTCommand_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 37F7E3AF617E0BF5874DE052CCFF4A53 /* PFRESTCommand_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 05E1825A084B452E32D6063463B3FDDB /* PFBase64Encoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E39257A1062D3B3E8CA265E73AF9795 /* PFBase64Encoder.m */; }; + 05F9EB16C3ED571BD0592AE09986458D /* PFRESTPushCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC06CCF32BA9A3FEE34142E70D19588 /* PFRESTPushCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0601A5D463502C68B57F87216DC01E47 /* RKAttributeMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 2551AB6C3C2A1C521E0184550321DE02 /* RKAttributeMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 06084AD9120FF151ADF37E92A8CDBE83 /* YALFoldingTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = F83D6439675ABF2D6040C5D9F2FFF217 /* YALFoldingTabBar.m */; }; + 06CC5B30A43EF1C3B526DEE380D8FE8A /* BFCancellationToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EB6FC1B35894D58DCAA447BFB3BB370 /* BFCancellationToken.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 06D70E3ED56542E6E150732ACE707585 /* FBSDKLoginButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A6E4A459DD6D5E686E59DC08B4D07F1 /* FBSDKLoginButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0799DA50D0F7AB26E77782D14A4D54AF /* PFAnonymousAuthenticationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 36C75B01624E2DCB9059D7ABADC2B668 /* PFAnonymousAuthenticationProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 07B38C643DE61100C2471A5E2061DB6D /* BFAppLink.m in Sources */ = {isa = PBXBuildFile; fileRef = C1C4E1C48CDDA8FCF1C074DCC0D2A656 /* BFAppLink.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 07ED5D3AADD2C1C41BD215C19C4E48C6 /* PFPushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AFDCBEB6665886D2633CB5495726E387 /* PFPushManager.m */; }; + 081F6FAFE0FC8BD6EFC6A517B0ADB614 /* FBSDKMessageDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 85F8F13323C74D0619E9E4B4BBB27CEE /* FBSDKMessageDialog.m */; }; + 082462DCFDC7A19F595743F10C8EC7EB /* PFInternalUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B16892D13DE46A8E0F04B376575D7B5C /* PFInternalUtils.m */; }; + 083A7602FC1ED21B8878784115D662F1 /* PFSQLiteDatabaseResult.h in Headers */ = {isa = PBXBuildFile; fileRef = EAA88DECC60605475F4AA3869B36A8FB /* PFSQLiteDatabaseResult.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 087E876A250108F964ABA6E268BE5846 /* PFEventuallyPin.m in Sources */ = {isa = PBXBuildFile; fileRef = 98262DA8D9F983FFA347D99C232021E5 /* PFEventuallyPin.m */; }; + 08A92B11564DA8300821C2F9E8851DB2 /* PFAnalytics_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BC07203CD82FF286D245D3A0306E62C5 /* PFAnalytics_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 08D84FA7E2537052744E64C7025A84E7 /* PFPushController.h in Headers */ = {isa = PBXBuildFile; fileRef = 10C11BD85333AB6363CF6EC82E870605 /* PFPushController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 091B7CD914893E81C39427757E3FB0FD /* RKValueTransformers.h in Headers */ = {isa = PBXBuildFile; fileRef = 37FC535483D9258C485125E0488ED3EF /* RKValueTransformers.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 097CE360D698CD7CC46F59B370318ED1 /* FBSDKLiking.h in Headers */ = {isa = PBXBuildFile; fileRef = 672B96E281A19DA7F2F22511F1093D16 /* FBSDKLiking.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 097DE14824DA65BDF81E4C5A2D73566F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 09FF1B52A8DE609DF1E2EF7378210758 /* RKDotNetDateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = F2ACCE7F5437F868E4BA7E2A0C645D43 /* RKDotNetDateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0A1E88ACE6A4D6D41EA0634DB6A94256 /* PFObjectSubclassingController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F2BB3EBFE218C47714938D29CF23EF9 /* PFObjectSubclassingController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0A45B6A339543EC83754D28F87523802 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6114EBA3A5CB7CB8ECE0A9BEFA6DB026 /* Security.framework */; }; + 0A6A5BA0942FF096A2D641E8F49C0F79 /* FBSDKAppInviteContent.m in Sources */ = {isa = PBXBuildFile; fileRef = D24F985E3661241D2C0921E8022E66C2 /* FBSDKAppInviteContent.m */; }; + 0AAD3502C3D2BB1E3E7F4377C5111691 /* BFTaskCompletionSource.m in Sources */ = {isa = PBXBuildFile; fileRef = F6F4C2DDD2D3755D276BC06E4C5B319E /* BFTaskCompletionSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 0AD287666FAFC490CAD4CBFBF47431AE /* PFCommandRunning.m in Sources */ = {isa = PBXBuildFile; fileRef = A94107D173054A31E231EA3E081AC080 /* PFCommandRunning.m */; }; + 0ADF250658B54EA51FC500CB76783CB5 /* PFInstallation.h in Headers */ = {isa = PBXBuildFile; fileRef = A51B1A321088E7B66FD0BCAE78FD96F9 /* PFInstallation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0B96F448CA70A5E1B7389BD7015EFE01 /* RKObjectMappingOperationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DFC0AEEC2FC3F3A422A6A76F818E344 /* RKObjectMappingOperationDataSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 0BB5BE4B4A8C410F2248DE8D14BB4663 /* FBSDKGameRequestContent.h in Headers */ = {isa = PBXBuildFile; fileRef = EFF0339213287B595E2857A1BCA7B7E8 /* FBSDKGameRequestContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0C08BCEA5FE46370A36AEF6BEFCC41EA /* FBSDKAppEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D7387AFD498FF6D486BEF5755B9D7B3 /* FBSDKAppEvents.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0C132DF2B2F5648112EE398656EE0962 /* PFRelationState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CD4D52B14CF2360DE429DCB655B00642 /* PFRelationState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0C4D309AE4178F282BAD4DC9EB1E5B03 /* RKNSJSONSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 8275725385A9F6C10AF8B7A642A129F8 /* RKNSJSONSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0CA55F1868EDE312E4DD0713C9AEAE99 /* POPLayerExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = BDEF6D63702D3C9DE58BBBC7977D10BA /* POPLayerExtras.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0CAA65756A68A9D5C473ABECAA0B50BF /* POPAnimationExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 325AD4A9548841B8B429CC3D00DF02E4 /* POPAnimationExtras.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0D0CFD86DC5D95BB25D65B84461D031B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 0D52952BF5B3A015FA024A23981EA5BD /* RKRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 868CF57091A5F8B47E4CF9B82CD4715D /* RKRouter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0D5354A9FFC479301962382BF42F5597 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 433B51CC13747ACBE8AA93F02C6D784A /* RKMapperOperation_Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0D6F37CCD07F22936439247F6189A056 /* RKPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EB1F29228069356CCA0E5D8E0C8DA3C /* RKPathUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0DA197860573F04B990BB55CED47EB2F /* PFRESTSessionCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 030B329DF20766AE685434CD734BC3B2 /* PFRESTSessionCommand.m */; }; + 0DB80F6F97A5BEB7A1839EBAF3FCA9AF /* FBSDKSendButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8039DDB4E996A03FF15AD2DF8D4D1CA9 /* FBSDKSendButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E089188D74319CC3ED824652B776895 /* FBSDKLikeButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D7D382B54C6E6B265B154F079E1CDDB /* FBSDKLikeButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E47EB82346F3A93F6FC3AF3AEA778E3 /* PFConfigController.m in Sources */ = {isa = PBXBuildFile; fileRef = E1F89AA6B095AAB2C7CEB2BEAC5A7F1B /* PFConfigController.m */; }; + 0E688D49284AEE76C3B651E3CFE54C94 /* PFFileState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = EC599B21BE1C0853A0234AD38F8FC07E /* PFFileState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0EA556CC3DBCD3806D56508332A5FB59 /* PFMutableACLState.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E3480D6C7EF4C1D5B97238AFFE8D127 /* PFMutableACLState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0ECA745830D272585C68ECDF8C5569D7 /* PFURLSessionCommandRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D0B957E23560E8729AFBC541E7F0401 /* PFURLSessionCommandRunner.m */; }; + 0EEABB9AABDED87C8B9F585D82062063 /* AFURLConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 35CC150A7EE20543758EB2CBCB3D0D9D /* AFURLConnectionOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0EF3F474C4F968CC78351909F0C76A70 /* RKValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DDC6BF6D637CEFC8BEDA82F87D0A60D /* RKValueTransformers.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 0F4202BC6561358918BED3708C095673 /* POPAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 11CBB787D4E85EE9F313E56D6B653B6F /* POPAnimator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1002547EB73320964BC1B10D757EAE2D /* FBSDKUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = A9971360D666FDBC3DDD421157793868 /* FBSDKUtility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1005515B34A7CCF2EF97A317B71D2632 /* POPVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7F6E4B0E19B7E3633F89483FC21D852C /* POPVector.mm */; }; + 10B055EF9DE001B011240568093FE8AB /* PFHTTPURLRequestConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 5733C650048839167646DC7974A01ABA /* PFHTTPURLRequestConstructor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 10B85E5BCE0729452FFC72D7BB376F59 /* FBSDKShareDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = A8051434722A3494196DC122D8029D34 /* FBSDKShareDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 12824DFDC12C14097AF56D630AD2D8FB /* PFPushState.h in Headers */ = {isa = PBXBuildFile; fileRef = AB87FFD2A22D9F8F81F29DD24782E89A /* PFPushState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 12D4BF5F8785937DA809F9D90E6FB565 /* BFMeasurementEvent_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = CB172E497F3C842C06931402446C2D4B /* BFMeasurementEvent_Internal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 134441CFC16A905CB51B70597FF4B61B /* PFObjectPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 31AE16032795BC110759FE0D71DD7F32 /* PFObjectPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1345483A67FB02C778D2D3639930AED7 /* FBSDKBridgeAPIRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F44E8E904E1CD028316E671E43453DCE /* FBSDKBridgeAPIRequest.m */; }; + 138917EC340B4D359138CD16C4383D1D /* FBSDKCopying.h in Headers */ = {isa = PBXBuildFile; fileRef = BA69ED7E54B79F2B468E042414006FC8 /* FBSDKCopying.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 13F6C4E6B73C633E8D58029DEB14DF5A /* RKStringTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2562927BDB580A25FD1C5DE23213DD83 /* RKStringTokenizer.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 14545C481D346027B2C0E703B8AFDAAA /* RKResponseMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 033F7B99C3A65CD435C0B7A09C59F876 /* RKResponseMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1497B8CAE9DE252B51DC38604B76AD7A /* RKResponseDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = AEA43D8F8666C7D28DA8F862B304C5B8 /* RKResponseDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 14D6E494E0D7E904AD960AE602238451 /* PFObjectFileCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C1F3D82C36D976C5759677F623553F /* PFObjectFileCoder.m */; }; + 150FD95BCF7C18E9717A863C6B645DC6 /* PFPushChannelsController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB90E78B06FCB922FD3083DB6AFE5ECA /* PFPushChannelsController.m */; }; + 1540A63B0BF8B0C782AE91A5B67FEF38 /* BFAppLinkTarget.m in Sources */ = {isa = PBXBuildFile; fileRef = F22BFE44135812D7404BBDAF34C010E3 /* BFAppLinkTarget.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 1546A097DB78CBCC3268F3EB5541DE8F /* PFUser.h in Headers */ = {isa = PBXBuildFile; fileRef = FCDD09913DC7F28BA260222EED8670BE /* PFUser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 156967851249D30F7710773EC47EB1F3 /* FBSDKCoreKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2423BDB586DF4DF3F1525A1B5C40C54F /* FBSDKCoreKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1570AA3EA1A480ADB0757319269174D1 /* PFAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C7BBFE7402E447E0363B1BF78CFD3A0 /* PFAssert.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 15C98EE5B0B19EC8B2B69FFF3836F90A /* POPAnimationTracer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A5C02D17E47A222D470066E80F5230B /* POPAnimationTracer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 168754543C69B5763F69864E4180CA20 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 764FFD75345B6B6A979A9D10F2D2907B /* AFHTTPClient.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 16A0D1D260C2A0C9456093033B7B2704 /* TKState.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CB6F2CF47DB783D84FBBB6F2B1A451F /* TKState.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 16ADFA9976DB0641CC700CE33921E328 /* RKMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = F09DC66B579DD76F90EDE78627D95BB3 /* RKMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 16E3CEBF59A2D8E5A9B04AF979FDF14A /* FBSDKShareLinkContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 864B619977C41FA41083B23778DFD471 /* FBSDKShareLinkContent.m */; }; + 1700592C1709E23CF04D2CA3F4BEC83D /* PFSession_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B03B11C4675A010812829BDD0481A90F /* PFSession_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1708C44508662C2D5867EB8DB869B93E /* PFQueryController.h in Headers */ = {isa = PBXBuildFile; fileRef = 137AE6FE411D32FD166221B1257A8D27 /* PFQueryController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1742414744E4A0DF8BB946045C2EB827 /* POPAnimationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 761DB1B71490B54C854E88186480B4EA /* POPAnimationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 17D0DD03C923128099A9737F317E5D29 /* PFObjectUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C78765A1425D0F41319511A796357B1F /* PFObjectUtilities.m */; }; + 18128AAED9116077EDF701E1098C9954 /* PFQueryState.h in Headers */ = {isa = PBXBuildFile; fileRef = BD91B010ED73759E99DB85B7CA9FA867 /* PFQueryState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 188C54485E358878521C5C15A0AFE626 /* PFObjectControlling.h in Headers */ = {isa = PBXBuildFile; fileRef = 20512742319C64711FFF5148A7214E8D /* PFObjectControlling.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 18BA1F40271FF44B3A0508ABFD1600FF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 18C091723B432584B085686061A0CEE0 /* FBSDKShareOpenGraphValueContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B1BBDE1A0182E4AAFF80CDBBDF1DAB9 /* FBSDKShareOpenGraphValueContainer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 18CF81105FB6E0685A26F83F128F4E47 /* FBSDKButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4A6D24A88D4B18ED3D60681DF68270 /* FBSDKButton.m */; }; + 18D7A90C450EC893C4428E23D8B47E9F /* BFMeasurementEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = FB3A9DED47A72521C01855CCB13A10EA /* BFMeasurementEvent.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 18EAF4167A160D50758673E49250402C /* FBSDKAppGroupContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CFFE5B32D8DD018AAF9EB4733D6315B /* FBSDKAppGroupContent.m */; }; + 195B7EACB9E277F950B7C1BC314BB968 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEBA4E2BFC884C1F4B170F5BC7DE8B77 /* CoreGraphics.framework */; }; + 1961C4A9AD59A951688C260E91482AA0 /* PFPurchase.m in Sources */ = {isa = PBXBuildFile; fileRef = 01A50C2394596A1AAF49C7A2877C776E /* PFPurchase.m */; }; + 196864B89AC2C8A21D31595D9A7E05A0 /* BFCancellationTokenSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B8AE15FBFEC0BE016020B8970ADE865 /* BFCancellationTokenSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 1A8EA6EABBDB4F9D5170BBC9F31E9FB9 /* PFRESTAnalyticsCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1CFA906E2A5ECA69FDBCAC00497F72 /* PFRESTAnalyticsCommand.m */; }; + 1AD36782B0606C9AB186A075420F1EA3 /* FBSDKShareUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E3D3427A00B557DE42EED0B4C015942 /* FBSDKShareUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B11A9CD89258EFE81856DDA597C2826 /* PFGeoPointPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 407C402A54C0C81D42BEA7147982FA35 /* PFGeoPointPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B3C45012DD6C877AF2B3757B48D2CEA /* RKMappingOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FE7C0F12060A4C3CEE3C5427762A616 /* RKMappingOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 1B3FD4504118844C3450B1F75C2EC2B1 /* PFObjectSubclassInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A7AAF29A747A53F757B1A76CF477460A /* PFObjectSubclassInfo.m */; }; + 1B732797EE1CF10C328DFDC742E866A6 /* FBSDKErrorRecoveryConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA6A8C4B5B6F7C4E38F45C438720C50 /* FBSDKErrorRecoveryConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1B7C3D5167896D20FDA7AD2B99B9B442 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 114DF71DB16E01CD9902FA71F5FCB868 /* RKObjectManager.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 1BBA57EDDB94507AC5DAA85D6489D942 /* FBSDKAppGroupJoinDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 79630B324053224BBFAB6E9D26A18148 /* FBSDKAppGroupJoinDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1BF89E326EBB865184A47A1B76EA44B6 /* PFOfflineQueryLogic.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EA63193596C0C6A36407E53BE350DC2 /* PFOfflineQueryLogic.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1BFCFA4856B9BE43C5FB24EA58662689 /* PFAnonymousAuthenticationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = D46B8631F4A20A30B5C1E47D9F2A6FEB /* PFAnonymousAuthenticationProvider.m */; }; + 1C2AF8394E4C8C86B7F42AF545C80281 /* PFPropertyInfo_Runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = F29DD5432F60CE09614541D4BE9A4FB8 /* PFPropertyInfo_Runtime.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1C5FC139D9A229EC782BD8D26071C29E /* BFTask+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F0F7C3B1D42E74B34C118D7F55D56DC /* BFTask+Private.m */; }; + 1C906268C5AA213F8CFCDCC95D00C718 /* PFOfflineObjectController.h in Headers */ = {isa = PBXBuildFile; fileRef = 129476AE26D881F46C3F727D95A2D8EE /* PFOfflineObjectController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1CE911A8315F4C7A5844415DC9933260 /* PFRESTObjectBatchCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF50A43880E07D46E8A97B575A92405 /* PFRESTObjectBatchCommand.m */; }; + 1D66DABAD4D2C36AAF8062BE3D55C7DB /* FBSDKTimeSpentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 84E5CF3BD81C4C414BE88556EB18D08F /* FBSDKTimeSpentData.m */; }; + 1D840EA09132B2B34413FA16BD0E1AA5 /* FBSDKApplicationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7558DBD1AF61B17AF39F3565B9F68601 /* FBSDKApplicationDelegate.m */; }; + 1DA6669105771BA38E2C69FDC90286A6 /* PFObject.m in Sources */ = {isa = PBXBuildFile; fileRef = A12B03B24DC7C654F172A6A53E9C7603 /* PFObject.m */; }; + 1DBC9B7D710CE712D9F4C8E497DE1E0B /* PFSQLiteDatabaseController.h in Headers */ = {isa = PBXBuildFile; fileRef = 19397C043A357D696BBA9A55EFD5B167 /* PFSQLiteDatabaseController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1DD387B9558E7C1759425FCA6C52D4F5 /* ParseModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BD6DD4F4195C174C8DC06D3C85DDF8A8 /* ParseModule.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1DD3895D39730377AEA9BEA6D66767CA /* PFDateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 99B423A79E8F8A42FC5D676612B33E2F /* PFDateFormatter.m */; }; + 1DFA8E2E3190F5321761EE4BE95C9ADC /* FBSDKUIUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = D849F8915909B1847A03276B640112BC /* FBSDKUIUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1E37A7B04ECBE439CE8A683823B663B7 /* RKDynamicMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 849262636C1FD7E1D283D86137BE70B8 /* RKDynamicMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 1E8874FFFC0B19D20C001681F1942855 /* FBSDKShareAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = ADBAF2BABA39070672917C80E4F74CBA /* FBSDKShareAPI.m */; }; + 1F2BB357DDF0A1CE916761ED5DBB98D2 /* FBSDKGraphRequestBody.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E7D0F10FA61E6BAC091324113D02F2 /* FBSDKGraphRequestBody.m */; }; + 1F2C79C7C24FCC4784A09BF594C6F1ED /* RestKit.h in Headers */ = {isa = PBXBuildFile; fileRef = F2FBDEBC39B29A9DA41247E2D96331E6 /* RestKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1F3D5A5A5067181846196EEC61D25961 /* PFWeakValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 205214C203BF751A124F1153AD9CBA8E /* PFWeakValue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F85CC0A24315E41F1DB39068E4684A8 /* PFPaymentTransactionObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 60D3C2480A1362A32E373ED42790BD7C /* PFPaymentTransactionObserver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 200F941DC68314422A92DECA8D213082 /* PFObjectBatchController.h in Headers */ = {isa = PBXBuildFile; fileRef = ADBEDE77334D88F47F1AD897ECEFAC8D /* PFObjectBatchController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 205E1195DEF1603010BA47F3A8A39ACA /* FBSDKShareKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B468DC6F25FAF7381C563D8A3A3C32E /* FBSDKShareKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 206B7172BAA6262F77700E4347C0F8D5 /* PFUserState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 138471689F57812BFA9933C75A79A7D5 /* PFUserState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2086289033B670D4FFE18F8578E911F2 /* CATransaction+TransactionWithAnimationsAndCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = FBFE9966A9FB854C5D85375D24F936C5 /* CATransaction+TransactionWithAnimationsAndCompletion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 20A2B211D75692571DE1A418220365D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 20CA33378056E289649C0616BF5C5E08 /* FBSDKLikeBoxView.h in Headers */ = {isa = PBXBuildFile; fileRef = A8710983B393BA50AECE51EA8D90E727 /* FBSDKLikeBoxView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 210C00EF879DEDEA7EB09EC8C91A80A2 /* FBSDKSettings+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B432A363E0081BD273051415B767D749 /* FBSDKSettings+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2132812C756FB96D0AB12B601F84A802 /* PFRESTFileCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = A1F131A4365C559659FC1FBB194A13E9 /* PFRESTFileCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 216D6126C206D951C489C95FD37BD8CF /* FBSDKAppEventsState.h in Headers */ = {isa = PBXBuildFile; fileRef = E75B973B4239A8C33C3DF18D0F41168D /* FBSDKAppEventsState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 21C13796DE839F92D14C6CA50671E5BF /* PFPushState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C3843CD6AEFE5F515E6142799F801CA /* PFPushState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 21E2ED6EFD8559848B98705909DEA010 /* FBSDKLikeDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 3394EE87DFC9E88439AB265D59382138 /* FBSDKLikeDialog.m */; }; + 22080662EA8952370B284F798F16D4B2 /* FBSDKShareVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3135C42A396F109267EA88F6641A9194 /* FBSDKShareVideo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 227CE567B059758E1C977990BFAD75AF /* PFDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BAE999CCCB6D83C2D4DFA288FE9C7BF /* PFDevice.m */; }; + 229318A2EF0A83A1BC417DBB54FAE450 /* POPCGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 09343BA3B921E20A6185A17744E53B63 /* POPCGUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 22BB0A3493753E3DE40426F8E2A8D98F /* RKResponseMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AC2271F01F29748BDF976CEF2EE767A /* RKResponseMapperOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 22C38A31A84F31B9EF5B40892497DA44 /* PFLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1804AEAE0A042ABB0AB0F3B3CCD54B2A /* PFLocationManager.m */; }; + 22E435D60724A7D16B950FC453C5E34C /* FBSDKConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E867F3D72745F4BA824FC362CEBFACB /* FBSDKConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 231A46F0855F96400AFB1832C605FF6F /* RKLog.h in Headers */ = {isa = PBXBuildFile; fileRef = E8A3F0FA2907B71EC0DCB074D0E32D52 /* RKLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23F22339DEDBD778AB5D1DA13BFECC4F /* FBSDKGraphRequestMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 190B3059AD121705B18018211A6B6C66 /* FBSDKGraphRequestMetadata.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2453E44572F93FE8CFB1E9C2B07F8142 /* FBSDKInternalUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 20EA58DC0A0DC1E01333E2DC71658378 /* FBSDKInternalUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 24FA587A203EB1838E92394C128065EA /* FBSDKSystemAccountStoreAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = E2E5158BDE2438D1F296202C6A65CAD9 /* FBSDKSystemAccountStoreAdapter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 25435509864D8830160361E72AA5E31F /* FBSDKLogo.m in Sources */ = {isa = PBXBuildFile; fileRef = B80B9804F9EC77183DFB3A54E58272CF /* FBSDKLogo.m */; }; + 2556A6696795A705FF3AAA00CAAF1879 /* PFCoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C5E9FB336C0917EC02E4034B2B66FE /* PFCoreManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 25C7617B2D122A04E33E3B78CA426B60 /* Support.h in Headers */ = {isa = PBXBuildFile; fileRef = 9ADB5C6CFDD59CB906870DA9025B3B8A /* Support.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 25C893D3F81918CA2748927B5F02A595 /* FBSDKBase64.m in Sources */ = {isa = PBXBuildFile; fileRef = 56FE36E9C6BEFFC89DD1BC36E6289234 /* FBSDKBase64.m */; }; + 25EFA69D90204A5BFBC506669A97C683 /* PFFileController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FE19DF082B2711D3D79E3BDF50FA146 /* PFFileController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2617C1651BDE360A04512FF5DFEE55B1 /* FBSDKMonotonicTime.h in Headers */ = {isa = PBXBuildFile; fileRef = 933D9439D53FAC2493C8D8F5ADD21D74 /* FBSDKMonotonicTime.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 264457704BDD888C92CAAEBE20E709FC /* FBSDKTestUsersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 324AAABDF5EC040480FF7DD0137ACC3A /* FBSDKTestUsersManager.m */; }; + 267A29AA34A9D757450EBE41A4A5F40B /* PFInstallation.m in Sources */ = {isa = PBXBuildFile; fileRef = 892F0F257D5AF973E182934E5D03C911 /* PFInstallation.m */; }; + 269ABC30C8CD9E74E46491F5B6FB9D17 /* PFMutableQueryState.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F9A3C84F3CC18CABCD97E1DFB774A49 /* PFMutableQueryState.m */; }; + 273413858783060A2A4F5AB76A2855CE /* RKObjectMappingMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E5C990C91B211AE926078950B8630516 /* RKObjectMappingMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 275BF668E4B40AEBF35F411A56F05B6D /* RKTestNotificationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = F6FB42658DA37641EE0F5D6EE5236722 /* RKTestNotificationObserver.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 2763640E3F9F25BCE1BC36B60364A740 /* FBSDKSharePhoto.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE70DA06AD37A88DD393A98C73C7D07 /* FBSDKSharePhoto.m */; }; + 27DAF03799622546C24B79D72DFF1003 /* Parse_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 503253CFCA3206291EBDFF00B0FDE5BF /* Parse_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 27F8C6DBEE3149A4A1FE4682E23111A5 /* POPAction.h in Headers */ = {isa = PBXBuildFile; fileRef = C70FA986190A848DD39EB171EF041F33 /* POPAction.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2894A71BD9B82830C0DE27EDB9DEC7E0 /* lcl_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = D284CA3DDD91571D70CF7256A3C248FE /* lcl_RK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 28BA0A9D61D5B23A53B9D09A7A9896CC /* RKObjectMappingOperationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = F25269A960ACE3EBB3FE45F44DE4D5BC /* RKObjectMappingOperationDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 28E0C7D4EAB83F94E8BED7A8A6588F17 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A2D57E341463F67AF53255008B5CAB0A /* AFNetworkActivityIndicatorManager.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 28EBF852662F1A1004F220F004B2FB27 /* PFFileStagingController.h in Headers */ = {isa = PBXBuildFile; fileRef = FCB8001E15C66CA1A4ADC3B7AB26C08D /* PFFileStagingController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 29A195C90E8CFB19E874DE1984AF015E /* RKTestHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = F3BB79D7E31BCBC04BA5D076D3B1A9BC /* RKTestHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 29E9B7D045DD5219B0D17A1289A1E228 /* FBSDKShareUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = C5934D49963F991DC729306B6D2ECA94 /* FBSDKShareUtility.m */; }; + 2A2484F1773729BB256973910B7340DB /* FBSDKAppEventsUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 8904DD3C8A8AC8A1A2F48DEB0DBC1B95 /* FBSDKAppEventsUtility.m */; }; + 2A9CDB714501BF7551C376135E06CB77 /* FBSDKDynamicFrameworkLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8988609857673ACE16552A1C00D45091 /* FBSDKDynamicFrameworkLoader.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 2ADFEB8C12A6F30CE83BC5AB3316C6E4 /* PFKeyValueCache.m in Sources */ = {isa = PBXBuildFile; fileRef = E22A1C7E80FE2BA8CE59C7C924410D0E /* PFKeyValueCache.m */; }; + 2B19F33BE94964880FAA3A6B58CCE963 /* RKOperationStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E668F82944D74008FA69DF68A0E96F9 /* RKOperationStateMachine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2B868B020F9C681F76C506EF6BC9A801 /* FBSDKSharePhotoContent.m in Sources */ = {isa = PBXBuildFile; fileRef = B16533489604D2247F7EC997C13BA975 /* FBSDKSharePhotoContent.m */; }; + 2BE316C68D11EAF02F9288B25FEFF2B8 /* PFPinningEventuallyQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 131783F296EC8FE80CA0ACE2C3C056CC /* PFPinningEventuallyQueue.m */; }; + 2BFE426FBB2EF7A91EAC0893828A3F5C /* FBSDKShareKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = EAA5D41EBB47944D263EB028AA677026 /* FBSDKShareKit-dummy.m */; }; + 2C04A25EF87B39A7378F852D3A251514 /* PFQueryState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A6D705A7C393E18FCFACEC1D2F07D098 /* PFQueryState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2C61A57B4DA38760CFE42C7F3AFF489E /* PFURLSessionDataTaskDelegate_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CBEF54F1256217E4780DB8ABBF5AC3 /* PFURLSessionDataTaskDelegate_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2CC921A632237030D7C642FF4D3E2216 /* PFUserFileCodingLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = D605FE4F41A283271B93F93C8E0C5932 /* PFUserFileCodingLogic.m */; }; + 2D3A10AB5D0CAECCEEDE49132B5F4330 /* AFHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C1CC5AA0EB4EDA9432A7D5463BE4901 /* AFHTTPClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D4F9228E33B7CB031B9344EA22E3AE7 /* PFRESTQueryCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 0842DD1DCDFD9683C89B6A9078E9D0FC /* PFRESTQueryCommand.m */; }; + 2D6AF7788EA8D30E93BEB5F0CAC89C68 /* PFAnonymousUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B2A7FD3B5E9C5F68CC0E991780A0EC /* PFAnonymousUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D7129239566598FD9FC8204D9D26793 /* PFCloudCodeController.m in Sources */ = {isa = PBXBuildFile; fileRef = E758F865F37D77788EE4B4551EF1487D /* PFCloudCodeController.m */; }; + 2D8855CDA875AC8AD7AE0DFCC4250493 /* YALSpringAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = BD5D724AF948672175ECFB8781A0F2F5 /* YALSpringAnimation.m */; }; + 2D8BA321D46E84251856DED2E84239DD /* PFPinningObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = B70778A88E35241FD05E8017A5D78CFD /* PFPinningObjectStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2DC488DF3C90086C17087C2BB72189AA /* FBSDKMessengerIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = 804F2F0EDB0F2FE68B74F5D2D1ED5A94 /* FBSDKMessengerIcon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2DE0A008B557C991779E119572071163 /* PFFieldOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 91E9125BDC1505BCE865985502732B9D /* PFFieldOperation.m */; }; + 2E29ABDC3BF7E6B7FF03C02FDD08B45F /* PFCommandRunningConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 26A9C85767DC8FE594E7F2DF14F867B2 /* PFCommandRunningConstants.m */; }; + 2E74D36D8D8BAD8D55380944015FD120 /* PFSQLiteDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 255D43CCCFDFD52C9090EF3B8972D72C /* PFSQLiteDatabase.m */; }; + 2E8782D39FA5B415D526EBE5C8AFA32E /* PFAnalyticsUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 32584F1C40CC0FB3ACD703733332AA08 /* PFAnalyticsUtilities.m */; }; + 2E87F7494BC2023ED83CCB2C93E67B69 /* FBSDKBridgeAPIProtocolWebV2.m in Sources */ = {isa = PBXBuildFile; fileRef = AE15675496460EEA4051AF5F4AB4E504 /* FBSDKBridgeAPIProtocolWebV2.m */; }; + 2EF035CF21D5D9B2F876D73D145DCBAC /* POPAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E0A91B803AD2D9F9BBC9C9C40485EFB /* POPAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2F4C116B777496BAB15E7D6442D221BF /* FBSDKErrorConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = E436D932FA7C17E15674EB32E957ABE2 /* FBSDKErrorConfiguration.m */; }; + 2F67C0F2B19DD7478B7C6089401D10D8 /* POPDecayAnimationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 64DFE094C387E0DA1F62DB6912006497 /* POPDecayAnimationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2F8A6D5D298FE5F63CFA909D0A63D26B /* PFRESTObjectCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = E0650188B522893BF764569662B5E542 /* PFRESTObjectCommand.m */; }; + 2FB0531893E490ACEC556B0F43C44591 /* FBSDKLikeActionControllerCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 68133029060DA29FD5C9C26119CFA51B /* FBSDKLikeActionControllerCache.m */; }; + 2FBCC263A4CF83AF299AAC0CEE750AD6 /* BFURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F63108EF1315E6D7E404F9ABF304F1A /* BFURL.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FC94CCAED9DD09203580A70DECF2A4A /* PFCommandURLRequestConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = 87EE4B2AFFD85E9F75C94F5661D717F2 /* PFCommandURLRequestConstructor.m */; }; + 2FD8DABDCB30DFD548402447EDD982B7 /* POPGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 25913693021196FC72C7A8E7A937AFCC /* POPGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3053488EEEBCD0385576315DBE9EC11E /* FBSDKCheckmarkIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E4E096EFFA1494BC822896BB3BD15AB /* FBSDKCheckmarkIcon.m */; }; + 307D54623092903A6C49A7C219BA3252 /* FBSDKMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 851FD672C97DC80E95B543E7678B133F /* FBSDKMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 313C10C6A642FC61680D2E00D59E5FD5 /* POPAnimationTracerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = BC8D8339F84A5B54DDC0F0B6C03E6C30 /* POPAnimationTracerInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 31B7827480A2AD779C80D1E428F0F758 /* FBSDKKeychainStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 42B37BE48C6B242CC345A82EFFCA35CD /* FBSDKKeychainStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 324B462950BF05B9CF8C8B4E1556D1A3 /* PFOfflineQueryLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = 778D8D7F4CD22FFBC60450393224961A /* PFOfflineQueryLogic.m */; }; + 329EEBF461254C9F4C4F7DFF196498F3 /* RKMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0803B22C601D5D4145A1B91DB87E04E3 /* RKMapperOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 32E214F119A1BF1D749C05323F252756 /* POPSpringSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D50729BCCBCCC5A423CBB509507C3DC /* POPSpringSolver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3358C947C2329AD593909B5A55839B9C /* Network.h in Headers */ = {isa = PBXBuildFile; fileRef = 85B4596D7B3771E5ABD20C9631F9B18A /* Network.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 336A9DE5FB7C4ED8DF5B7E6EC76D0822 /* RKRoute.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C78256463C46E887FB8962C96ADF343 /* RKRoute.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 336B220F124974D444746D194367422A /* BFAppLink_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5732F9BC7E2742FFFC7C3BA8F1225459 /* BFAppLink_Internal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 33808782CCEF801D53209D523D9C7358 /* FBSDKButton+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE570F7AF0D238D396B8C1BD1233F8 /* FBSDKButton+Subclass.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 33E51CF359A60B9BF66BE9C279AB3E43 /* FBSDKAccessTokenCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 17713158760C0CE314D469EF9DAB5E98 /* FBSDKAccessTokenCache.m */; }; + 34139CCA6481211B5C8BC57918F8FF3B /* POPSpringAnimationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7915DC37B74D252F701BF85B55880ACF /* POPSpringAnimationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 343BA26395BFBF73CFC3F42871C03BB9 /* YALFoldingTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = AE3ADE078ECB5E4868892A8EA3936EA5 /* YALFoldingTabBarController.m */; }; + 34B1786FA4EBC179AC660B83CF1A4F82 /* FBSDKShareButton.m in Sources */ = {isa = PBXBuildFile; fileRef = BEEE1441A35504F5C1462BCBEE30EE7F /* FBSDKShareButton.m */; }; + 34FE928299E6FCBB43826BDB66144FD7 /* FBSDKLikeObjectType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB618D67D94F32578DF5336651E7855 /* FBSDKLikeObjectType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3515249853196B72457D26E35A75A0D5 /* PFUserController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1A37998F9BF6B81FA68488F9A55BC50 /* PFUserController.m */; }; + 35599C4F9F10FC09064011AE354E20C5 /* FBSDKCheckmarkIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E9C149FB61E88BEF76CE74D5776813 /* FBSDKCheckmarkIcon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 35A2D271C4A91DC464251B9245103DB5 /* PFCommandCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 999823937ADC925F2F63F241A5995EFE /* PFCommandCache.m */; }; + 3618426AB7A42805D853A084743D6138 /* TKStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = A78C310CE96FB8C96AB74FE6A10686E7 /* TKStateMachine.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 361A366D11CECA15C3B45FC3ACEDA050 /* FBSDKGraphRequestDataAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 45911FDD1904204B994BBBABE59D8DAA /* FBSDKGraphRequestDataAttachment.m */; }; + 36CAD613B46C6F3F7B092EDDE2BFD87B /* PFApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = E516EBEC7356A04879F93CDEB1C0A839 /* PFApplication.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36CB170B89C0B4642CB663616BC47E5B /* PFURLSessionDataTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22E1D8AA11E50E9A37281052037D86FF /* PFURLSessionDataTaskDelegate.m */; }; + 37623963889357DF56CD5A4023A293D0 /* RKMIMETypeSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB0E62AEBB7CEA6AAB32321B17C4DA4 /* RKMIMETypeSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 379BA3F1B3C1F43A72C4C17B61215FDE /* PFProductsRequestHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = E7909E9598E022C3C0A3969A59F14279 /* PFProductsRequestHandler.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 37C6195201D97353994A4B323BD7EC39 /* PFMutableFileState.m in Sources */ = {isa = PBXBuildFile; fileRef = 800204DFA7DE3E6060355FB89A24FEB1 /* PFMutableFileState.m */; }; + 37E32240C69433B8D41BF206C15BDE91 /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = D8C9CB701E4F6C654174000392CF24D9 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 390565C6A1B7B2060B10FCF3BCC97989 /* lcl_config_components_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C6C852E7C915FBEDD2E5B3C2CDD20A8 /* lcl_config_components_RK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 392F1056919E38CEDEB5A545DA4C820B /* FBSDKLogo.h in Headers */ = {isa = PBXBuildFile; fileRef = 947DE8E91AEF7DBF7FD80A52A76B2360 /* FBSDKLogo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 397DD286C0935623C81E4AA9AE2E4C2C /* PFPurchaseController.h in Headers */ = {isa = PBXBuildFile; fileRef = A0DE6D1F31DEFED040F4E85B6631177D /* PFPurchaseController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3A4A4D139CCD0A806197BF7A723800F2 /* AFJSONRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3880A4A4324ED988B85901DAD4519018 /* AFJSONRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3B2C344B306A3FB19169E1F4AA62E103 /* PFACLState.h in Headers */ = {isa = PBXBuildFile; fileRef = 95C137F2DF407C83936DE0B2BB3D6F86 /* PFACLState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3B34B9CF9A34E235FD457006303C757D /* FBSDKErrorRecoveryConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE4C9BDAE4E6537716122FED10B39E1 /* FBSDKErrorRecoveryConfiguration.m */; }; + 3B88684885F6A92894F9B1C6DF2CB127 /* FBSDKAppEventsDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 503DF747F3430012E621A5BB819767FB /* FBSDKAppEventsDeviceInfo.m */; }; + 3BC5621A2DA38E302E4D3A891CAD35CE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 3BF789DD91B049645722960CC51287EB /* CATransaction+TransactionWithAnimationsAndCompletion.m in Sources */ = {isa = PBXBuildFile; fileRef = 266541F607EB34A777991BD29D5D2556 /* CATransaction+TransactionWithAnimationsAndCompletion.m */; }; + 3C0DEBB740DFB646BB292668FF187A3C /* FBSDKCloseIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = ADCF28A6ED4B159F06F12E95D86E08B2 /* FBSDKCloseIcon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3C31ED01B7466FD05173FEB6F86953BA /* FBSDKTestUsersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B625AE6C787AB113D7EF7F05FB0637 /* FBSDKTestUsersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C6DF2FA1EA6BE60192A77E7270D6212 /* FBSDKGameRequestFrictionlessRecipientCache.m in Sources */ = {isa = PBXBuildFile; fileRef = A99D66855595DD2F9E379F9A258C7FD4 /* FBSDKGameRequestFrictionlessRecipientCache.m */; }; + 3CCACCF079947A68FE7E62AF0303CAC3 /* PFConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 163A2E68515F17EBB397973CE01A2E02 /* PFConfig.m */; }; + 3D91615B81BDE2505C751BD7D4FB5EDB /* FBSDKLoginTooltipView.h in Headers */ = {isa = PBXBuildFile; fileRef = 87C33535E86A40250BA126A6209213CC /* FBSDKLoginTooltipView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D9DF25BBCE11AC3A9A684C418F6C89F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 3DDFA2D0FCEE1978143B685D1C3A9D7A /* FBSDKLikeControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E3DEF8E2E27C00D59DC5DE4C876E0D1 /* FBSDKLikeControl.m */; }; + 3E00A40C8893EE63BA63D4A9008594A7 /* RKHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA6FF9AD89559AE8FE2FD106DCB87C5 /* RKHTTPUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 3E16E0BEF69F5BA97F8E9F07A617E509 /* FBSDKAccessTokenCache.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA4ADF879DDDE1CAAA0ABFB4BC7210D /* FBSDKAccessTokenCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3E41E38FF7A69B85994E73EABE7FF57F /* PFJSONSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF07391CA6A2181CE0A3C3765B8F4BF /* PFJSONSerialization.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3EC6C51767337E859A4F15C5FBC1770E /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C345096A388C3F1F4E486E39C9D61CD4 /* UIImageView+AFNetworking.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 3F569B5B27E0603B07C858321F23FB9B /* PFInstallationIdentifierStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC50F7EF899B70145D9D7DB1F55E927 /* PFInstallationIdentifierStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3F7A18D123E044CFAC2A0D1322E727BF /* FBSDKShareOpenGraphObject.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3EA52DCFB7D558F88A88501D54E2B9 /* FBSDKShareOpenGraphObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3FBCAD82A3A69CB7850136E6D8613AD0 /* PFSessionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1375129BA8E11876FE8F3530124E4FF9 /* PFSessionController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4029E4F75B527907B5ADAD8E3E0264E2 /* FBSDKGraphRequestPiggybackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B9BFA03B5504E854577C5000A356AFB /* FBSDKGraphRequestPiggybackManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4075B036E32B6718E9B9523BC0059DF2 /* PFProduct.m in Sources */ = {isa = PBXBuildFile; fileRef = 5076A61842278BC01BD246CD9F6A6831 /* PFProduct.m */; }; + 40987DD554F4D5EB29B8B0948FCAC33B /* RKMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 65962B65C068EE02DAE719D8D70CA321 /* RKMapperOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4172EFFB5E73F4A2625FDD8790ADA86F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 41CCAB61BAA581E58CB30F56F9F372F4 /* FBSDKGraphRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CC27E380BD4D02E6D8E8A25280C06A29 /* FBSDKGraphRequest.m */; }; + 41DDB4BD2A89F44F733C82B65BE76ACA /* FBSDKKeychainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BFB7F5189C7630850B466033A6828EF /* FBSDKKeychainStore.m */; }; + 427DD66260DDD2F6345D7196B90E3DEE /* PFPropertyInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E051BB78BF5591341C31848B9AE0E0B /* PFPropertyInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 429897FA95FC01863ACF624955ED030D /* FloatConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F7C74984ABBD35EBF1A84D46747BF45 /* FloatConversion.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 42F787E07A69C27C09E049303C8E8530 /* FBSDKServerConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 473792C704D2EB34B69FD30D4C8A4195 /* FBSDKServerConfiguration.m */; }; + 4348B4727F59DB738A1A33721BB29AA8 /* PFRESTCloudCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = CAEFED956777B69C5958C0E809EC11BB /* PFRESTCloudCommand.m */; }; + 434F58B870A20B1FFBF38579DF600676 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D5B9C19265F524EBC4ED733155E3DB3B /* RKObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 435602DE03BDC37F6F724BE3A943F1AB /* FBSDKSharePhotoContent.h in Headers */ = {isa = PBXBuildFile; fileRef = A7AC1819EBC907C93BA5F2B790C16D0E /* FBSDKSharePhotoContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 438CA2F1118781D63B470E41E4C7889C /* PFFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C0773511F8B57D80E82BBCED6576C5D2 /* PFFileManager.m */; }; + 43A7D7D1E2E0828AC2FCD3155471E59E /* BoltsVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 29DAD99804B5BD08F3A74008FD65BAE7 /* BoltsVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43EDB848BEACB773962B589EC73AA826 /* PFNetworkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = C303ED3A2C18CE2AAADCC69948039080 /* PFNetworkCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 440457C5E92E83101E8970FFC6086762 /* RKResponseDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = BA0DEBD43672CEB35AC053C3EDBD0BF9 /* RKResponseDescriptor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 4426214315E4D8313D27EE3F16CF8C13 /* BFURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6681893EA2BE8AA8ED08B44B774980 /* BFURL.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 444F2DDB714D8D83F59764F223E6EE70 /* FBSDKServerConfigurationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B5920113D86FC36BEBC6F899C9034F7 /* FBSDKServerConfigurationManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4458C6C127D3030A17A791B3BA9A0CE0 /* FBSDKShareConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = B53170EBE3F4D7BAA67CDA6A2C198542 /* FBSDKShareConstants.m */; }; + 44731A7D10EF496E7DED3DCA05410767 /* FBSDKShareDialogMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F3FC0B3D497637B402F51B44E5B28F5 /* FBSDKShareDialogMode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 44A5248789F660D19C2D6D8CBCCC7C13 /* RKMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = CB3D0EFB3CB9EFB991A6BD44384669BB /* RKMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4505527808576A44D861B0A13154F425 /* FBSDKURLOpening.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FE49164D11028318A5BFC6389C361A /* FBSDKURLOpening.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4508BEB10E935ADE1BBC8AD18BB3F581 /* Bolts.h in Headers */ = {isa = PBXBuildFile; fileRef = C5052DE726F89E27E1CA5D188FD32C5D /* Bolts.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 451A0964C7CDBD5043BBD97DD3BB59EF /* RKTestFixture.m in Sources */ = {isa = PBXBuildFile; fileRef = BF6BCF95270D89143AE2BD11E8C58467 /* RKTestFixture.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 452F0DCF8F0D3525E9DC890D389684D9 /* RKMappingOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FD07183D5459C1861CCC80EC5514A9AA /* RKMappingOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 46434AF620227311479C776B81BA97F6 /* FBSDKLoginCompletion+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 517FE5FCB5C6241B8A66BE083CA1AAE6 /* FBSDKLoginCompletion+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 467E37A4D9DFFFA4BE812456B18B5766 /* TransformationMatrix.h in Headers */ = {isa = PBXBuildFile; fileRef = DD2FCA295F0F6EC84DC796D623DC209F /* TransformationMatrix.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 46A761F0B52B393302374F202159EF83 /* _FBSDKLoginRecoveryAttempter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D540B5BA940B77762F525759CD9E2F7 /* _FBSDKLoginRecoveryAttempter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 46C77E33FBFB6CDD2042AFC7251C0192 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E3783F1A59CCE93EEF653593AFAD5B5 /* CoreLocation.framework */; }; + 46E222D8EF5404BBB0ADEC81B1DF1874 /* PFRESTSessionCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = F8B8D967E928682C85109A85124DEEC4 /* PFRESTSessionCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4727F1C349747A7F96CA2EE6098BA7E6 /* FBSDKBridgeAPICrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 950E0A9F91ED212D2423C57E6D94CE04 /* FBSDKBridgeAPICrypto.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 478F099B2EDD4376B8C1183745A5B4B9 /* PFHTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 209E38BB2ADFFA4C0E2497F629810AEB /* PFHTTPRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4864EC253C572D7696B5849BB72291D0 /* RKPropertyMappingTestExpectation.m in Sources */ = {isa = PBXBuildFile; fileRef = 20B291B44372ECD90FA4961CB9F9C9C4 /* RKPropertyMappingTestExpectation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 488F77FF13E79A72AD87E8B838E827E4 /* FBSDKShareOpenGraphAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 6768924E65317D0E30521724DC081C08 /* FBSDKShareOpenGraphAction.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49A306F39FCE73FFB0E1A6589D331F35 /* BFAppLinkResolving.h in Headers */ = {isa = PBXBuildFile; fileRef = B99772D5AE952C0693DC05AAA4538D94 /* BFAppLinkResolving.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49F2BA3E1D32E882B51DC0A899D3C229 /* FBSDKLoginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 59EAFD88B92A3912D4951328AF334D28 /* FBSDKLoginManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49FB341D2B6AB6B34B968D145F42A04C /* RKErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E3E506FDF95C78237F089FED94DAB76 /* RKErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4A30A8F0DDE8E4D807E1F48C169CA7EE /* SOCKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4081A3EAA34140F505CCBE9D98C0C8 /* SOCKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4A4CF9C7D69DC9049FD677165FADA59E /* FBSDKShareDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 6569377CC0B0AA51EBA394C782985089 /* FBSDKShareDialog.m */; }; + 4A7FBB52488D368CFDFDB1B6516C2CE4 /* FBSDKMessengerIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 134ACDC2444EE29856334D3196F53AC0 /* FBSDKMessengerIcon.m */; }; + 4BABB36619011AA0B6039422203CFC5E /* PFInstallationConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 22F77D342CCB58DBAA7457C6289C028C /* PFInstallationConstants.m */; }; + 4BC610C052636A802256616F808FD2AE /* FBSDKAccessTokenCacheV3_21.m in Sources */ = {isa = PBXBuildFile; fileRef = BF44B45F9B1A350C1FB2F6D209A9BC4D /* FBSDKAccessTokenCacheV3_21.m */; }; + 4C3A2F763EEE360861027C7097748A42 /* PFMutableObjectState.h in Headers */ = {isa = PBXBuildFile; fileRef = 924EED608166B7F9A30865D80A87407F /* PFMutableObjectState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4CB1746E41309F454F4CB59CCB120634 /* RKErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EA0BB06D8B077DFC855CBF92505F74A /* RKErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4D07C5CE0CD51D48D58268926E71C534 /* POPAnimationEventInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 632D62E7B544FFB77F14C130A2EC4510 /* POPAnimationEventInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4D2FE3A028403C4E9545B01159BBE9CB /* PFInstallationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 19393B003CB10D5DCBF525994DDE8462 /* PFInstallationController.m */; }; + 4D4A07890A079F8AA2090CF76EF82A90 /* PFObjectLocalIdStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C114A540E5318937EFA769F5D2A5372 /* PFObjectLocalIdStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4E13085CB448418E957E9EB41D88F5E2 /* BFTask+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 882472CF6BA62D86D2BF8542B479D3CB /* BFTask+Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4E5A7BE76B5EC309DAB207FAFB7FE7FC /* FBSDKSharing.h in Headers */ = {isa = PBXBuildFile; fileRef = AF22BCCC30F4473554DFAAAEBC740BE7 /* FBSDKSharing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4E7740FDD29E3D20879999C4584BA7E0 /* RKTestFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EE2EBDC54FDE1E50CD9A33DDF48404D /* RKTestFactory.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4EC1B8AAA4341E02B888E2CDBED626DD /* FBSDKApplicationDelegate+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = CA018EEB50C81D92939C0E4379941FE9 /* FBSDKApplicationDelegate+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4FA4189FA17793F898C1A79920893A7D /* PFMutableFileState.h in Headers */ = {isa = PBXBuildFile; fileRef = B93B968FDB3F20E1EB2FA742FA119F61 /* PFMutableFileState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4FC468A52568F12ED267007F0AD753FC /* PFPurchaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0648A7B89F8F0C429E649E87FBFBD699 /* PFPurchaseController.m */; }; + 50570F0F317C5A916AD5BE1D82F49641 /* FBSDKGraphRequestDataAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = C3743DDF0F64379FD843ED463460FF90 /* FBSDKGraphRequestDataAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 506994605B778659CB416E37C461D150 /* PFEventuallyPin.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AAB2C033ACD2C5EDF5AFECCDE5BC95D /* PFEventuallyPin.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 50A19E0D54B5ABC2DF718485876675BF /* PFRole.h in Headers */ = {isa = PBXBuildFile; fileRef = 409EF16B93600F84E2CC3287F2C35D7E /* PFRole.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 50ED958AFAB156499B1D88CD2C0394B7 /* _FBSDKLoginRecoveryAttempter.m in Sources */ = {isa = PBXBuildFile; fileRef = C5C2B2C9BECEC9F64477D3C8051CFDB5 /* _FBSDKLoginRecoveryAttempter.m */; }; + 512D2E7F3E98E29CD6338D40FC3CBEEE /* PFPin.h in Headers */ = {isa = PBXBuildFile; fileRef = B3AE7C57230B414B51B418F0B88252FB /* PFPin.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 516780FBAE8477C063977B67B0C4F64A /* PFCurrentConfigController.h in Headers */ = {isa = PBXBuildFile; fileRef = F19938456DF0C30C53CBE44847B3E479 /* PFCurrentConfigController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 51A4B3F64553C8AF7DAD4F16035044C7 /* RKObjectMappingMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = C42E29EF756BB8A7BCE6151C6229BA3D /* RKObjectMappingMatcher.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 51F742896037EA588D6157B105922B77 /* FBSDKShareOpenGraphValueContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C6CEAC74231F31EC9DDED4C3E2BBF48 /* FBSDKShareOpenGraphValueContainer.m */; }; + 5208CEE9E04A230A895075F81179E9C0 /* BFWebViewAppLinkResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 9045C664399C37132A893F2E170BEA3C /* BFWebViewAppLinkResolver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 52474B3F869DBA64CC57CC8E1031F87B /* FBSDKSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = B477BB1DB6E55636C30151FED839DBEC /* FBSDKSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5290E96A370ECE9B13F91391BFECE059 /* RKLumberjackLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AFF7959F2290BD0027C49FBA305DFE5 /* RKLumberjackLogger.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 52D0E5B4BE2960D5264CA76B3287BA53 /* RKRoute.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E4CECC242634F51EA5250B5A8FF795 /* RKRoute.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 530AC824CCD371BAA717F8ACAB33F958 /* FBSDKAccessToken.h in Headers */ = {isa = PBXBuildFile; fileRef = C537E17C3097299FCBF860A93C47B723 /* FBSDKAccessToken.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5322CA0A34DB0348C3603AFAD04A7DF5 /* FBSDKLoginConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = E160D14CDAB0E17CC1D0024A8673A34C /* FBSDKLoginConstants.m */; }; + 53A73625D6FFEC0A47C83977EE7CDBCC /* PFDataProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = D9F9A1B8EB6CBAF33BDC895542AB64E9 /* PFDataProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5449D946ADE982013F5C2069E0BE45F0 /* BFAppLinkTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = E362D4507FC775D8570A80D797BC3E91 /* BFAppLinkTarget.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5482BE85008ECE92916F583C9A15378B /* PFCommandCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 36C8AD8E2390F415DC7425C9734EFAFB /* PFCommandCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 54D559AFA627AFA735FB0D6D878F5D7F /* FBSDKAppInviteContent.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8BD2902C2FE3B67C86F30BFEAE4A3E /* FBSDKAppInviteContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 555466B7EA6454B1E1968FB7A7BD1334 /* FBSDKBoltsMeasurementEventListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE8F8508C70E584E9DC322D6E30DB1 /* FBSDKBoltsMeasurementEventListener.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5557E69BD0A14921486F9974F746737C /* PFCurrentInstallationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 40AB5DCC80577C96F4732C2FA58B903D /* PFCurrentInstallationController.m */; }; + 558CA36485EBAAE1ACFC94ECF26A4C13 /* RKDotNetDateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57A42437229DCF10EA2D792B45EC0449 /* RKDotNetDateFormatter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 55F36BBE4FE82BCCD0C9A4E06DC26BEF /* PFRelationState.m in Sources */ = {isa = PBXBuildFile; fileRef = 468C80083455F41B26E5C3D366E6F467 /* PFRelationState.m */; }; + 560BB49A70689476862EE5E1F179D36A /* PFQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = F19CD8D613E04AF9291C97EC57B1C08D /* PFQuery.m */; }; + 5621D0F1F50874AACD396E2AC5A8ED7B /* RKStringTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9766DA2E569D10FE157FA2E355CC9802 /* RKStringTokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5624B5B3EB50D43FB54BACDDB45228AD /* PFPin.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB59734D65B77DD76ADC6A7069BEFCA /* PFPin.m */; }; + 562CF85B86D5B01C4F9A7B9ADB016D2C /* RKObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A7550A91022A017F5AFB8DF01AAFDFA /* RKObjectRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 565365EA7F73C65562A3FC4459E770B5 /* YALSpringAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = B7B6A72DD28FBD988E0B1E6A930C1BCA /* YALSpringAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 57503516957EEFAFFAD7A789730E7B9C /* FBSDKShareVideoContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 69B2823ABCAD80D975C9E8C29A5E869F /* FBSDKShareVideoContent.m */; }; + 5774AA430101105FF0F41887984D6011 /* PFURLSessionJSONDataTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B1126558A8CA869CAE3169CD0485A400 /* PFURLSessionJSONDataTaskDelegate.m */; }; + 577FB11637F9A3CF218053ADC3A5F10E /* PFCurrentConfigController.m in Sources */ = {isa = PBXBuildFile; fileRef = 012EA998B79C045DB5F3DF0D066F78B1 /* PFCurrentConfigController.m */; }; + 578485DD86226126B8E08842D826D2DC /* FBSDKWebDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FC2F31E95438D43C0ACB4E6B5287B8D /* FBSDKWebDialog.m */; }; + 57B1DEE062B9373E350E5EB3DC657FC8 /* POPCustomAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C9E34AAA6316628D1EF4D8BC3CDCAB1 /* POPCustomAnimation.mm */; }; + 57BDE2372BC4BBC34CAB643A2A95E416 /* PFSessionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 73136CB5DF8D9FDC9C0B3FF336E53790 /* PFSessionController.m */; }; + 580B7575D5092F73CADB0DC057A8DD20 /* PFMutableUserState.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E5A00420D365F9C27CF6F943E8EB990 /* PFMutableUserState.m */; }; + 58597619340E5853CDA8DBC80D53D577 /* RKBenchmark.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C7FFDC2B7A4F0D5C315F44B0165D091 /* RKBenchmark.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 587ED101545A953414998ABFA4479B5D /* FBSDKContainerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AA04EC3FE92A62CDADA2A69B932DDF3 /* FBSDKContainerViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 58F4A4DF57C22014622BB042607EB8EE /* BFAppLinkNavigation.m in Sources */ = {isa = PBXBuildFile; fileRef = CFEE369DBDB3AF968FCC81B9E15BD259 /* BFAppLinkNavigation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 591282C08F383491158606060CF4799A /* RKLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 667F8446CCEAF60B9DCD4E68CCB9ED5E /* RKLog.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 591FE63D036F4A539784293BCAD97493 /* FBSDKGraphRequestMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 370FAC093160183505C296D12A84BF0A /* FBSDKGraphRequestMetadata.m */; }; + 5925CFB0F01031178978AF59986A8836 /* TKEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 62923837C0899ECA2BAD6224F5A7B22E /* TKEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 598CA7FEDEDFDBF38831C0015C044596 /* PFFile_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D298D539E71478D6340E3FA832E4778 /* PFFile_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 59B602D97CE0027EE607A6D59E7FAEC4 /* PFPaymentTransactionObserver_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 305A419FED9C718C8ACAE5D2F9173F27 /* PFPaymentTransactionObserver_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5A1CB5B72C92E43BF844377DC72DA072 /* FBSDKAppGroupContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 87352A5CFA4016F286A66829B0D2BFB9 /* FBSDKAppGroupContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5A3E09336161889373CC89326260ADE5 /* PFOfflineObjectController.m in Sources */ = {isa = PBXBuildFile; fileRef = E53C7B0A7D27C453923DDE2311E75A27 /* PFOfflineObjectController.m */; }; + 5AAE55DFA2869211ADAE99C345C0192E /* PFObjectConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 936E7B213612ECBF1630386CE6D7B1D2 /* PFObjectConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5AF64E5EEA043722E238A8C5EE47A63A /* BFAppLinkReturnToRefererView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = D7AC47EB8D0E9C9582957C2869B7517D /* BFAppLinkReturnToRefererView_Internal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5B619FB7B735B3AE6E29CD79496C39C0 /* PFACLPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = C4DAAE6C562288FB95B1415AF6763317 /* PFACLPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5BAB981C0B0E5CA4456C701E0D4C8C3D /* RKPropertyMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9E4087FDB2FFD655EB8FA58B697B4E /* RKPropertyMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 5D8F8D57EC3D51CD74969DAA5BFBC15C /* PFQueryUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 512FA3A57C3C25DEB20BFDE24938517B /* PFQueryUtilities.m */; }; + 5DB44075B06EAE0B3D695B29CCF444DA /* PFURLSessionUploadTaskDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0EB6E9BC99D4CE39BCEA9AB574501691 /* PFURLSessionUploadTaskDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5DD4705F866F09E0FA008D068DD31F48 /* PFKeychainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6674B326B12A30BE2A6BCDFC2F890324 /* PFKeychainStore.m */; }; + 5E1AB8EC72407D7A56EE8074AC99F4AC /* FBSDKTypeUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 1488210FE220BBA6CCA5EBE2C7D73FA7 /* FBSDKTypeUtility.m */; }; + 5EEB7C03214B977E5D8925797BCCF7B1 /* FBSDKLoginManagerLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = C45478301558D880893FA55C99879E3C /* FBSDKLoginManagerLogger.m */; }; + 5F2CF6350F306F78D40161C01EEDD731 /* FBSDKMutableCopying.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BE12FA64DB24FF7A1DF7937AEF98D6 /* FBSDKMutableCopying.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5F51961B26B43B74BC1F3504C2AA68ED /* RKRouteSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 66C350784D8C52C699FE7DD47EF906FB /* RKRouteSet.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 5FBB039F53D31783622E144DF3B0DC7B /* POPBasicAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96A6F76476CACBAADE4A258C71998683 /* POPBasicAnimation.mm */; }; + 5FBDA19530CA26D2F5E37B02FFA15D50 /* PFMulticastDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BBAD9DCAFF06BB669E8D77482B04BDB /* PFMulticastDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5FCA3879482A03418CCB75CE50EEA9C1 /* FBSDKLikeButtonPopWAV.h in Headers */ = {isa = PBXBuildFile; fileRef = CEF0CE91FC9080D9E33E9B362D760F18 /* FBSDKLikeButtonPopWAV.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6080A31C682280C87E76F93D3D1C7D42 /* PFSession.h in Headers */ = {isa = PBXBuildFile; fileRef = B0AF344F89667D8F50F4A22C146ACF21 /* PFSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 609CCC1A9F655B5B7E6F6D3FF89E80D5 /* RKRequestDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = F4B09A465BA0ED9168954ACE5D869AD1 /* RKRequestDescriptor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 60F370DA778C2C58337885BA2E21047C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 61BCC6DAB9276D969FCC0F848B69DB86 /* FBSDKMaleSilhouetteIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D4E7099B46D1C3E524DA77BA96A3960 /* FBSDKMaleSilhouetteIcon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 61C04EFBF42F1F1275B42E1DB6103AAC /* PFEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8837B1CB6DAF343BD8C545163EA2DA58 /* PFEncoder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6239684B7D89D4F446BF5B4383804BFE /* RKRelationshipMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3DEC35A890AB8929D5A78F2D24DC7A /* RKRelationshipMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 62A4E5BEAC5F31E0EB99CDCB8179311B /* PFCurrentObjectControlling.h in Headers */ = {isa = PBXBuildFile; fileRef = 658BD9C8EBCC6CE298417312A7B194FF /* PFCurrentObjectControlling.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 62D812F2EF8DA118C618FF5349055C57 /* PFRESTCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 3962BED4A779536F2E41B1C36D6285AB /* PFRESTCommand.m */; }; + 62DDEB5456833B4AD3A84F7AADBE9099 /* FBSDKGraphRequest+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = F87C75C1F03CFABBB54EC631815288C0 /* FBSDKGraphRequest+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 630A23A824A9AE5B03C54172F5F9556F /* POPAnimationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8707552112C343BFF840516C1AAD0D31 /* POPAnimationPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 634D85A94A89FB79C887AEB085DECA60 /* Bolts-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = DA196AA463D20F7402232B546DE1EEC4 /* Bolts-dummy.m */; }; + 6370111F8E53B9FCB359DE67FB0A5768 /* RKDictionaryUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 611F4CE6ED5017088CB427383A3D1445 /* RKDictionaryUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 63B17895BA064D712385A40C63BD7EA2 /* PFFieldOperationDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ABF2667D317A8E92F4DAB58CAEEB37A /* PFFieldOperationDecoder.m */; }; + 641656C3A17793081B0B55EF4183369C /* PFObjectLocalIdStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6426FFE9B7D5877E4580324A76A08178 /* PFObjectLocalIdStore.m */; }; + 647E650A08B67B558A6C1A0041544B1D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0F29E0D66F63131F371330D93CB4583 /* QuartzCore.framework */; }; + 64BD30EF98CC4A38D8BF92656D4A6AD0 /* FBSDKShareButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CBCFD5CCB1FD15EED54F82E909DC031 /* FBSDKShareButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 658F5F398CDC2959D9D80E71D58CF261 /* PFQueryController.m in Sources */ = {isa = PBXBuildFile; fileRef = ABE4BA05E14673159DDEE660B13A5B00 /* PFQueryController.m */; }; + 666C8261EF1AB3272F89C4CA09FC631D /* POPAnimatorPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5251CF87DD5578A90ADED5D340FF960B /* POPAnimatorPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6678A92E1C40BF48F96D3FCF476C03BC /* PFNullability.h in Headers */ = {isa = PBXBuildFile; fileRef = B27AB7689D28F34F8A9D466ACAB162DA /* PFNullability.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 66F445220BAF1CCE856A11B0B7F803A4 /* PFInstallationConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = DCDABFE826ADB96F79D0DFB7BF9C4259 /* PFInstallationConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6713CDF473C3A1F71B852C8F354780A0 /* RKMappingErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = FBEB6D4BDCEFC529A9705D5228053B04 /* RKMappingErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6765D67511A02AD8B1C22BFD59E32233 /* PFACLState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B6054861B48456D5D8D1E661F92EE5D /* PFACLState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 67767415823A98D8A2C93A953551A571 /* PFFieldOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 97D4677BC9F2D88DF946E204DF242D38 /* PFFieldOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 67F789F4A32CA7A82DE43CD27AEA87BD /* FBSDKBridgeAPIRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B7304E8EFDCC873E1CE3D2CA2076A74 /* FBSDKBridgeAPIRequest.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 693563EF1DB59CD00D1B0B8685D0819E /* PFReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B799574EF27A1E8D4FD50ADAA42EC77 /* PFReachability.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 696305155D2765894FA3E5EBC092A650 /* RKMappingOperationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = B7478D31F88F47602170505B415F4CEB /* RKMappingOperationDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69F828062553D0A5623207630EB9FB21 /* FBSDKUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = E4528F78B1F397E3730075143FD93C99 /* FBSDKUtility.m */; }; + 6A7AA0924113739F682D6E35E4B71540 /* PFFileDataStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BFECAFEA1EF171D5BA9CFAFE63B895 /* PFFileDataStream.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6AAB88174D5DAE8A23C47D20961B3DDE /* PFConfig_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 58DD77FFA76457DC7826A465EB970094 /* PFConfig_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6B00AF25CFB12372D5281D7B9D51E3E2 /* FBSDKProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 55DBD79D6CDD908C9E0151AF56A3EFCE /* FBSDKProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6B2DD9967AB4D947BDECC65AC4CCB1EE /* FBSDKLoginError.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E2D1B4FCC4918686DEAF9094B908917 /* FBSDKLoginError.m */; }; + 6B6E69822F96D41917A1791C1873A1D1 /* PFNetworkActivityIndicatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ADC8E7B23140B59FA2BE5667DEC580B9 /* PFNetworkActivityIndicatorManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6B8F8457EE06C9B9F37CA931F439DB4A /* PFKeyValueCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B754CD741EB603D2A92BACC3F38A430 /* PFKeyValueCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6B980244FC648CB685E9AD30A9780D1C /* RKObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = F4EC41878B622B137CC4B622FC53F3ED /* RKObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6C003AB01A869DC27CDDCD6CCC0CACE9 /* pop-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C03EC589275AA21D375F405EB48AB374 /* pop-dummy.m */; }; + 6C052D12CBAB4B9CEC3E0B97C3B0CA00 /* PFCloudCodeController.h in Headers */ = {isa = PBXBuildFile; fileRef = 74B44F24917A72CA781246EA2632A00C /* PFCloudCodeController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6C13E0E83471C1104A40CB5D928C5C78 /* Pods-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 272643F56613CA0D336AE3DBF19DC404 /* Pods-dummy.m */; }; + 6C6B44FB16E5ABD292E2D77D89DDFF32 /* FBSDKCloseIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 7719F6B5924888F0A267790B6E5647FD /* FBSDKCloseIcon.m */; }; + 6CC372C70EE09A01AEC3B0C9A077B395 /* PFPinningEventuallyQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = A7540E284803A52212B2DE3FD4678F87 /* PFPinningEventuallyQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6D1ED30B474D96450E7B0D1E548CDC60 /* PFEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 07D8A98D56E6D538D6FA0B232BBCBA03 /* PFEncoder.m */; }; + 6D2E47E46AED98D49CD7E1D7DCA449B3 /* BFTaskCompletionSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 72766C115F290B685E1C527E77EDEDEE /* BFTaskCompletionSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6D3FD8968A8524A1D88687C9861581B7 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = A9CA1C8C41256C5E7CEDBAF354C19AE5 /* AFXMLRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 6DFB846C756551ECD366F5AC7B189C2C /* YALTabBarInteracting.h in Headers */ = {isa = PBXBuildFile; fileRef = CCD58C1FE0A285B35DC39096400FF8C5 /* YALTabBarInteracting.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6E33ED273C645E70EF87C0C05807D1A2 /* FBSDKLoginManagerLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = EF79FDCF0AF41A384FB770643D79F0E6 /* FBSDKLoginManagerLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6E7A504266921DE5FEDD84D1A38F473F /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C544CA6F07611BFE8BFC800E9D59E5AE /* AFHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 6E81F98DB0508128E08205B0290F7F66 /* FBSDKLoginError.h in Headers */ = {isa = PBXBuildFile; fileRef = 044941FE89AB594A010087B94F17D923 /* FBSDKLoginError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6EA031F1089FBD5D7E5DACD68EDC2F5A /* FBSDKShareLinkContent+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E08B70AB72ECE4DA87BFED9B17F956 /* FBSDKShareLinkContent+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6EFA282EB5DD6C5347CCE430844E5CAA /* POPMath.h in Headers */ = {isa = PBXBuildFile; fileRef = A303568877AD7BACE17E962FDF4513C1 /* POPMath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6F5BB8563523FEB8914557A0C379361F /* FBSDKAccessTokenCaching.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FB151E5B82946D404F611FAC81C546B /* FBSDKAccessTokenCaching.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7051CE40FD16869F0BF9CD028A658782 /* FBSDKCoreKit+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 95A9E38BEC3EF5836FF1194D04DDB98F /* FBSDKCoreKit+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 70687046EC0243F807433D9D44DB7EB1 /* POPAnimationRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 6467B92BD94142011900B81E0476CB0E /* POPAnimationRuntime.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 70905E1AFD8E61FF829458D67B744EB4 /* PFPushManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 368A5760A18AE27F46F5243BA3BFD13C /* PFPushManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 716A44DCF2417118DDAEAD57B69029BA /* PFSQLiteDatabaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97044BE056C705C44778E090F30A538B /* PFSQLiteDatabaseController.m */; }; + 7171DEAFC5A2F780E670B8395EF8F07B /* BFDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B1F248FA3EE75C351E1B383AB977DF7 /* BFDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 72DDA136310E1878B3393479B38B83F9 /* FBSDKURLConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BD1AFE5456BC7AAC15A5D308229EC88 /* FBSDKURLConnection.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 73518A8EAF46D85112E2CB85D02BF9C0 /* FBSDKCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = D9C1F4F92487D9DCADCD60039710D816 /* FBSDKCrypto.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7491B632AA9E26DA9BC69374DE8BF0FA /* ISO8601DateFormatterValueTransformer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A0C95D96D102F597D4543F77E2DBE642 /* ISO8601DateFormatterValueTransformer-dummy.m */; }; + 74935B997B546A6E2D523ECE6E06E4FC /* POPAnimatableProperty.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5ADBAA054DAFCE013EB3EF9DF965F744 /* POPAnimatableProperty.mm */; }; + 74B1B04C2705C12FDA25D308C6F8F669 /* FBSDKAppEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3482F3977AA386E991A54C5181BDE1 /* FBSDKAppEvents.m */; }; + 74D22BA7DDF7C44219CE3E793CE0AC6F /* FBSDKGameRequestDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 346CED5D6B988E5318DBD8CC9C98A073 /* FBSDKGameRequestDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 74EB4B274B8CF5543B9DB2B77394CC60 /* PFHTTPURLRequestConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BCD0EFCBE498C67A5B0097360333011 /* PFHTTPURLRequestConstructor.m */; }; + 75092C6F60330AA447A66ADEB43581C6 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C758B84874FBB01F1E2CE355BEA77660 /* StoreKit.framework */; }; + 7569FD90D7667E15A7B67B62E4A72E5D /* FBSDKTriStateBOOL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C268AB8BD173983B11C4C2D404A9C57 /* FBSDKTriStateBOOL.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 75928CD63004AE9767341F79B565BEAC /* PFMultiProcessFileLockController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5404656CDC7518E20D0C557EF9C53B63 /* PFMultiProcessFileLockController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 75F412B1EE494A57BC9AED52E8F28700 /* FBSDKLoginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 03549C9A2FD883CD12D063617A47E0D3 /* FBSDKLoginManager.m */; }; + 76EACBDAB632DF356DEB855DD97A09A6 /* FBSDKSharePhoto.h in Headers */ = {isa = PBXBuildFile; fileRef = B91E34DFD041EF9B4895EC618300E024 /* FBSDKSharePhoto.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 774E19492156820F5CC848D34D9AA4A6 /* FBSDKLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D28D5F66862955E51F3A4E12B34C7A6 /* FBSDKLogger.m */; }; + 77B5397CB9EB225E9C0BB7318B12E949 /* FBSDKBridgeAPICrypto.m in Sources */ = {isa = PBXBuildFile; fileRef = FA60E1C8D40A78F03AAD7CA1CAE03991 /* FBSDKBridgeAPICrypto.m */; }; + 77CF177F2CDC9BEBEF5BE1DD296E1E2C /* FBSDKErrorRecoveryAttempter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FE12F1A4097AA56DD490CFF1B57E4AB /* FBSDKErrorRecoveryAttempter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 77D00913E6BC46EF1D8E536BA5A36A93 /* PFSQLiteDatabase_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 31EC6AF4DEA7F85F68A5CE8C3ECA3280 /* PFSQLiteDatabase_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 78952ACEF38C155ADF7CA3B63C38A5E6 /* FBSDKProfilePictureView.h in Headers */ = {isa = PBXBuildFile; fileRef = E1657F05C4EF96882F28C1692CBF05CE /* FBSDKProfilePictureView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 791E4A4DAC2DF15F7846EBC44911F06E /* UIImageView+AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = FBB3B5641F66495915C56779C21569E7 /* UIImageView+AFNetworking.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 796EC3DD53C2C28010D03E1E323A1DDB /* FBSDKLikeButtonPopWAV.m in Sources */ = {isa = PBXBuildFile; fileRef = F2575C28B5137ABEB1B9557B34F3448C /* FBSDKLikeButtonPopWAV.m */; }; + 798D21067BF1C22C12D8A94001BF5A59 /* RKObjectUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0673474C0D02C740FB04EE10B58213D9 /* RKObjectUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 7A11240D567F7A3207F0F9882ED2AB75 /* _FBSDKTemporaryErrorRecoveryAttempter.h in Headers */ = {isa = PBXBuildFile; fileRef = A585F71D8045AD5FFA838F5907C9DCFE /* _FBSDKTemporaryErrorRecoveryAttempter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7A67EA6F03AFFE55FAA759B11890E468 /* PFRESTConfigCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E4BCF2AF417571FAAD5D3A0AF5FFB93 /* PFRESTConfigCommand.m */; }; + 7AE92FAE0E12991264A8E657D4187884 /* POPSpringAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = BDC0554AEE7F2D9DF98C2D8FC049FD2A /* POPSpringAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7B38759EF062D9FF703E7D297DAB27E6 /* FBSDKLikeControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 424184F6AAB828CA2D22E450BB52A081 /* FBSDKLikeControl.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7C9D94C465AE6FEED19A76EF32EE9DB0 /* PFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FE38696DEEE3653F1AF4FB0CA7BC07F /* PFNetworkActivityIndicatorManager.m */; }; + 7CE53AEEEB82A1729F0A343B85F1FA7E /* FBSDKAppLinkResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 0FBD3B84E14ADBD2E513A3522C2777DC /* FBSDKAppLinkResolver.m */; }; + 7D1605EE6FF513FDFB9A9827C2930B89 /* RKRouteSet.h in Headers */ = {isa = PBXBuildFile; fileRef = C7FD5D8AEF9C721E9A8B50A73398561A /* RKRouteSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7DAD345A47688CC2FF5EEF4E6576DA9D /* PFObjectConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = D0E010198F9F57F3C1F5251591AC52B6 /* PFObjectConstants.m */; }; + 7E50C34963B8ED1D60B79E534C5627AC /* RKTestFixture.h in Headers */ = {isa = PBXBuildFile; fileRef = D5B2F6DAB138D6C0AFB76C250456D0A9 /* RKTestFixture.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7E6125121D979F1802CAD8FB88B66E4C /* PFAsyncTaskQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BEC90C5581726DE80B840585A9F4174 /* PFAsyncTaskQueue.m */; }; + 7E7AB5CD972320B0ADA45CD3A96BF892 /* PFEventuallyQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 41BB788E886BFA89367834A4426A765E /* PFEventuallyQueue.m */; }; + 7EE9BE9884D5807EC2C980930CB99B06 /* YALFoldingTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 352259996AE7807E58AB7D6E88FAC9F7 /* YALFoldingTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7F35603B737B2A4B465CAE4B481C34BB /* FBSDKGraphErrorRecoveryProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 405BEEF0AFD44793580DDB9D43634820 /* FBSDKGraphErrorRecoveryProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80511BB81FC091E526BECA78607C0FC2 /* BFMeasurementEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = E5A9EBDF50D04397C922F9D0AB7B0512 /* BFMeasurementEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 805398D3248C43C8DE072375177A8354 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E62E80C06B8D2394C56D10220D1CCB6F /* MobileCoreServices.framework */; }; + 8071A999E075ED48380A5AAACDA0E0E9 /* FBSDKGameRequestContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAC4524798CD2351824DF502E226F2E /* FBSDKGameRequestContent.m */; }; + 808276E084690B816C4FE2938B4E3F38 /* PFDateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4035095FBC067B91C5DECADD26277EB1 /* PFDateFormatter.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 809C53B31BE1AC40886B82DFD238136D /* FBSDKBridgeAPIProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 502875FAB22E086DDEA2AD3FB860D1A5 /* FBSDKBridgeAPIProtocol.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 80AC86A7716C9D9FE484C461CECF64A5 /* PFMultiProcessFileLock.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F8116D4E8780C6E74C186A8402C69F9 /* PFMultiProcessFileLock.m */; }; + 81193EC84CBFB74E91526F896C9BA770 /* PFCurrentInstallationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2572DB6B289BFC9AA6F1D1DCFF16D994 /* PFCurrentInstallationController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 813ADFF01E988125B016E0A604A0FCC4 /* RKRequestDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4521F82969CCAF3A290F34A7DA26A9DF /* RKRequestDescriptor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8173E2EA7A6ED5AF96950F1C983E7D8E /* RKMIMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E4DB2AB05ABDFB2096CBD1A0D1C960A /* RKMIMETypes.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 81A2A1E607483054B4C595CA92987E08 /* FBSDKAudioResourceLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 83831950A74E93412A274C95A90D1337 /* FBSDKAudioResourceLoader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 81BBD301442755592686C551DE726C06 /* PFCategoryLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AA9561725BB1FB9134A92D8DC5A504B /* PFCategoryLoader.m */; }; + 81D3161E66F074CAE137695C259391D6 /* PFRelationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = B5439DB8932AAF79667AED53097CC2C9 /* PFRelationPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 82023A97B43D2DEC58CA0092A2A63835 /* PFUserState.h in Headers */ = {isa = PBXBuildFile; fileRef = 099E673F2FD9E7D461C9590B6D38BA1F /* PFUserState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 82360B32AC1B887E85DC592D62CB046F /* FBSDKSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE8B19B5BBBF2EEE591030CB12399C6 /* FBSDKSettings.m */; }; + 824F558CFBB6BFD7FC2D2E9FB1FCA5B3 /* PFMutableObjectState.m in Sources */ = {isa = PBXBuildFile; fileRef = B5D03113C677A7DDA961E0D9E46E949A /* PFMutableObjectState.m */; }; + 827A9685D68B9BD092DD85970625C1F2 /* FBSDKShareDialogMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 36A9A82E6520CD02FD9422940934EACB /* FBSDKShareDialogMode.m */; }; + 8286DA65B1C86544369DF6D387CA87DB /* PFQueryPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = D18B76D6F749D3B45BAA4E3B0F2EFFD1 /* PFQueryPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8365B59553252085916A6D4ECCE383BB /* AFImageRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A3794B030BCB9C4408CA8A2839964ED1 /* AFImageRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8392255CCB63818562D4F58555DDDB08 /* FBSDKColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 615339A2EDD3CE627A27EBB1ECFF21B3 /* FBSDKColor.m */; }; + 83A32D0DCD7B1179BE18D0B98A61B20D /* RKMappingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 817589AA5C8BA17E8B2F9808EC23788B /* RKMappingTest.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 83C5AD87D4B7BF94A4B000FC4C254798 /* FBSDKMaleSilhouetteIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 650F210D5B2E4ADBF30ED15408D730D3 /* FBSDKMaleSilhouetteIcon.m */; }; + 847C86711AC58480F93EE157EC762827 /* PFRelationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 9441797DDFA8DBDB595E9BA19BE1342D /* PFRelationState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 85030A540670174CA31F4F4226C54C4F /* FBSDKAccessTokenCacheV3_17.h in Headers */ = {isa = PBXBuildFile; fileRef = D9AA4942A33D49D6BD6342E82EF21F2F /* FBSDKAccessTokenCacheV3_17.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 854828D77E6CD3D9B82D9498EF24E92E /* PFObjectFilePersistenceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39D2341AC19A6B3AD747ABBF9D3A13E5 /* PFObjectFilePersistenceController.m */; }; + 85738B1734F9BE17BEE9520D89D2D133 /* PFAlertView.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EEF5F821C5CAF35FB96774AFF53120A /* PFAlertView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 857C325B0A6E76A01EACF737B6D4FD1A /* PFInstallationIdentifierStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 79A12CFC76EC1B0BF26367E0922426FD /* PFInstallationIdentifierStore.m */; }; + 86043DABC677904AEAAD37E3C8981439 /* PFFile.m in Sources */ = {isa = PBXBuildFile; fileRef = E3F194E608C0A87A1EA1DBA9B49CDFC8 /* PFFile.m */; }; + 86201505E0AE8888C1DE7E594A2D17E9 /* PFConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F70D98B41C9E7EEBC1231E9885224AA /* PFConstants.m */; }; + 862060E613DA5CEF2678D462DA797828 /* POPMath.mm in Sources */ = {isa = PBXBuildFile; fileRef = 723C3B2158211623464D6751F8AB7101 /* POPMath.mm */; }; + 862FE930B3C40926DC7101D0D25931B1 /* PFThreadsafety.h in Headers */ = {isa = PBXBuildFile; fileRef = 909C0AD7538FB9457B86EC3AC7D973FD /* PFThreadsafety.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 86444AC2A924F63C45BEC54A0DDB7E8E /* FBSDKBridgeAPIProtocolNativeV1.m in Sources */ = {isa = PBXBuildFile; fileRef = BC931BFEE302F10CF84316FC396B1F01 /* FBSDKBridgeAPIProtocolNativeV1.m */; }; + 864CF85CA92D5D4313B0A57692C45881 /* PFRESTPushCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 47C5EB9BE6709541AB17E0F38FB1BB1A /* PFRESTPushCommand.m */; }; + 86EF71FE1E8C350F37E45235765F15F4 /* PFMutablePushState.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC8BFB1DFE3D689F572296A0DA6E236 /* PFMutablePushState.m */; }; + 872A4C2396A30AA64CF2786166CB6562 /* RKPropertyInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = CF3513EE8625253892B05EFF20F16B57 /* RKPropertyInspector.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 87E208C4BC2E8A5C74E1D01087F195FF /* FBSDKMessageDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = BF50A2188E832EC70F211B3F3932C51C /* FBSDKMessageDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 88410794220AF1062177201E82FF9DBA /* YALTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = A75314C0637DF9AD59C4F573E3CB78C6 /* YALTabBarItem.m */; }; + 88B5193C02621657A8A1599944D7966A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16621039C0E3312C216165BEF8D567DE /* SystemConfiguration.framework */; }; + 89131DE7914EFB6BDBAF0E0BA46E0B81 /* PFRESTAnalyticsCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B9E911ACAAECA0172448CD4E62137AF4 /* PFRESTAnalyticsCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8933272E50BAE580EAB845528BE0E364 /* POPDecayAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4659EF2651456627D2DF254CD1ABA4FB /* POPDecayAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 893E921270F96758F3799A3949DECB9E /* PFMutableRelationState.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ED50EE6CEF264393D61B359E4FD13BB /* PFMutableRelationState.m */; }; + 89564402FD876B2472994636049AC191 /* PFDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11575C24EBD20B38803926830ED63640 /* PFDecoder.m */; }; + 899C1F6FEAF906667F0E67D51EDA44FD /* FBSDKWebDialogView.m in Sources */ = {isa = PBXBuildFile; fileRef = 47B246252A39D38E7CC3D6CD2C4549AA /* FBSDKWebDialogView.m */; }; + 89BD9A798D541EC62FA93EDC9B45CFAA /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E62E80C06B8D2394C56D10220D1CCB6F /* MobileCoreServices.framework */; }; + 89E9143B078C3D9D56CDA6BE3AAA16D3 /* FBSDKTimeSpentData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DDC81A1F4448D392C77D59D57719404 /* FBSDKTimeSpentData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8A0852C94F274C951A8FF2C0E53CC203 /* PFURLConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 55DFDBF9FA07FC6282738752A376B991 /* PFURLConstructor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8A96BC7922311E4546CA119B3CF1249D /* PFObjectBatchController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC451FC53B248606339FEF2A083812CA /* PFObjectBatchController.m */; }; + 8A9D36221679B9C6AF86158044A8AB80 /* PFObjectEstimatedData.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC337098F42B8A25439D02AF67102E7 /* PFObjectEstimatedData.m */; }; + 8AF36C0CC65E3A5D7AF4AEA8BEA5F8DD /* FBSDKShareKit+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DE175F2297AFCBB1C62B1B16B5891F1 /* FBSDKShareKit+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8B1097E93AE1F424DE31FFB1D83C1E99 /* PFRESTObjectCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = F1B5BCEFFE5D1ED352C01484C83D6924 /* PFRESTObjectCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8BF233CF21110FBB9A78A0E9C6FCDD49 /* PFCategoryLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1747B6933EBB45F17399984642773739 /* PFCategoryLoader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8C62414E0ABD89DD5A595B207B4F3DA8 /* PFObjectFileCodingLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF111BF52B8C1648F8023FC642FF2C8 /* PFObjectFileCodingLogic.m */; }; + 8C66B8A503EE7CDAF2C8B843D7839113 /* FBSDKGameRequestDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F609FCDD81EB1ADED68C1FE461C3594 /* FBSDKGameRequestDialog.m */; }; + 8CDA43D636A5808F5E87A816EB9F0D78 /* PFPropertyInfo_Runtime.m in Sources */ = {isa = PBXBuildFile; fileRef = C52117BAFED1734D3269D56FE3D842E0 /* PFPropertyInfo_Runtime.m */; }; + 8CDAFE25429AD7F8885827F293890076 /* FBSDKGraphErrorRecoveryProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 5030E7EB9027091137C392A948E0D5A8 /* FBSDKGraphErrorRecoveryProcessor.m */; }; + 8D606E6C43F0BE373F14A15848E78FE8 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16621039C0E3312C216165BEF8D567DE /* SystemConfiguration.framework */; }; + 8D66E14F4E946CF7C4A203E9DC27E301 /* AFPropertyListRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 89CDFA61E00364C5AE6882B31CA90BB4 /* AFPropertyListRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8D9641967C1ACD51CE3ACACF1B1D2860 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + 8D9E418F4BF4FF9ABF3F4E5932589C3D /* FBSDKBoltsMeasurementEventListener.m in Sources */ = {isa = PBXBuildFile; fileRef = 8030921BFF7BB8CE71AE970906855522 /* FBSDKBoltsMeasurementEventListener.m */; }; + 8E3F310FB34E020A985BF37D34582619 /* FBSDKKeychainStoreViaBundleID.h in Headers */ = {isa = PBXBuildFile; fileRef = 67CF036576967715D363A2E7C16E4AAD /* FBSDKKeychainStoreViaBundleID.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8E562933760503079FD82D5E56CCCAF5 /* PFObjectSubclassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FE58183D7C1721963488765C5C8C2AC5 /* PFObjectSubclassInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8E576F91BE595E20B1D97319B3E40EE0 /* PFURLSessionFileDownloadTaskDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DFC97B9CEA18DDABF91F38573337059 /* PFURLSessionFileDownloadTaskDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8E5C4F9E02DA0CE1FB4656E19A803A23 /* PFHash.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1BD0504C0DB02DE656D603F622159C /* PFHash.m */; }; + 8EAD9F99B96C0786E0B85D4D00F096DC /* PFCommandURLRequestConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DF84BAF1C49F7A7466D1F88D650A50 /* PFCommandURLRequestConstructor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8EE441E5EBD7EAFFDDCCB5F247B160F6 /* FBSDKLoginUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 957013533FBA66B6F24FF31441FF1EC3 /* FBSDKLoginUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8F8BE93BB0467F675822961A702D55F1 /* RKMappingResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 903947141B4DCB4B32507DADE29354A1 /* RKMappingResult.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 8FA163961DCFE696DD2BA76D1B0467AF /* PFConfigController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6447BB55EEB3096AE38B4D07B1F5F620 /* PFConfigController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 905D0A5FE23B08D47AA9AB3F584B626D /* FBSDKContainerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3FA9E55331EB6F5C9D6ABE4173AF97 /* FBSDKContainerViewController.m */; }; + 909D78EE968D364B5DDD6C8CF7E375A2 /* PFMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EB5396864F3EE4D9E7D3994DBD1015 /* PFMacros.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 90A1C18005CD010BC306C9E32ED37C72 /* POPAnimatableProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FDB069FE07BA949728D658261EA3E40 /* POPAnimatableProperty.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 90F2175480DE7324ADEEF602757134D7 /* FBSDKBridgeAPIRequest+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CBA6686079E7409ED27CC9A6ADEBF36A /* FBSDKBridgeAPIRequest+Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 916B7BBE0652142389AB4290D8E4ECB2 /* POPGeometry.mm in Sources */ = {isa = PBXBuildFile; fileRef = 696513A0EDF7E7D3B1DA9E8871E05685 /* POPGeometry.mm */; }; + 91D8984FCF7711FFFA4E5A8795A49B19 /* PFPush.m in Sources */ = {isa = PBXBuildFile; fileRef = CBF4F2328A16C47BFD1BCF837B76EB35 /* PFPush.m */; }; + 92450C8A67B02D5312E98B29C29FE89C /* PFACL.h in Headers */ = {isa = PBXBuildFile; fileRef = B934A04F1A258C2A0713237E8C4DB79E /* PFACL.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 924D2586BFCD36A807E0E047454317A8 /* FBSDKServerConfiguration+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E55C935E4DD635C29A2B334C8AB06254 /* FBSDKServerConfiguration+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 926F1FF1ADA93F8BE4339C7AE28BD968 /* FBSDKButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A840F03EBE584ACE4D413A297B04FC9 /* FBSDKButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92C02E7583FDE1D396BB88B19EE2831E /* RKPathMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = CD158942FBF8358677B8D9A4BEA9332E /* RKPathMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92CC0855895CFD948F305B30546B0414 /* TransitionKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 7F1DA5784F757925FC9B2C359AE8F07C /* TransitionKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92D14F626066984B8740E9484071B7C1 /* FBSDKGameRequestFrictionlessRecipientCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E73D941475103F44552CBBF7A9C2578A /* FBSDKGameRequestFrictionlessRecipientCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 93508BB9AD5671C0AB3E4E890FF01C95 /* PFAnalyticsUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B6CBDBFAF7E5AFEF7AE3D397FB6EE762 /* PFAnalyticsUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 93511A4AF61BEA29A4FD4EEE7157E023 /* PFUser.m in Sources */ = {isa = PBXBuildFile; fileRef = DE726D284DFE5BC0144139D8575114FE /* PFUser.m */; }; + 939F928ECFFE801E912A133DB6158E86 /* POPPropertyAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 80519B32A7AC044BA72391DA03E6E140 /* POPPropertyAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 93BDA0F9D51A5F9D4EE287129BDBB99D /* PFProduct.h in Headers */ = {isa = PBXBuildFile; fileRef = 4920838C7C35EE540CFF086D92C435AC /* PFProduct.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 946BB4E027BBEDA5EC360607902B1EB0 /* PFQueryState.m in Sources */ = {isa = PBXBuildFile; fileRef = DD4E641A4F7583F57A2818E33113A0CF /* PFQueryState.m */; }; + 94812F8C5A752C24A9B6D7635CB77A89 /* PFErrorUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D4F5FFBEC5EF679476BD610B31B04B36 /* PFErrorUtilities.m */; }; + 949F1878AC4A43632EFADACFC8140683 /* FBSDKGraphRequestBody.h in Headers */ = {isa = PBXBuildFile; fileRef = B9BAFC471A7F7E390879132FBD1B3B21 /* FBSDKGraphRequestBody.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94C8C1F85C2C32F8D8C4843B10603DF0 /* RKPropertyInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 33A88DE3DA4EB5064A997FFAF0C23DCF /* RKPropertyInspector.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 94E9756648CDAC618994DEA3D28ECC18 /* RKConnectionTestExpectation.h in Headers */ = {isa = PBXBuildFile; fileRef = EA4EBDCE8C9C8A5582D7231A544E96A8 /* RKConnectionTestExpectation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9519538BB8C70220B80F280767FD1CE4 /* lcl_RK.m in Sources */ = {isa = PBXBuildFile; fileRef = 997269FD4178F2BC0707886B0C405A8D /* lcl_RK.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 954B302CD45EB32FEC37295F3EC0206C /* POPPropertyAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = B53D5E1A96FE30D9B7F8D596BF9E2F80 /* POPPropertyAnimation.mm */; }; + 958CCFDA315803AE6E8B769C3985BF57 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7C0590FD149B2C227C59AB38DF61DC /* AFPropertyListRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 95D14872174A30E8C238C5334ED744D4 /* PFCoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0FD81CD43134464279746BA1F66D5A48 /* PFCoreManager.m */; }; + 9634B50A041722E070888114E161E4EE /* PFFileState.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FD94F67395BDA44DD37B2CEBB86BB64 /* PFFileState.m */; }; + 96E1FE094390E35BE4E0D715675C16B0 /* BFAppLinkNavigation.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FDE21F99879BAFCD8007510D41FD42B /* BFAppLinkNavigation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 976C79EBB302D6FD69733210FFC97DDF /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0F29E0D66F63131F371330D93CB4583 /* QuartzCore.framework */; }; + 977939FF92D57042F939439588EB0E6F /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 82E57F9588CEC77612BC5E9A20CCC2E5 /* AFJSONRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 97996933B25E24DAF9D18F8E188B03CA /* FBSDKMath.m in Sources */ = {isa = PBXBuildFile; fileRef = ADAFAB54F5C5506CF7186CD16CA90EFA /* FBSDKMath.m */; }; + 98350E1EE789CEB57D91ADF6F225D62E /* FBSDKShareError.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B843EB1DFCFEE6E5EE55AC6767E4E13 /* FBSDKShareError.m */; }; + 9934291C79A7EBE51544EDDB2193FD01 /* PFUserConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 5CA0A29FC7FC84E10BBE7CB9F915C818 /* PFUserConstants.m */; }; + 9988B7041D7B470C3F7D1938D965F654 /* PFMultiProcessFileLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A5BA6A301883961C6DA165D6089A985 /* PFMultiProcessFileLock.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 99D055FF3D067DC24E05819741E06945 /* PFRESTConfigCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E03D377B70A81B7EE7DF0A8F510E529 /* PFRESTConfigCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9AB561BA236CB930E21B38DE886155A6 /* FBSDKViewImpressionTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3CDC2D78E68FD7654C42F67C29EF3A /* FBSDKViewImpressionTracker.m */; }; + 9B516F3168787E2C9732AC0C00479971 /* FBSDKAppLinkResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5783E79BEDB98581985EEC5EEAD67953 /* FBSDKAppLinkResolver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9B7B596E21B20063D8870D27F93990BF /* FBSDKAccessTokenCacheV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 80E3A4DA55D79A2A163A82080683C403 /* FBSDKAccessTokenCacheV3.m */; }; + 9BFBEB3B8ABB7F24555374DAFDEE5A43 /* PFACL.m in Sources */ = {isa = PBXBuildFile; fileRef = FD8688B0EFB589FA74DDBEE72083D4A3 /* PFACL.m */; }; + 9CBF1E478681F7C22EC2F5B1303DBEF8 /* PFPushUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 4235B0900E27A7ECBA96EAFDECF2D5A0 /* PFPushUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9CF9ABEBAA86E37078F793BAF2C4F18B /* ISO8601DateFormatterValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = E4C5528C376F1D824C32FC5049A22958 /* ISO8601DateFormatterValueTransformer.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9D1E20F07E1C09F60E2F35F6119A0F42 /* FBSDKError.m in Sources */ = {isa = PBXBuildFile; fileRef = CD1F87198E6B2738076E71BB2C4A8C71 /* FBSDKError.m */; }; + 9D3D9A7D232F06FADE0D0D036D96A598 /* PFSQLiteDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AD029CD6F8ADD2E864E5FE1699BB70D /* PFSQLiteDatabase.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9D8543C5F547215DBD30C9C18E525F33 /* PFURLSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 7981192FA1E3FF14D8C9EBA4511FD33B /* PFURLSession.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9D89845489A310CB56E647F143BEA677 /* PFLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = F9C6A17A0DB2E5C15C0B38508DC16669 /* PFLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9DA2B0C972429DD7AD7064E9E09475C3 /* PFPush.h in Headers */ = {isa = PBXBuildFile; fileRef = FE71E48A323238BEC2BB8D62940ED886 /* PFPush.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9DC8CA8457330A93C4CCC547F530F6A0 /* TKTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = E83EDDC94D7F78C9A89A9BBF973667B6 /* TKTransition.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9E1DFD298D2638A443CF2EA5B47BFC51 /* FBSDKCrypto.m in Sources */ = {isa = PBXBuildFile; fileRef = 860BB3AFC2DD08EF4599D8D42484D2CC /* FBSDKCrypto.m */; }; + 9EFC61F27D88241A96D3FB13EF831E02 /* FBSDKProfile+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C4E2E6E86AEBB3B50EE86E4B1074A32 /* FBSDKProfile+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9EFD8B6E9A0DFB23D0458D0071283130 /* AFNetworking-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E089DC06AFABF3AB162039B0DCA20D14 /* AFNetworking-dummy.m */; }; + 9F04CB08F3037EDF755036F82BCC418F /* PFPushUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = A3152B830DE11B9029E12D3C5B928C17 /* PFPushUtilities.m */; }; + 9F309454D3B0FA1C2701DD3226C97074 /* PFCloud.m in Sources */ = {isa = PBXBuildFile; fileRef = 37382D15DA0BBCC18167A1B61E72CD64 /* PFCloud.m */; }; + 9F3D3656F5864DED6AF668D1AB68975E /* FBSDKGraphRequestConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = B40775302C0516B1FB09E3523DC34D30 /* FBSDKGraphRequestConnection.m */; }; + 9F6482097A50B68DAE48BE9D3CB3D28D /* RKMIMETypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6AD9092DA1F9CCC04506CAA7CAD0EC83 /* RKMIMETypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9F836AA840436BDA62D7D6325F233221 /* PFUserFileCodingLogic.h in Headers */ = {isa = PBXBuildFile; fileRef = B3AC4F0EFC27421FCDFE376464524DBB /* PFUserFileCodingLogic.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9FCAE5105CB7AB9D7B5CD6457B323B06 /* RKObjectUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B037353120BA03ACEF0F5DA52B84530E /* RKObjectUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9FE10640F0AED83B16480FFAD9CEA3CD /* PFFileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B818BE16D0901DD3F720DF4447B592B0 /* PFFileManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A00E98DC15CC981738CFBE96AEB16EB6 /* PFPushChannelsController.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE43287C4A621BABEBFD4D7ACA4D0CB /* PFPushChannelsController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A03EE16F31569592C179BC824D019DC9 /* PFRESTUserCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D3AD3AB61D09EFC9C322C57F9239AFF8 /* PFRESTUserCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A0F75CBE72EE4F9B74838F6F01191D06 /* BFAppLinkReturnToRefererView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E3D7476264442440AC1374D1E0418A1 /* BFAppLinkReturnToRefererView.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A161B6BDF507ABF1322BB74A9D437D4B /* FBSDKShareError.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D612FDB5856A0B0DC71C9A83AF67537 /* FBSDKShareError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A1732411203D091E1FC231EB20F5A8C7 /* POPCGUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05A46A1CCAAB75FBBA2C67F460435143 /* POPCGUtils.mm */; }; + A1752CBBCEED5A344FDA136B0EF771A5 /* PFCurrentUserController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FF8DA1F7EEE96CC61CEEB687513A615 /* PFCurrentUserController.m */; }; + A18206D679C80B4AFF6654B5677DBFDB /* FBSDKInternalUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = CA8D44F0BCF9802F38A1799B6EBF1407 /* FBSDKInternalUtility.m */; }; + A1B7647A3A40381C4430FBDBF794C699 /* PFCommandCache_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B8C1F1B3446748EE4B4240C0CC009D67 /* PFCommandCache_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A1D7AF47B734259F42226B7577014F7C /* PFUserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 092AA11ADB8FDDCC538A0ABDD75F38E8 /* PFUserController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A1FCC931AC4A1A8D148E28C4572BB307 /* FBSDKShareDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B9C80D740936B42747C456E06BD4210 /* FBSDKShareDefines.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A248810839C65E5881B7B7B3F264078F /* FBSDKBridgeAPIProtocolWebV1.h in Headers */ = {isa = PBXBuildFile; fileRef = F7114C7234DA9F23563BF6C254E6458A /* FBSDKBridgeAPIProtocolWebV1.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A2B99500387BF0FB3062AB1D0FFD57A5 /* POPAnimationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D3B7CDCE9EF138FF8BB043F7239498 /* POPAnimationEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A31552A8B1F14534DDBA1DFC4E09C195 /* FBSDKShareOpenGraphContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 26576E563FF51DD9C6683E959913991D /* FBSDKShareOpenGraphContent.m */; }; + A3353245628DEA268387441F4EF31877 /* PFSQLiteDatabaseResult.m in Sources */ = {isa = PBXBuildFile; fileRef = C60BCCB74CDC88B04B7014C507F2D137 /* PFSQLiteDatabaseResult.m */; }; + A3C1C7BA97AC39DFAB85B13E827BD182 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 733D51F628A8649F5A0790296BA3E42A /* CFNetwork.framework */; }; + A3F739BF4CBFB653314B4737DABB5E7B /* RKTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = FF461E4535F2215F6A9DDAA832E1BC7F /* RKTestHelpers.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A41BB882FD7A74A2F25113D6A5644F7D /* PFObjectState.h in Headers */ = {isa = PBXBuildFile; fileRef = 81E010F8251FD4453C9DDE44ED09C4F4 /* PFObjectState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A466E7239F778C5E117BA4008114B272 /* PFPushPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B791C6AA6D3B48C2C1AA9496E0790AD /* PFPushPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A48B34E8A4056CAF37BF815D80F851FB /* TKEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = FBBB3B26B24BB1791ACE441DFDA19FF2 /* TKEvent.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A4A05FBBDDB993E56073550A63C1727E /* PFObjectUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D65E69134BE531C727A15EAC5D6BD404 /* PFObjectUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A4AA61EF4E7E175383F829835B3690B6 /* FBSDKCoreKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 231F7C139C4CE6856490CCC6331A4BB0 /* FBSDKCoreKit-dummy.m */; }; + A51B5663618D00E23D7124EC97861DD4 /* RKDynamicMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D6A9F671AC5AAF2E4BDEE1D46C1A2DF /* RKDynamicMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A55D4E06A15BD0D7189518E2B96DB8A3 /* FBSDKWebDialogView.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DE9B680DB183FA614D58C42EADD38D7 /* FBSDKWebDialogView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A56E60590F48B3C632A71A0B970F8E90 /* PFURLSessionUploadTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F129E4F0636DB79526F8F6270198B942 /* PFURLSessionUploadTaskDelegate.m */; }; + A5A2E68EC92D877AE2289A67BA94C9E7 /* CAAnimation+YALTabBarViewAnimations.m in Sources */ = {isa = PBXBuildFile; fileRef = 26B6710576834D59FB5352DD3F5EB069 /* CAAnimation+YALTabBarViewAnimations.m */; }; + A5E23287231B8CED31D97C44BA2702F9 /* FBSDKGraphRequestConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = FE89E1667DF47EC79AB1E8C414DE79EB /* FBSDKGraphRequestConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A5EF7E6ADB37EC0A0DE6145812D8998D /* FoldingTabBar-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FDF375C76C5BA4A7F1EA1C46DC3B142C /* FoldingTabBar-dummy.m */; }; + A6381412CBAD67981B189C3D03FF02B6 /* PFEventuallyQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = A43A3FE9CF5B7E721E9179EB461EBDD7 /* PFEventuallyQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A661008071892B0148336A0636FC59A1 /* FBSDKIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = F2D002F7CD0CB8A3551420036A594D40 /* FBSDKIcon.m */; }; + A6A403231A96C6C21C83BAEF0BB1093F /* CAAnimation+YALTabBarViewAnimations.h in Headers */ = {isa = PBXBuildFile; fileRef = 955C4C780B4D5A0582BF89B0379CB61E /* CAAnimation+YALTabBarViewAnimations.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A6D8B881BC31F26E99F56A4B5144F72D /* FBSDKAppEventsDeviceInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = C1B7244F3402CF0B20BFF0228719CDD1 /* FBSDKAppEventsDeviceInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A71645666E899BA6FCD0A105BCF4554D /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F0414F682EAAC899BF6D1350B23F4920 /* AFImageRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A721709FC277E75DE5C95BB094C3D554 /* PFAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FBA963311C705B8BC3B0E2FC0EB8529 /* PFAlertView.m */; }; + A72805273E466C273A4B10C6ACB993AA /* FBSDKShareAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCED2B89C49FCB98FAE1186D1725F5B /* FBSDKShareAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A734638E2FD9CD1F9174C76669F0DF6B /* PFObjectController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F8334729245B982D2786A77F61C281C /* PFObjectController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A75FE2B82568636BBA4E284DD4E782B8 /* PFObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C5363E7D4FF99528A9F857EE9F2DF437 /* PFObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A7B200E0CE52F38A4D17E432C3D5D44B /* RKHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DDC10303447DF4E3E657F2B4AD92925 /* RKHTTPRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A80A4BCE5F0BE99CC5D0D79ABC6EFC84 /* PFKeychainStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C08FCA3A865F9181B3EAED5D081E6DB /* PFKeychainStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A8FB9C2DF4996A5647C43D1D20B34154 /* FBSDKTooltipView.h in Headers */ = {isa = PBXBuildFile; fileRef = DF3BBA8D585F58897AE3BA414EDE35C2 /* FBSDKTooltipView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A8FFC32B766D8160348983C902A0FBCF /* PFRESTCloudCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B1E4C81276B30550CB3CDA51070D862 /* PFRESTCloudCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9514FF859C895C0BB0BCE528FF507D3 /* ISO8601DateFormatterValueTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB70DB4EE93F869DBC66617E527E62E /* ISO8601DateFormatterValueTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A9821C932984F979E72D5984C1E3A87E /* FBSDKIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BA86EF4EAFD3D4475A169859BB0B633 /* FBSDKIcon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9D01434F1CFFFF1277E3429A43FA1C0 /* FBSDKAppEventsStateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 57EA8E1B5446775F4608110823A9BF8C /* FBSDKAppEventsStateManager.m */; }; + A9F8CCF3E9E7A1F8BB906AE75CDD76A1 /* PFMutableQueryState.h in Headers */ = {isa = PBXBuildFile; fileRef = AA02D2B63E8F9A35484FF74BB175EDCF /* PFMutableQueryState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AA196672E44A737889F2795FEA012F6D /* PFAnonymousUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AA9ED123D1A01B9CE0864DF21669E32 /* PFAnonymousUtils.m */; }; + AAB25408151750ECBBDAD5A765D5C652 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + AABB7281DE92C99CC47D5985438FFAF8 /* RKMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 40C31A1DA0DE91B3BDC70194B9B9E75B /* RKMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + AAEA1275B8DBCEDED978E0E5967D1440 /* FBSDKTooltipView.m in Sources */ = {isa = PBXBuildFile; fileRef = BFBDACDD0805704D189CA36FE17373B8 /* FBSDKTooltipView.m */; }; + AB54E487727ABF1E4455A951FFEF2C82 /* PFRESTObjectBatchCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 1635AF96EB71FB3FEBEE52A4395CFA1B /* PFRESTObjectBatchCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AB61AD540531ED95F49168BD4C8C1936 /* PFOfflineStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 632C18854DE2E319E9B6834A93514CC5 /* PFOfflineStore.m */; }; + AB7CAA7D0CB1D37DB84BF83644CF6E41 /* FBSDKAppEventsUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = A16A70655423A834331503E4979C4422 /* FBSDKAppEventsUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AB8D18ED889E13CC5F738DD1A59CC510 /* FBSDKGraphRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = CF6DFEAD49E3B96B670A4AB662D78229 /* FBSDKGraphRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ABBA98083D66AA8745D3CE85508A4B54 /* PFFileController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39F780E56F26B16CAF1CF2F0EBC58660 /* PFFileController.m */; }; + AC0D3A56A07AF56CCCB9E6A24C68C969 /* PFMutablePushState.h in Headers */ = {isa = PBXBuildFile; fileRef = 240CCFABDE66FE6ADE38A4B02CB89687 /* PFMutablePushState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AC70F2D05DDEE9CA1E15F5FBC259E974 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16621039C0E3312C216165BEF8D567DE /* SystemConfiguration.framework */; }; + AD0387E79E49576C00BEAED9E903F6B9 /* PFFileDataStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D24D9A1393699B9007901EB5221D9018 /* PFFileDataStream.m */; }; + AD94C0E58E9E796C2461FB990370B8B9 /* RKDictionaryUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B5AA14CFC28475D9E28E32A363674B8F /* RKDictionaryUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ADA73C3403D0DCBA9ADC9737B71F448B /* PFRelation.h in Headers */ = {isa = PBXBuildFile; fileRef = AC8C608A0D3BE700536D0C6D4011931A /* PFRelation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ADDFED5198FA5284E28022251BA98C1D /* RKLumberjackLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = EE16E8E41B610CE73E8BC061D6E6E102 /* RKLumberjackLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE279B6C3893C1BB12A7D761A8F70EA1 /* FBSDKError.h in Headers */ = {isa = PBXBuildFile; fileRef = 1851DD5C5804EC9A837131EDAC8D3EDB /* FBSDKError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AEC8FB690EB9BAD0F86F1B972089BD4A /* POPPropertyAnimationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 59F15D7F5CA85CC8436BD1872518AB18 /* POPPropertyAnimationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AECC0656F68B2EF64F2FE95EE733659A /* RKPropertyMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = D4D4E125C0EFD510E0171C24783AD02F /* RKPropertyMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AF896EF80A89E677C2FEAD7D25B5CA13 /* PFObjectController.m in Sources */ = {isa = PBXBuildFile; fileRef = F9F517D67552371A385D10A6D780C46C /* PFObjectController.m */; }; + AF923C2C11D76B65500D200EF0BAFA33 /* TKTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 76BDB3E82FE4A935AACD2F637F371589 /* TKTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AFC9F60694818B7903ED6065CA9E7E38 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + AFCC73E1C178EA83628FBECB44C75A50 /* RKPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = F288F2786DB87278DEB0D83B15A2B5B2 /* RKPathUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + AFD33F9C5B99DD2201D2F07DBB808E79 /* Parse-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD8C56BA64752CBF457FB1F3473747F /* Parse-dummy.m */; }; + B00E930CCC7EF81612BF8392339E17A8 /* PFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 06FB17807D8F9BB90C006F1AA1422EEB /* PFSQLiteStatement.m */; }; + B05B85B93FE4C40364989A851D0E4C95 /* FBSDKLoginConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 25070753B1B37A1665F1F5332C0EF515 /* FBSDKLoginConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B072A694A0A46131BB3A56636471FAE1 /* PFGeoPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B650BB26CA49F23280F611BC06CAB7A /* PFGeoPoint.m */; }; + B0C1C3993C766809A801540862C105E2 /* RKRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A36A67D8095CA8BA88F3D9C867BF723 /* RKRouter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B16764D185993A3DA87BD56929F05480 /* POPAnimator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 996415B7247FE7D0C37780B180517ACB /* POPAnimator.mm */; }; + B17336576943ADD8ABE250E808D8B72D /* FBSDKAppInviteDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 49293A25955435D7FC5E29D841FA4456 /* FBSDKAppInviteDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B1864DAD1E71AE119D92AD90D4075B44 /* RKErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = C31FC859AAD2E2012636FC6B877D6EB6 /* RKErrors.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B1B5542A3966742AC81F380E955AA85B /* BFAppLinkReturnToRefererController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91D5B36C33B97E32AFA561C868667F87 /* BFAppLinkReturnToRefererController.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B1E2BB1A1186B0C02B35C1C6F5509D36 /* FBSDKLoginKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 880C326DB82974026154DE2FEE6DF8EA /* FBSDKLoginKit-dummy.m */; }; + B220008A1D3DD1B6628E2AC2A64A02AA /* FBSDKShareConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 29B13B33590257BF7A80C3602DC87B09 /* FBSDKShareConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B253780C6017BCC8E3B9457E3048462C /* TransformationMatrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A2F4083D494D045689BC3A072187C3B /* TransformationMatrix.cpp */; }; + B25E3751AB01594311494F5E9AFC5322 /* FBSDKLikeDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F1B1BCD1E0ECE22C24CC82032B14A95 /* FBSDKLikeDialog.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B28E7BE90D0898F34164A3649D16E978 /* FBSDKLikeObjectType.m in Sources */ = {isa = PBXBuildFile; fileRef = B8DA6BF199DF0CAB4F3B6FE8589F18F9 /* FBSDKLikeObjectType.m */; }; + B2C7E9065BD6BF8E3F3017B802865B56 /* FBSDKAccessTokenCacheV3.h in Headers */ = {isa = PBXBuildFile; fileRef = A0356870F75E493C4A0C432FFFDF4798 /* FBSDKAccessTokenCacheV3.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B2DB66509B953232772CC24828B2A2D6 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6FDEF44D035ECEB171CF49BE68D54D0 /* UIKit.framework */; }; + B2ECB596CD8B0A8925E2221C87668493 /* PFPinningObjectStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 82EA1A7E2F5B25D7DECB8BE35B3072F0 /* PFPinningObjectStore.m */; }; + B3539900ACA90E11ED43DD92C1AC3C8C /* ParseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 02AEBA17B69A4D55F659D4F44440127E /* ParseManager.m */; }; + B3777DF9804F4FD5656FF7A89A266CC3 /* PFDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = DC4C06AF4A9CCA7E3F9A2C7F97FFCE87 /* PFDevice.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B4035BD0031BD154E70AF698B10B48A7 /* FBSDKSendButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 92D9BAF18D3C2495B07204C2404BFEEB /* FBSDKSendButton.m */; }; + B4AECD7B0079602334FD0CA11106AC3F /* RKPathMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 09BC6A273BD14FEC82E66ADE94F2D7AB /* RKPathMatcher.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B4E61680387E0E5146734C1EB81255C5 /* PFOfflineStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C1D9153F43B4ABADD58C382A1292332B /* PFOfflineStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B50EA8AB3CF7CF9162E24421784D4BAD /* YALFoldingTabBar.h in Headers */ = {isa = PBXBuildFile; fileRef = F7EEEC622363411316A89CF3A6941695 /* YALFoldingTabBar.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B5983C745D96CF344F4DE9DEF60C5ECF /* PFInstallationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9ABAB9B040DE06F9C8CAD85CCC2D4A4D /* PFInstallationPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B60AAB7F842EAE538F42641F811DBC07 /* SOCKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD24718CA4BD9604C201D989FD03218 /* SOCKit-dummy.m */; }; + B60C299FB6D6C13D99621CDBF557AB27 /* PFCachedQueryController.h in Headers */ = {isa = PBXBuildFile; fileRef = 9152B5335813665EC6B08F73411A813E /* PFCachedQueryController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B63E72E378C0C4DEBC0EF1A6EE5CAD25 /* POPAnimationRuntime.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54E5949F2C78F11D2017067D065794BD /* POPAnimationRuntime.mm */; }; + B68EF6DB36966D13E557D2247702E8C5 /* BFExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 2775CBEED05B03B513848BE46301ECA6 /* BFExecutor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B71F48BE352CE58652003A3A8BE5EDC2 /* AFNetworkActivityIndicatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = CEB32A7ACC2D1268332E3ED6413E04AE /* AFNetworkActivityIndicatorManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B7BBC12792F777B1ACF0CF3C28355EEB /* POPCustomAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 09A74F4E5B1694ED02FEFEE3567FD5C4 /* POPCustomAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B84F69EEEA9898307D85749FD54502D0 /* FBSDKLikeActionController.h in Headers */ = {isa = PBXBuildFile; fileRef = BFAC7C03033A9B1F15075F4565BC1328 /* FBSDKLikeActionController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B85FA9794E00DFF09C3ECB91A3D45882 /* POP.h in Headers */ = {isa = PBXBuildFile; fileRef = 78A05813E9EC11B010C6A344D9AAC05A /* POP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B903E58329FDF7F6E815312255B967F7 /* PFCommandRunningConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 34467D773B15C784E43F77DA67A5790C /* PFCommandRunningConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B91DBAED5B544D03577FAFF5722F865E /* PFMulticastDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FE71002F43E4EE07FF4CEB964FE6D44 /* PFMulticastDelegate.m */; }; + B9A074BC3A31106AEC6667D7684FB0F6 /* PFDefaultACLController.h in Headers */ = {isa = PBXBuildFile; fileRef = 951E09F02C4842CACF36CAD6D5398E11 /* PFDefaultACLController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BA61EA5F3CCE71914D2E8405C76CE42A /* ParseInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 749A8D41E182E9883688C41D2D257554 /* ParseInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BA9C553426A8678957BAED9B891E4B96 /* PFReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 20FCD32AE2B10221B23EC19A5B380953 /* PFReachability.m */; }; + BAB82247B24428DCAC2A4F4E9207F60A /* ParseModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 67B4C66668FC14A61182B73575A193DE /* ParseModule.m */; }; + BADD59CEDAC52C54651BF484D6490C67 /* RKObjectParameterization.m in Sources */ = {isa = PBXBuildFile; fileRef = 73C100898C88FF4043F6002195DD6293 /* RKObjectParameterization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + BAF2CCC3F6782690F1534565B877278F /* FBSDKShareOpenGraphAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 05D4509ED8E7E863F79C2BDF6FE4471C /* FBSDKShareOpenGraphAction.m */; }; + BAF2D4F797832511A4718AE2F9D4C9E2 /* RKConnectionTestExpectation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC4913285E98A56C951839A999352AB /* RKConnectionTestExpectation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + BB1151A40AE6E5AA064A5AAC684EEF46 /* _FBSDKTemporaryErrorRecoveryAttempter.m in Sources */ = {isa = PBXBuildFile; fileRef = 19A473DF4573D2A6FDD72DA3BA1C2C04 /* _FBSDKTemporaryErrorRecoveryAttempter.m */; }; + BC852E5C003C0E1C337D9C642F826513 /* FBSDKAppLinkUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F9DBE01AF3666AF5DF673F0B8302A852 /* FBSDKAppLinkUtility.m */; }; + BCC52FD8A4B950C4F0A918C1E7C04A8B /* FBSDKLoginManagerLoginResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 826C988F437410449787F4BDCE07E6B7 /* FBSDKLoginManagerLoginResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD3CB42C142417AFADFDF458A7B580E7 /* PFRESTCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C9A888CC23B37A508B946C18FBA51D5 /* PFRESTCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BD8A5E25C13BF645294D97EB1ED09CA0 /* PFAnalyticsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77DB8925A606DF13F24DBF2AD343EB8D /* PFAnalyticsController.m */; }; + BE0F6955D03D6DF536335CAC10A8CFC5 /* FBSDKAccessTokenCacheV3_21.h in Headers */ = {isa = PBXBuildFile; fileRef = 735D8A9263762B7D4E5C5EDB816A7CB6 /* FBSDKAccessTokenCacheV3_21.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BE269944FF4E5E554223D2E055E4F1A6 /* PFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = D4AB7EDD51484D69712FC0BAF2EEFB20 /* PFAnalytics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BE695DFD8590BE457047A5B07B829199 /* POPAnimationTracer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 72B29870F05A80283BE95E71DEBEE1D2 /* POPAnimationTracer.mm */; }; + BEBFDE40361511989AD4318B1B5E578E /* PFObjectController_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 10475FA9B1F63748681C1D95ED038819 /* PFObjectController_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BEFC0134FE56543E669CD06873F5BB8F /* PFAnonymousUtils_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE23EA20C48234573BE370B97423C3A /* PFAnonymousUtils_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BF7290A7C875C362F762B2D6C1B991B7 /* PFObjectState_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E37BF385DA04A9EDE7E17A3AD82FB48D /* PFObjectState_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFA8895521CECBF82A30964B918DDD3A /* PFLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = B92B54D733F8824AD766092F58A3F50C /* PFLogging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFAAE2E16A1F2007BD7CDF1DB8D2CDAD /* FBSDKAudioResourceLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = B8046097AB97D9EBA30FEAF579C44F56 /* FBSDKAudioResourceLoader.m */; }; + C03ACB5DC566E5F4BCC725F8A8D6F195 /* POPLayerExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = 79F07C09208B3EA7236791BBBDD1D459 /* POPLayerExtras.mm */; }; + C0575A904CA77375C3DC6B600B99CEAD /* Parse.m in Sources */ = {isa = PBXBuildFile; fileRef = D1B966C2A921DE73042AA8B317E629EA /* Parse.m */; }; + C067F0759FE44C28F074EFF6C754A11D /* POPAnimationEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 996EADA337EAC02210FEC4506EB335B5 /* POPAnimationEvent.mm */; }; + C09CA6A4AA52E14E894A7A328C0D8178 /* PFFieldOperationDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 5AAE8E50B932782D92F325DCE2EDEBBB /* PFFieldOperationDecoder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C0C7A1E73D584A4F93A286FA1753D5B1 /* FBSDKBridgeAPIProtocolWebV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 95FF2C409A7211FB7720DA60E56153C4 /* FBSDKBridgeAPIProtocolWebV1.m */; }; + C0CA4956B32616DC4919F00A7EC9B92C /* PFCommandResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6273DBD91B70BE5A81E0EF6B816A31E1 /* PFCommandResult.m */; }; + C15F9AD9C17E18B25E1EF6B788309E6F /* PFObjectFileCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = ACE07B046AA72822B46EAC882E565640 /* PFObjectFileCoder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C195E761865347834BB306A41FBFD8B7 /* RKSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E0DB2127804727AC549721870914323 /* RKSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C234A73209753EDCFE73464F05EA45E1 /* POPAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0C43080C0B2655A28B3CE9D3DD9B32B2 /* POPAnimation.mm */; }; + C35F6A896E802A315D7EE2BB54CBEFA5 /* AFXMLRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F51C083C4D1E3AAFE06A8F4BDF8EBB88 /* AFXMLRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C412C0A9241FD8CB88314EB3BD8E528C /* FBSDKWebDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB3E3D5DFF77A79169D2E7390145CE7 /* FBSDKWebDialog.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C419D5E278F540F1644BA4741785CC8A /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A4DD5212BA2630DC90D52AB2A7B05B85 /* RKObjectManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C46A8064365E409811A4E812177A4041 /* POPSpringAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D3359292FE89A636801514727B628BCA /* POPSpringAnimation.mm */; }; + C50BE142E604DE751E9B8AF5DD6B0363 /* FBSDKShareLinkContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EE26090EAD13C1FFD39BB6A7C89193B /* FBSDKShareLinkContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C5BCED302898250D42DAB9622E61A2D2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3849FCCD9604B569E0277015CC30071D /* AudioToolbox.framework */; }; + C63F51531975AE0BE6BC871568A6475D /* PFTaskQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 79A805E2776C2CC27AB7764874C93173 /* PFTaskQueue.m */; }; + C66C913D05F70FF30EC65B1143CDC84E /* PFSubclassing.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C8E5BBEB36882FAEA0C74B322ADC266 /* PFSubclassing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C674B4D84DEE46658392F9A5C6CE6429 /* RKBenchmark.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F6B679BDA82770D971194798F95DC69 /* RKBenchmark.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C72DD6BF1D64A4F33EBF2D6B77A8824C /* ParseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 23397924D53E7B536CB59C3373E47BCC /* ParseManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C7ADD9A2DC3411145922D13FE552AD20 /* PFPaymentTransactionObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B6241CE08565BB6864AEF668F68FA18 /* PFPaymentTransactionObserver.m */; }; + C7DCD67DF808CAC96CFFB404088D2CC5 /* FBSDKLikeActionControllerCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 535545A6AC7290701119A0B61C887EFF /* FBSDKLikeActionControllerCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C8650F51B96E23879C9133719B5CE14A /* PFCommandResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 45A41F6A2E3BF848EF5F335556B27EC1 /* PFCommandResult.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C8A8F4BE07EDC15A6921CD68990C0F98 /* FBSDKBridgeAPIResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = C01B234F69300CBE9F042A18823A2C64 /* FBSDKBridgeAPIResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C8DF39D35A8ACF9F10F8392AF8C407A0 /* PFURLConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF57BE3A8EF2D78A282E7FEE79783DB3 /* PFURLConstructor.m */; }; + C8E9B871537B5C88280E56A9778803A4 /* FBSDKAppEventsStateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A2FAF2092D4C51EAE9E68E2B1EB0071B /* FBSDKAppEventsStateManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C920759127C01FDD99644BB6806F24FC /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AF2857CEDB6464020434166DEB5A36F /* AFURLConnectionOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C938FA47C6276A28C9F0E0C1933E3E51 /* PFCoreDataProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = D8EF0F918739185C24D9BE7DDED005BB /* PFCoreDataProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C95B6FEA0DB3899E1F52C07D40DD4DA0 /* FBSDKDialogConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = E0976F3A16E6127C870E863609F006DF /* FBSDKDialogConfiguration.m */; }; + C9774E7792D3CF37A4D1C7C208FD14E2 /* PFPropertyInfo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B4A9DBE857C85DBC4FCF8511B67E7FF3 /* PFPropertyInfo_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C981DB324F5A971F06590A5FDEB937F0 /* RKObjectParameterization.h in Headers */ = {isa = PBXBuildFile; fileRef = 12148D9B34DE0B074CF161C3B74EA2F9 /* RKObjectParameterization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9ADB5534B9078FBD0215BCB05701219 /* TKState.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DA5437028A51B95A1C0B0B8B5CB334B /* TKState.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CA0A64C7187BFF5B6143C3D3A7FF8D94 /* FBSDKAppEvents+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC237868E24D8CCBA8AA21DB4F43584 /* FBSDKAppEvents+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CB0C14620CFC843788BBAF4AC8A4E6DB /* POPBasicAnimationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 280AB1BDCC3841953AE8E7E78F9326A1 /* POPBasicAnimationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CB4B0DCDDB21473382F6B2B6666EC6DC /* PFConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DA32C8430B17D1CEF6CC0C2F20702C6 /* PFConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CB7A2EB58EBA82B7CE519F8C2EEAFBC4 /* FBSDKAccessTokenCacheV4.h in Headers */ = {isa = PBXBuildFile; fileRef = 8496664844E09F7B412D05544D90E123 /* FBSDKAccessTokenCacheV4.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CBC28D34E7E02B4E254099B15B674080 /* BFAppLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 74089267A9387B60B1CE108DFAA883BC /* BFAppLink.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CC0225659881638027E96EFF8EE41228 /* PFSQLiteStatement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4788A28C6827C4BF85BEB5920CADFEE4 /* PFSQLiteStatement.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CCF1CD4428BA2944666A829E767A6C15 /* PFCachedQueryController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AECAEEB58E4CB5EFF8D61951BC17DB1 /* PFCachedQueryController.m */; }; + CD2E86E2BA9BE8DBAA7FE88993F1E41E /* PFSessionUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = A4B28BD09271EAECA8D4D7EE69556765 /* PFSessionUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD5054A2ECB96B3ABB0B3794A299A822 /* PFHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A1EA9C9D41AE2090A25AEB7774EFF7F /* PFHash.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD6F43B3511A0FBF3E573962063BD5B9 /* PFCurrentUserController.h in Headers */ = {isa = PBXBuildFile; fileRef = F105D77D5F0461FECD9BAEB70A50AE87 /* PFCurrentUserController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD70F46AD007D42A6E7E4C03AD654B48 /* PFAsyncTaskQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BB5593B161ABABA1D0209ECA5074EA3 /* PFAsyncTaskQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CD714C0FC030441A7466E26DE9A3AC29 /* PFOfflineQueryController.m in Sources */ = {isa = PBXBuildFile; fileRef = 136503C1BC94CD505033988EB9C16090 /* PFOfflineQueryController.m */; }; + CDD83F91D134051FA132923E3D4096DD /* RKMappingResult.h in Headers */ = {isa = PBXBuildFile; fileRef = DECD8E5B530D5D0B9FB27660D6A00BA3 /* RKMappingResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CEF61BB75902C8E0148259A5DF63854E /* FBSDKAppInviteDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 3265A08CD5F3A28A6541A985B0B75664 /* FBSDKAppInviteDialog.m */; }; + CF027C0D4F7C6873C8BEA392044BE467 /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = A0A6F3B1842359B2087C2C8FE2CDB03A /* RKPaginator.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + CF49B64886C0C73CE0EB0549FA20E21F /* FBSDKDynamicFrameworkLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 74338BD705AD4CAADD5CA90BD8EF2D96 /* FBSDKDynamicFrameworkLoader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CF49D485A500B363E1DDEF68072F9F36 /* PFSession.m in Sources */ = {isa = PBXBuildFile; fileRef = A7780E3BA6732D798F3374CA43890F7C /* PFSession.m */; }; + CF61365D13FDC0E6A145C012AB9B98AE /* RKISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6101E1788344FEF66BFB8A3BD80CF650 /* RKISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + CF6A6DAB258596DF234FDDA9F2B214CF /* BFURL_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 44420C2483949613227FDC09A152A3F2 /* BFURL_Internal.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CFFAEE251FC130E14DF2831B504F748D /* FBSDKAppGroupJoinDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 610EC8334EB48B27B2BBE37D785AF2B2 /* FBSDKAppGroupJoinDialog.m */; }; + D041A6307B8BE12B6F1D2C7B11DB335F /* FBSDKLoginManagerLoginResult+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = C737DBF986FE1FF02706679384A58608 /* FBSDKLoginManagerLoginResult+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D052ADE6387927B8A72F291AB6D821EF /* PFConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 1516B2B4A8F91019AE5E4283AA8F5E5D /* PFConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D16EF56685DA7EE0C6F714819F926216 /* PFURLSessionCommandRunner_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 55116A6D2C15718DE59AF5A2B7B5C7F2 /* PFURLSessionCommandRunner_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D183B6B66F20B85A64F5B7603D0A473B /* FBSDKDialogConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = F48BCECC8EA184F5975C3532819CFFA2 /* FBSDKDialogConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D1E16869A350E851F31AE83FAB93361B /* PFOperationSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 108401CAD15D4703C0D17F39835C74AE /* PFOperationSet.m */; }; + D1F17C848BA03A0D38CC8D8B815B75C8 /* FBSDKMath.h in Headers */ = {isa = PBXBuildFile; fileRef = E511AFB10E1282BD8E6813EEEAD607E0 /* FBSDKMath.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D224C6471A4DA408043B4E72EA97721E /* PFBaseState.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDA61BB7A1F8AD65676757226E8A74 /* PFBaseState.m */; }; + D270E51BC7362F767D5429DF7A368E0B /* PFBase64Encoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A7261E40A7493778EDD34738B42676E /* PFBase64Encoder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D279CC9D345EBC4120F60408E3392608 /* SOCKit.m in Sources */ = {isa = PBXBuildFile; fileRef = D011D1FC8B93C93581E9C03ABF791BCF /* SOCKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + D2B66E29F3D4324178B40D412922503D /* POPDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = C66092953B80DE287E77614DFA2D2FE3 /* POPDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2C8A050CA49DB3967B01D9B9354FC16 /* FBSDKViewImpressionTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = FEE6386026272731739CFEE82C813032 /* FBSDKViewImpressionTracker.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D2DF8F3B252BED46B455366674FC5F8D /* PFLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B0314DD062570E8416F2523D03B9EF6 /* PFLocationManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D33E2DE9B21F540B2BF1812B90F33155 /* PFURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 24851AC75A717461DF249C574A7E59B5 /* PFURLSession.m */; }; + D3A453D5AB624E0B9703A6E8542657A0 /* RKHTTPUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB59A851D792D3D60B16A08B9F07134 /* RKHTTPUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D3CBA0C9A2F20A2AE8D9E8FA5F2326DA /* FBSDKKeychainStoreViaBundleID.m in Sources */ = {isa = PBXBuildFile; fileRef = CC228E158C60DD94DF7B3EA5E18D8125 /* FBSDKKeychainStoreViaBundleID.m */; }; + D4163483905F3CE49898DD8AAC0E0910 /* FBSDKAccessTokenCacheV3_17.m in Sources */ = {isa = PBXBuildFile; fileRef = B7B30077DB15E3549CCF53E8707A36D6 /* FBSDKAccessTokenCacheV3_17.m */; }; + D41A41DB158B8E95575669C635CCD82D /* PFURLSession_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A0A5F9F3C3457E2ECD91932E225F1F /* PFURLSession_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D4315EE9D6AA73520E3C28206BB12A2E /* PFFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CDD229A4ED63D296862C7CC3E93D079 /* PFFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D466AEB0B97EDC9663AFFD5F94C04630 /* FBSDKErrorRecoveryAttempter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B4CFCBF40F579D60F6CA51813334980 /* FBSDKErrorRecoveryAttempter.m */; }; + D5DE272410B216A538955743C7C9574F /* PFFileStagingController.m in Sources */ = {isa = PBXBuildFile; fileRef = E4865AB05BFD84B7B6E65342C643E18E /* PFFileStagingController.m */; }; + D5EE317B7D0E35A376DF8328CEA3252B /* FBSDKAccessToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 06292442821AF9572A443AF0D949122D /* FBSDKAccessToken.m */; }; + D6027C66071A9702E15C8A733DBF6FF6 /* PFPropertyInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F8A42FF495AB8897D09E00CAD01440B /* PFPropertyInfo.m */; }; + D637A12D921733D3173960A61DB8AE92 /* PFObjectEstimatedData.h in Headers */ = {isa = PBXBuildFile; fileRef = EFC29774AABC76F1B26B97B146F2A1C9 /* PFObjectEstimatedData.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D66BEA50BF7F894CCCA235694CF7590B /* PFInstallationController.h in Headers */ = {isa = PBXBuildFile; fileRef = BC16505461748776619D43C6BDC6A703 /* PFInstallationController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D6B9D996B48B90EB489E54CDC7A9D401 /* BFTask.m in Sources */ = {isa = PBXBuildFile; fileRef = BE404DC24F62FA97CDAEF063B4413139 /* BFTask.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + D6C7199C3F4D973B0E6ACA2C6ACF5FF3 /* PFCommandRunning.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ED668482FAFCC7E2F744E4B45E21C00 /* PFCommandRunning.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D7B46B6BD03E88E70CAECBDCED8F4744 /* PFInstallationIdentifierStore_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F0E8603DBA1064D73E0E7EB92BED0DA0 /* PFInstallationIdentifierStore_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D808382848DE98DF7860D36066C0B58B /* PFPushController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E16ED5531463D4705B39EE950AF115 /* PFPushController.m */; }; + D83032130352AB7F72E4AF6EE0024D11 /* PFDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = E2C63AFAC34B0E794D2603EF0F27DF0E /* PFDecoder.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D8ADDAF044D6B1B3B763D0334FD8BDAD /* PFQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = 616A0DE1DAFFD10BF5A8DD300548447E /* PFQuery.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D8B32C5FF3597EEDD220A394295B194B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + D963CE53920E664E9CAD6F4B834B315C /* BFAppLinkReturnToRefererController.h in Headers */ = {isa = PBXBuildFile; fileRef = AE3D34F74057747813B67E0E716F8275 /* BFAppLinkReturnToRefererController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D97FDB91BBA6D010CA658A611FC4A9A1 /* FBSDKSystemAccountStoreAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C13271F07F590F5CD4297A3A11F07EA /* FBSDKSystemAccountStoreAdapter.m */; }; + D985CD1702B209DE6E69F600B59751DC /* RKURLEncodedSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 10D33DBF4C307AD2EA9D10FA2001F6E0 /* RKURLEncodedSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D9CF728584EBF7AD231EF28A2BB2F158 /* RKErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6380D4168C668F109E1A03B20D714BBE /* RKErrorMessage.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + DA62A034CB079FDF722A66A09E878E5E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6114EBA3A5CB7CB8ECE0A9BEFA6DB026 /* Security.framework */; }; + DA880A2094CF94108583D78E4097D554 /* FBSDKAppGroupAddDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0587E0A5FA037D15DDF1E0DD7E70CD5D /* FBSDKAppGroupAddDialog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA957B3EC09252118B3E9ABE033421A5 /* PFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = D9283FF2298CF4AB76D39E0BB4601791 /* PFAnalytics.m */; }; + DA96A28C136407B16A3F0C70656042AF /* FBSDKProfilePictureView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11A34265733816DD6719407EE51BEDD9 /* FBSDKProfilePictureView.m */; }; + DAD881A7C7DDA8848FF17E18DB99295C /* PFRESTQueryCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 118B70D2949B865CA76511460D9D0C92 /* PFRESTQueryCommand.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DB8CE9C5C660790137E0C7B7364E8E82 /* PFRESTUserCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F097273140B23B664D84C6DF75EE2D1 /* PFRESTUserCommand.m */; }; + DCA33BB2A983A45F3617A576ACBC26E1 /* PFDefaultACLController.m in Sources */ = {isa = PBXBuildFile; fileRef = F51B8874D2E27F0F4E6BB3A745216087 /* PFDefaultACLController.m */; }; + DCF16A999DCFC281A8744148B305482C /* FBSDKServerConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DC702CD32C7B1F95EBB4525985776E1A /* FBSDKServerConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DD60532519B073DDC5A56E7426B983B4 /* PFRESTFileCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D5F29001AB83C450101AC6122BCC4EA0 /* PFRESTFileCommand.m */; }; + DDAB1F17EC68C8B719BA8C80FB5DC317 /* FBSDKURLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E03B26327B08731B36701D28A33B9C9 /* FBSDKURLConnection.m */; }; + DE479B83E277F9913E9A6CBE17BD6B3E /* FBSDKAppGroupAddDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 782AF7A5FC9A3571F42003CD07FE5A3C /* FBSDKAppGroupAddDialog.m */; }; + DE61C9B48F5213CCAB8012BE4C261842 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6114EBA3A5CB7CB8ECE0A9BEFA6DB026 /* Security.framework */; }; + DF5A96668809AF7FF9E04130C5D9A1D2 /* PFTaskQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CE3CC21857556B51CB17BCFCF1EE7B1 /* PFTaskQueue.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DF6FA2E0FCB935C5FF9824699BF32C2F /* PFLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = AEA3B8A0B629E223E8AD2FFCA8C65F21 /* PFLogger.m */; }; + E03421EE59E06D90EC9F0E07B93E1C2D /* FBSDKColor.h in Headers */ = {isa = PBXBuildFile; fileRef = D68CBFCA3F276272B2040E6469C8D1DE /* FBSDKColor.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E0614739E177590ABDB7BE575E24118C /* PFCloud.h in Headers */ = {isa = PBXBuildFile; fileRef = EC54205F1719C5C45D60A2253F84C5ED /* PFCloud.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E06A12A765D316CFB2E9E26FB48C3AC1 /* PFPushState.m in Sources */ = {isa = PBXBuildFile; fileRef = 939D831BAB14BEA5394F15D3E348976C /* PFPushState.m */; }; + E0724D062B05BEC513826196D0DF36F2 /* PFSessionUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 72C1FA5A8BDBCEC19E41771957BEB9E3 /* PFSessionUtilities.m */; }; + E0DEC8F4B52DC0BDAD4F633262232B7D /* PFURLSessionFileDownloadTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 423887AF6686942102218A073BC526E2 /* PFURLSessionFileDownloadTaskDelegate.m */; }; + E0E49C694EE64CD46539BAD3D4F08AC9 /* PFRole.m in Sources */ = {isa = PBXBuildFile; fileRef = 66754BB67AA131A94D10F42D109E8523 /* PFRole.m */; }; + E0EAD57AC8EA4C3510C04CDDC9A28DE6 /* FBSDKBridgeAPIProtocolWebV2.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A17ADE2F078B621C983D99D2F0F0047 /* FBSDKBridgeAPIProtocolWebV2.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E10A2574E0EE99F47BC9CAC0AF33FC47 /* FBSDKAppLinkUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = C651AC06095B97EDAEF872B6D7032F4E /* FBSDKAppLinkUtility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E10ED2683F83860B93799B1241CE8C22 /* RKNSJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB19F616008A121FAA50E14B62D67A0 /* RKNSJSONSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + E159EF1028A9794B189D47DD79C6A0CC /* FBSDKAccessTokenCacheV4.m in Sources */ = {isa = PBXBuildFile; fileRef = B352E84B1EE885140F4F4DC84329D6CB /* FBSDKAccessTokenCacheV4.m */; }; + E15B9B510B4BFB5AAF2F8BFAC5EBC997 /* BFCancellationTokenRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = F22636EFE5E1A5651E0A1520C5F281E5 /* BFCancellationTokenRegistration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E19528B349AA57299BED8F28FFCDB92D /* FBSDKErrorConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 49B69C4B030D1D72B8261D35EB560A56 /* FBSDKErrorConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E1A643D9DE8D164F5D1179CF5117F763 /* RKMappingTest.h in Headers */ = {isa = PBXBuildFile; fileRef = CA3CB4DD07E35F520C793BA9032F51FC /* RKMappingTest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E1B5FD2855EE2B8E7393E7DB0C494946 /* FBSDKLoginButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DD91926B9C031018B2F9CB9019718F3E /* FBSDKLoginButton.m */; }; + E228987782C3CA4BC276D56CD25AA911 /* PFURLSessionDataTaskDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 701190361150FF2EEDEF10D05ABE7065 /* PFURLSessionDataTaskDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E2360651E2E5A293C9E59863EC157308 /* RKObjectMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD34821324463B1C81B2802AFA7B01C /* RKObjectMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + E288DE93014B057EC4C1871E17F3FA89 /* YALTabBarItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 44A2841E1C0E28AFEE0B7288D6E47D4E /* YALTabBarItem.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E2D2F28DE8D25857A0143D0C99E1264C /* FBSDKShareOpenGraphContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 97F4FC4FF392B72657F42F96261BBC3F /* FBSDKShareOpenGraphContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E30BD9620B97DF000E8F31104048D432 /* FBSDKServerConfigurationManager+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DB170D4C4F763AED7B36159D448013E /* FBSDKServerConfigurationManager+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E346D04E3F0539B358C1194F02FB8809 /* FBSDKLikeButton+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DEFDD3A6DB314308247D22FF14AFA98 /* FBSDKLikeButton+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E347F996B822D8480FF7B718185C46DD /* BFAppLinkReturnToRefererView.h in Headers */ = {isa = PBXBuildFile; fileRef = 5444C22939A582C105AC91CE65D666F4 /* BFAppLinkReturnToRefererView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E35FADAE8EF72A1419545CEE70610D27 /* FBSDKPaymentObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = B163A0D63692C83B09ED63F3D357CC5D /* FBSDKPaymentObserver.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E459591E18120BB2457AA3AB88FD94E5 /* RKTestNotificationObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0EDCBE9EDEE91346EC864E690AF4D08E /* RKTestNotificationObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E461DC7FBE41300801EE6D160AE29860 /* FBSDKServerConfigurationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 21E3824444DF9349B08182DF250A028D /* FBSDKServerConfigurationManager.m */; }; + E46B5DC4D2646D5DD81881A2D4EA57F0 /* RKISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = D68125D407CB86FE46338C7579765331 /* RKISO8601DateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E47D4E86203EFA7643A44E5109117967 /* FBSDKGraphRequestConnection+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7239EC1173010662F747781299C375DA /* FBSDKGraphRequestConnection+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E497F7EAC903A7C28D8CC1FD0D90CCDF /* FBSDKConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 48C62F55A4F3241648089904B527F6D1 /* FBSDKConstants.m */; }; + E538CE431B0B1742D219C8D91483FDEA /* FBSDKLoginTooltipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 335A3DE810AEDFE589A9325169A59E46 /* FBSDKLoginTooltipView.m */; }; + E544AA008F4106DB432AFF71DD5B5654 /* PFUserAuthenticationController.h in Headers */ = {isa = PBXBuildFile; fileRef = A36C3225AB6FDE49BE8F8859C30A7D7D /* PFUserAuthenticationController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E571D44B22235633760C6FB955906D99 /* FBSDKShareVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = E6D171B8D3792811D774B92580727FAB /* FBSDKShareVideo.m */; }; + E5BE3915A6A2859B581A8300E69A2B8E /* PFWeakValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C91AECE7686A27F9032A4DCC43165E /* PFWeakValue.m */; }; + E65B5BAA6FD361DED892118A76ECF21E /* FBSDKLoginManager+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 20B8F6A2F2E484CD2E09B61345C563A0 /* FBSDKLoginManager+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E6D6A687F8FD1088F5EBB283308B0DC2 /* FBSDKGraphRequestPiggybackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A473C610615EE15F20D33C59B9CC54B8 /* FBSDKGraphRequestPiggybackManager.m */; }; + E6E0B008759D9B3D9EE25FD2FE56E715 /* YALAnimatingTabBarConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 57319DCE064A4F4C9DD2D290FD88D642 /* YALAnimatingTabBarConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E704C533E6A5D7805AAF9761C8017D51 /* RKMIMETypeSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 93EE612E26F15D494EE5870F082534C2 /* RKMIMETypeSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E7A1E7F0498A21036EE756DA807E34B0 /* PFKeyValueCache_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E043164BEB509D5E2D2B9698903390E7 /* PFKeyValueCache_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E7AC21B4D847D0F421132DCD478589F6 /* FBSDKBridgeAPIProtocolType.h in Headers */ = {isa = PBXBuildFile; fileRef = 568C2C82ED942F4F6D68EBFBDD16316F /* FBSDKBridgeAPIProtocolType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E7C91F488C152026DF77891E905E49BC /* PFACLState.m in Sources */ = {isa = PBXBuildFile; fileRef = 62BEED70070D14A0FF9C95200AA22741 /* PFACLState.m */; }; + E81433D0931C25789180EA53A62C940E /* FBSDKBridgeAPIResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E7F67EBB1F0265AF0F708FA1006B162 /* FBSDKBridgeAPIResponse.m */; }; + E81D0A4FB179B72572B6E7521484EB16 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */; }; + E92D54EC2B8A52C24D9C34F2A37F2996 /* PFURLSessionJSONDataTaskDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 3198F91D01D488AAEE2E37C91C36109C /* PFURLSessionJSONDataTaskDelegate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E936CBE6114F820C4E7408AC11114C9F /* UnitBezier.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CFCEB3A58ECB73BB6D930BB1A66A2DE /* UnitBezier.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E97B61F439BAE5B0BC4AE0382AF6E4B3 /* FBSDKPaymentObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D1A4CAC7340A038BDCFECC7E0BFE95 /* FBSDKPaymentObserver.m */; }; + E998F4250A20099ECF4980ECA881988E /* PFUserConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 616C83AFE6D3B13DB326EFFDA4E56218 /* PFUserConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E9BBD9ED8781DB4B08B9A35068B2E0D9 /* FBSDKSharingButton.h in Headers */ = {isa = PBXBuildFile; fileRef = D80B172E70B3B5E8CAEA6069D1DE5D71 /* FBSDKSharingButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EA3208DE2E2A3C5B240A0C832A77DDCF /* FBSDKTriStateBOOL.m in Sources */ = {isa = PBXBuildFile; fileRef = 592AA9AF2651D5C86E7E8D122F958616 /* FBSDKTriStateBOOL.m */; }; + EBB6F0BB04FCFC82D12723EF3E740261 /* FBSDKLikeControl+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BB0273CAD372752E68ECCBCD48E5842 /* FBSDKLikeControl+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EBE1D926D326775167E082772E23D000 /* FBSDKShareOpenGraphObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 224595D0364E886259E4B2F44C937D02 /* FBSDKShareOpenGraphObject.m */; }; + EC5F8395D48ED1C0BE2C2D7EB7D9F4B9 /* BFTask.h in Headers */ = {isa = PBXBuildFile; fileRef = D2A208C22FB8BC1DAFD34F05A88E7349 /* BFTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EC7025C98AE47F5E2D9CBEA4AC041890 /* Bolts.m in Sources */ = {isa = PBXBuildFile; fileRef = 20D1F9C0BECD5D6036F5F1A63383C39D /* Bolts.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + EC988E57B95BF4C3D8D67B5A3B382A8C /* PFMutableACLState.m in Sources */ = {isa = PBXBuildFile; fileRef = 24B58875AADE4ED78AB3942781E1AECC /* PFMutableACLState.m */; }; + ECECB6E62DA076603D8F2A805641CA27 /* FBSDKLoginKit.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB4D0E3F5DD747BCD44340E26E9755F /* FBSDKLoginKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED4ECDAC11F885A77723CE05B89A65AA /* AFHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 7771BB9434E69A691392A0970DD10E28 /* AFHTTPRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED6709D08D9B015AB6FC3F9A6B207DD3 /* RKManagedObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 078AB2530E4CDAB1E634AE38A5545949 /* RKManagedObjectRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + ED6B6D31DCF0E36BB88E225710AA83DB /* PFInternalUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = A3FBF62848DF8B263E30542353335091 /* PFInternalUtils.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ED6FD3AB4D6A18C000AEA269BC8D7F29 /* RKManagedObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BECD1A40487A504B56D704C9D21E36C /* RKManagedObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EDB2BA3AEA3A7A4EC735BAF9804D75D4 /* FBSDKShareVideoContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 56EDB2104DA13588CD5B4334FF77452F /* FBSDKShareVideoContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EDE804E78EDBA4011460F800C7E8F9FB /* RKRelationshipMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DAAC9A8E0D5362E749A6821734AF0 /* RKRelationshipMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE0DAF5E510D971C9A34D617DA2438EC /* PFObjectState.m in Sources */ = {isa = PBXBuildFile; fileRef = DC865D74F3C01339E7A0C969FDED834E /* PFObjectState.m */; }; + EE76A64B08255C079A379BC77864B85F /* FBSDKProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C86B91E8FA37A02DFCBC13C26C5599E /* FBSDKProfile.m */; }; + EED88C9780961006A6F988AFECD7BED3 /* FBSDKLikeBoxBorderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 95C0B6DA20609F0B05D9D1AB1D2FC475 /* FBSDKLikeBoxBorderView.m */; }; + EF10BDF15001F7DFC2CB2B2F898A40B9 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 55B8770724B1C27628F366C0CF2D3B85 /* RKPaginator.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF254F401AD05830A53E37EB6ED1A20D /* PFOfflineQueryController.h in Headers */ = {isa = PBXBuildFile; fileRef = B6D4806630F08E4A693BB13FD80E2B85 /* PFOfflineQueryController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EF38756A5556C26335245407A2D3C876 /* FBSDKLoginCompletion.m in Sources */ = {isa = PBXBuildFile; fileRef = BBB5809E48E2B4BEFFDD671C03A673A1 /* FBSDKLoginCompletion.m */; }; + EFB0AF9D9768F6BD8723FFCB40AD7D39 /* PFThreadsafety.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BDC71820826E3AC85B7BE2E689790EA /* PFThreadsafety.m */; }; + F060AADC6126A31918F62A205D714C32 /* PFUserAuthenticationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 40E39D31FE7DC01DD03AA4AF8530EC8D /* PFUserAuthenticationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F10CE2BA1CE785FB8EC2CE0595A7FBBE /* FBSDKLikeActionController.m in Sources */ = {isa = PBXBuildFile; fileRef = ECF9B9F2BA04D70CD7253751FF94CCD5 /* FBSDKLikeActionController.m */; }; + F1B80D56445F494B2F82BB577E4CB42A /* FBSDKShareOpenGraphValueContainer+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = F42B1B0D93B9783D48D27AAF873BC978 /* FBSDKShareOpenGraphValueContainer+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F1FB40054787172F5817A61DF16AA000 /* PFProductsRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2246103381BDCE264B43C19253CCF7C6 /* PFProductsRequestHandler.m */; }; + F21561635F6B62CFBA1A70ED0D86BE5A /* PFFileState.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F16209AB717FBAFF4C2730320EF9840 /* PFFileState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F2614C38AA4BB27104AD7BAB99E2BDD3 /* FBSDKSharingContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 3ACEDF4D677834B067A9DD0F82954897 /* FBSDKSharingContent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F2948A142B6234A6E12DF2AD5FC390CF /* PFObject+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D1361066E091AA4FB6E9B94B50118177 /* PFObject+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F3D8FC254CCC51A7FBC764EDCF823A3C /* POPVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 64E0C0D87C1527E39C8527751DB7D005 /* POPVector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F3F9AFABE12CF6EF4371A4A8DC5C9D46 /* PFPurchase.h in Headers */ = {isa = PBXBuildFile; fileRef = BF0336CCD7C95A339E279331D898870E /* PFPurchase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F48F08F807C465B2DC535CE521E66D97 /* FBSDKLikeBoxBorderView.h in Headers */ = {isa = PBXBuildFile; fileRef = CF478811F261A5C3A4200EF18BD59E46 /* FBSDKLikeBoxBorderView.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F4F96AF7AC5C83FA96E172128610B1F2 /* FBSDKBase64.h in Headers */ = {isa = PBXBuildFile; fileRef = 2784369F5F5CCA4ADE551377F245E131 /* FBSDKBase64.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F50BE85096146332D4C00C17546561DA /* BFCancellationToken.m in Sources */ = {isa = PBXBuildFile; fileRef = D340DC8D2BC61B7C8A044A46F47ED4D0 /* BFCancellationToken.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + F53BB2B5B2739CED55C0738568C22BE0 /* PFQueryUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 76EDBE5B4444693672560F0B38D5C4D3 /* PFQueryUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F54F01DCDD820F6EF621E915C1BF6E0D /* AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F529E412A09BF39D8AEC42AFFDF2F46 /* AFNetworking.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F636A430FBAA6F63A249AD7B432C57CD /* lcl_config_logger_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = C3B87B3E4AC8A18214858CF42A599D50 /* lcl_config_logger_RK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F6439BF34231EC9F4CBB3F01C862CEFA /* PFJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F93FF0560F945FADCA311FD06CA31D3 /* PFJSONSerialization.m */; }; + F69121DAB7F11950A7942C4D70A1B556 /* RKPropertyMappingTestExpectation.h in Headers */ = {isa = PBXBuildFile; fileRef = 10FAFCCD6FB4FC9E877FCB27902EA1F7 /* RKPropertyMappingTestExpectation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F6B3F611DF383CE5E1E8E62665449291 /* TKStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD657A091CF82605FA8A0100D16E83E /* TKStateMachine.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F6C1716F0805EA68532FF09E380B40D7 /* BFWebViewAppLinkResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = EED2B7513CB5A03507BE982601143DEC /* BFWebViewAppLinkResolver.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + F7077CE67CBD9DAAAE91FBED372BA0CD /* PFURLSessionCommandRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 327724504C5129C28E647306963F3042 /* PFURLSessionCommandRunner.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F728C30DC692908961A286369C3A5D56 /* PFMultiProcessFileLockController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E79E027951925EA1691B4B8E395973 /* PFMultiProcessFileLockController.m */; }; + F743978153F2A7013B2066B1B306E5F5 /* PFUserAuthenticationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 16AA732281290E4169524C7073D0E8C9 /* PFUserAuthenticationController.m */; }; + F751CEADDC757850DAE30E3411FD494D /* POPAnimationExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = EF2907AA3AD4FE98405EC818A63855DA /* POPAnimationExtras.mm */; }; + F7A16A60215390EB56EFF7E65F4CF803 /* PFMutableRelationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B162D277A2037FD2A114DD8C9CB5922 /* PFMutableRelationState.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F7B6B5468F0E365CBF4AC5F003E17684 /* RKOperationStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A3FF0A4A486E57DD176B3DF5F619173 /* RKOperationStateMachine.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + F7CC6A2F5288951581078FA3B7C9A215 /* PFObjectFileCodingLogic.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E44BCC5A1A8313C135B429B4AA92FE8 /* PFObjectFileCodingLogic.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F7DD4882D66BDDF093E01A1050E60F2E /* PFApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = B78A7E4B40882223B829568BDECFF65F /* PFApplication.m */; }; + F7E42776080FF0BDBE07365A2AFE2834 /* FBSDKLikeBoxView.m in Sources */ = {isa = PBXBuildFile; fileRef = A473E7C40F24CE11C1FE9F416C8E5EC2 /* FBSDKLikeBoxView.m */; }; + F9198070ED60C8E1F3AF0910B05EA446 /* FBSDKLikeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 64264592576D6C230E966AC098067DAB /* FBSDKLikeButton.m */; }; + F935343777FB6C7405A086E0FA59F28C /* TransitionKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 83319D45D8AE5D8BF57D365983A41750 /* TransitionKit-dummy.m */; }; + F9814C410ADDB3A0797E70914157D3A0 /* FBSDKLoginUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = DB72A1AC246E5FC4E81A0DBB8B1F0737 /* FBSDKLoginUtility.m */; }; + F9A49E306CE246D7F327C43091688131 /* FBSDKLoginCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = 763D59D54C57DA2AAFAD336EE912908D /* FBSDKLoginCompletion.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F9DC54B44C2DA79FEE1FE863F3185504 /* PFGeoPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 40DC3C427F03295338C11BDDD89C3D2A /* PFGeoPoint.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FA27E23894DFC2F77A0EA14C2D1A3DD4 /* FBSDKMonotonicTime.m in Sources */ = {isa = PBXBuildFile; fileRef = 26A9B6AD16C16524DC90D9F1759B3E86 /* FBSDKMonotonicTime.m */; }; + FA3330484B355C821E59E5DE1C0BA454 /* ObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = C647E341C56F994FDA336B094DDC681B /* ObjectMapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FA8E3B41E8BBAC3A94F8040161250867 /* PFErrorUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = E5FEF8F1937676245479BD46246EE956 /* PFErrorUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FAE3BF2AD91A39EB7B33F722AB050FDF /* Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = B25EAE7B7171B287489EDA0C0A129426 /* Testing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FB1E08557D01F434CD5C340084CC4AE1 /* RKValueTransformers-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A1C16BDC310A2EF19DE55901CD5B41 /* RKValueTransformers-dummy.m */; }; + FB27D03B5B38BC7F5B6E70EF758693B9 /* PFEventuallyQueue_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 33D917AEA2C6B3BD1FB6DE5E32B94689 /* PFEventuallyQueue_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FB9237E38009CB01D2D2BC136D5924B7 /* BFCancellationTokenSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D147E7F72F838ED5D3C66A4E3546EC11 /* BFCancellationTokenSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FBFCD80E29C5DB1702D3FB255115D1C5 /* PFUserPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EBA7EC1BD2D3653F709A5C97063B990 /* PFUserPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FCAB2361E009734F6BE467ED760F2E00 /* RKURLEncodedSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F756E1A3BA52E99D6635DE49C0331CB /* RKURLEncodedSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FCDC22BD5A90775000A728831060EDCC /* BFCancellationTokenRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE55AE735F6A67726031719677B1B38 /* BFCancellationTokenRegistration.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FD2A1B5A3B8F58A419B8030AB3B0C900 /* PFOperationSet.h in Headers */ = {isa = PBXBuildFile; fileRef = F918BC0806DF4B41E1EF8762440B3FAF /* PFOperationSet.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FD60C452AEB7A05724E5BC76D389C794 /* RKHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9086156C9220E522C597B7BE572F6BFB /* RKHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FDF39F9BC888D9146BC087518C89A8F6 /* FBSDKTypeUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 220DF0DD34431D9668F2D2A15D25B3E7 /* FBSDKTypeUtility.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FE0C5ACB05FF0C1803B48C2A0FDBFB2D /* POPBasicAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CDA9E34CFAB4648EC74D9ED76EF02AC /* POPBasicAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FE44D1FCA03026E71140FBE5FE12FBAA /* RKObjectRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = A8E3AF8A6E915006D004A9CF92CA325D /* RKObjectRequestOperationSubclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FEAB4AF7F2C57BDEFD6081038CFD20FB /* FBSDKLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 9860C0C7692D5A2C0C40448F5323C485 /* FBSDKLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FF185ADF983855172EE9FA3D34A91DD6 /* POPDecayAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55795C67F8572CA13753F14AC059940B /* POPDecayAnimation.mm */; }; + FF6C07931C151FAE59F3FB55F032AF23 /* FBSDKAppEventsState.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1059A8B21D1214B8EA1A8BCF6B2CE5 /* FBSDKAppEventsState.m */; }; + FF7920785C7F9A6CBCDBFB44A8C63791 /* PFObjectFilePersistenceController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1906627F9057BDB4DC26FC8D67A0AD0D /* PFObjectFilePersistenceController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FFEDBF912F4CF43D78BC4F4331F09059 /* PFAnalyticsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D9C8B62E94BADCE53C2B3A336B91A66 /* PFAnalyticsController.h */; settings = {ATTRIBUTES = (Project, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0AF81BBB1D00CE9364E007A09C3C2829 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = A48601FEE4437A924848DB48369BA809; + remoteInfo = Bolts; + }; + 276A34C32823D237C256532097A068EB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C78CAB9013653EB1A250B2DFD3BC7666; + remoteInfo = FBSDKShareKit; + }; + 302ED64CEF8BCEB768A5A5686F9E9202 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 81D7FE2A0FD9258247B1232874B837DA; + remoteInfo = FBSDKCoreKit; + }; + 4201516B1237D71DE5D182C3E05A7889 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C47E006176ABF4755350B88C088C3F0D; + remoteInfo = RKValueTransformers; + }; + 5F9ACE740BBE74B9EF18ED10D402EBFB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = A48601FEE4437A924848DB48369BA809; + remoteInfo = Bolts; + }; + 675BFDC98D3AE67CA01D558BDCB9A6B7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4E286D373D75563CE26E479A68203892; + remoteInfo = FBSDKLoginKit; + }; + 7FC4D59C7661F1F90B9637A4AA76565C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C47E006176ABF4755350B88C088C3F0D; + remoteInfo = RKValueTransformers; + }; + A909E61D233546F6A1FB381F7E377CA7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 080AF914A09167DB5759A733917B840F; + remoteInfo = ISO8601DateFormatterValueTransformer; + }; + A94178143C22B923AD7FB31DE66228B0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = A48601FEE4437A924848DB48369BA809; + remoteInfo = Bolts; + }; + AF0BFB883EC6A98CD8AE8E24C8F426B1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0EB292B9319B2DAFB20D9A12B70C9D45; + remoteInfo = RestKit; + }; + B1A299548977B6ABB67A7B67B42367D6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 080AF914A09167DB5759A733917B840F; + remoteInfo = ISO8601DateFormatterValueTransformer; + }; + B523CD37BCE78A7AE1C6DB51DA33B0C8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 05AF921757BAF218468C62708B020AA6; + remoteInfo = TransitionKit; + }; + BAACCA3BC071717750DC231D62B73AD2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 61681BF0E677683490353B846C61A129; + remoteInfo = AFNetworking; + }; + D0849CD3CF9A05520CE20A883B2B4F39 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C47E006176ABF4755350B88C088C3F0D; + remoteInfo = RKValueTransformers; + }; + D1818ED7610953D782FE1124E1218D77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 05AF921757BAF218468C62708B020AA6; + remoteInfo = TransitionKit; + }; + D38BE89B6FB2301AC09AD26156B819E8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 81D7FE2A0FD9258247B1232874B837DA; + remoteInfo = FBSDKCoreKit; + }; + E06E7B292C6EE211982F723016ADBF4B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5366B7F679CF2BA31EA583EA35CA2D90; + remoteInfo = Parse; + }; + E530D725F329BCA4799A9262ABCAE598 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD71C0AD634DC4E364BC189688A42294; + remoteInfo = pop; + }; + E92B930C85A1D208110782E0EDC04E3C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = D8FDBC10A40DB83968987CBA76E4F7DD; + remoteInfo = SOCKit; + }; + F2525FB3B5405DC4B1BAF37F01F4D2AB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 81D7FE2A0FD9258247B1232874B837DA; + remoteInfo = FBSDKCoreKit; + }; + FAD9FE9F58E1BE6A32DD807949F6E4A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 9145E070690055EA2D82D264E78B0F71; + remoteInfo = FoldingTabBar; + }; + FDFB1A8326188F82A80CD07E5ACA2D87 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 61681BF0E677683490353B846C61A129; + remoteInfo = AFNetworking; + }; + FE69D65D7B77276503ADD40689F26FD5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = D8FDBC10A40DB83968987CBA76E4F7DD; + remoteInfo = SOCKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00867696A579EF950503FFC6BFDC74DD /* AFNetworking-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "AFNetworking-prefix.pch"; sourceTree = ""; }; + 011534C01155F79E4047CADDE68EF6B8 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 012EA998B79C045DB5F3DF0D066F78B1 /* PFCurrentConfigController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCurrentConfigController.m; path = Parse/Internal/Config/Controller/PFCurrentConfigController.m; sourceTree = ""; }; + 01A50C2394596A1AAF49C7A2877C776E /* PFPurchase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPurchase.m; path = Parse/PFPurchase.m; sourceTree = ""; }; + 02AEBA17B69A4D55F659D4F44440127E /* ParseManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ParseManager.m; path = Parse/Internal/ParseManager.m; sourceTree = ""; }; + 030B329DF20766AE685434CD734BC3B2 /* PFRESTSessionCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTSessionCommand.m; path = Parse/Internal/Commands/PFRESTSessionCommand.m; sourceTree = ""; }; + 033F7B99C3A65CD435C0B7A09C59F876 /* RKResponseMapperOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKResponseMapperOperation.h; path = Code/Network/RKResponseMapperOperation.h; sourceTree = ""; }; + 03549C9A2FD883CD12D063617A47E0D3 /* FBSDKLoginManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginManager.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.m; sourceTree = ""; }; + 03B64D2A236E8A41E92A66B21F198BFB /* FBSDKCoreKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FBSDKCoreKit-prefix.pch"; sourceTree = ""; }; + 03C91AECE7686A27F9032A4DCC43165E /* PFWeakValue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFWeakValue.m; path = Parse/Internal/PFWeakValue.m; sourceTree = ""; }; + 044941FE89AB594A010087B94F17D923 /* FBSDKLoginError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginError.h; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.h; sourceTree = ""; }; + 04E79E027951925EA1691B4B8E395973 /* PFMultiProcessFileLockController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMultiProcessFileLockController.m; path = Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.m; sourceTree = ""; }; + 0587E0A5FA037D15DDF1E0DD7E70CD5D /* FBSDKAppGroupAddDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppGroupAddDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.h; sourceTree = ""; }; + 05A46A1CCAAB75FBBA2C67F460435143 /* POPCGUtils.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPCGUtils.mm; path = pop/POPCGUtils.mm; sourceTree = ""; }; + 05D4509ED8E7E863F79C2BDF6FE4471C /* FBSDKShareOpenGraphAction.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareOpenGraphAction.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.m; sourceTree = ""; }; + 06292442821AF9572A443AF0D949122D /* FBSDKAccessToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessToken.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.m; sourceTree = ""; }; + 0648A7B89F8F0C429E649E87FBFBD699 /* PFPurchaseController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPurchaseController.m; path = Parse/Internal/Purchase/Controller/PFPurchaseController.m; sourceTree = ""; }; + 0673474C0D02C740FB04EE10B58213D9 /* RKObjectUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectUtilities.m; path = Code/ObjectMapping/RKObjectUtilities.m; sourceTree = ""; }; + 06FB17807D8F9BB90C006F1AA1422EEB /* PFSQLiteStatement.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSQLiteStatement.m; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.m; sourceTree = ""; }; + 078AB2530E4CDAB1E634AE38A5545949 /* RKManagedObjectRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKManagedObjectRequestOperation.m; path = Code/Network/RKManagedObjectRequestOperation.m; sourceTree = ""; }; + 07D8A98D56E6D538D6FA0B232BBCBA03 /* PFEncoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFEncoder.m; path = Parse/Internal/PFEncoder.m; sourceTree = ""; }; + 0803B22C601D5D4145A1B91DB87E04E3 /* RKMapperOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMapperOperation.m; path = Code/ObjectMapping/RKMapperOperation.m; sourceTree = ""; }; + 0842DD1DCDFD9683C89B6A9078E9D0FC /* PFRESTQueryCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTQueryCommand.m; path = Parse/Internal/Commands/PFRESTQueryCommand.m; sourceTree = ""; }; + 092AA11ADB8FDDCC538A0ABDD75F38E8 /* PFUserController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserController.h; path = Parse/Internal/User/Controller/PFUserController.h; sourceTree = ""; }; + 09343BA3B921E20A6185A17744E53B63 /* POPCGUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPCGUtils.h; path = pop/POPCGUtils.h; sourceTree = ""; }; + 099E673F2FD9E7D461C9590B6D38BA1F /* PFUserState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserState.h; path = Parse/Internal/User/State/PFUserState.h; sourceTree = ""; }; + 09A74F4E5B1694ED02FEFEE3567FD5C4 /* POPCustomAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPCustomAnimation.h; path = pop/POPCustomAnimation.h; sourceTree = ""; }; + 09BC6A273BD14FEC82E66ADE94F2D7AB /* RKPathMatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPathMatcher.m; path = Code/Network/RKPathMatcher.m; sourceTree = ""; }; + 0A1EA9C9D41AE2090A25AEB7774EFF7F /* PFHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFHash.h; path = Parse/Internal/PFHash.h; sourceTree = ""; }; + 0A36A67D8095CA8BA88F3D9C867BF723 /* RKRouter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRouter.m; path = Code/Network/RKRouter.m; sourceTree = ""; }; + 0A7261E40A7493778EDD34738B42676E /* PFBase64Encoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFBase64Encoder.h; path = Parse/Internal/PFBase64Encoder.h; sourceTree = ""; }; + 0B0314DD062570E8416F2523D03B9EF6 /* PFLocationManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFLocationManager.h; path = Parse/Internal/PFLocationManager.h; sourceTree = ""; }; + 0B843EB1DFCFEE6E5EE55AC6767E4E13 /* FBSDKShareError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareError.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.m; sourceTree = ""; }; + 0B8AE15FBFEC0BE016020B8970ADE865 /* BFCancellationTokenSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenSource.m; path = Bolts/Common/BFCancellationTokenSource.m; sourceTree = ""; }; + 0BAE999CCCB6D83C2D4DFA288FE9C7BF /* PFDevice.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFDevice.m; path = Parse/Internal/PFDevice.m; sourceTree = ""; }; + 0C43080C0B2655A28B3CE9D3DD9B32B2 /* POPAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimation.mm; path = pop/POPAnimation.mm; sourceTree = ""; }; + 0D0B957E23560E8729AFBC541E7F0401 /* PFURLSessionCommandRunner.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSessionCommandRunner.m; path = Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.m; sourceTree = ""; }; + 0D612FDB5856A0B0DC71C9A83AF67537 /* FBSDKShareError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareError.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareError.h; sourceTree = ""; }; + 0D63D25E0D4B1B1573FC3216A3041E64 /* BFExecutor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFExecutor.h; path = Bolts/Common/BFExecutor.h; sourceTree = ""; }; + 0D6A9F671AC5AAF2E4BDEE1D46C1A2DF /* RKDynamicMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDynamicMapping.h; path = Code/ObjectMapping/RKDynamicMapping.h; sourceTree = ""; }; + 0EB6E9BC99D4CE39BCEA9AB574501691 /* PFURLSessionUploadTaskDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionUploadTaskDelegate.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.h; sourceTree = ""; }; + 0EDCBE9EDEE91346EC864E690AF4D08E /* RKTestNotificationObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKTestNotificationObserver.h; path = Code/Testing/RKTestNotificationObserver.h; sourceTree = ""; }; + 0FBD3B84E14ADBD2E513A3522C2777DC /* FBSDKAppLinkResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppLinkResolver.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.m; sourceTree = ""; }; + 0FCED2B89C49FCB98FAE1186D1725F5B /* FBSDKShareAPI.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareAPI.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.h; sourceTree = ""; }; + 0FD81CD43134464279746BA1F66D5A48 /* PFCoreManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCoreManager.m; path = Parse/Internal/PFCoreManager.m; sourceTree = ""; }; + 10475FA9B1F63748681C1D95ED038819 /* PFObjectController_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectController_Private.h; path = Parse/Internal/Object/Controller/PFObjectController_Private.h; sourceTree = ""; }; + 10834806BD7B412BC24F347361FA2C8E /* Pods-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-acknowledgements.plist"; sourceTree = ""; }; + 108401CAD15D4703C0D17F39835C74AE /* PFOperationSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFOperationSet.m; path = Parse/Internal/Object/OperationSet/PFOperationSet.m; sourceTree = ""; }; + 10C11BD85333AB6363CF6EC82E870605 /* PFPushController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushController.h; path = Parse/Internal/Push/Controller/PFPushController.h; sourceTree = ""; }; + 10D33DBF4C307AD2EA9D10FA2001F6E0 /* RKURLEncodedSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKURLEncodedSerialization.h; path = Code/Support/RKURLEncodedSerialization.h; sourceTree = ""; }; + 10FAFCCD6FB4FC9E877FCB27902EA1F7 /* RKPropertyMappingTestExpectation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPropertyMappingTestExpectation.h; path = Code/Testing/RKPropertyMappingTestExpectation.h; sourceTree = ""; }; + 114DF71DB16E01CD9902FA71F5FCB868 /* RKObjectManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectManager.m; path = Code/Network/RKObjectManager.m; sourceTree = ""; }; + 11575C24EBD20B38803926830ED63640 /* PFDecoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFDecoder.m; path = Parse/Internal/PFDecoder.m; sourceTree = ""; }; + 118B70D2949B865CA76511460D9D0C92 /* PFRESTQueryCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTQueryCommand.h; path = Parse/Internal/Commands/PFRESTQueryCommand.h; sourceTree = ""; }; + 11A34265733816DD6719407EE51BEDD9 /* FBSDKProfilePictureView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKProfilePictureView.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.m; sourceTree = ""; }; + 11CBB787D4E85EE9F313E56D6B653B6F /* POPAnimator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimator.h; path = pop/POPAnimator.h; sourceTree = ""; }; + 12148D9B34DE0B074CF161C3B74EA2F9 /* RKObjectParameterization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectParameterization.h; path = Code/Network/RKObjectParameterization.h; sourceTree = ""; }; + 129476AE26D881F46C3F727D95A2D8EE /* PFOfflineObjectController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFOfflineObjectController.h; path = Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.h; sourceTree = ""; }; + 131783F296EC8FE80CA0ACE2C3C056CC /* PFPinningEventuallyQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPinningEventuallyQueue.m; path = Parse/Internal/PFPinningEventuallyQueue.m; sourceTree = ""; }; + 134ACDC2444EE29856334D3196F53AC0 /* FBSDKMessengerIcon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKMessengerIcon.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.m; sourceTree = ""; }; + 136503C1BC94CD505033988EB9C16090 /* PFOfflineQueryController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFOfflineQueryController.m; path = Parse/Internal/Query/Controller/PFOfflineQueryController.m; sourceTree = ""; }; + 1375129BA8E11876FE8F3530124E4FF9 /* PFSessionController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSessionController.h; path = Parse/Internal/Session/Controller/PFSessionController.h; sourceTree = ""; }; + 137AE6FE411D32FD166221B1257A8D27 /* PFQueryController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQueryController.h; path = Parse/Internal/Query/Controller/PFQueryController.h; sourceTree = ""; }; + 138471689F57812BFA9933C75A79A7D5 /* PFUserState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserState_Private.h; path = Parse/Internal/User/State/PFUserState_Private.h; sourceTree = ""; }; + 13B2A7FD3B5E9C5F68CC0E991780A0EC /* PFAnonymousUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnonymousUtils.h; path = Parse/PFAnonymousUtils.h; sourceTree = ""; }; + 13E16ED5531463D4705B39EE950AF115 /* PFPushController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPushController.m; path = Parse/Internal/Push/Controller/PFPushController.m; sourceTree = ""; }; + 1488210FE220BBA6CCA5EBE2C7D73FA7 /* FBSDKTypeUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKTypeUtility.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.m; sourceTree = ""; }; + 1516B2B4A8F91019AE5E4283AA8F5E5D /* PFConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFConstants.h; path = Parse/PFConstants.h; sourceTree = ""; }; + 1635AF96EB71FB3FEBEE52A4395CFA1B /* PFRESTObjectBatchCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTObjectBatchCommand.h; path = Parse/Internal/Commands/PFRESTObjectBatchCommand.h; sourceTree = ""; }; + 163A2E68515F17EBB397973CE01A2E02 /* PFConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFConfig.m; path = Parse/PFConfig.m; sourceTree = ""; }; + 16621039C0E3312C216165BEF8D567DE /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + 16AA732281290E4169524C7073D0E8C9 /* PFUserAuthenticationController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUserAuthenticationController.m; path = Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.m; sourceTree = ""; }; + 1747B6933EBB45F17399984642773739 /* PFCategoryLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCategoryLoader.h; path = Parse/Internal/PFCategoryLoader.h; sourceTree = ""; }; + 17713158760C0CE314D469EF9DAB5E98 /* FBSDKAccessTokenCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessTokenCache.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.m; sourceTree = ""; }; + 17E73976887C42E701026CD6E8B7F4E4 /* FBSDKLoginKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FBSDKLoginKit-prefix.pch"; sourceTree = ""; }; + 1804AEAE0A042ABB0AB0F3B3CCD54B2A /* PFLocationManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFLocationManager.m; path = Parse/Internal/PFLocationManager.m; sourceTree = ""; }; + 1851DD5C5804EC9A837131EDAC8D3EDB /* FBSDKError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKError.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.h; sourceTree = ""; }; + 1851F12158736155A52C64E33E513999 /* RKValueTransformers-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RKValueTransformers-prefix.pch"; sourceTree = ""; }; + 18811D86AFD569DE58C69DE2D674A00D /* lcl_config_extensions_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_extensions_RK.h; path = Code/Support/lcl_config_extensions_RK.h; sourceTree = ""; }; + 1906627F9057BDB4DC26FC8D67A0AD0D /* PFObjectFilePersistenceController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectFilePersistenceController.h; path = Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.h; sourceTree = ""; }; + 190B3059AD121705B18018211A6B6C66 /* FBSDKGraphRequestMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequestMetadata.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.h; sourceTree = ""; }; + 19393B003CB10D5DCBF525994DDE8462 /* PFInstallationController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFInstallationController.m; path = Parse/Internal/Installation/Controller/PFInstallationController.m; sourceTree = ""; }; + 19397C043A357D696BBA9A55EFD5B167 /* PFSQLiteDatabaseController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSQLiteDatabaseController.h; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.h; sourceTree = ""; }; + 19A473DF4573D2A6FDD72DA3BA1C2C04 /* _FBSDKTemporaryErrorRecoveryAttempter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _FBSDKTemporaryErrorRecoveryAttempter.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.m; sourceTree = ""; }; + 19FFE36E5537E1838031F0725CD641C2 /* Bolts.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Bolts.xcconfig; sourceTree = ""; }; + 1ABF2667D317A8E92F4DAB58CAEEB37A /* PFFieldOperationDecoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFieldOperationDecoder.m; path = Parse/Internal/FieldOperation/PFFieldOperationDecoder.m; sourceTree = ""; }; + 1AF2857CEDB6464020434166DEB5A36F /* AFURLConnectionOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFURLConnectionOperation.m; path = AFNetworking/AFURLConnectionOperation.m; sourceTree = ""; }; + 1B162D277A2037FD2A114DD8C9CB5922 /* PFMutableRelationState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableRelationState.h; path = Parse/Internal/Relation/State/PFMutableRelationState.h; sourceTree = ""; }; + 1B1BBDE1A0182E4AAFF80CDBBDF1DAB9 /* FBSDKShareOpenGraphValueContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareOpenGraphValueContainer.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.h; sourceTree = ""; }; + 1B4CFCBF40F579D60F6CA51813334980 /* FBSDKErrorRecoveryAttempter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKErrorRecoveryAttempter.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.m; sourceTree = ""; }; + 1B6241CE08565BB6864AEF668F68FA18 /* PFPaymentTransactionObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPaymentTransactionObserver.m; path = Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.m; sourceTree = ""; }; + 1BDC71820826E3AC85B7BE2E689790EA /* PFThreadsafety.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFThreadsafety.m; path = Parse/Internal/ThreadSafety/PFThreadsafety.m; sourceTree = ""; }; + 1C268AB8BD173983B11C4C2D404A9C57 /* FBSDKTriStateBOOL.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKTriStateBOOL.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.h; sourceTree = ""; }; + 1C6681893EA2BE8AA8ED08B44B774980 /* BFURL.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFURL.m; path = Bolts/iOS/BFURL.m; sourceTree = ""; }; + 1C9E34AAA6316628D1EF4D8BC3CDCAB1 /* POPCustomAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPCustomAnimation.mm; path = pop/POPCustomAnimation.mm; sourceTree = ""; }; + 1CE3CC21857556B51CB17BCFCF1EE7B1 /* PFTaskQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFTaskQueue.h; path = Parse/Internal/PFTaskQueue.h; sourceTree = ""; }; + 1D50729BCCBCCC5A423CBB509507C3DC /* POPSpringSolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPSpringSolver.h; path = pop/POPSpringSolver.h; sourceTree = ""; }; + 1D9362003B89F08493A37902350DA1BC /* libParse.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libParse.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E3783F1A59CCE93EEF653593AFAD5B5 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CoreLocation.framework; sourceTree = DEVELOPER_DIR; }; + 1EA0BB06D8B077DFC855CBF92505F74A /* RKErrorMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKErrorMessage.h; path = Code/ObjectMapping/RKErrorMessage.h; sourceTree = ""; }; + 1EC237868E24D8CCBA8AA21DB4F43584 /* FBSDKAppEvents+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKAppEvents+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h"; sourceTree = ""; }; + 1EE55AE735F6A67726031719677B1B38 /* BFCancellationTokenRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenRegistration.m; path = Bolts/Common/BFCancellationTokenRegistration.m; sourceTree = ""; }; + 1FB151E5B82946D404F611FAC81C546B /* FBSDKAccessTokenCaching.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCaching.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h; sourceTree = ""; }; + 1FC50F7EF899B70145D9D7DB1F55E927 /* PFInstallationIdentifierStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallationIdentifierStore.h; path = Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.h; sourceTree = ""; }; + 20512742319C64711FFF5148A7214E8D /* PFObjectControlling.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectControlling.h; path = Parse/Internal/Object/Controller/PFObjectControlling.h; sourceTree = ""; }; + 205214C203BF751A124F1153AD9CBA8E /* PFWeakValue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFWeakValue.h; path = Parse/Internal/PFWeakValue.h; sourceTree = ""; }; + 207C347476CAA87AD1032D236FA290A2 /* en.lproj */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder; name = en.lproj; path = Parse/Resources/en.lproj; sourceTree = ""; }; + 209E38BB2ADFFA4C0E2497F629810AEB /* PFHTTPRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFHTTPRequest.h; path = Parse/Internal/HTTPRequest/PFHTTPRequest.h; sourceTree = ""; }; + 20B291B44372ECD90FA4961CB9F9C9C4 /* RKPropertyMappingTestExpectation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPropertyMappingTestExpectation.m; path = Code/Testing/RKPropertyMappingTestExpectation.m; sourceTree = ""; }; + 20B8F6A2F2E484CD2E09B61345C563A0 /* FBSDKLoginManager+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLoginManager+Internal.h"; path = "FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManager+Internal.h"; sourceTree = ""; }; + 20D1F9C0BECD5D6036F5F1A63383C39D /* Bolts.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Bolts.m; path = Bolts/Common/Bolts.m; sourceTree = ""; }; + 20EA58DC0A0DC1E01333E2DC71658378 /* FBSDKInternalUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKInternalUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.h; sourceTree = ""; }; + 20FCD32AE2B10221B23EC19A5B380953 /* PFReachability.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFReachability.m; path = Parse/Internal/PFReachability.m; sourceTree = ""; }; + 21E3824444DF9349B08182DF250A028D /* FBSDKServerConfigurationManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKServerConfigurationManager.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.m; sourceTree = ""; }; + 220DF0DD34431D9668F2D2A15D25B3E7 /* FBSDKTypeUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKTypeUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTypeUtility.h; sourceTree = ""; }; + 224595D0364E886259E4B2F44C937D02 /* FBSDKShareOpenGraphObject.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareOpenGraphObject.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.m; sourceTree = ""; }; + 2246103381BDCE264B43C19253CCF7C6 /* PFProductsRequestHandler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFProductsRequestHandler.m; path = Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.m; sourceTree = ""; }; + 22E1D8AA11E50E9A37281052037D86FF /* PFURLSessionDataTaskDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSessionDataTaskDelegate.m; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.m; sourceTree = ""; }; + 22F77D342CCB58DBAA7457C6289C028C /* PFInstallationConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFInstallationConstants.m; path = Parse/Internal/Installation/Constants/PFInstallationConstants.m; sourceTree = ""; }; + 231F7C139C4CE6856490CCC6331A4BB0 /* FBSDKCoreKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FBSDKCoreKit-dummy.m"; sourceTree = ""; }; + 23397924D53E7B536CB59C3373E47BCC /* ParseManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ParseManager.h; path = Parse/Internal/ParseManager.h; sourceTree = ""; }; + 240CCFABDE66FE6ADE38A4B02CB89687 /* PFMutablePushState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutablePushState.h; path = Parse/Internal/Push/State/PFMutablePushState.h; sourceTree = ""; }; + 2423BDB586DF4DF3F1525A1B5C40C54F /* FBSDKCoreKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKCoreKit.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h; sourceTree = ""; }; + 24851AC75A717461DF249C574A7E59B5 /* PFURLSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSession.m; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.m; sourceTree = ""; }; + 24B58875AADE4ED78AB3942781E1AECC /* PFMutableACLState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableACLState.m; path = Parse/Internal/ACL/State/PFMutableACLState.m; sourceTree = ""; }; + 25070753B1B37A1665F1F5332C0EF515 /* FBSDKLoginConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginConstants.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.h; sourceTree = ""; }; + 2551AB6C3C2A1C521E0184550321DE02 /* RKAttributeMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKAttributeMapping.m; path = Code/ObjectMapping/RKAttributeMapping.m; sourceTree = ""; }; + 255D43CCCFDFD52C9090EF3B8972D72C /* PFSQLiteDatabase.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSQLiteDatabase.m; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.m; sourceTree = ""; }; + 2562927BDB580A25FD1C5DE23213DD83 /* RKStringTokenizer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKStringTokenizer.m; path = Code/Support/RKStringTokenizer.m; sourceTree = ""; }; + 2572DB6B289BFC9AA6F1D1DCFF16D994 /* PFCurrentInstallationController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCurrentInstallationController.h; path = Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.h; sourceTree = ""; }; + 25913693021196FC72C7A8E7A937AFCC /* POPGeometry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPGeometry.h; path = pop/POPGeometry.h; sourceTree = ""; }; + 25EF987A717711C8CEAE29DFF3C12EA0 /* PFRelation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRelation.m; path = Parse/PFRelation.m; sourceTree = ""; }; + 26576E563FF51DD9C6683E959913991D /* FBSDKShareOpenGraphContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareOpenGraphContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.m; sourceTree = ""; }; + 266541F607EB34A777991BD29D5D2556 /* CATransaction+TransactionWithAnimationsAndCompletion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "CATransaction+TransactionWithAnimationsAndCompletion.m"; path = "FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.m"; sourceTree = ""; }; + 26A9B6AD16C16524DC90D9F1759B3E86 /* FBSDKMonotonicTime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKMonotonicTime.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.m; sourceTree = ""; }; + 26A9C85767DC8FE594E7F2DF14F867B2 /* PFCommandRunningConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCommandRunningConstants.m; path = Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.m; sourceTree = ""; }; + 26B6710576834D59FB5352DD3F5EB069 /* CAAnimation+YALTabBarViewAnimations.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "CAAnimation+YALTabBarViewAnimations.m"; path = "FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.m"; sourceTree = ""; }; + 26BE12FA64DB24FF7A1DF7937AEF98D6 /* FBSDKMutableCopying.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMutableCopying.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h; sourceTree = ""; }; + 272643F56613CA0D336AE3DBF19DC404 /* Pods-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dummy.m"; sourceTree = ""; }; + 2775CBEED05B03B513848BE46301ECA6 /* BFExecutor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFExecutor.m; path = Bolts/Common/BFExecutor.m; sourceTree = ""; }; + 2784369F5F5CCA4ADE551377F245E131 /* FBSDKBase64.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBase64.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h; sourceTree = ""; }; + 280AB1BDCC3841953AE8E7E78F9326A1 /* POPBasicAnimationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPBasicAnimationInternal.h; path = pop/POPBasicAnimationInternal.h; sourceTree = ""; }; + 2870EF5BFCF54FA3B58A74A16C8DEA99 /* YALAnimatingTabBarConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = YALAnimatingTabBarConstants.m; path = FoldingTabBar/Constants/YALAnimatingTabBarConstants.m; sourceTree = ""; }; + 28ACD3CB82BEF500AB8A021A9907BF32 /* libRKValueTransformers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRKValueTransformers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 29B13B33590257BF7A80C3602DC87B09 /* FBSDKShareConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareConstants.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.h; sourceTree = ""; }; + 29DAD99804B5BD08F3A74008FD65BAE7 /* BoltsVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BoltsVersion.h; path = Bolts/Common/BoltsVersion.h; sourceTree = ""; }; + 2A17ADE2F078B621C983D99D2F0F0047 /* FBSDKBridgeAPIProtocolWebV2.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIProtocolWebV2.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h; sourceTree = ""; }; + 2AA04EC3FE92A62CDADA2A69B932DDF3 /* FBSDKContainerViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKContainerViewController.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h; sourceTree = ""; }; + 2AA9ED123D1A01B9CE0864DF21669E32 /* PFAnonymousUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAnonymousUtils.m; path = Parse/PFAnonymousUtils.m; sourceTree = ""; }; + 2AECAEEB58E4CB5EFF8D61951BC17DB1 /* PFCachedQueryController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCachedQueryController.m; path = Parse/Internal/Query/Controller/PFCachedQueryController.m; sourceTree = ""; }; + 2B468DC6F25FAF7381C563D8A3A3C32E /* FBSDKShareKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareKit.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareKit.h; sourceTree = ""; }; + 2BB0273CAD372752E68ECCBCD48E5842 /* FBSDKLikeControl+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLikeControl+Internal.h"; path = "FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeControl+Internal.h"; sourceTree = ""; }; + 2CFCEB3A58ECB73BB6D930BB1A66A2DE /* UnitBezier.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = UnitBezier.h; path = pop/WebCore/UnitBezier.h; sourceTree = ""; }; + 2DA32C8430B17D1CEF6CC0C2F20702C6 /* PFConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFConfig.h; path = Parse/PFConfig.h; sourceTree = ""; }; + 2DDC81A1F4448D392C77D59D57719404 /* FBSDKTimeSpentData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKTimeSpentData.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.h; sourceTree = ""; }; + 2DE175F2297AFCBB1C62B1B16B5891F1 /* FBSDKShareKit+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKShareKit+Internal.h"; path = "FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareKit+Internal.h"; sourceTree = ""; }; + 2DFC0AEEC2FC3F3A422A6A76F818E344 /* RKObjectMappingOperationDataSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMappingOperationDataSource.m; path = Code/ObjectMapping/RKObjectMappingOperationDataSource.m; sourceTree = ""; }; + 2E051BB78BF5591341C31848B9AE0E0B /* PFPropertyInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPropertyInfo.h; path = Parse/Internal/PropertyInfo/PFPropertyInfo.h; sourceTree = ""; }; + 2E3E506FDF95C78237F089FED94DAB76 /* RKErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKErrors.h; path = Code/Support/RKErrors.h; sourceTree = ""; }; + 2E4BCF2AF417571FAAD5D3A0AF5FFB93 /* PFRESTConfigCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTConfigCommand.m; path = Parse/Internal/Commands/PFRESTConfigCommand.m; sourceTree = ""; }; + 2E4DB2AB05ABDFB2096CBD1A0D1C960A /* RKMIMETypes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMIMETypes.m; path = Code/Support/RKMIMETypes.m; sourceTree = ""; }; + 2E7F67EBB1F0265AF0F708FA1006B162 /* FBSDKBridgeAPIResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPIResponse.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.m; sourceTree = ""; }; + 2E867F3D72745F4BA824FC362CEBFACB /* FBSDKConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKConstants.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h; sourceTree = ""; }; + 2F0F7C3B1D42E74B34C118D7F55D56DC /* BFTask+Private.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "BFTask+Private.m"; path = "Parse/Internal/BFTask+Private.m"; sourceTree = ""; }; + 305A419FED9C718C8ACAE5D2F9173F27 /* PFPaymentTransactionObserver_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPaymentTransactionObserver_Private.h; path = Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver_Private.h; sourceTree = ""; }; + 3135C42A396F109267EA88F6641A9194 /* FBSDKShareVideo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareVideo.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.h; sourceTree = ""; }; + 3198F91D01D488AAEE2E37C91C36109C /* PFURLSessionJSONDataTaskDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionJSONDataTaskDelegate.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.h; sourceTree = ""; }; + 31AE16032795BC110759FE0D71DD7F32 /* PFObjectPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectPrivate.h; path = Parse/Internal/Object/PFObjectPrivate.h; sourceTree = ""; }; + 31EC6AF4DEA7F85F68A5CE8C3ECA3280 /* PFSQLiteDatabase_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSQLiteDatabase_Private.h; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase_Private.h; sourceTree = ""; }; + 324AAABDF5EC040480FF7DD0137ACC3A /* FBSDKTestUsersManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKTestUsersManager.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.m; sourceTree = ""; }; + 32584F1C40CC0FB3ACD703733332AA08 /* PFAnalyticsUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAnalyticsUtilities.m; path = Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.m; sourceTree = ""; }; + 325AD4A9548841B8B429CC3D00DF02E4 /* POPAnimationExtras.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationExtras.h; path = pop/POPAnimationExtras.h; sourceTree = ""; }; + 3265A08CD5F3A28A6541A985B0B75664 /* FBSDKAppInviteDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppInviteDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.m; sourceTree = ""; }; + 327724504C5129C28E647306963F3042 /* PFURLSessionCommandRunner.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionCommandRunner.h; path = Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner.h; sourceTree = ""; }; + 335A3DE810AEDFE589A9325169A59E46 /* FBSDKLoginTooltipView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginTooltipView.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.m; sourceTree = ""; }; + 3394EE87DFC9E88439AB265D59382138 /* FBSDKLikeDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeDialog.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.m; sourceTree = ""; }; + 33A88DE3DA4EB5064A997FFAF0C23DCF /* RKPropertyInspector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPropertyInspector.h; path = Code/ObjectMapping/RKPropertyInspector.h; sourceTree = ""; }; + 33D917AEA2C6B3BD1FB6DE5E32B94689 /* PFEventuallyQueue_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFEventuallyQueue_Private.h; path = Parse/Internal/PFEventuallyQueue_Private.h; sourceTree = ""; }; + 34467D773B15C784E43F77DA67A5790C /* PFCommandRunningConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandRunningConstants.h; path = Parse/Internal/Commands/CommandRunner/PFCommandRunningConstants.h; sourceTree = ""; }; + 346CED5D6B988E5318DBD8CC9C98A073 /* FBSDKGameRequestDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGameRequestDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.h; sourceTree = ""; }; + 34C584E3410A80115A9107E13C995E70 /* libSOCKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSOCKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 352259996AE7807E58AB7D6E88FAC9F7 /* YALFoldingTabBarController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALFoldingTabBarController.h; path = FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.h; sourceTree = ""; }; + 35CC150A7EE20543758EB2CBCB3D0D9D /* AFURLConnectionOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFURLConnectionOperation.h; path = AFNetworking/AFURLConnectionOperation.h; sourceTree = ""; }; + 368A5760A18AE27F46F5243BA3BFD13C /* PFPushManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushManager.h; path = Parse/Internal/Push/Manager/PFPushManager.h; sourceTree = ""; }; + 36A9A82E6520CD02FD9422940934EACB /* FBSDKShareDialogMode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareDialogMode.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.m; sourceTree = ""; }; + 36C75B01624E2DCB9059D7ABADC2B668 /* PFAnonymousAuthenticationProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnonymousAuthenticationProvider.h; path = Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.h; sourceTree = ""; }; + 36C8AD8E2390F415DC7425C9734EFAFB /* PFCommandCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandCache.h; path = Parse/Internal/PFCommandCache.h; sourceTree = ""; }; + 370FAC093160183505C296D12A84BF0A /* FBSDKGraphRequestMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequestMetadata.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestMetadata.m; sourceTree = ""; }; + 37382D15DA0BBCC18167A1B61E72CD64 /* PFCloud.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCloud.m; path = Parse/PFCloud.m; sourceTree = ""; }; + 37DB56D75062CC75FCB0966E1C6E8A8E /* Pods-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-acknowledgements.markdown"; sourceTree = ""; }; + 37F7E3AF617E0BF5874DE052CCFF4A53 /* PFRESTCommand_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTCommand_Private.h; path = Parse/Internal/Commands/PFRESTCommand_Private.h; sourceTree = ""; }; + 37FC535483D9258C485125E0488ED3EF /* RKValueTransformers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKValueTransformers.h; path = Code/RKValueTransformers.h; sourceTree = ""; }; + 3849FCCD9604B569E0277015CC30071D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; }; + 3880A4A4324ED988B85901DAD4519018 /* AFJSONRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFJSONRequestOperation.h; path = AFNetworking/AFJSONRequestOperation.h; sourceTree = ""; }; + 3962BED4A779536F2E41B1C36D6285AB /* PFRESTCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTCommand.m; path = Parse/Internal/Commands/PFRESTCommand.m; sourceTree = ""; }; + 39D2341AC19A6B3AD747ABBF9D3A13E5 /* PFObjectFilePersistenceController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectFilePersistenceController.m; path = Parse/Internal/Object/FilePersistence/PFObjectFilePersistenceController.m; sourceTree = ""; }; + 39F780E56F26B16CAF1CF2F0EBC58660 /* PFFileController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFileController.m; path = Parse/Internal/File/Controller/PFFileController.m; sourceTree = ""; }; + 3ACEDF4D677834B067A9DD0F82954897 /* FBSDKSharingContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSharingContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharingContent.h; sourceTree = ""; }; + 3B1F248FA3EE75C351E1B383AB977DF7 /* BFDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFDefines.h; path = Bolts/Common/BFDefines.h; sourceTree = ""; }; + 3B5920113D86FC36BEBC6F899C9034F7 /* FBSDKServerConfigurationManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKServerConfigurationManager.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager.h; sourceTree = ""; }; + 3BCD0EFCBE498C67A5B0097360333011 /* PFHTTPURLRequestConstructor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFHTTPURLRequestConstructor.m; path = Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.m; sourceTree = ""; }; + 3BF16968FBC656E49A7B643EED4B84F6 /* ISO8601DateFormatterValueTransformer.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ISO8601DateFormatterValueTransformer.xcconfig; sourceTree = ""; }; + 3C1CC5AA0EB4EDA9432A7D5463BE4901 /* AFHTTPClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFHTTPClient.h; path = AFNetworking/AFHTTPClient.h; sourceTree = ""; }; + 3C4E2E6E86AEBB3B50EE86E4B1074A32 /* FBSDKProfile+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKProfile+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKProfile+Internal.h"; sourceTree = ""; }; + 3C6C852E7C915FBEDD2E5B3C2CDD20A8 /* lcl_config_components_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_components_RK.h; path = Code/Support/lcl_config_components_RK.h; sourceTree = ""; }; + 3C9A888CC23B37A508B946C18FBA51D5 /* PFRESTCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTCommand.h; path = Parse/Internal/Commands/PFRESTCommand.h; sourceTree = ""; }; + 3CE5F2F0D15646E1D82418047325DB76 /* FoldingTabBar-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FoldingTabBar-prefix.pch"; sourceTree = ""; }; + 3CFFE5B32D8DD018AAF9EB4733D6315B /* FBSDKAppGroupContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppGroupContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.m; sourceTree = ""; }; + 3D1059A8B21D1214B8EA1A8BCF6B2CE5 /* FBSDKAppEventsState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppEventsState.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.m; sourceTree = ""; }; + 3D9C8B62E94BADCE53C2B3A336B91A66 /* PFAnalyticsController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnalyticsController.h; path = Parse/Internal/Analytics/Controller/PFAnalyticsController.h; sourceTree = ""; }; + 3DD24718CA4BD9604C201D989FD03218 /* SOCKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SOCKit-dummy.m"; sourceTree = ""; }; + 3DDC10303447DF4E3E657F2B4AD92925 /* RKHTTPRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKHTTPRequestOperation.h; path = Code/Network/RKHTTPRequestOperation.h; sourceTree = ""; }; + 3E03D377B70A81B7EE7DF0A8F510E529 /* PFRESTConfigCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTConfigCommand.h; path = Parse/Internal/Commands/PFRESTConfigCommand.h; sourceTree = ""; }; + 3E4E096EFFA1494BC822896BB3BD15AB /* FBSDKCheckmarkIcon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKCheckmarkIcon.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.m; sourceTree = ""; }; + 3ED50EE6CEF264393D61B359E4FD13BB /* PFMutableRelationState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableRelationState.m; path = Parse/Internal/Relation/State/PFMutableRelationState.m; sourceTree = ""; }; + 3EE26090EAD13C1FFD39BB6A7C89193B /* FBSDKShareLinkContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareLinkContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.h; sourceTree = ""; }; + 3F045700822563CB163FE8B3F606352C /* FBSDKLoginKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FBSDKLoginKit.xcconfig; sourceTree = ""; }; + 3F16209AB717FBAFF4C2730320EF9840 /* PFFileState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileState.h; path = Parse/Internal/File/State/PFFileState.h; sourceTree = ""; }; + 3F3FC0B3D497637B402F51B44E5B28F5 /* FBSDKShareDialogMode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareDialogMode.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareDialogMode.h; sourceTree = ""; }; + 3F756E1A3BA52E99D6635DE49C0331CB /* RKURLEncodedSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKURLEncodedSerialization.m; path = Code/Support/RKURLEncodedSerialization.m; sourceTree = ""; }; + 3FE19DF082B2711D3D79E3BDF50FA146 /* PFFileController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileController.h; path = Parse/Internal/File/Controller/PFFileController.h; sourceTree = ""; }; + 4035095FBC067B91C5DECADD26277EB1 /* PFDateFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFDateFormatter.h; path = Parse/Internal/PFDateFormatter.h; sourceTree = ""; }; + 405BEEF0AFD44793580DDB9D43634820 /* FBSDKGraphErrorRecoveryProcessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphErrorRecoveryProcessor.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h; sourceTree = ""; }; + 407C402A54C0C81D42BEA7147982FA35 /* PFGeoPointPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFGeoPointPrivate.h; path = Parse/Internal/PFGeoPointPrivate.h; sourceTree = ""; }; + 409EF16B93600F84E2CC3287F2C35D7E /* PFRole.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRole.h; path = Parse/PFRole.h; sourceTree = ""; }; + 40AB5DCC80577C96F4732C2FA58B903D /* PFCurrentInstallationController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCurrentInstallationController.m; path = Parse/Internal/Installation/CurrentInstallationController/PFCurrentInstallationController.m; sourceTree = ""; }; + 40C31A1DA0DE91B3BDC70194B9B9E75B /* RKMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMapping.m; path = Code/ObjectMapping/RKMapping.m; sourceTree = ""; }; + 40DC3C427F03295338C11BDDD89C3D2A /* PFGeoPoint.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFGeoPoint.h; path = Parse/PFGeoPoint.h; sourceTree = ""; }; + 40E39D31FE7DC01DD03AA4AF8530EC8D /* PFUserAuthenticationDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserAuthenticationDelegate.h; path = Parse/PFUserAuthenticationDelegate.h; sourceTree = ""; }; + 41BB788E886BFA89367834A4426A765E /* PFEventuallyQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFEventuallyQueue.m; path = Parse/Internal/PFEventuallyQueue.m; sourceTree = ""; }; + 41DE8F8508C70E584E9DC322D6E30DB1 /* FBSDKBoltsMeasurementEventListener.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBoltsMeasurementEventListener.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h; sourceTree = ""; }; + 4235B0900E27A7ECBA96EAFDECF2D5A0 /* PFPushUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushUtilities.h; path = Parse/Internal/Push/Utilites/PFPushUtilities.h; sourceTree = ""; }; + 423887AF6686942102218A073BC526E2 /* PFURLSessionFileDownloadTaskDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSessionFileDownloadTaskDelegate.m; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.m; sourceTree = ""; }; + 424184F6AAB828CA2D22E450BB52A081 /* FBSDKLikeControl.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeControl.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.h; sourceTree = ""; }; + 42B37BE48C6B242CC345A82EFFCA35CD /* FBSDKKeychainStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKKeychainStore.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.h; sourceTree = ""; }; + 42CBEF54F1256217E4780DB8ABBF5AC3 /* PFURLSessionDataTaskDelegate_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionDataTaskDelegate_Private.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate_Private.h; sourceTree = ""; }; + 433B51CC13747ACBE8AA93F02C6D784A /* RKMapperOperation_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapperOperation_Private.h; path = Code/ObjectMapping/RKMapperOperation_Private.h; sourceTree = ""; }; + 44420C2483949613227FDC09A152A3F2 /* BFURL_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFURL_Internal.h; path = Bolts/iOS/BFURL_Internal.h; sourceTree = ""; }; + 44A2841E1C0E28AFEE0B7288D6E47D4E /* YALTabBarItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALTabBarItem.h; path = FoldingTabBar/Model/TabBarItem/YALTabBarItem.h; sourceTree = ""; }; + 4521F82969CCAF3A290F34A7DA26A9DF /* RKRequestDescriptor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRequestDescriptor.h; path = Code/Network/RKRequestDescriptor.h; sourceTree = ""; }; + 45911FDD1904204B994BBBABE59D8DAA /* FBSDKGraphRequestDataAttachment.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequestDataAttachment.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.m; sourceTree = ""; }; + 45A41F6A2E3BF848EF5F335556B27EC1 /* PFCommandResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandResult.h; path = Parse/Internal/PFCommandResult.h; sourceTree = ""; }; + 45C1F3D82C36D976C5759677F623553F /* PFObjectFileCoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectFileCoder.m; path = Parse/Internal/Object/Coder/File/PFObjectFileCoder.m; sourceTree = ""; }; + 4659EF2651456627D2DF254CD1ABA4FB /* POPDecayAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPDecayAnimation.h; path = pop/POPDecayAnimation.h; sourceTree = ""; }; + 468C80083455F41B26E5C3D366E6F467 /* PFRelationState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRelationState.m; path = Parse/Internal/Relation/State/PFRelationState.m; sourceTree = ""; }; + 473792C704D2EB34B69FD30D4C8A4195 /* FBSDKServerConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKServerConfiguration.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.m; sourceTree = ""; }; + 4788A28C6827C4BF85BEB5920CADFEE4 /* PFSQLiteStatement.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSQLiteStatement.h; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteStatement.h; sourceTree = ""; }; + 47B246252A39D38E7CC3D6CD2C4549AA /* FBSDKWebDialogView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKWebDialogView.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.m; sourceTree = ""; }; + 47C5EB9BE6709541AB17E0F38FB1BB1A /* PFRESTPushCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTPushCommand.m; path = Parse/Internal/Commands/PFRESTPushCommand.m; sourceTree = ""; }; + 48C62F55A4F3241648089904B527F6D1 /* FBSDKConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKConstants.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.m; sourceTree = ""; }; + 4920838C7C35EE540CFF086D92C435AC /* PFProduct.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFProduct.h; path = Parse/PFProduct.h; sourceTree = ""; }; + 49293A25955435D7FC5E29D841FA4456 /* FBSDKAppInviteDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppInviteDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteDialog.h; sourceTree = ""; }; + 49B69C4B030D1D72B8261D35EB560A56 /* FBSDKErrorConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKErrorConfiguration.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.h; sourceTree = ""; }; + 49BFECAFEA1EF171D5BA9CFAFE63B895 /* PFFileDataStream.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileDataStream.h; path = Parse/Internal/File/FileDataStream/PFFileDataStream.h; sourceTree = ""; }; + 4A3FF0A4A486E57DD176B3DF5F619173 /* RKOperationStateMachine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKOperationStateMachine.m; path = Code/Support/RKOperationStateMachine.m; sourceTree = ""; }; + 4A5BA6A301883961C6DA165D6089A985 /* PFMultiProcessFileLock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMultiProcessFileLock.h; path = Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.h; sourceTree = ""; }; + 4AB618D67D94F32578DF5336651E7855 /* FBSDKLikeObjectType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeObjectType.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.h; sourceTree = ""; }; + 4B9BFA03B5504E854577C5000A356AFB /* FBSDKGraphRequestPiggybackManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequestPiggybackManager.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.h; sourceTree = ""; }; + 4BF07391CA6A2181CE0A3C3765B8F4BF /* PFJSONSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFJSONSerialization.h; path = Parse/Internal/PFJSONSerialization.h; sourceTree = ""; }; + 4C08FCA3A865F9181B3EAED5D081E6DB /* PFKeychainStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFKeychainStore.h; path = Parse/Internal/PFKeychainStore.h; sourceTree = ""; }; + 4C3FA9E55331EB6F5C9D6ABE4173AF97 /* FBSDKContainerViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKContainerViewController.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.m; sourceTree = ""; }; + 4C7FFDC2B7A4F0D5C315F44B0165D091 /* RKBenchmark.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKBenchmark.h; path = Code/Testing/RKBenchmark.h; sourceTree = ""; }; + 4C86B91E8FA37A02DFCBC13C26C5599E /* FBSDKProfile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKProfile.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.m; sourceTree = ""; }; + 4C8E5BBEB36882FAEA0C74B322ADC266 /* PFSubclassing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSubclassing.h; path = Parse/PFSubclassing.h; sourceTree = ""; }; + 4CDA9E34CFAB4648EC74D9ED76EF02AC /* POPBasicAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPBasicAnimation.h; path = pop/POPBasicAnimation.h; sourceTree = ""; }; + 4CDDA61BB7A1F8AD65676757226E8A74 /* PFBaseState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFBaseState.m; path = Parse/Internal/PFBaseState.m; sourceTree = ""; }; + 4D18572FD7945CECB627B25FAFC28DF5 /* PFProduct+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "PFProduct+Private.h"; path = "Parse/Internal/Product/PFProduct+Private.h"; sourceTree = ""; }; + 4DA5437028A51B95A1C0B0B8B5CB334B /* TKState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKState.h; path = Code/TKState.h; sourceTree = ""; }; + 4DC337098F42B8A25439D02AF67102E7 /* PFObjectEstimatedData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectEstimatedData.m; path = Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.m; sourceTree = ""; }; + 4E762F23EC34ED4A6FF3312D84E33A40 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.debug.xcconfig; sourceTree = ""; }; + 4EA63193596C0C6A36407E53BE350DC2 /* PFOfflineQueryLogic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFOfflineQueryLogic.h; path = Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.h; sourceTree = ""; }; + 4EB1F29228069356CCA0E5D8E0C8DA3C /* RKPathUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPathUtilities.h; path = Code/Support/RKPathUtilities.h; sourceTree = ""; }; + 4F609FCDD81EB1ADED68C1FE461C3594 /* FBSDKGameRequestDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGameRequestDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestDialog.m; sourceTree = ""; }; + 4F6B679BDA82770D971194798F95DC69 /* RKBenchmark.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKBenchmark.m; path = Code/Testing/RKBenchmark.m; sourceTree = ""; }; + 4F70D98B41C9E7EEBC1231E9885224AA /* PFConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFConstants.m; path = Parse/PFConstants.m; sourceTree = ""; }; + 4F93FF0560F945FADCA311FD06CA31D3 /* PFJSONSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFJSONSerialization.m; path = Parse/Internal/PFJSONSerialization.m; sourceTree = ""; }; + 4F9A3C84F3CC18CABCD97E1DFB774A49 /* PFMutableQueryState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableQueryState.m; path = Parse/Internal/Query/State/PFMutableQueryState.m; sourceTree = ""; }; + 4FD94F67395BDA44DD37B2CEBB86BB64 /* PFFileState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFileState.m; path = Parse/Internal/File/State/PFFileState.m; sourceTree = ""; }; + 4FE71002F43E4EE07FF4CEB964FE6D44 /* PFMulticastDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMulticastDelegate.m; path = Parse/Internal/PFMulticastDelegate.m; sourceTree = ""; }; + 502875FAB22E086DDEA2AD3FB860D1A5 /* FBSDKBridgeAPIProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIProtocol.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h; sourceTree = ""; }; + 5030E7EB9027091137C392A948E0D5A8 /* FBSDKGraphErrorRecoveryProcessor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphErrorRecoveryProcessor.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.m; sourceTree = ""; }; + 503253CFCA3206291EBDFF00B0FDE5BF /* Parse_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Parse_Private.h; path = Parse/Internal/Parse_Private.h; sourceTree = ""; }; + 503DF747F3430012E621A5BB819767FB /* FBSDKAppEventsDeviceInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppEventsDeviceInfo.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.m; sourceTree = ""; }; + 5076A61842278BC01BD246CD9F6A6831 /* PFProduct.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFProduct.m; path = Parse/PFProduct.m; sourceTree = ""; }; + 512FA3A57C3C25DEB20BFDE24938517B /* PFQueryUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFQueryUtilities.m; path = Parse/Internal/Query/Utilities/PFQueryUtilities.m; sourceTree = ""; }; + 517FE5FCB5C6241B8A66BE083CA1AAE6 /* FBSDKLoginCompletion+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLoginCompletion+Internal.h"; path = "FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion+Internal.h"; sourceTree = ""; }; + 5251CF87DD5578A90ADED5D340FF960B /* POPAnimatorPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimatorPrivate.h; path = pop/POPAnimatorPrivate.h; sourceTree = ""; }; + 525A38283E17DE63638B7101EDD603A5 /* FBSDKCoreKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FBSDKCoreKit.xcconfig; sourceTree = ""; }; + 530B742954AE4C60876DC3128D82F154 /* RKTestFactory.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKTestFactory.m; path = Code/Testing/RKTestFactory.m; sourceTree = ""; }; + 535545A6AC7290701119A0B61C887EFF /* FBSDKLikeActionControllerCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeActionControllerCache.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.h; sourceTree = ""; }; + 5404656CDC7518E20D0C557EF9C53B63 /* PFMultiProcessFileLockController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMultiProcessFileLockController.h; path = Parse/Internal/MultiProcessLock/PFMultiProcessFileLockController.h; sourceTree = ""; }; + 5444C22939A582C105AC91CE65D666F4 /* BFAppLinkReturnToRefererView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkReturnToRefererView.h; path = Bolts/iOS/BFAppLinkReturnToRefererView.h; sourceTree = ""; }; + 54E5949F2C78F11D2017067D065794BD /* POPAnimationRuntime.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimationRuntime.mm; path = pop/POPAnimationRuntime.mm; sourceTree = ""; }; + 55116A6D2C15718DE59AF5A2B7B5C7F2 /* PFURLSessionCommandRunner_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionCommandRunner_Private.h; path = Parse/Internal/Commands/CommandRunner/URLSession/PFURLSessionCommandRunner_Private.h; sourceTree = ""; }; + 556F7F390D364FD2B3DA48C98E500E2C /* TransitionKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = TransitionKit.xcconfig; sourceTree = ""; }; + 55795C67F8572CA13753F14AC059940B /* POPDecayAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPDecayAnimation.mm; path = pop/POPDecayAnimation.mm; sourceTree = ""; }; + 55B8770724B1C27628F366C0CF2D3B85 /* RKPaginator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPaginator.h; path = Code/Network/RKPaginator.h; sourceTree = ""; }; + 55DBD79D6CDD908C9E0151AF56A3EFCE /* FBSDKProfile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKProfile.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h; sourceTree = ""; }; + 55DFDBF9FA07FC6282738752A376B991 /* PFURLConstructor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLConstructor.h; path = Parse/Internal/HTTPRequest/PFURLConstructor.h; sourceTree = ""; }; + 568C2C82ED942F4F6D68EBFBDD16316F /* FBSDKBridgeAPIProtocolType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIProtocolType.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h; sourceTree = ""; }; + 56EDB2104DA13588CD5B4334FF77452F /* FBSDKShareVideoContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareVideoContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.h; sourceTree = ""; }; + 56FE36E9C6BEFFC89DD1BC36E6289234 /* FBSDKBase64.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBase64.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.m; sourceTree = ""; }; + 57319DCE064A4F4C9DD2D290FD88D642 /* YALAnimatingTabBarConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALAnimatingTabBarConstants.h; path = FoldingTabBar/Constants/YALAnimatingTabBarConstants.h; sourceTree = ""; }; + 5732F9BC7E2742FFFC7C3BA8F1225459 /* BFAppLink_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLink_Internal.h; path = Bolts/iOS/BFAppLink_Internal.h; sourceTree = ""; }; + 5733C650048839167646DC7974A01ABA /* PFHTTPURLRequestConstructor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFHTTPURLRequestConstructor.h; path = Parse/Internal/HTTPRequest/PFHTTPURLRequestConstructor.h; sourceTree = ""; }; + 5783E79BEDB98581985EEC5EEAD67953 /* FBSDKAppLinkResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppLinkResolver.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h; sourceTree = ""; }; + 57A42437229DCF10EA2D792B45EC0449 /* RKDotNetDateFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDotNetDateFormatter.m; path = Code/Support/RKDotNetDateFormatter.m; sourceTree = ""; }; + 57B625AE6C787AB113D7EF7F05FB0637 /* FBSDKTestUsersManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKTestUsersManager.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKTestUsersManager.h; sourceTree = ""; }; + 57EA8E1B5446775F4608110823A9BF8C /* FBSDKAppEventsStateManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppEventsStateManager.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.m; sourceTree = ""; }; + 58DD77FFA76457DC7826A465EB970094 /* PFConfig_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFConfig_Private.h; path = Parse/Internal/Config/PFConfig_Private.h; sourceTree = ""; }; + 58E4CECC242634F51EA5250B5A8FF795 /* RKRoute.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRoute.m; path = Code/Network/RKRoute.m; sourceTree = ""; }; + 592AA9AF2651D5C86E7E8D122F958616 /* FBSDKTriStateBOOL.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKTriStateBOOL.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKTriStateBOOL.m; sourceTree = ""; }; + 59EAFD88B92A3912D4951328AF334D28 /* FBSDKLoginManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginManager.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManager.h; sourceTree = ""; }; + 59F15D7F5CA85CC8436BD1872518AB18 /* POPPropertyAnimationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPPropertyAnimationInternal.h; path = pop/POPPropertyAnimationInternal.h; sourceTree = ""; }; + 5A5C02D17E47A222D470066E80F5230B /* POPAnimationTracer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationTracer.h; path = pop/POPAnimationTracer.h; sourceTree = ""; }; + 5A840F03EBE584ACE4D413A297B04FC9 /* FBSDKButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKButton.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h; sourceTree = ""; }; + 5AAE8E50B932782D92F325DCE2EDEBBB /* PFFieldOperationDecoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFieldOperationDecoder.h; path = Parse/Internal/FieldOperation/PFFieldOperationDecoder.h; sourceTree = ""; }; + 5ADBAA054DAFCE013EB3EF9DF965F744 /* POPAnimatableProperty.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimatableProperty.mm; path = pop/POPAnimatableProperty.mm; sourceTree = ""; }; + 5B791C6AA6D3B48C2C1AA9496E0790AD /* PFPushPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushPrivate.h; path = Parse/Internal/Push/PFPushPrivate.h; sourceTree = ""; }; + 5B799574EF27A1E8D4FD50ADAA42EC77 /* PFReachability.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFReachability.h; path = Parse/Internal/PFReachability.h; sourceTree = ""; }; + 5BEC90C5581726DE80B840585A9F4174 /* PFAsyncTaskQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAsyncTaskQueue.m; path = Parse/Internal/PFAsyncTaskQueue.m; sourceTree = ""; }; + 5C4081A3EAA34140F505CCBE9D98C0C8 /* SOCKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = SOCKit.h; sourceTree = ""; }; + 5CA0A29FC7FC84E10BBE7CB9F915C818 /* PFUserConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUserConstants.m; path = Parse/Internal/User/Constants/PFUserConstants.m; sourceTree = ""; }; + 5DDC6BF6D637CEFC8BEDA82F87D0A60D /* RKValueTransformers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKValueTransformers.m; path = Code/RKValueTransformers.m; sourceTree = ""; }; + 5E0DB2127804727AC549721870914323 /* RKSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKSerialization.h; path = Code/Support/RKSerialization.h; sourceTree = ""; }; + 5E44BCC5A1A8313C135B429B4AA92FE8 /* PFObjectFileCodingLogic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectFileCodingLogic.h; path = Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.h; sourceTree = ""; }; + 5ED668482FAFCC7E2F744E4B45E21C00 /* PFCommandRunning.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandRunning.h; path = Parse/Internal/Commands/CommandRunner/PFCommandRunning.h; sourceTree = ""; }; + 5EEF5F821C5CAF35FB96774AFF53120A /* PFAlertView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAlertView.h; path = Parse/Internal/PFAlertView.h; sourceTree = ""; }; + 5F5D256457EA109A0FD3C2B7F2AFFFD8 /* FBSDKLoginManagerLoginResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginManagerLoginResult.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.m; sourceTree = ""; }; + 5F8A42FF495AB8897D09E00CAD01440B /* PFPropertyInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPropertyInfo.m; path = Parse/Internal/PropertyInfo/PFPropertyInfo.m; sourceTree = ""; }; + 5FC2F31E95438D43C0ACB4E6B5287B8D /* FBSDKWebDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKWebDialog.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.m; sourceTree = ""; }; + 5FDB069FE07BA949728D658261EA3E40 /* POPAnimatableProperty.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimatableProperty.h; path = pop/POPAnimatableProperty.h; sourceTree = ""; }; + 60D3C2480A1362A32E373ED42790BD7C /* PFPaymentTransactionObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPaymentTransactionObserver.h; path = Parse/Internal/Purchase/PaymentTransactionObserver/PFPaymentTransactionObserver.h; sourceTree = ""; }; + 6101E1788344FEF66BFB8A3BD80CF650 /* RKISO8601DateFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKISO8601DateFormatter.m; path = Code/RKISO8601DateFormatter.m; sourceTree = ""; }; + 610EC8334EB48B27B2BBE37D785AF2B2 /* FBSDKAppGroupJoinDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppGroupJoinDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.m; sourceTree = ""; }; + 6114EBA3A5CB7CB8ECE0A9BEFA6DB026 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 611F4CE6ED5017088CB427383A3D1445 /* RKDictionaryUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDictionaryUtilities.m; path = Code/Support/RKDictionaryUtilities.m; sourceTree = ""; }; + 615339A2EDD3CE627A27EBB1ECFF21B3 /* FBSDKColor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKColor.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.m; sourceTree = ""; }; + 616A0DE1DAFFD10BF5A8DD300548447E /* PFQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQuery.h; path = Parse/PFQuery.h; sourceTree = ""; }; + 616C83AFE6D3B13DB326EFFDA4E56218 /* PFUserConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserConstants.h; path = Parse/Internal/User/Constants/PFUserConstants.h; sourceTree = ""; }; + 6273DBD91B70BE5A81E0EF6B816A31E1 /* PFCommandResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCommandResult.m; path = Parse/Internal/PFCommandResult.m; sourceTree = ""; }; + 62923837C0899ECA2BAD6224F5A7B22E /* TKEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKEvent.h; path = Code/TKEvent.h; sourceTree = ""; }; + 62BEED70070D14A0FF9C95200AA22741 /* PFACLState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFACLState.m; path = Parse/Internal/ACL/State/PFACLState.m; sourceTree = ""; }; + 632C18854DE2E319E9B6834A93514CC5 /* PFOfflineStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFOfflineStore.m; path = Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m; sourceTree = ""; }; + 632D62E7B544FFB77F14C130A2EC4510 /* POPAnimationEventInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationEventInternal.h; path = pop/POPAnimationEventInternal.h; sourceTree = ""; }; + 6380D4168C668F109E1A03B20D714BBE /* RKErrorMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKErrorMessage.m; path = Code/ObjectMapping/RKErrorMessage.m; sourceTree = ""; }; + 64264592576D6C230E966AC098067DAB /* FBSDKLikeButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeButton.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.m; sourceTree = ""; }; + 6426FFE9B7D5877E4580324A76A08178 /* PFObjectLocalIdStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectLocalIdStore.m; path = Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.m; sourceTree = ""; }; + 6447BB55EEB3096AE38B4D07B1F5F620 /* PFConfigController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFConfigController.h; path = Parse/Internal/Config/Controller/PFConfigController.h; sourceTree = ""; }; + 6467B92BD94142011900B81E0476CB0E /* POPAnimationRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationRuntime.h; path = pop/POPAnimationRuntime.h; sourceTree = ""; }; + 64DFE094C387E0DA1F62DB6912006497 /* POPDecayAnimationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPDecayAnimationInternal.h; path = pop/POPDecayAnimationInternal.h; sourceTree = ""; }; + 64E0C0D87C1527E39C8527751DB7D005 /* POPVector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPVector.h; path = pop/POPVector.h; sourceTree = ""; }; + 650F210D5B2E4ADBF30ED15408D730D3 /* FBSDKMaleSilhouetteIcon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKMaleSilhouetteIcon.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.m; sourceTree = ""; }; + 655746194AED6433F130ACB5AA120F9B /* SOCKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SOCKit.xcconfig; sourceTree = ""; }; + 6569377CC0B0AA51EBA394C782985089 /* FBSDKShareDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.m; sourceTree = ""; }; + 658BD9C8EBCC6CE298417312A7B194FF /* PFCurrentObjectControlling.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCurrentObjectControlling.h; path = Parse/Internal/Object/CurrentController/PFCurrentObjectControlling.h; sourceTree = ""; }; + 65962B65C068EE02DAE719D8D70CA321 /* RKMapperOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapperOperation.h; path = Code/ObjectMapping/RKMapperOperation.h; sourceTree = ""; }; + 6674B326B12A30BE2A6BCDFC2F890324 /* PFKeychainStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFKeychainStore.m; path = Parse/Internal/PFKeychainStore.m; sourceTree = ""; }; + 66754BB67AA131A94D10F42D109E8523 /* PFRole.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRole.m; path = Parse/PFRole.m; sourceTree = ""; }; + 667F8446CCEAF60B9DCD4E68CCB9ED5E /* RKLog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKLog.m; path = Code/Support/RKLog.m; sourceTree = ""; }; + 66C350784D8C52C699FE7DD47EF906FB /* RKRouteSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRouteSet.m; path = Code/Network/RKRouteSet.m; sourceTree = ""; }; + 672B96E281A19DA7F2F22511F1093D16 /* FBSDKLiking.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLiking.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKLiking.h; sourceTree = ""; }; + 6768924E65317D0E30521724DC081C08 /* FBSDKShareOpenGraphAction.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareOpenGraphAction.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphAction.h; sourceTree = ""; }; + 67B4C66668FC14A61182B73575A193DE /* ParseModule.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ParseModule.m; path = Parse/Internal/ParseModule.m; sourceTree = ""; }; + 67CF036576967715D363A2E7C16E4AAD /* FBSDKKeychainStoreViaBundleID.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKKeychainStoreViaBundleID.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.h; sourceTree = ""; }; + 67DBA3140A542C45905BA912DF9D6D93 /* RestKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RestKit.xcconfig; sourceTree = ""; }; + 68133029060DA29FD5C9C26119CFA51B /* FBSDKLikeActionControllerCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeActionControllerCache.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionControllerCache.m; sourceTree = ""; }; + 68FE49164D11028318A5BFC6389C361A /* FBSDKURLOpening.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKURLOpening.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKURLOpening.h; sourceTree = ""; }; + 6911BECA35E7518D864239B7E898EEF3 /* Pods-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-frameworks.sh"; sourceTree = ""; }; + 696513A0EDF7E7D3B1DA9E8871E05685 /* POPGeometry.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPGeometry.mm; path = pop/POPGeometry.mm; sourceTree = ""; }; + 69B2823ABCAD80D975C9E8C29A5E869F /* FBSDKShareVideoContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareVideoContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareVideoContent.m; sourceTree = ""; }; + 6A2F4083D494D045689BC3A072187C3B /* TransformationMatrix.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = TransformationMatrix.cpp; path = pop/WebCore/TransformationMatrix.cpp; sourceTree = ""; }; + 6A45C57C5D3CBC79D400F49C075773AE /* libAFNetworking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAFNetworking.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 6A986FCBAFF66C34031E230F059A2DCF /* RKTestConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKTestConstants.m; path = Code/Testing/RKTestConstants.m; sourceTree = ""; }; + 6AD9092DA1F9CCC04506CAA7CAD0EC83 /* RKMIMETypes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMIMETypes.h; path = Code/Support/RKMIMETypes.h; sourceTree = ""; }; + 6AE20D46FEA8C73D4CD5828D72E4D47B /* ISO8601DateFormatterValueTransformer-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ISO8601DateFormatterValueTransformer-prefix.pch"; sourceTree = ""; }; + 6AFF7959F2290BD0027C49FBA305DFE5 /* RKLumberjackLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKLumberjackLogger.m; path = Code/Support/RKLumberjackLogger.m; sourceTree = ""; }; + 6B650BB26CA49F23280F611BC06CAB7A /* PFGeoPoint.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFGeoPoint.m; path = Parse/PFGeoPoint.m; sourceTree = ""; }; + 6B7304E8EFDCC873E1CE3D2CA2076A74 /* FBSDKBridgeAPIRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIRequest.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h; sourceTree = ""; }; + 6BBAD9DCAFF06BB669E8D77482B04BDB /* PFMulticastDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMulticastDelegate.h; path = Parse/Internal/PFMulticastDelegate.h; sourceTree = ""; }; + 6BD1AFE5456BC7AAC15A5D308229EC88 /* FBSDKURLConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKURLConnection.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.h; sourceTree = ""; }; + 6BFB7F5189C7630850B466033A6828EF /* FBSDKKeychainStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKKeychainStore.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStore.m; sourceTree = ""; }; + 6C3843CD6AEFE5F515E6142799F801CA /* PFPushState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushState_Private.h; path = Parse/Internal/Push/State/PFPushState_Private.h; sourceTree = ""; }; + 6D052546B61C8CA0E3EB34475BFB60D0 /* PFMutableUserState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableUserState.h; path = Parse/Internal/User/State/PFMutableUserState.h; sourceTree = ""; }; + 6D169B7683E9DA4DE1D139D6CD10D190 /* RestKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RestKit-dummy.m"; sourceTree = ""; }; + 6D298D539E71478D6340E3FA832E4778 /* PFFile_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFile_Private.h; path = Parse/Internal/File/PFFile_Private.h; sourceTree = ""; }; + 6D540B5BA940B77762F525759CD9E2F7 /* _FBSDKLoginRecoveryAttempter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _FBSDKLoginRecoveryAttempter.h; path = FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.h; sourceTree = ""; }; + 6D7387AFD498FF6D486BEF5755B9D7B3 /* FBSDKAppEvents.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppEvents.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h; sourceTree = ""; }; + 6DC8BFB1DFE3D689F572296A0DA6E236 /* PFMutablePushState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutablePushState.m; path = Parse/Internal/Push/State/PFMutablePushState.m; sourceTree = ""; }; + 6E2D1B4FCC4918686DEAF9094B908917 /* FBSDKLoginError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginError.m; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginError.m; sourceTree = ""; }; + 6E3D7476264442440AC1374D1E0418A1 /* BFAppLinkReturnToRefererView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFAppLinkReturnToRefererView.m; path = Bolts/iOS/BFAppLinkReturnToRefererView.m; sourceTree = ""; }; + 6EBA7EC1BD2D3653F709A5C97063B990 /* PFUserPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserPrivate.h; path = Parse/Internal/User/PFUserPrivate.h; sourceTree = ""; }; + 6F2BB3EBFE218C47714938D29CF23EF9 /* PFObjectSubclassingController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectSubclassingController.h; path = Parse/Internal/Object/Subclassing/PFObjectSubclassingController.h; sourceTree = ""; }; + 6F529E412A09BF39D8AEC42AFFDF2F46 /* AFNetworking.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFNetworking.h; path = AFNetworking/AFNetworking.h; sourceTree = ""; }; + 6FE7C0F12060A4C3CEE3C5427762A616 /* RKMappingOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMappingOperation.m; path = Code/ObjectMapping/RKMappingOperation.m; sourceTree = ""; }; + 6FF111BF52B8C1648F8023FC642FF2C8 /* PFObjectFileCodingLogic.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectFileCodingLogic.m; path = Parse/Internal/Object/Coder/File/PFObjectFileCodingLogic.m; sourceTree = ""; }; + 6FF8DA1F7EEE96CC61CEEB687513A615 /* PFCurrentUserController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCurrentUserController.m; path = Parse/Internal/User/CurrentUserController/PFCurrentUserController.m; sourceTree = ""; }; + 701190361150FF2EEDEF10D05ABE7065 /* PFURLSessionDataTaskDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionDataTaskDelegate.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionDataTaskDelegate.h; sourceTree = ""; }; + 7239EC1173010662F747781299C375DA /* FBSDKGraphRequestConnection+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKGraphRequestConnection+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestConnection+Internal.h"; sourceTree = ""; }; + 723C3B2158211623464D6751F8AB7101 /* POPMath.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPMath.mm; path = pop/POPMath.mm; sourceTree = ""; }; + 72766C115F290B685E1C527E77EDEDEE /* BFTaskCompletionSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTaskCompletionSource.h; path = Bolts/Common/BFTaskCompletionSource.h; sourceTree = ""; }; + 72B29870F05A80283BE95E71DEBEE1D2 /* POPAnimationTracer.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimationTracer.mm; path = pop/POPAnimationTracer.mm; sourceTree = ""; }; + 72C1FA5A8BDBCEC19E41771957BEB9E3 /* PFSessionUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSessionUtilities.m; path = Parse/Internal/Session/Utilities/PFSessionUtilities.m; sourceTree = ""; }; + 73136CB5DF8D9FDC9C0B3FF336E53790 /* PFSessionController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSessionController.m; path = Parse/Internal/Session/Controller/PFSessionController.m; sourceTree = ""; }; + 733D51F628A8649F5A0790296BA3E42A /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + 735D8A9263762B7D4E5C5EDB816A7CB6 /* FBSDKAccessTokenCacheV3_21.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCacheV3_21.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h; sourceTree = ""; }; + 73C100898C88FF4043F6002195DD6293 /* RKObjectParameterization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectParameterization.m; path = Code/Network/RKObjectParameterization.m; sourceTree = ""; }; + 74089267A9387B60B1CE108DFAA883BC /* BFAppLink.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLink.h; path = Bolts/iOS/BFAppLink.h; sourceTree = ""; }; + 74338BD705AD4CAADD5CA90BD8EF2D96 /* FBSDKDynamicFrameworkLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKDynamicFrameworkLoader.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.h; sourceTree = ""; }; + 749A8D41E182E9883688C41D2D257554 /* ParseInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ParseInternal.h; path = Parse/Internal/ParseInternal.h; sourceTree = ""; }; + 74B44F24917A72CA781246EA2632A00C /* PFCloudCodeController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCloudCodeController.h; path = Parse/Internal/CloudCode/PFCloudCodeController.h; sourceTree = ""; }; + 7558DBD1AF61B17AF39F3565B9F68601 /* FBSDKApplicationDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKApplicationDelegate.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.m; sourceTree = ""; }; + 761DB1B71490B54C854E88186480B4EA /* POPAnimationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationInternal.h; path = pop/POPAnimationInternal.h; sourceTree = ""; }; + 763D59D54C57DA2AAFAD336EE912908D /* FBSDKLoginCompletion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginCompletion.h; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.h; sourceTree = ""; }; + 764FFD75345B6B6A979A9D10F2D2907B /* AFHTTPClient.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFHTTPClient.m; path = AFNetworking/AFHTTPClient.m; sourceTree = ""; }; + 76BDB3E82FE4A935AACD2F637F371589 /* TKTransition.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKTransition.h; path = Code/TKTransition.h; sourceTree = ""; }; + 76EDBE5B4444693672560F0B38D5C4D3 /* PFQueryUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQueryUtilities.h; path = Parse/Internal/Query/Utilities/PFQueryUtilities.h; sourceTree = ""; }; + 7719F6B5924888F0A267790B6E5647FD /* FBSDKCloseIcon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKCloseIcon.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.m; sourceTree = ""; }; + 776A46D7EBDABB85B1A452ED93BEFBF9 /* RKAttributeMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKAttributeMapping.h; path = Code/ObjectMapping/RKAttributeMapping.h; sourceTree = ""; }; + 7771BB9434E69A691392A0970DD10E28 /* AFHTTPRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFHTTPRequestOperation.h; path = AFNetworking/AFHTTPRequestOperation.h; sourceTree = ""; }; + 778D8D7F4CD22FFBC60450393224961A /* PFOfflineQueryLogic.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFOfflineQueryLogic.m; path = Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m; sourceTree = ""; }; + 77DB8925A606DF13F24DBF2AD343EB8D /* PFAnalyticsController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAnalyticsController.m; path = Parse/Internal/Analytics/Controller/PFAnalyticsController.m; sourceTree = ""; }; + 782AF7A5FC9A3571F42003CD07FE5A3C /* FBSDKAppGroupAddDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppGroupAddDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupAddDialog.m; sourceTree = ""; }; + 78A05813E9EC11B010C6A344D9AAC05A /* POP.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POP.h; path = pop/POP.h; sourceTree = ""; }; + 7915DC37B74D252F701BF85B55880ACF /* POPSpringAnimationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPSpringAnimationInternal.h; path = pop/POPSpringAnimationInternal.h; sourceTree = ""; }; + 79630B324053224BBFAB6E9D26A18148 /* FBSDKAppGroupJoinDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppGroupJoinDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupJoinDialog.h; sourceTree = ""; }; + 7981192FA1E3FF14D8C9EBA4511FD33B /* PFURLSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSession.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession.h; sourceTree = ""; }; + 79A12CFC76EC1B0BF26367E0922426FD /* PFInstallationIdentifierStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFInstallationIdentifierStore.m; path = Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore.m; sourceTree = ""; }; + 79A805E2776C2CC27AB7764874C93173 /* PFTaskQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFTaskQueue.m; path = Parse/Internal/PFTaskQueue.m; sourceTree = ""; }; + 79EE570F7AF0D238D396B8C1BD1233F8 /* FBSDKButton+Subclass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKButton+Subclass.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h"; sourceTree = ""; }; + 79F07C09208B3EA7236791BBBDD1D459 /* POPLayerExtras.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPLayerExtras.mm; path = pop/POPLayerExtras.mm; sourceTree = ""; }; + 7A71B1896C184DD250A8FB4EF534051E /* FBSDKShareKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FBSDKShareKit-prefix.pch"; sourceTree = ""; }; + 7AAB2C033ACD2C5EDF5AFECCDE5BC95D /* PFEventuallyPin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFEventuallyPin.h; path = Parse/Internal/PFEventuallyPin.h; sourceTree = ""; }; + 7AC2271F01F29748BDF976CEF2EE767A /* RKResponseMapperOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKResponseMapperOperation.m; path = Code/Network/RKResponseMapperOperation.m; sourceTree = ""; }; + 7AD029CD6F8ADD2E864E5FE1699BB70D /* PFSQLiteDatabase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSQLiteDatabase.h; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabase.h; sourceTree = ""; }; + 7B6054861B48456D5D8D1E661F92EE5D /* PFACLState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFACLState_Private.h; path = Parse/Internal/ACL/State/PFACLState_Private.h; sourceTree = ""; }; + 7B754CD741EB603D2A92BACC3F38A430 /* PFKeyValueCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFKeyValueCache.h; path = Parse/Internal/KeyValueCache/PFKeyValueCache.h; sourceTree = ""; }; + 7BA86EF4EAFD3D4475A169859BB0B633 /* FBSDKIcon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKIcon.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.h; sourceTree = ""; }; + 7BB5593B161ABABA1D0209ECA5074EA3 /* PFAsyncTaskQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAsyncTaskQueue.h; path = Parse/Internal/PFAsyncTaskQueue.h; sourceTree = ""; }; + 7BC4913285E98A56C951839A999352AB /* RKConnectionTestExpectation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKConnectionTestExpectation.m; path = Code/Testing/RKConnectionTestExpectation.m; sourceTree = ""; }; + 7C114A540E5318937EFA769F5D2A5372 /* PFObjectLocalIdStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectLocalIdStore.h; path = Parse/Internal/Object/LocalIdStore/PFObjectLocalIdStore.h; sourceTree = ""; }; + 7C6CEAC74231F31EC9DDED4C3E2BBF48 /* FBSDKShareOpenGraphValueContainer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareOpenGraphValueContainer.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphValueContainer.m; sourceTree = ""; }; + 7C7BBFE7402E447E0363B1BF78CFD3A0 /* PFAssert.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAssert.h; path = Parse/Internal/PFAssert.h; sourceTree = ""; }; + 7CB6F2CF47DB783D84FBBB6F2B1A451F /* TKState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKState.m; path = Code/TKState.m; sourceTree = ""; }; + 7CE70DA06AD37A88DD393A98C73C7D07 /* FBSDKSharePhoto.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKSharePhoto.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.m; sourceTree = ""; }; + 7DA6FF9AD89559AE8FE2FD106DCB87C5 /* RKHTTPUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKHTTPUtilities.m; path = Code/ObjectMapping/RKHTTPUtilities.m; sourceTree = ""; }; + 7DAC4524798CD2351824DF502E226F2E /* FBSDKGameRequestContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGameRequestContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.m; sourceTree = ""; }; + 7DEFDD3A6DB314308247D22FF14AFA98 /* FBSDKLikeButton+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLikeButton+Internal.h"; path = "FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButton+Internal.h"; sourceTree = ""; }; + 7DFC97B9CEA18DDABF91F38573337059 /* PFURLSessionFileDownloadTaskDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSessionFileDownloadTaskDelegate.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionFileDownloadTaskDelegate.h; sourceTree = ""; }; + 7E03B26327B08731B36701D28A33B9C9 /* FBSDKURLConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKURLConnection.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKURLConnection.m; sourceTree = ""; }; + 7E0A91B803AD2D9F9BBC9C9C40485EFB /* POPAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimation.h; path = pop/POPAnimation.h; sourceTree = ""; }; + 7E3480D6C7EF4C1D5B97238AFFE8D127 /* PFMutableACLState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableACLState.h; path = Parse/Internal/ACL/State/PFMutableACLState.h; sourceTree = ""; }; + 7E668F82944D74008FA69DF68A0E96F9 /* RKOperationStateMachine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKOperationStateMachine.h; path = Code/Support/RKOperationStateMachine.h; sourceTree = ""; }; + 7EE2EBDC54FDE1E50CD9A33DDF48404D /* RKTestFactory.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKTestFactory.h; path = Code/Testing/RKTestFactory.h; sourceTree = ""; }; + 7F1DA5784F757925FC9B2C359AE8F07C /* TransitionKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TransitionKit.h; path = Code/TransitionKit.h; sourceTree = ""; }; + 7F63108EF1315E6D7E404F9ABF304F1A /* BFURL.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFURL.h; path = Bolts/iOS/BFURL.h; sourceTree = ""; }; + 7F6E4B0E19B7E3633F89483FC21D852C /* POPVector.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPVector.mm; path = pop/POPVector.mm; sourceTree = ""; }; + 7FDE21F99879BAFCD8007510D41FD42B /* BFAppLinkNavigation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkNavigation.h; path = Bolts/iOS/BFAppLinkNavigation.h; sourceTree = ""; }; + 800204DFA7DE3E6060355FB89A24FEB1 /* PFMutableFileState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableFileState.m; path = Parse/Internal/File/State/PFMutableFileState.m; sourceTree = ""; }; + 8030921BFF7BB8CE71AE970906855522 /* FBSDKBoltsMeasurementEventListener.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBoltsMeasurementEventListener.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.m; sourceTree = ""; }; + 8039DDB4E996A03FF15AD2DF8D4D1CA9 /* FBSDKSendButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSendButton.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.h; sourceTree = ""; }; + 804F2F0EDB0F2FE68B74F5D2D1ED5A94 /* FBSDKMessengerIcon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMessengerIcon.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKMessengerIcon.h; sourceTree = ""; }; + 80519B32A7AC044BA72391DA03E6E140 /* POPPropertyAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPPropertyAnimation.h; path = pop/POPPropertyAnimation.h; sourceTree = ""; }; + 80D183F090FB2841492B19FAC5CD77B6 /* libRestKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 80E3A4DA55D79A2A163A82080683C403 /* FBSDKAccessTokenCacheV3.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessTokenCacheV3.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.m; sourceTree = ""; }; + 80E5F5E0AE0F6B7B2757A6066BCC8612 /* libFoldingTabBar.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFoldingTabBar.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 817589AA5C8BA17E8B2F9808EC23788B /* RKMappingTest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMappingTest.m; path = Code/Testing/RKMappingTest.m; sourceTree = ""; }; + 81E010F8251FD4453C9DDE44ED09C4F4 /* PFObjectState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectState.h; path = Parse/Internal/Object/State/PFObjectState.h; sourceTree = ""; }; + 826C988F437410449787F4BDCE07E6B7 /* FBSDKLoginManagerLoginResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginManagerLoginResult.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginManagerLoginResult.h; sourceTree = ""; }; + 8275725385A9F6C10AF8B7A642A129F8 /* RKNSJSONSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKNSJSONSerialization.h; path = Code/Support/RKNSJSONSerialization.h; sourceTree = ""; }; + 82E57F9588CEC77612BC5E9A20CCC2E5 /* AFJSONRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFJSONRequestOperation.m; path = AFNetworking/AFJSONRequestOperation.m; sourceTree = ""; }; + 82EA1A7E2F5B25D7DECB8BE35B3072F0 /* PFPinningObjectStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPinningObjectStore.m; path = Parse/Internal/Object/PinningStore/PFPinningObjectStore.m; sourceTree = ""; }; + 83319D45D8AE5D8BF57D365983A41750 /* TransitionKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "TransitionKit-dummy.m"; sourceTree = ""; }; + 83831950A74E93412A274C95A90D1337 /* FBSDKAudioResourceLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAudioResourceLoader.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h; sourceTree = ""; }; + 83A7B0C8AF063198C8EBF6559688D469 /* Bolts-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-prefix.pch"; sourceTree = ""; }; + 83C5E9FB336C0917EC02E4034B2B66FE /* PFCoreManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCoreManager.h; path = Parse/Internal/PFCoreManager.h; sourceTree = ""; }; + 849262636C1FD7E1D283D86137BE70B8 /* RKDynamicMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDynamicMapping.m; path = Code/ObjectMapping/RKDynamicMapping.m; sourceTree = ""; }; + 8496664844E09F7B412D05544D90E123 /* FBSDKAccessTokenCacheV4.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCacheV4.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h; sourceTree = ""; }; + 84E5CF3BD81C4C414BE88556EB18D08F /* FBSDKTimeSpentData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKTimeSpentData.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKTimeSpentData.m; sourceTree = ""; }; + 851FD672C97DC80E95B543E7678B133F /* FBSDKMacros.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMacros.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h; sourceTree = ""; }; + 85B4596D7B3771E5ABD20C9631F9B18A /* Network.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Network.h; path = Code/Network.h; sourceTree = ""; }; + 85F8F13323C74D0619E9E4B4BBB27CEE /* FBSDKMessageDialog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKMessageDialog.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.m; sourceTree = ""; }; + 860BB3AFC2DD08EF4599D8D42484D2CC /* FBSDKCrypto.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKCrypto.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.m; sourceTree = ""; }; + 864B619977C41FA41083B23778DFD471 /* FBSDKShareLinkContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareLinkContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareLinkContent.m; sourceTree = ""; }; + 868CF57091A5F8B47E4CF9B82CD4715D /* RKRouter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRouter.h; path = Code/Network/RKRouter.h; sourceTree = ""; }; + 8707552112C343BFF840516C1AAD0D31 /* POPAnimationPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationPrivate.h; path = pop/POPAnimationPrivate.h; sourceTree = ""; }; + 87352A5CFA4016F286A66829B0D2BFB9 /* FBSDKAppGroupContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppGroupContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppGroupContent.h; sourceTree = ""; }; + 87C33535E86A40250BA126A6209213CC /* FBSDKLoginTooltipView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginTooltipView.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginTooltipView.h; sourceTree = ""; }; + 87EE4B2AFFD85E9F75C94F5661D717F2 /* PFCommandURLRequestConstructor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCommandURLRequestConstructor.m; path = Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.m; sourceTree = ""; }; + 880C326DB82974026154DE2FEE6DF8EA /* FBSDKLoginKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FBSDKLoginKit-dummy.m"; sourceTree = ""; }; + 882472CF6BA62D86D2BF8542B479D3CB /* BFTask+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "BFTask+Private.h"; path = "Parse/Internal/BFTask+Private.h"; sourceTree = ""; }; + 8837B1CB6DAF343BD8C545163EA2DA58 /* PFEncoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFEncoder.h; path = Parse/Internal/PFEncoder.h; sourceTree = ""; }; + 8904DD3C8A8AC8A1A2F48DEB0DBC1B95 /* FBSDKAppEventsUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppEventsUtility.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.m; sourceTree = ""; }; + 892F0F257D5AF973E182934E5D03C911 /* PFInstallation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFInstallation.m; path = Parse/PFInstallation.m; sourceTree = ""; }; + 8988609857673ACE16552A1C00D45091 /* FBSDKDynamicFrameworkLoader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKDynamicFrameworkLoader.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKDynamicFrameworkLoader.m; sourceTree = ""; }; + 89CDFA61E00364C5AE6882B31CA90BB4 /* AFPropertyListRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFPropertyListRequestOperation.h; path = AFNetworking/AFPropertyListRequestOperation.h; sourceTree = ""; }; + 8A6E4A459DD6D5E686E59DC08B4D07F1 /* FBSDKLoginButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginButton.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.h; sourceTree = ""; }; + 8A7550A91022A017F5AFB8DF01AAFDFA /* RKObjectRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectRequestOperation.m; path = Code/Network/RKObjectRequestOperation.m; sourceTree = ""; }; + 8B1E4C81276B30550CB3CDA51070D862 /* PFRESTCloudCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTCloudCommand.h; path = Parse/Internal/Commands/PFRESTCloudCommand.h; sourceTree = ""; }; + 8B9E4087FDB2FFD655EB8FA58B697B4E /* RKPropertyMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPropertyMapping.m; path = Code/ObjectMapping/RKPropertyMapping.m; sourceTree = ""; }; + 8BECD1A40487A504B56D704C9D21E36C /* RKManagedObjectRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectRequestOperation.h; path = Code/Network/RKManagedObjectRequestOperation.h; sourceTree = ""; }; + 8C78256463C46E887FB8962C96ADF343 /* RKRoute.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRoute.h; path = Code/Network/RKRoute.h; sourceTree = ""; }; + 8CBCFD5CCB1FD15EED54F82E909DC031 /* FBSDKShareButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareButton.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.h; sourceTree = ""; }; + 8D28D5F66862955E51F3A4E12B34C7A6 /* FBSDKLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLogger.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.m; sourceTree = ""; }; + 8DB170D4C4F763AED7B36159D448013E /* FBSDKServerConfigurationManager+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKServerConfigurationManager+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfigurationManager+Internal.h"; sourceTree = ""; }; + 8DE9B680DB183FA614D58C42EADD38D7 /* FBSDKWebDialogView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKWebDialogView.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialogView.h; sourceTree = ""; }; + 8E39257A1062D3B3E8CA265E73AF9795 /* PFBase64Encoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFBase64Encoder.m; path = Parse/Internal/PFBase64Encoder.m; sourceTree = ""; }; + 8F8116D4E8780C6E74C186A8402C69F9 /* PFMultiProcessFileLock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMultiProcessFileLock.m; path = Parse/Internal/MultiProcessLock/PFMultiProcessFileLock.m; sourceTree = ""; }; + 8F8334729245B982D2786A77F61C281C /* PFObjectController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectController.h; path = Parse/Internal/Object/Controller/PFObjectController.h; sourceTree = ""; }; + 8FB19F616008A121FAA50E14B62D67A0 /* RKNSJSONSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKNSJSONSerialization.m; path = Code/Support/RKNSJSONSerialization.m; sourceTree = ""; }; + 903947141B4DCB4B32507DADE29354A1 /* RKMappingResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMappingResult.m; path = Code/ObjectMapping/RKMappingResult.m; sourceTree = ""; }; + 9045C664399C37132A893F2E170BEA3C /* BFWebViewAppLinkResolver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFWebViewAppLinkResolver.h; path = Bolts/iOS/BFWebViewAppLinkResolver.h; sourceTree = ""; }; + 9086156C9220E522C597B7BE572F6BFB /* RKHTTPRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKHTTPRequestOperation.m; path = Code/Network/RKHTTPRequestOperation.m; sourceTree = ""; }; + 909C0AD7538FB9457B86EC3AC7D973FD /* PFThreadsafety.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFThreadsafety.h; path = Parse/Internal/ThreadSafety/PFThreadsafety.h; sourceTree = ""; }; + 9152B5335813665EC6B08F73411A813E /* PFCachedQueryController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCachedQueryController.h; path = Parse/Internal/Query/Controller/PFCachedQueryController.h; sourceTree = ""; }; + 91D5B36C33B97E32AFA561C868667F87 /* BFAppLinkReturnToRefererController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFAppLinkReturnToRefererController.m; path = Bolts/iOS/BFAppLinkReturnToRefererController.m; sourceTree = ""; }; + 91E9125BDC1505BCE865985502732B9D /* PFFieldOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFieldOperation.m; path = Parse/Internal/FieldOperation/PFFieldOperation.m; sourceTree = ""; }; + 924EED608166B7F9A30865D80A87407F /* PFMutableObjectState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableObjectState.h; path = Parse/Internal/Object/State/PFMutableObjectState.h; sourceTree = ""; }; + 92D9BAF18D3C2495B07204C2404BFEEB /* FBSDKSendButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKSendButton.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKSendButton.m; sourceTree = ""; }; + 933D9439D53FAC2493C8D8F5ADD21D74 /* FBSDKMonotonicTime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMonotonicTime.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMonotonicTime.h; sourceTree = ""; }; + 936E7B213612ECBF1630386CE6D7B1D2 /* PFObjectConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectConstants.h; path = Parse/Internal/Object/Constants/PFObjectConstants.h; sourceTree = ""; }; + 939D831BAB14BEA5394F15D3E348976C /* PFPushState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPushState.m; path = Parse/Internal/Push/State/PFPushState.m; sourceTree = ""; }; + 93EE612E26F15D494EE5870F082534C2 /* RKMIMETypeSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMIMETypeSerialization.h; path = Code/Support/RKMIMETypeSerialization.h; sourceTree = ""; }; + 9441797DDFA8DBDB595E9BA19BE1342D /* PFRelationState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRelationState.h; path = Parse/Internal/Relation/State/PFRelationState.h; sourceTree = ""; }; + 947DE8E91AEF7DBF7FD80A52A76B2360 /* FBSDKLogo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLogo.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.h; sourceTree = ""; }; + 950E0A9F91ED212D2423C57E6D94CE04 /* FBSDKBridgeAPICrypto.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPICrypto.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h; sourceTree = ""; }; + 951E09F02C4842CACF36CAD6D5398E11 /* PFDefaultACLController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFDefaultACLController.h; path = Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.h; sourceTree = ""; }; + 955C4C780B4D5A0582BF89B0379CB61E /* CAAnimation+YALTabBarViewAnimations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "CAAnimation+YALTabBarViewAnimations.h"; path = "FoldingTabBar/Category/CAAnimation/CAAnimation+YALTabBarViewAnimations/CAAnimation+YALTabBarViewAnimations.h"; sourceTree = ""; }; + 957013533FBA66B6F24FF31441FF1EC3 /* FBSDKLoginUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginUtility.h; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.h; sourceTree = ""; }; + 95A9E38BEC3EF5836FF1194D04DDB98F /* FBSDKCoreKit+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKCoreKit+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h"; sourceTree = ""; }; + 95C0B6DA20609F0B05D9D1AB1D2FC475 /* FBSDKLikeBoxBorderView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeBoxBorderView.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.m; sourceTree = ""; }; + 95C137F2DF407C83936DE0B2BB3D6F86 /* PFACLState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFACLState.h; path = Parse/Internal/ACL/State/PFACLState.h; sourceTree = ""; }; + 95FF2C409A7211FB7720DA60E56153C4 /* FBSDKBridgeAPIProtocolWebV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPIProtocolWebV1.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.m; sourceTree = ""; }; + 96A6F76476CACBAADE4A258C71998683 /* POPBasicAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPBasicAnimation.mm; path = pop/POPBasicAnimation.mm; sourceTree = ""; }; + 96EB5396864F3EE4D9E7D3994DBD1015 /* PFMacros.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMacros.h; path = Parse/Internal/PFMacros.h; sourceTree = ""; }; + 97044BE056C705C44778E090F30A538B /* PFSQLiteDatabaseController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSQLiteDatabaseController.m; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseController.m; sourceTree = ""; }; + 9766DA2E569D10FE157FA2E355CC9802 /* RKStringTokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKStringTokenizer.h; path = Code/Support/RKStringTokenizer.h; sourceTree = ""; }; + 979C040C22C6D7527C085E98ED8D71A0 /* libFBSDKShareKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFBSDKShareKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 97D4677BC9F2D88DF946E204DF242D38 /* PFFieldOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFieldOperation.h; path = Parse/Internal/FieldOperation/PFFieldOperation.h; sourceTree = ""; }; + 97F4FC4FF392B72657F42F96261BBC3F /* FBSDKShareOpenGraphContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareOpenGraphContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphContent.h; sourceTree = ""; }; + 98262DA8D9F983FFA347D99C232021E5 /* PFEventuallyPin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFEventuallyPin.m; path = Parse/Internal/PFEventuallyPin.m; sourceTree = ""; }; + 9860C0C7692D5A2C0C40448F5323C485 /* FBSDKLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLogger.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKLogger.h; sourceTree = ""; }; + 98C98CDFB3F20F2925F6CD1F141BB14F /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.release.xcconfig; sourceTree = ""; }; + 98D1A4CAC7340A038BDCFECC7E0BFE95 /* FBSDKPaymentObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKPaymentObserver.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.m; sourceTree = ""; }; + 996415B7247FE7D0C37780B180517ACB /* POPAnimator.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimator.mm; path = pop/POPAnimator.mm; sourceTree = ""; }; + 996EADA337EAC02210FEC4506EB335B5 /* POPAnimationEvent.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimationEvent.mm; path = pop/POPAnimationEvent.mm; sourceTree = ""; }; + 997269FD4178F2BC0707886B0C405A8D /* lcl_RK.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = lcl_RK.m; path = Vendor/LibComponentLogging/Core/lcl_RK.m; sourceTree = ""; }; + 999823937ADC925F2F63F241A5995EFE /* PFCommandCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCommandCache.m; path = Parse/Internal/PFCommandCache.m; sourceTree = ""; }; + 99B423A79E8F8A42FC5D676612B33E2F /* PFDateFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFDateFormatter.m; path = Parse/Internal/PFDateFormatter.m; sourceTree = ""; }; + 9A3DEC35A890AB8929D5A78F2D24DC7A /* RKRelationshipMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRelationshipMapping.m; path = Code/ObjectMapping/RKRelationshipMapping.m; sourceTree = ""; }; + 9AA9561725BB1FB9134A92D8DC5A504B /* PFCategoryLoader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCategoryLoader.m; path = Parse/Internal/PFCategoryLoader.m; sourceTree = ""; }; + 9ABAB9B040DE06F9C8CAD85CCC2D4A4D /* PFInstallationPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallationPrivate.h; path = Parse/Internal/Installation/PFInstallationPrivate.h; sourceTree = ""; }; + 9ADB5C6CFDD59CB906870DA9025B3B8A /* Support.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Support.h; path = Code/Support.h; sourceTree = ""; }; + 9AE4C9BDAE4E6537716122FED10B39E1 /* FBSDKErrorRecoveryConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKErrorRecoveryConfiguration.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.m; sourceTree = ""; }; + 9B9C80D740936B42747C456E06BD4210 /* FBSDKShareDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareDefines.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareDefines.h; sourceTree = ""; }; + 9BD8C56BA64752CBF457FB1F3473747F /* Parse-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Parse-dummy.m"; sourceTree = ""; }; + 9C13271F07F590F5CD4297A3A11F07EA /* FBSDKSystemAccountStoreAdapter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKSystemAccountStoreAdapter.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.m; sourceTree = ""; }; + 9CDD229A4ED63D296862C7CC3E93D079 /* PFFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFile.h; path = Parse/PFFile.h; sourceTree = ""; }; + 9CE70D7D33DCB5A7B77D431309FF7DED /* FBSDKBridgeAPIProtocolNativeV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIProtocolNativeV1.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h; sourceTree = ""; }; + 9D4E7099B46D1C3E524DA77BA96A3960 /* FBSDKMaleSilhouetteIcon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMaleSilhouetteIcon.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKMaleSilhouetteIcon.h; sourceTree = ""; }; + 9D7377386CC3EBA3E3B7C409D23C69B6 /* libFBSDKLoginKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFBSDKLoginKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 9D7D382B54C6E6B265B154F079E1CDDB /* FBSDKLikeButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeButton.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeButton.h; sourceTree = ""; }; + 9E3D3427A00B557DE42EED0B4C015942 /* FBSDKShareUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareUtility.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.h; sourceTree = ""; }; + 9E3DEF8E2E27C00D59DC5DE4C876E0D1 /* FBSDKLikeControl.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeControl.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeControl.m; sourceTree = ""; }; + 9E5A00420D365F9C27CF6F943E8EB990 /* PFMutableUserState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableUserState.m; path = Parse/Internal/User/State/PFMutableUserState.m; sourceTree = ""; }; + 9EB6FC1B35894D58DCAA447BFB3BB370 /* BFCancellationToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationToken.h; path = Bolts/Common/BFCancellationToken.h; sourceTree = ""; }; + 9F097273140B23B664D84C6DF75EE2D1 /* PFRESTUserCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTUserCommand.m; path = Parse/Internal/Commands/PFRESTUserCommand.m; sourceTree = ""; }; + 9F1B1BCD1E0ECE22C24CC82032B14A95 /* FBSDKLikeDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeDialog.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeDialog.h; sourceTree = ""; }; + 9F7C74984ABBD35EBF1A84D46747BF45 /* FloatConversion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FloatConversion.h; path = pop/WebCore/FloatConversion.h; sourceTree = ""; }; + 9FBA963311C705B8BC3B0E2FC0EB8529 /* PFAlertView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAlertView.m; path = Parse/Internal/PFAlertView.m; sourceTree = ""; }; + 9FE12F1A4097AA56DD490CFF1B57E4AB /* FBSDKErrorRecoveryAttempter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKErrorRecoveryAttempter.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/FBSDKErrorRecoveryAttempter.h; sourceTree = ""; }; + 9FE38696DEEE3653F1AF4FB0CA7BC07F /* PFNetworkActivityIndicatorManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFNetworkActivityIndicatorManager.m; path = Parse/PFNetworkActivityIndicatorManager.m; sourceTree = ""; }; + A0356870F75E493C4A0C432FFFDF4798 /* FBSDKAccessTokenCacheV3.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCacheV3.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h; sourceTree = ""; }; + A0A6F3B1842359B2087C2C8FE2CDB03A /* RKPaginator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPaginator.m; path = Code/Network/RKPaginator.m; sourceTree = ""; }; + A0C95D96D102F597D4543F77E2DBE642 /* ISO8601DateFormatterValueTransformer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ISO8601DateFormatterValueTransformer-dummy.m"; sourceTree = ""; }; + A0DE6D1F31DEFED040F4E85B6631177D /* PFPurchaseController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPurchaseController.h; path = Parse/Internal/Purchase/Controller/PFPurchaseController.h; sourceTree = ""; }; + A12B03B24DC7C654F172A6A53E9C7603 /* PFObject.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObject.m; path = Parse/PFObject.m; sourceTree = ""; }; + A16A70655423A834331503E4979C4422 /* FBSDKAppEventsUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppEventsUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h; sourceTree = ""; }; + A1A36D34413696BE466E2CA0AFF194DA /* Pods-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-resources.sh"; sourceTree = ""; }; + A1F131A4365C559659FC1FBB194A13E9 /* PFRESTFileCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTFileCommand.h; path = Parse/Internal/Commands/PFRESTFileCommand.h; sourceTree = ""; }; + A28864FB7EB36A5080B6D12B1B94125F /* AFNetworking.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = AFNetworking.xcconfig; sourceTree = ""; }; + A2D57E341463F67AF53255008B5CAB0A /* AFNetworkActivityIndicatorManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFNetworkActivityIndicatorManager.m; path = AFNetworking/AFNetworkActivityIndicatorManager.m; sourceTree = ""; }; + A2FAF2092D4C51EAE9E68E2B1EB0071B /* FBSDKAppEventsStateManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppEventsStateManager.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h; sourceTree = ""; }; + A303568877AD7BACE17E962FDF4513C1 /* POPMath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPMath.h; path = pop/POPMath.h; sourceTree = ""; }; + A3152B830DE11B9029E12D3C5B928C17 /* PFPushUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPushUtilities.m; path = Parse/Internal/Push/Utilites/PFPushUtilities.m; sourceTree = ""; }; + A36C3225AB6FDE49BE8F8859C30A7D7D /* PFUserAuthenticationController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserAuthenticationController.h; path = Parse/Internal/User/AuthenticationProviders/Controller/PFUserAuthenticationController.h; sourceTree = ""; }; + A3794B030BCB9C4408CA8A2839964ED1 /* AFImageRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFImageRequestOperation.h; path = AFNetworking/AFImageRequestOperation.h; sourceTree = ""; }; + A38DBD435D9B08BE5E3BBE4C171BB0B9 /* Parse.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Parse.xcconfig; sourceTree = ""; }; + A3FBF62848DF8B263E30542353335091 /* PFInternalUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInternalUtils.h; path = Parse/Internal/PFInternalUtils.h; sourceTree = ""; }; + A43A3FE9CF5B7E721E9179EB461EBDD7 /* PFEventuallyQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFEventuallyQueue.h; path = Parse/Internal/PFEventuallyQueue.h; sourceTree = ""; }; + A473C610615EE15F20D33C59B9CC54B8 /* FBSDKGraphRequestPiggybackManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequestPiggybackManager.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestPiggybackManager.m; sourceTree = ""; }; + A473E7C40F24CE11C1FE9F416C8E5EC2 /* FBSDKLikeBoxView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeBoxView.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.m; sourceTree = ""; }; + A4B28BD09271EAECA8D4D7EE69556765 /* PFSessionUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSessionUtilities.h; path = Parse/Internal/Session/Utilities/PFSessionUtilities.h; sourceTree = ""; }; + A4DD5212BA2630DC90D52AB2A7B05B85 /* RKObjectManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectManager.h; path = Code/Network/RKObjectManager.h; sourceTree = ""; }; + A51B1A321088E7B66FD0BCAE78FD96F9 /* PFInstallation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallation.h; path = Parse/PFInstallation.h; sourceTree = ""; }; + A585F71D8045AD5FFA838F5907C9DCFE /* _FBSDKTemporaryErrorRecoveryAttempter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _FBSDKTemporaryErrorRecoveryAttempter.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ErrorRecovery/_FBSDKTemporaryErrorRecoveryAttempter.h; sourceTree = ""; }; + A6D705A7C393E18FCFACEC1D2F07D098 /* PFQueryState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQueryState_Private.h; path = Parse/Internal/Query/State/PFQueryState_Private.h; sourceTree = ""; }; + A75314C0637DF9AD59C4F573E3CB78C6 /* YALTabBarItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = YALTabBarItem.m; path = FoldingTabBar/Model/TabBarItem/YALTabBarItem.m; sourceTree = ""; }; + A7540E284803A52212B2DE3FD4678F87 /* PFPinningEventuallyQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPinningEventuallyQueue.h; path = Parse/Internal/PFPinningEventuallyQueue.h; sourceTree = ""; }; + A7780E3BA6732D798F3374CA43890F7C /* PFSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSession.m; path = Parse/PFSession.m; sourceTree = ""; }; + A78C310CE96FB8C96AB74FE6A10686E7 /* TKStateMachine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKStateMachine.m; path = Code/TKStateMachine.m; sourceTree = ""; }; + A7AAF29A747A53F757B1A76CF477460A /* PFObjectSubclassInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectSubclassInfo.m; path = Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.m; sourceTree = ""; }; + A7AC1819EBC907C93BA5F2B790C16D0E /* FBSDKSharePhotoContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSharePhotoContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.h; sourceTree = ""; }; + A8051434722A3494196DC122D8029D34 /* FBSDKShareDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareDialog.h; sourceTree = ""; }; + A8710983B393BA50AECE51EA8D90E727 /* FBSDKLikeBoxView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeBoxView.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxView.h; sourceTree = ""; }; + A8E3AF8A6E915006D004A9CF92CA325D /* RKObjectRequestOperationSubclass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectRequestOperationSubclass.h; path = Code/Network/RKObjectRequestOperationSubclass.h; sourceTree = ""; }; + A94107D173054A31E231EA3E081AC080 /* PFCommandRunning.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCommandRunning.m; path = Parse/Internal/Commands/CommandRunner/PFCommandRunning.m; sourceTree = ""; }; + A9971360D666FDBC3DDD421157793868 /* FBSDKUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.h; sourceTree = ""; }; + A99D66855595DD2F9E379F9A258C7FD4 /* FBSDKGameRequestFrictionlessRecipientCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGameRequestFrictionlessRecipientCache.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.m; sourceTree = ""; }; + A9CA1C8C41256C5E7CEDBAF354C19AE5 /* AFXMLRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFXMLRequestOperation.m; path = AFNetworking/AFXMLRequestOperation.m; sourceTree = ""; }; + A9E08B70AB72ECE4DA87BFED9B17F956 /* FBSDKShareLinkContent+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKShareLinkContent+Internal.h"; path = "FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareLinkContent+Internal.h"; sourceTree = ""; }; + AA02D2B63E8F9A35484FF74BB175EDCF /* PFMutableQueryState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableQueryState.h; path = Parse/Internal/Query/State/PFMutableQueryState.h; sourceTree = ""; }; + AA158698DE160B78310B78C6F5F5EEBF /* SOCKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SOCKit-prefix.pch"; sourceTree = ""; }; + AA2DB152E74138129BF1919667D8AA5C /* RestKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RestKit-prefix.pch"; sourceTree = ""; }; + AAB9F7182025D4FEB1027A192204588E /* PFBaseState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFBaseState.h; path = Parse/Internal/PFBaseState.h; sourceTree = ""; }; + AB87FFD2A22D9F8F81F29DD24782E89A /* PFPushState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushState.h; path = Parse/Internal/Push/State/PFPushState.h; sourceTree = ""; }; + ABE4BA05E14673159DDEE660B13A5B00 /* PFQueryController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFQueryController.m; path = Parse/Internal/Query/Controller/PFQueryController.m; sourceTree = ""; }; + AC8C608A0D3BE700536D0C6D4011931A /* PFRelation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRelation.h; path = Parse/PFRelation.h; sourceTree = ""; }; + ACE07B046AA72822B46EAC882E565640 /* PFObjectFileCoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectFileCoder.h; path = Parse/Internal/Object/Coder/File/PFObjectFileCoder.h; sourceTree = ""; }; + ADAFAB54F5C5506CF7186CD16CA90EFA /* FBSDKMath.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKMath.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.m; sourceTree = ""; }; + ADBAF2BABA39070672917C80E4F74CBA /* FBSDKShareAPI.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareAPI.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareAPI.m; sourceTree = ""; }; + ADBEDE77334D88F47F1AD897ECEFAC8D /* PFObjectBatchController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectBatchController.h; path = Parse/Internal/Object/BatchController/PFObjectBatchController.h; sourceTree = ""; }; + ADC8E7B23140B59FA2BE5667DEC580B9 /* PFNetworkActivityIndicatorManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFNetworkActivityIndicatorManager.h; path = Parse/PFNetworkActivityIndicatorManager.h; sourceTree = ""; }; + ADCF28A6ED4B159F06F12E95D86E08B2 /* FBSDKCloseIcon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKCloseIcon.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h; sourceTree = ""; }; + ADD34821324463B1C81B2802AFA7B01C /* RKObjectMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMapping.m; path = Code/ObjectMapping/RKObjectMapping.m; sourceTree = ""; }; + AE15675496460EEA4051AF5F4AB4E504 /* FBSDKBridgeAPIProtocolWebV2.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPIProtocolWebV2.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.m; sourceTree = ""; }; + AE3ADE078ECB5E4868892A8EA3936EA5 /* YALFoldingTabBarController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = YALFoldingTabBarController.m; path = FoldingTabBar/Controller/FoldingTabBarController/YALFoldingTabBarController.m; sourceTree = ""; }; + AE3D34F74057747813B67E0E716F8275 /* BFAppLinkReturnToRefererController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkReturnToRefererController.h; path = Bolts/iOS/BFAppLinkReturnToRefererController.h; sourceTree = ""; }; + AEA3B8A0B629E223E8AD2FFCA8C65F21 /* PFLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFLogger.m; path = Parse/Internal/PFLogger.m; sourceTree = ""; }; + AEA43D8F8666C7D28DA8F862B304C5B8 /* RKResponseDescriptor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKResponseDescriptor.h; path = Code/Network/RKResponseDescriptor.h; sourceTree = ""; }; + AEB3E3D5DFF77A79169D2E7390145CE7 /* FBSDKWebDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKWebDialog.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/WebDialog/FBSDKWebDialog.h; sourceTree = ""; }; + AEB4D0E3F5DD747BCD44340E26E9755F /* FBSDKLoginKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginKit.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginKit.h; sourceTree = ""; }; + AF22BCCC30F4473554DFAAAEBC740BE7 /* FBSDKSharing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSharing.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharing.h; sourceTree = ""; }; + AFDCBEB6665886D2633CB5495726E387 /* PFPushManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPushManager.m; path = Parse/Internal/Push/Manager/PFPushManager.m; sourceTree = ""; }; + B037353120BA03ACEF0F5DA52B84530E /* RKObjectUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectUtilities.h; path = Code/ObjectMapping/RKObjectUtilities.h; sourceTree = ""; }; + B03B11C4675A010812829BDD0481A90F /* PFSession_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSession_Private.h; path = Parse/Internal/Session/PFSession_Private.h; sourceTree = ""; }; + B0AF344F89667D8F50F4A22C146ACF21 /* PFSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSession.h; path = Parse/PFSession.h; sourceTree = ""; }; + B0F29E0D66F63131F371330D93CB4583 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + B1126558A8CA869CAE3169CD0485A400 /* PFURLSessionJSONDataTaskDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSessionJSONDataTaskDelegate.m; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionJSONDataTaskDelegate.m; sourceTree = ""; }; + B163A0D63692C83B09ED63F3D357CC5D /* FBSDKPaymentObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKPaymentObserver.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKPaymentObserver.h; sourceTree = ""; }; + B16533489604D2247F7EC997C13BA975 /* FBSDKSharePhotoContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKSharePhotoContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharePhotoContent.m; sourceTree = ""; }; + B16892D13DE46A8E0F04B376575D7B5C /* PFInternalUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFInternalUtils.m; path = Parse/Internal/PFInternalUtils.m; sourceTree = ""; }; + B25EAE7B7171B287489EDA0C0A129426 /* Testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Testing.h; path = Code/Testing.h; sourceTree = ""; }; + B27AB7689D28F34F8A9D466ACAB162DA /* PFNullability.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFNullability.h; path = Parse/PFNullability.h; sourceTree = ""; }; + B3362FF57BC5AE2D2552F6F4C4ACD2C9 /* FBSDKLoginKit+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLoginKit+Internal.h"; path = "FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginKit+Internal.h"; sourceTree = ""; }; + B352E84B1EE885140F4F4DC84329D6CB /* FBSDKAccessTokenCacheV4.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessTokenCacheV4.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.m; sourceTree = ""; }; + B3AC4F0EFC27421FCDFE376464524DBB /* PFUserFileCodingLogic.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUserFileCodingLogic.h; path = Parse/Internal/User/Coder/File/PFUserFileCodingLogic.h; sourceTree = ""; }; + B3AE7C57230B414B51B418F0B88252FB /* PFPin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPin.h; path = Parse/Internal/LocalDataStore/Pin/PFPin.h; sourceTree = ""; }; + B40775302C0516B1FB09E3523DC34D30 /* FBSDKGraphRequestConnection.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequestConnection.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.m; sourceTree = ""; }; + B432A363E0081BD273051415B767D749 /* FBSDKSettings+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKSettings+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSettings+Internal.h"; sourceTree = ""; }; + B477BB1DB6E55636C30151FED839DBEC /* FBSDKSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSettings.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.h; sourceTree = ""; }; + B4A9DBE857C85DBC4FCF8511B67E7FF3 /* PFPropertyInfo_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPropertyInfo_Private.h; path = Parse/Internal/PropertyInfo/PFPropertyInfo_Private.h; sourceTree = ""; }; + B53170EBE3F4D7BAA67CDA6A2C198542 /* FBSDKShareConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareConstants.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareConstants.m; sourceTree = ""; }; + B53D5E1A96FE30D9B7F8D596BF9E2F80 /* POPPropertyAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPPropertyAnimation.mm; path = pop/POPPropertyAnimation.mm; sourceTree = ""; }; + B5439DB8932AAF79667AED53097CC2C9 /* PFRelationPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRelationPrivate.h; path = Parse/Internal/Relation/PFRelationPrivate.h; sourceTree = ""; }; + B5AA14CFC28475D9E28E32A363674B8F /* RKDictionaryUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDictionaryUtilities.h; path = Code/Support/RKDictionaryUtilities.h; sourceTree = ""; }; + B5D03113C677A7DDA961E0D9E46E949A /* PFMutableObjectState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFMutableObjectState.m; path = Parse/Internal/Object/State/PFMutableObjectState.m; sourceTree = ""; }; + B6CBDBFAF7E5AFEF7AE3D397FB6EE762 /* PFAnalyticsUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnalyticsUtilities.h; path = Parse/Internal/Analytics/Utilities/PFAnalyticsUtilities.h; sourceTree = ""; }; + B6D4806630F08E4A693BB13FD80E2B85 /* PFOfflineQueryController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFOfflineQueryController.h; path = Parse/Internal/Query/Controller/PFOfflineQueryController.h; sourceTree = ""; }; + B6E7D0F10FA61E6BAC091324113D02F2 /* FBSDKGraphRequestBody.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequestBody.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.m; sourceTree = ""; }; + B6FDEF44D035ECEB171CF49BE68D54D0 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + B70778A88E35241FD05E8017A5D78CFD /* PFPinningObjectStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPinningObjectStore.h; path = Parse/Internal/Object/PinningStore/PFPinningObjectStore.h; sourceTree = ""; }; + B7478D31F88F47602170505B415F4CEB /* RKMappingOperationDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingOperationDataSource.h; path = Code/ObjectMapping/RKMappingOperationDataSource.h; sourceTree = ""; }; + B78A7E4B40882223B829568BDECFF65F /* PFApplication.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFApplication.m; path = Parse/Internal/PFApplication.m; sourceTree = ""; }; + B7B30077DB15E3549CCF53E8707A36D6 /* FBSDKAccessTokenCacheV3_17.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessTokenCacheV3_17.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.m; sourceTree = ""; }; + B7B6A72DD28FBD988E0B1E6A930C1BCA /* YALSpringAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALSpringAnimation.h; path = FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.h; sourceTree = ""; }; + B8046097AB97D9EBA30FEAF579C44F56 /* FBSDKAudioResourceLoader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAudioResourceLoader.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.m; sourceTree = ""; }; + B80B9804F9EC77183DFB3A54E58272CF /* FBSDKLogo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLogo.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKLogo.m; sourceTree = ""; }; + B818BE16D0901DD3F720DF4447B592B0 /* PFFileManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileManager.h; path = Parse/Internal/PFFileManager.h; sourceTree = ""; }; + B8C1F1B3446748EE4B4240C0CC009D67 /* PFCommandCache_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandCache_Private.h; path = Parse/Internal/PFCommandCache_Private.h; sourceTree = ""; }; + B8DA6BF199DF0CAB4F3B6FE8589F18F9 /* FBSDKLikeObjectType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeObjectType.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKLikeObjectType.m; sourceTree = ""; }; + B91E34DFD041EF9B4895EC618300E024 /* FBSDKSharePhoto.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSharePhoto.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharePhoto.h; sourceTree = ""; }; + B92B54D733F8824AD766092F58A3F50C /* PFLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFLogging.h; path = Parse/Internal/PFLogging.h; sourceTree = ""; }; + B934A04F1A258C2A0713237E8C4DB79E /* PFACL.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFACL.h; path = Parse/PFACL.h; sourceTree = ""; }; + B93B968FDB3F20E1EB2FA742FA119F61 /* PFMutableFileState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFMutableFileState.h; path = Parse/Internal/File/State/PFMutableFileState.h; sourceTree = ""; }; + B99772D5AE952C0693DC05AAA4538D94 /* BFAppLinkResolving.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkResolving.h; path = Bolts/iOS/BFAppLinkResolving.h; sourceTree = ""; }; + B9BAFC471A7F7E390879132FBD1B3B21 /* FBSDKGraphRequestBody.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequestBody.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequestBody.h; sourceTree = ""; }; + B9E911ACAAECA0172448CD4E62137AF4 /* PFRESTAnalyticsCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTAnalyticsCommand.h; path = Parse/Internal/Commands/PFRESTAnalyticsCommand.h; sourceTree = ""; }; + BA0DEBD43672CEB35AC053C3EDBD0BF9 /* RKResponseDescriptor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKResponseDescriptor.m; path = Code/Network/RKResponseDescriptor.m; sourceTree = ""; }; + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + BA69ED7E54B79F2B468E042414006FC8 /* FBSDKCopying.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKCopying.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h; sourceTree = ""; }; + BBB5809E48E2B4BEFFDD671C03A673A1 /* FBSDKLoginCompletion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginCompletion.m; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginCompletion.m; sourceTree = ""; }; + BC07203CD82FF286D245D3A0306E62C5 /* PFAnalytics_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnalytics_Private.h; path = Parse/Internal/Analytics/PFAnalytics_Private.h; sourceTree = ""; }; + BC16505461748776619D43C6BDC6A703 /* PFInstallationController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallationController.h; path = Parse/Internal/Installation/Controller/PFInstallationController.h; sourceTree = ""; }; + BC451FC53B248606339FEF2A083812CA /* PFObjectBatchController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectBatchController.m; path = Parse/Internal/Object/BatchController/PFObjectBatchController.m; sourceTree = ""; }; + BC8D8339F84A5B54DDC0F0B6C03E6C30 /* POPAnimationTracerInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationTracerInternal.h; path = pop/POPAnimationTracerInternal.h; sourceTree = ""; }; + BC931BFEE302F10CF84316FC396B1F01 /* FBSDKBridgeAPIProtocolNativeV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPIProtocolNativeV1.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.m; sourceTree = ""; }; + BCA4ADF879DDDE1CAAA0ABFB4BC7210D /* FBSDKAccessTokenCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCache.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h; sourceTree = ""; }; + BCB59A851D792D3D60B16A08B9F07134 /* RKHTTPUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKHTTPUtilities.h; path = Code/ObjectMapping/RKHTTPUtilities.h; sourceTree = ""; }; + BD5D724AF948672175ECFB8781A0F2F5 /* YALSpringAnimation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = YALSpringAnimation.m; path = FoldingTabBar/Animation/YALSpringAnimation/YALSpringAnimation.m; sourceTree = ""; }; + BD6DD4F4195C174C8DC06D3C85DDF8A8 /* ParseModule.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ParseModule.h; path = Parse/Internal/ParseModule.h; sourceTree = ""; }; + BD91B010ED73759E99DB85B7CA9FA867 /* PFQueryState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQueryState.h; path = Parse/Internal/Query/State/PFQueryState.h; sourceTree = ""; }; + BDA6A8C4B5B6F7C4E38F45C438720C50 /* FBSDKErrorRecoveryConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKErrorRecoveryConfiguration.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorRecoveryConfiguration.h; sourceTree = ""; }; + BDC0554AEE7F2D9DF98C2D8FC049FD2A /* POPSpringAnimation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPSpringAnimation.h; path = pop/POPSpringAnimation.h; sourceTree = ""; }; + BDEF6D63702D3C9DE58BBBC7977D10BA /* POPLayerExtras.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPLayerExtras.h; path = pop/POPLayerExtras.h; sourceTree = ""; }; + BE404DC24F62FA97CDAEF063B4413139 /* BFTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTask.m; path = Bolts/Common/BFTask.m; sourceTree = ""; }; + BEEE1441A35504F5C1462BCBEE30EE7F /* FBSDKShareButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareButton.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareButton.m; sourceTree = ""; }; + BF0336CCD7C95A339E279331D898870E /* PFPurchase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPurchase.h; path = Parse/PFPurchase.h; sourceTree = ""; }; + BF428BEC06706AA0A98B6805206833C2 /* RKValueTransformers.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RKValueTransformers.xcconfig; sourceTree = ""; }; + BF44B45F9B1A350C1FB2F6D209A9BC4D /* FBSDKAccessTokenCacheV3_21.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAccessTokenCacheV3_21.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.m; sourceTree = ""; }; + BF50A2188E832EC70F211B3F3932C51C /* FBSDKMessageDialog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMessageDialog.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKMessageDialog.h; sourceTree = ""; }; + BF6BCF95270D89143AE2BD11E8C58467 /* RKTestFixture.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKTestFixture.m; path = Code/Testing/RKTestFixture.m; sourceTree = ""; }; + BF8BD2902C2FE3B67C86F30BFEAE4A3E /* FBSDKAppInviteContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppInviteContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.h; sourceTree = ""; }; + BFAC7C03033A9B1F15075F4565BC1328 /* FBSDKLikeActionController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeActionController.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.h; sourceTree = ""; }; + BFBDACDD0805704D189CA36FE17373B8 /* FBSDKTooltipView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKTooltipView.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.m; sourceTree = ""; }; + BFCC23211BE47A527079FEF69772F5CE /* libBolts.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBolts.a; sourceTree = BUILT_PRODUCTS_DIR; }; + C01B234F69300CBE9F042A18823A2C64 /* FBSDKBridgeAPIResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIResponse.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h; sourceTree = ""; }; + C03EC589275AA21D375F405EB48AB374 /* pop-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "pop-dummy.m"; sourceTree = ""; }; + C0773511F8B57D80E82BBCED6576C5D2 /* PFFileManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFileManager.m; path = Parse/Internal/PFFileManager.m; sourceTree = ""; }; + C1A37998F9BF6B81FA68488F9A55BC50 /* PFUserController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUserController.m; path = Parse/Internal/User/Controller/PFUserController.m; sourceTree = ""; }; + C1B7244F3402CF0B20BFF0228719CDD1 /* FBSDKAppEventsDeviceInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppEventsDeviceInfo.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h; sourceTree = ""; }; + C1C4E1C48CDDA8FCF1C074DCC0D2A656 /* BFAppLink.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFAppLink.m; path = Bolts/iOS/BFAppLink.m; sourceTree = ""; }; + C1D9153F43B4ABADD58C382A1292332B /* PFOfflineStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFOfflineStore.h; path = Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.h; sourceTree = ""; }; + C2DF84BAF1C49F7A7466D1F88D650A50 /* PFCommandURLRequestConstructor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCommandURLRequestConstructor.h; path = Parse/Internal/Commands/CommandRunner/URLRequestConstructor/PFCommandURLRequestConstructor.h; sourceTree = ""; }; + C2E9C149FB61E88BEF76CE74D5776813 /* FBSDKCheckmarkIcon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKCheckmarkIcon.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKCheckmarkIcon.h; sourceTree = ""; }; + C303ED3A2C18CE2AAADCC69948039080 /* PFNetworkCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFNetworkCommand.h; path = Parse/Internal/PFNetworkCommand.h; sourceTree = ""; }; + C31FC859AAD2E2012636FC6B877D6EB6 /* RKErrors.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKErrors.m; path = Code/Support/RKErrors.m; sourceTree = ""; }; + C345096A388C3F1F4E486E39C9D61CD4 /* UIImageView+AFNetworking.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+AFNetworking.m"; path = "AFNetworking/UIImageView+AFNetworking.m"; sourceTree = ""; }; + C3743DDF0F64379FD843ED463460FF90 /* FBSDKGraphRequestDataAttachment.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequestDataAttachment.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h; sourceTree = ""; }; + C3B87B3E4AC8A18214858CF42A599D50 /* lcl_config_logger_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_logger_RK.h; path = Code/Support/lcl_config_logger_RK.h; sourceTree = ""; }; + C42E29EF756BB8A7BCE6151C6229BA3D /* RKObjectMappingMatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMappingMatcher.m; path = Code/ObjectMapping/RKObjectMappingMatcher.m; sourceTree = ""; }; + C45478301558D880893FA55C99879E3C /* FBSDKLoginManagerLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginManagerLogger.m; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.m; sourceTree = ""; }; + C4DAAE6C562288FB95B1415AF6763317 /* PFACLPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFACLPrivate.h; path = Parse/Internal/ACL/PFACLPrivate.h; sourceTree = ""; }; + C4FAEDC2711A67FEFF48FE305A9A04C6 /* PFUserState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUserState.m; path = Parse/Internal/User/State/PFUserState.m; sourceTree = ""; }; + C5052DE726F89E27E1CA5D188FD32C5D /* Bolts.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Bolts.h; path = Bolts/Common/Bolts.h; sourceTree = ""; }; + C52117BAFED1734D3269D56FE3D842E0 /* PFPropertyInfo_Runtime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPropertyInfo_Runtime.m; path = Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.m; sourceTree = ""; }; + C5363E7D4FF99528A9F857EE9F2DF437 /* PFObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObject.h; path = Parse/PFObject.h; sourceTree = ""; }; + C537E17C3097299FCBF860A93C47B723 /* FBSDKAccessToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessToken.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h; sourceTree = ""; }; + C544CA6F07611BFE8BFC800E9D59E5AE /* AFHTTPRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFHTTPRequestOperation.m; path = AFNetworking/AFHTTPRequestOperation.m; sourceTree = ""; }; + C5934D49963F991DC729306B6D2ECA94 /* FBSDKShareUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareUtility.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareUtility.m; sourceTree = ""; }; + C5C2B2C9BECEC9F64477D3C8051CFDB5 /* _FBSDKLoginRecoveryAttempter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _FBSDKLoginRecoveryAttempter.m; path = FBSDKLoginKit/FBSDKLoginKit/Internal/_FBSDKLoginRecoveryAttempter.m; sourceTree = ""; }; + C5F83C7A2BEAFF6FFAEAD7A6F73B7D49 /* libISO8601DateFormatterValueTransformer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libISO8601DateFormatterValueTransformer.a; sourceTree = BUILT_PRODUCTS_DIR; }; + C60BCCB74CDC88B04B7014C507F2D137 /* PFSQLiteDatabaseResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFSQLiteDatabaseResult.m; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.m; sourceTree = ""; }; + C647E341C56F994FDA336B094DDC681B /* ObjectMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ObjectMapping.h; path = Code/ObjectMapping.h; sourceTree = ""; }; + C651AC06095B97EDAEF872B6D7032F4E /* FBSDKAppLinkUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppLinkUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h; sourceTree = ""; }; + C66092953B80DE287E77614DFA2D2FE3 /* POPDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPDefines.h; path = pop/POPDefines.h; sourceTree = ""; }; + C70FA986190A848DD39EB171EF041F33 /* POPAction.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAction.h; path = pop/POPAction.h; sourceTree = ""; }; + C737DBF986FE1FF02706679384A58608 /* FBSDKLoginManagerLoginResult+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKLoginManagerLoginResult+Internal.h"; path = "FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLoginResult+Internal.h"; sourceTree = ""; }; + C758B84874FBB01F1E2CE355BEA77660 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; }; + C78765A1425D0F41319511A796357B1F /* PFObjectUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectUtilities.m; path = Parse/Internal/Object/Utilities/PFObjectUtilities.m; sourceTree = ""; }; + C7FD5D8AEF9C721E9A8B50A73398561A /* RKRouteSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRouteSet.h; path = Code/Network/RKRouteSet.h; sourceTree = ""; }; + CA018EEB50C81D92939C0E4379941FE9 /* FBSDKApplicationDelegate+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKApplicationDelegate+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h"; sourceTree = ""; }; + CA3482F3977AA386E991A54C5181BDE1 /* FBSDKAppEvents.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppEvents.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.m; sourceTree = ""; }; + CA3CB4DD07E35F520C793BA9032F51FC /* RKMappingTest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingTest.h; path = Code/Testing/RKMappingTest.h; sourceTree = ""; }; + CA3CDC2D78E68FD7654C42F67C29EF3A /* FBSDKViewImpressionTracker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKViewImpressionTracker.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.m; sourceTree = ""; }; + CA8D44F0BCF9802F38A1799B6EBF1407 /* FBSDKInternalUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKInternalUtility.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m; sourceTree = ""; }; + CAEFED956777B69C5958C0E809EC11BB /* PFRESTCloudCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTCloudCommand.m; path = Parse/Internal/Commands/PFRESTCloudCommand.m; sourceTree = ""; }; + CB172E497F3C842C06931402446C2D4B /* BFMeasurementEvent_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFMeasurementEvent_Internal.h; path = Bolts/iOS/BFMeasurementEvent_Internal.h; sourceTree = ""; }; + CB3D0EFB3CB9EFB991A6BD44384669BB /* RKMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapping.h; path = Code/ObjectMapping/RKMapping.h; sourceTree = ""; }; + CBA6686079E7409ED27CC9A6ADEBF36A /* FBSDKBridgeAPIRequest+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKBridgeAPIRequest+Private.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h"; sourceTree = ""; }; + CBF4F2328A16C47BFD1BCF837B76EB35 /* PFPush.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPush.m; path = Parse/PFPush.m; sourceTree = ""; }; + CC228E158C60DD94DF7B3EA5E18D8125 /* FBSDKKeychainStoreViaBundleID.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKKeychainStoreViaBundleID.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKKeychainStoreViaBundleID.m; sourceTree = ""; }; + CC27E380BD4D02E6D8E8A25280C06A29 /* FBSDKGraphRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKGraphRequest.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.m; sourceTree = ""; }; + CC7C0590FD149B2C227C59AB38DF61DC /* AFPropertyListRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFPropertyListRequestOperation.m; path = AFNetworking/AFPropertyListRequestOperation.m; sourceTree = ""; }; + CCD58C1FE0A285B35DC39096400FF8C5 /* YALTabBarInteracting.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALTabBarInteracting.h; path = FoldingTabBar/Protocol/TabBarInteracting/YALTabBarInteracting.h; sourceTree = ""; }; + CCE6CAC57669DAF95F75350ACA64D8F5 /* Parse-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Parse-prefix.pch"; sourceTree = ""; }; + CD158942FBF8358677B8D9A4BEA9332E /* RKPathMatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPathMatcher.h; path = Code/Network/RKPathMatcher.h; sourceTree = ""; }; + CD1F87198E6B2738076E71BB2C4A8C71 /* FBSDKError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKError.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKError.m; sourceTree = ""; }; + CD4D52B14CF2360DE429DCB655B00642 /* PFRelationState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRelationState_Private.h; path = Parse/Internal/Relation/State/PFRelationState_Private.h; sourceTree = ""; }; + CEB32A7ACC2D1268332E3ED6413E04AE /* AFNetworkActivityIndicatorManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFNetworkActivityIndicatorManager.h; path = AFNetworking/AFNetworkActivityIndicatorManager.h; sourceTree = ""; }; + CEF0CE91FC9080D9E33E9B362D760F18 /* FBSDKLikeButtonPopWAV.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeButtonPopWAV.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.h; sourceTree = ""; }; + CF09A05A7A248669395E6778DD2838AE /* TransitionKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "TransitionKit-prefix.pch"; sourceTree = ""; }; + CF3513EE8625253892B05EFF20F16B57 /* RKPropertyInspector.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPropertyInspector.m; path = Code/ObjectMapping/RKPropertyInspector.m; sourceTree = ""; }; + CF478811F261A5C3A4200EF18BD59E46 /* FBSDKLikeBoxBorderView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLikeBoxBorderView.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeBoxBorderView.h; sourceTree = ""; }; + CF6DFEAD49E3B96B670A4AB662D78229 /* FBSDKGraphRequest.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequest.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h; sourceTree = ""; }; + CFEE369DBDB3AF968FCC81B9E15BD259 /* BFAppLinkNavigation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFAppLinkNavigation.m; path = Bolts/iOS/BFAppLinkNavigation.m; sourceTree = ""; }; + D011D1FC8B93C93581E9C03ABF791BCF /* SOCKit.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = SOCKit.m; sourceTree = ""; }; + D0E010198F9F57F3C1F5251591AC52B6 /* PFObjectConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectConstants.m; path = Parse/Internal/Object/Constants/PFObjectConstants.m; sourceTree = ""; }; + D1361066E091AA4FB6E9B94B50118177 /* PFObject+Subclass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "PFObject+Subclass.h"; path = "Parse/PFObject+Subclass.h"; sourceTree = ""; }; + D147E7F72F838ED5D3C66A4E3546EC11 /* BFCancellationTokenSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenSource.h; path = Bolts/Common/BFCancellationTokenSource.h; sourceTree = ""; }; + D18B76D6F749D3B45BAA4E3B0F2EFFD1 /* PFQueryPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFQueryPrivate.h; path = Parse/Internal/Query/PFQueryPrivate.h; sourceTree = ""; }; + D1B966C2A921DE73042AA8B317E629EA /* Parse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Parse.m; path = Parse/Parse.m; sourceTree = ""; }; + D24D9A1393699B9007901EB5221D9018 /* PFFileDataStream.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFileDataStream.m; path = Parse/Internal/File/FileDataStream/PFFileDataStream.m; sourceTree = ""; }; + D24F985E3661241D2C0921E8022E66C2 /* FBSDKAppInviteContent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppInviteContent.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKAppInviteContent.m; sourceTree = ""; }; + D284CA3DDD91571D70CF7256A3C248FE /* lcl_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_RK.h; path = Vendor/LibComponentLogging/Core/lcl_RK.h; sourceTree = ""; }; + D2A208C22FB8BC1DAFD34F05A88E7349 /* BFTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTask.h; path = Bolts/Common/BFTask.h; sourceTree = ""; }; + D3359292FE89A636801514727B628BCA /* POPSpringAnimation.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPSpringAnimation.mm; path = pop/POPSpringAnimation.mm; sourceTree = ""; }; + D340DC8D2BC61B7C8A044A46F47ED4D0 /* BFCancellationToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationToken.m; path = Bolts/Common/BFCancellationToken.m; sourceTree = ""; }; + D3AD3AB61D09EFC9C322C57F9239AFF8 /* PFRESTUserCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTUserCommand.h; path = Parse/Internal/Commands/PFRESTUserCommand.h; sourceTree = ""; }; + D46B8631F4A20A30B5C1E47D9F2A6FEB /* PFAnonymousAuthenticationProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAnonymousAuthenticationProvider.m; path = Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousAuthenticationProvider.m; sourceTree = ""; }; + D4AB7EDD51484D69712FC0BAF2EEFB20 /* PFAnalytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnalytics.h; path = Parse/PFAnalytics.h; sourceTree = ""; }; + D4D4E125C0EFD510E0171C24783AD02F /* RKPropertyMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPropertyMapping.h; path = Code/ObjectMapping/RKPropertyMapping.h; sourceTree = ""; }; + D4F5FFBEC5EF679476BD610B31B04B36 /* PFErrorUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFErrorUtilities.m; path = Parse/Internal/PFErrorUtilities.m; sourceTree = ""; }; + D5B2F6DAB138D6C0AFB76C250456D0A9 /* RKTestFixture.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKTestFixture.h; path = Code/Testing/RKTestFixture.h; sourceTree = ""; }; + D5B9C19265F524EBC4ED733155E3DB3B /* RKObjectRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectRequestOperation.h; path = Code/Network/RKObjectRequestOperation.h; sourceTree = ""; }; + D5F29001AB83C450101AC6122BCC4EA0 /* PFRESTFileCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTFileCommand.m; path = Parse/Internal/Commands/PFRESTFileCommand.m; sourceTree = ""; }; + D605FE4F41A283271B93F93C8E0C5932 /* PFUserFileCodingLogic.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUserFileCodingLogic.m; path = Parse/Internal/User/Coder/File/PFUserFileCodingLogic.m; sourceTree = ""; }; + D65E69134BE531C727A15EAC5D6BD404 /* PFObjectUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectUtilities.h; path = Parse/Internal/Object/Utilities/PFObjectUtilities.h; sourceTree = ""; }; + D68125D407CB86FE46338C7579765331 /* RKISO8601DateFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKISO8601DateFormatter.h; path = Code/RKISO8601DateFormatter.h; sourceTree = ""; }; + D68CBFCA3F276272B2040E6469C8D1DE /* FBSDKColor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKColor.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h; sourceTree = ""; }; + D7AC47EB8D0E9C9582957C2869B7517D /* BFAppLinkReturnToRefererView_Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkReturnToRefererView_Internal.h; path = Bolts/iOS/BFAppLinkReturnToRefererView_Internal.h; sourceTree = ""; }; + D80B172E70B3B5E8CAEA6069D1DE5D71 /* FBSDKSharingButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSharingButton.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKSharingButton.h; sourceTree = ""; }; + D849F8915909B1847A03276B640112BC /* FBSDKUIUtility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKUIUtility.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKUIUtility.h; sourceTree = ""; }; + D8B4BCA52E13031B048A091F56EDD1FE /* FBSDKApplicationDelegate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKApplicationDelegate.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h; sourceTree = ""; }; + D8C9CB701E4F6C654174000392CF24D9 /* Parse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Parse.h; path = Parse/Parse.h; sourceTree = ""; }; + D8EF0F918739185C24D9BE7DDED005BB /* PFCoreDataProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCoreDataProvider.h; path = Parse/Internal/PFCoreDataProvider.h; sourceTree = ""; }; + D9283FF2298CF4AB76D39E0BB4601791 /* PFAnalytics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFAnalytics.m; path = Parse/PFAnalytics.m; sourceTree = ""; }; + D9AA4942A33D49D6BD6342E82EF21F2F /* FBSDKAccessTokenCacheV3_17.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAccessTokenCacheV3_17.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h; sourceTree = ""; }; + D9C1F4F92487D9DCADCD60039710D816 /* FBSDKCrypto.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKCrypto.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/Cryptography/FBSDKCrypto.h; sourceTree = ""; }; + D9F9A1B8EB6CBAF33BDC895542AB64E9 /* PFDataProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFDataProvider.h; path = Parse/Internal/PFDataProvider.h; sourceTree = ""; }; + DA196AA463D20F7402232B546DE1EEC4 /* Bolts-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Bolts-dummy.m"; sourceTree = ""; }; + DA1BD0504C0DB02DE656D603F622159C /* PFHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFHash.m; path = Parse/Internal/PFHash.m; sourceTree = ""; }; + DA3EA52DCFB7D558F88A88501D54E2B9 /* FBSDKShareOpenGraphObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKShareOpenGraphObject.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareOpenGraphObject.h; sourceTree = ""; }; + DA4A6D24A88D4B18ED3D60681DF68270 /* FBSDKButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKButton.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.m; sourceTree = ""; }; + DAB59734D65B77DD76ADC6A7069BEFCA /* PFPin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPin.m; path = Parse/Internal/LocalDataStore/Pin/PFPin.m; sourceTree = ""; }; + DAB70DB4EE93F869DBC66617E527E62E /* ISO8601DateFormatterValueTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ISO8601DateFormatterValueTransformer.h; path = Code/ISO8601DateFormatterValueTransformer.h; sourceTree = ""; }; + DAD657A091CF82605FA8A0100D16E83E /* TKStateMachine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKStateMachine.h; path = Code/TKStateMachine.h; sourceTree = ""; }; + DAE43287C4A621BABEBFD4D7ACA4D0CB /* PFPushChannelsController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPushChannelsController.h; path = Parse/Internal/Push/ChannelsController/PFPushChannelsController.h; sourceTree = ""; }; + DAF50A43880E07D46E8A97B575A92405 /* PFRESTObjectBatchCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTObjectBatchCommand.m; path = Parse/Internal/Commands/PFRESTObjectBatchCommand.m; sourceTree = ""; }; + DB72A1AC246E5FC4E81A0DBB8B1F0737 /* FBSDKLoginUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginUtility.m; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginUtility.m; sourceTree = ""; }; + DC4C06AF4A9CCA7E3F9A2C7F97FFCE87 /* PFDevice.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFDevice.h; path = Parse/Internal/PFDevice.h; sourceTree = ""; }; + DC702CD32C7B1F95EBB4525985776E1A /* FBSDKServerConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKServerConfiguration.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration.h; sourceTree = ""; }; + DC865D74F3C01339E7A0C969FDED834E /* PFObjectState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectState.m; path = Parse/Internal/Object/State/PFObjectState.m; sourceTree = ""; }; + DCDABFE826ADB96F79D0DFB7BF9C4259 /* PFInstallationConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallationConstants.h; path = Parse/Internal/Installation/Constants/PFInstallationConstants.h; sourceTree = ""; }; + DCE8B19B5BBBF2EEE591030CB12399C6 /* FBSDKSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKSettings.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKSettings.m; sourceTree = ""; }; + DD2FCA295F0F6EC84DC796D623DC209F /* TransformationMatrix.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TransformationMatrix.h; path = pop/WebCore/TransformationMatrix.h; sourceTree = ""; }; + DD4E641A4F7583F57A2818E33113A0CF /* PFQueryState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFQueryState.m; path = Parse/Internal/Query/State/PFQueryState.m; sourceTree = ""; }; + DD91926B9C031018B2F9CB9019718F3E /* FBSDKLoginButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginButton.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginButton.m; sourceTree = ""; }; + DDB0E62AEBB7CEA6AAB32321B17C4DA4 /* RKMIMETypeSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMIMETypeSerialization.m; path = Code/Support/RKMIMETypeSerialization.m; sourceTree = ""; }; + DE726D284DFE5BC0144139D8575114FE /* PFUser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFUser.m; path = Parse/PFUser.m; sourceTree = ""; }; + DECD8E5B530D5D0B9FB27660D6A00BA3 /* RKMappingResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingResult.h; path = Code/ObjectMapping/RKMappingResult.h; sourceTree = ""; }; + DF3BBA8D585F58897AE3BA414EDE35C2 /* FBSDKTooltipView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKTooltipView.h; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKTooltipView.h; sourceTree = ""; }; + E043164BEB509D5E2D2B9698903390E7 /* PFKeyValueCache_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFKeyValueCache_Private.h; path = Parse/Internal/KeyValueCache/PFKeyValueCache_Private.h; sourceTree = ""; }; + E0650188B522893BF764569662B5E542 /* PFRESTObjectCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTObjectCommand.m; path = Parse/Internal/Commands/PFRESTObjectCommand.m; sourceTree = ""; }; + E089DC06AFABF3AB162039B0DCA20D14 /* AFNetworking-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "AFNetworking-dummy.m"; sourceTree = ""; }; + E0976F3A16E6127C870E863609F006DF /* FBSDKDialogConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKDialogConfiguration.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.m; sourceTree = ""; }; + E0BEF4CC671BA1E579779C38712DC769 /* FBSDKShareKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FBSDKShareKit.xcconfig; sourceTree = ""; }; + E0E0D90BB11B78E84D92384725A9534E /* libFBSDKCoreKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFBSDKCoreKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + E160D14CDAB0E17CC1D0024A8673A34C /* FBSDKLoginConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLoginConstants.m; path = FBSDKLoginKit/FBSDKLoginKit/FBSDKLoginConstants.m; sourceTree = ""; }; + E1657F05C4EF96882F28C1692CBF05CE /* FBSDKProfilePictureView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKProfilePictureView.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h; sourceTree = ""; }; + E1F89AA6B095AAB2C7CEB2BEAC5A7F1B /* PFConfigController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFConfigController.m; path = Parse/Internal/Config/Controller/PFConfigController.m; sourceTree = ""; }; + E22A1C7E80FE2BA8CE59C7C924410D0E /* PFKeyValueCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFKeyValueCache.m; path = Parse/Internal/KeyValueCache/PFKeyValueCache.m; sourceTree = ""; }; + E2C63AFAC34B0E794D2603EF0F27DF0E /* PFDecoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFDecoder.h; path = Parse/Internal/PFDecoder.h; sourceTree = ""; }; + E2E5158BDE2438D1F296202C6A65CAD9 /* FBSDKSystemAccountStoreAdapter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKSystemAccountStoreAdapter.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKSystemAccountStoreAdapter.h; sourceTree = ""; }; + E362D4507FC775D8570A80D797BC3E91 /* BFAppLinkTarget.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFAppLinkTarget.h; path = Bolts/iOS/BFAppLinkTarget.h; sourceTree = ""; }; + E37BF385DA04A9EDE7E17A3AD82FB48D /* PFObjectState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectState_Private.h; path = Parse/Internal/Object/State/PFObjectState_Private.h; sourceTree = ""; }; + E3F194E608C0A87A1EA1DBA9B49CDFC8 /* PFFile.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFile.m; path = Parse/PFFile.m; sourceTree = ""; }; + E436D932FA7C17E15674EB32E957ABE2 /* FBSDKErrorConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKErrorConfiguration.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKErrorConfiguration.m; sourceTree = ""; }; + E4528F78B1F397E3730075143FD93C99 /* FBSDKUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKUtility.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKUtility.m; sourceTree = ""; }; + E4865AB05BFD84B7B6E65342C643E18E /* PFFileStagingController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFFileStagingController.m; path = Parse/Internal/File/Controller/PFFileStagingController.m; sourceTree = ""; }; + E49DAAC9A8E0D5362E749A6821734AF0 /* RKRelationshipMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRelationshipMapping.h; path = Code/ObjectMapping/RKRelationshipMapping.h; sourceTree = ""; }; + E4C5528C376F1D824C32FC5049A22958 /* ISO8601DateFormatterValueTransformer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ISO8601DateFormatterValueTransformer.m; path = Code/ISO8601DateFormatterValueTransformer.m; sourceTree = ""; }; + E511AFB10E1282BD8E6813EEEAD607E0 /* FBSDKMath.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKMath.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKMath.h; sourceTree = ""; }; + E516EBEC7356A04879F93CDEB1C0A839 /* PFApplication.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFApplication.h; path = Parse/Internal/PFApplication.h; sourceTree = ""; }; + E53C7B0A7D27C453923DDE2311E75A27 /* PFOfflineObjectController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFOfflineObjectController.m; path = Parse/Internal/Object/Controller/OfflineController/PFOfflineObjectController.m; sourceTree = ""; }; + E55C935E4DD635C29A2B334C8AB06254 /* FBSDKServerConfiguration+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKServerConfiguration+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKServerConfiguration+Internal.h"; sourceTree = ""; }; + E5A9EBDF50D04397C922F9D0AB7B0512 /* BFMeasurementEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFMeasurementEvent.h; path = Bolts/iOS/BFMeasurementEvent.h; sourceTree = ""; }; + E5C990C91B211AE926078950B8630516 /* RKObjectMappingMatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMappingMatcher.h; path = Code/ObjectMapping/RKObjectMappingMatcher.h; sourceTree = ""; }; + E5FEF8F1937676245479BD46246EE956 /* PFErrorUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFErrorUtilities.h; path = Parse/Internal/PFErrorUtilities.h; sourceTree = ""; }; + E62E80C06B8D2394C56D10220D1CCB6F /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + E6D171B8D3792811D774B92580727FAB /* FBSDKShareVideo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKShareVideo.m; path = FBSDKShareKit/FBSDKShareKit/FBSDKShareVideo.m; sourceTree = ""; }; + E73D941475103F44552CBBF7A9C2578A /* FBSDKGameRequestFrictionlessRecipientCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGameRequestFrictionlessRecipientCache.h; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKGameRequestFrictionlessRecipientCache.h; sourceTree = ""; }; + E758F865F37D77788EE4B4551EF1487D /* PFCloudCodeController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFCloudCodeController.m; path = Parse/Internal/CloudCode/PFCloudCodeController.m; sourceTree = ""; }; + E75B973B4239A8C33C3DF18D0F41168D /* FBSDKAppEventsState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKAppEventsState.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h; sourceTree = ""; }; + E7909E9598E022C3C0A3969A59F14279 /* PFProductsRequestHandler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFProductsRequestHandler.h; path = Parse/Internal/Product/ProductsRequestHandler/PFProductsRequestHandler.h; sourceTree = ""; }; + E83EDDC94D7F78C9A89A9BBF973667B6 /* TKTransition.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKTransition.m; path = Code/TKTransition.m; sourceTree = ""; }; + E8A1C16BDC310A2EF19DE55901CD5B41 /* RKValueTransformers-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RKValueTransformers-dummy.m"; sourceTree = ""; }; + E8A3F0FA2907B71EC0DCB074D0E32D52 /* RKLog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKLog.h; path = Code/Support/RKLog.h; sourceTree = ""; }; + EA4EBDCE8C9C8A5582D7231A544E96A8 /* RKConnectionTestExpectation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKConnectionTestExpectation.h; path = Code/Testing/RKConnectionTestExpectation.h; sourceTree = ""; }; + EAA5D41EBB47944D263EB028AA677026 /* FBSDKShareKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FBSDKShareKit-dummy.m"; sourceTree = ""; }; + EAA88DECC60605475F4AA3869B36A8FB /* PFSQLiteDatabaseResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFSQLiteDatabaseResult.h; path = Parse/Internal/LocalDataStore/SQLite/PFSQLiteDatabaseResult.h; sourceTree = ""; }; + EB97CD8D9BDC16D9E1CE5F863965790B /* pop.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = pop.xcconfig; sourceTree = ""; }; + EBC06CCF32BA9A3FEE34142E70D19588 /* PFRESTPushCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTPushCommand.h; path = Parse/Internal/Commands/PFRESTPushCommand.h; sourceTree = ""; }; + EBF45573BC8D86EF53B4B16396F99411 /* pop-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "pop-prefix.pch"; sourceTree = ""; }; + EC54205F1719C5C45D60A2253F84C5ED /* PFCloud.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCloud.h; path = Parse/PFCloud.h; sourceTree = ""; }; + EC599B21BE1C0853A0234AD38F8FC07E /* PFFileState_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileState_Private.h; path = Parse/Internal/File/State/PFFileState_Private.h; sourceTree = ""; }; + ECE23EA20C48234573BE370B97423C3A /* PFAnonymousUtils_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFAnonymousUtils_Private.h; path = Parse/Internal/User/AuthenticationProviders/Providers/Anonymous/PFAnonymousUtils_Private.h; sourceTree = ""; }; + ECF9B9F2BA04D70CD7253751FF94CCD5 /* FBSDKLikeActionController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeActionController.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeActionController.m; sourceTree = ""; }; + EE16E8E41B610CE73E8BC061D6E6E102 /* RKLumberjackLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKLumberjackLogger.h; path = Code/Support/RKLumberjackLogger.h; sourceTree = ""; }; + EEBA4E2BFC884C1F4B170F5BC7DE8B77 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + EED2B7513CB5A03507BE982601143DEC /* BFWebViewAppLinkResolver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFWebViewAppLinkResolver.m; path = Bolts/iOS/BFWebViewAppLinkResolver.m; sourceTree = ""; }; + EF2907AA3AD4FE98405EC818A63855DA /* POPAnimationExtras.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; name = POPAnimationExtras.mm; path = pop/POPAnimationExtras.mm; sourceTree = ""; }; + EF79FDCF0AF41A384FB770643D79F0E6 /* FBSDKLoginManagerLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKLoginManagerLogger.h; path = FBSDKLoginKit/FBSDKLoginKit/Internal/FBSDKLoginManagerLogger.h; sourceTree = ""; }; + EFC29774AABC76F1B26B97B146F2A1C9 /* PFObjectEstimatedData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectEstimatedData.h; path = Parse/Internal/Object/EstimatedData/PFObjectEstimatedData.h; sourceTree = ""; }; + EFF0339213287B595E2857A1BCA7B7E8 /* FBSDKGameRequestContent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGameRequestContent.h; path = FBSDKShareKit/FBSDKShareKit/FBSDKGameRequestContent.h; sourceTree = ""; }; + F0414F682EAAC899BF6D1350B23F4920 /* AFImageRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFImageRequestOperation.m; path = AFNetworking/AFImageRequestOperation.m; sourceTree = ""; }; + F09DC66B579DD76F90EDE78627D95BB3 /* RKMacros.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMacros.h; path = Code/Support/RKMacros.h; sourceTree = ""; }; + F0E8603DBA1064D73E0E7EB92BED0DA0 /* PFInstallationIdentifierStore_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFInstallationIdentifierStore_Private.h; path = Parse/Internal/Installation/InstallationIdentifierStore/PFInstallationIdentifierStore_Private.h; sourceTree = ""; }; + F105D77D5F0461FECD9BAEB70A50AE87 /* PFCurrentUserController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCurrentUserController.h; path = Parse/Internal/User/CurrentUserController/PFCurrentUserController.h; sourceTree = ""; }; + F129E4F0636DB79526F8F6270198B942 /* PFURLSessionUploadTaskDelegate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLSessionUploadTaskDelegate.m; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/TaskDelegate/PFURLSessionUploadTaskDelegate.m; sourceTree = ""; }; + F19938456DF0C30C53CBE44847B3E479 /* PFCurrentConfigController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFCurrentConfigController.h; path = Parse/Internal/Config/Controller/PFCurrentConfigController.h; sourceTree = ""; }; + F19CD8D613E04AF9291C97EC57B1C08D /* PFQuery.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFQuery.m; path = Parse/PFQuery.m; sourceTree = ""; }; + F1B5BCEFFE5D1ED352C01484C83D6924 /* PFRESTObjectCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTObjectCommand.h; path = Parse/Internal/Commands/PFRESTObjectCommand.h; sourceTree = ""; }; + F22636EFE5E1A5651E0A1520C5F281E5 /* BFCancellationTokenRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenRegistration.h; path = Bolts/Common/BFCancellationTokenRegistration.h; sourceTree = ""; }; + F22BFE44135812D7404BBDAF34C010E3 /* BFAppLinkTarget.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFAppLinkTarget.m; path = Bolts/iOS/BFAppLinkTarget.m; sourceTree = ""; }; + F25269A960ACE3EBB3FE45F44DE4D5BC /* RKObjectMappingOperationDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMappingOperationDataSource.h; path = Code/ObjectMapping/RKObjectMappingOperationDataSource.h; sourceTree = ""; }; + F2575C28B5137ABEB1B9557B34F3448C /* FBSDKLikeButtonPopWAV.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKLikeButtonPopWAV.m; path = FBSDKShareKit/FBSDKShareKit/Internal/FBSDKLikeButtonPopWAV.m; sourceTree = ""; }; + F288F2786DB87278DEB0D83B15A2B5B2 /* RKPathUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPathUtilities.m; path = Code/Support/RKPathUtilities.m; sourceTree = ""; }; + F29DD5432F60CE09614541D4BE9A4FB8 /* PFPropertyInfo_Runtime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPropertyInfo_Runtime.h; path = Parse/Internal/PropertyInfo/PFPropertyInfo_Runtime.h; sourceTree = ""; }; + F2ACCE7F5437F868E4BA7E2A0C645D43 /* RKDotNetDateFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDotNetDateFormatter.h; path = Code/Support/RKDotNetDateFormatter.h; sourceTree = ""; }; + F2D002F7CD0CB8A3551420036A594D40 /* FBSDKIcon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKIcon.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKIcon.m; sourceTree = ""; }; + F2FBDEBC39B29A9DA41247E2D96331E6 /* RestKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RestKit.h; path = Code/RestKit.h; sourceTree = ""; }; + F3BB79D7E31BCBC04BA5D076D3B1A9BC /* RKTestHelpers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKTestHelpers.h; path = Code/Testing/RKTestHelpers.h; sourceTree = ""; }; + F3D3B7CDCE9EF138FF8BB043F7239498 /* POPAnimationEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = POPAnimationEvent.h; path = pop/POPAnimationEvent.h; sourceTree = ""; }; + F42B1B0D93B9783D48D27AAF873BC978 /* FBSDKShareOpenGraphValueContainer+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKShareOpenGraphValueContainer+Internal.h"; path = "FBSDKShareKit/FBSDKShareKit/Internal/FBSDKShareOpenGraphValueContainer+Internal.h"; sourceTree = ""; }; + F44E8E904E1CD028316E671E43453DCE /* FBSDKBridgeAPIRequest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPIRequest.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.m; sourceTree = ""; }; + F48BCECC8EA184F5975C3532819CFFA2 /* FBSDKDialogConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKDialogConfiguration.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/ServerConfiguration/FBSDKDialogConfiguration.h; sourceTree = ""; }; + F4B09A465BA0ED9168954ACE5D869AD1 /* RKRequestDescriptor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRequestDescriptor.m; path = Code/Network/RKRequestDescriptor.m; sourceTree = ""; }; + F4EC41878B622B137CC4B622FC53F3ED /* RKObjectMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMapping.h; path = Code/ObjectMapping/RKObjectMapping.h; sourceTree = ""; }; + F51B8874D2E27F0F4E6BB3A745216087 /* PFDefaultACLController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFDefaultACLController.m; path = Parse/Internal/ACL/DefaultACLController/PFDefaultACLController.m; sourceTree = ""; }; + F51C083C4D1E3AAFE06A8F4BDF8EBB88 /* AFXMLRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFXMLRequestOperation.h; path = AFNetworking/AFXMLRequestOperation.h; sourceTree = ""; }; + F6F4C2DDD2D3755D276BC06E4C5B319E /* BFTaskCompletionSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTaskCompletionSource.m; path = Bolts/Common/BFTaskCompletionSource.m; sourceTree = ""; }; + F6FB42658DA37641EE0F5D6EE5236722 /* RKTestNotificationObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKTestNotificationObserver.m; path = Code/Testing/RKTestNotificationObserver.m; sourceTree = ""; }; + F7114C7234DA9F23563BF6C254E6458A /* FBSDKBridgeAPIProtocolWebV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKBridgeAPIProtocolWebV1.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h; sourceTree = ""; }; + F7EEEC622363411316A89CF3A6941695 /* YALFoldingTabBar.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = YALFoldingTabBar.h; path = FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.h; sourceTree = ""; }; + F83D6439675ABF2D6040C5D9F2FFF217 /* YALFoldingTabBar.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = YALFoldingTabBar.m; path = FoldingTabBar/View/FoldingTabBar/YALFoldingTabBar.m; sourceTree = ""; }; + F87C75C1F03CFABBB54EC631815288C0 /* FBSDKGraphRequest+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBSDKGraphRequest+Internal.h"; path = "FBSDKCoreKit/FBSDKCoreKit/Internal/Network/FBSDKGraphRequest+Internal.h"; sourceTree = ""; }; + F8B8D967E928682C85109A85124DEEC4 /* PFRESTSessionCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFRESTSessionCommand.h; path = Parse/Internal/Commands/PFRESTSessionCommand.h; sourceTree = ""; }; + F918BC0806DF4B41E1EF8762440B3FAF /* PFOperationSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFOperationSet.h; path = Parse/Internal/Object/OperationSet/PFOperationSet.h; sourceTree = ""; }; + F970BE5082817C3185CB918CBDAFE49B /* libTransitionKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTransitionKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F9A0A5F9F3C3457E2ECD91932E225F1F /* PFURLSession_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFURLSession_Private.h; path = Parse/Internal/Commands/CommandRunner/URLSession/Session/PFURLSession_Private.h; sourceTree = ""; }; + F9C6A17A0DB2E5C15C0B38508DC16669 /* PFLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFLogger.h; path = Parse/Internal/PFLogger.h; sourceTree = ""; }; + F9DBE01AF3666AF5DF673F0B8302A852 /* FBSDKAppLinkUtility.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKAppLinkUtility.m; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.m; sourceTree = ""; }; + F9E40B348CF74929CFC2ED015A0099CE /* PFObjectSubclassingController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectSubclassingController.m; path = Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m; sourceTree = ""; }; + F9F517D67552371A385D10A6D780C46C /* PFObjectController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFObjectController.m; path = Parse/Internal/Object/Controller/PFObjectController.m; sourceTree = ""; }; + FA60E1C8D40A78F03AAD7CA1CAE03991 /* FBSDKBridgeAPICrypto.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBSDKBridgeAPICrypto.m; path = FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.m; sourceTree = ""; }; + FB1CFA906E2A5ECA69FDBCAC00497F72 /* PFRESTAnalyticsCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFRESTAnalyticsCommand.m; path = Parse/Internal/Commands/PFRESTAnalyticsCommand.m; sourceTree = ""; }; + FB3A9DED47A72521C01855CCB13A10EA /* BFMeasurementEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFMeasurementEvent.m; path = Bolts/iOS/BFMeasurementEvent.m; sourceTree = ""; }; + FB90E78B06FCB922FD3083DB6AFE5ECA /* PFPushChannelsController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFPushChannelsController.m; path = Parse/Internal/Push/ChannelsController/PFPushChannelsController.m; sourceTree = ""; }; + FBB3B5641F66495915C56779C21569E7 /* UIImageView+AFNetworking.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+AFNetworking.h"; path = "AFNetworking/UIImageView+AFNetworking.h"; sourceTree = ""; }; + FBBB3B26B24BB1791ACE441DFDA19FF2 /* TKEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKEvent.m; path = Code/TKEvent.m; sourceTree = ""; }; + FBEB6D4BDCEFC529A9705D5228053B04 /* RKMappingErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingErrors.h; path = Code/ObjectMapping/RKMappingErrors.h; sourceTree = ""; }; + FBFE9966A9FB854C5D85375D24F936C5 /* CATransaction+TransactionWithAnimationsAndCompletion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "CATransaction+TransactionWithAnimationsAndCompletion.h"; path = "FoldingTabBar/Category/CATransaction/CATransaction+TransactionWithAnimationsAndCompletion/CATransaction+TransactionWithAnimationsAndCompletion.h"; sourceTree = ""; }; + FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + FCB8001E15C66CA1A4ADC3B7AB26C08D /* PFFileStagingController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFFileStagingController.h; path = Parse/Internal/File/Controller/PFFileStagingController.h; sourceTree = ""; }; + FCDD09913DC7F28BA260222EED8670BE /* PFUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFUser.h; path = Parse/PFUser.h; sourceTree = ""; }; + FD07183D5459C1861CCC80EC5514A9AA /* RKMappingOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingOperation.h; path = Code/ObjectMapping/RKMappingOperation.h; sourceTree = ""; }; + FD8688B0EFB589FA74DDBEE72083D4A3 /* PFACL.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFACL.m; path = Parse/PFACL.m; sourceTree = ""; }; + FDF375C76C5BA4A7F1EA1C46DC3B142C /* FoldingTabBar-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FoldingTabBar-dummy.m"; sourceTree = ""; }; + FE3AAD9A2F31FBC9D00D7715F65FDB26 /* libpop.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpop.a; sourceTree = BUILT_PRODUCTS_DIR; }; + FE58183D7C1721963488765C5C8C2AC5 /* PFObjectSubclassInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFObjectSubclassInfo.h; path = Parse/Internal/Object/Subclassing/PFObjectSubclassInfo.h; sourceTree = ""; }; + FE71E48A323238BEC2BB8D62940ED886 /* PFPush.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PFPush.h; path = Parse/PFPush.h; sourceTree = ""; }; + FE89E1667DF47EC79AB1E8C414DE79EB /* FBSDKGraphRequestConnection.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKGraphRequestConnection.h; path = FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h; sourceTree = ""; }; + FEE6386026272731739CFEE82C813032 /* FBSDKViewImpressionTracker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBSDKViewImpressionTracker.h; path = FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKViewImpressionTracker.h; sourceTree = ""; }; + FF461E4535F2215F6A9DDAA832E1BC7F /* RKTestHelpers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKTestHelpers.m; path = Code/Testing/RKTestHelpers.m; sourceTree = ""; }; + FF57BE3A8EF2D78A282E7FEE79783DB3 /* PFURLConstructor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PFURLConstructor.m; path = Parse/Internal/HTTPRequest/PFURLConstructor.m; sourceTree = ""; }; + FF5B972C0D2221C57AE6060DE6C9A600 /* FoldingTabBar.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FoldingTabBar.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 06397B19B46BC23B4020A7016F06E806 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 097DE14824DA65BDF81E4C5A2D73566F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4B6ED4A1B1BED7DD189B582654C25EB6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D8B32C5FF3597EEDD220A394295B194B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4B6FCC51F24F6991AAA4CC61597FD2DA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D9641967C1ACD51CE3ACACF1B1D2860 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5585D11E7E0A5A702DA209671365FADF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AAB25408151750ECBBDAD5A765D5C652 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 633F46B6757F8B68507D56B231750794 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D9DF25BBCE11AC3A9A684C418F6C89F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63458E103C17B332F0872EC549B57894 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A3C1C7BA97AC39DFAB85B13E827BD182 /* CFNetwork.framework in Frameworks */, + 20A2B211D75692571DE1A418220365D2 /* Foundation.framework in Frameworks */, + 89BD9A798D541EC62FA93EDC9B45CFAA /* MobileCoreServices.framework in Frameworks */, + DA62A034CB079FDF722A66A09E878E5E /* Security.framework in Frameworks */, + 8D606E6C43F0BE373F14A15848E78FE8 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6772349FF73FC6301A658A55439FAB73 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0277D1C85C0C1E1358C7AAD044B40757 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8303124DDA063FE89C9AEFC94E6AB54E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0D0CFD86DC5D95BB25D65B84461D031B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AAABAAEC6D245621B8DDE1ACF9BB7918 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4172EFFB5E73F4A2625FDD8790ADA86F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AB6236FDABEA71A344A72311A20E9129 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60F370DA778C2C58337885BA2E21047C /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E2152948655C0A221BBD699822F629C0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C5BCED302898250D42DAB9622E61A2D2 /* AudioToolbox.framework in Frameworks */, + 04CF8AD033C179325590EA52685AE224 /* CFNetwork.framework in Frameworks */, + 02437AFB910783C6BD25E492758C46D9 /* CoreGraphics.framework in Frameworks */, + 46C77E33FBFB6CDD2042AFC7251C0192 /* CoreLocation.framework in Frameworks */, + E81D0A4FB179B72572B6E7521484EB16 /* Foundation.framework in Frameworks */, + 976C79EBB302D6FD69733210FFC97DDF /* QuartzCore.framework in Frameworks */, + DE61C9B48F5213CCAB8012BE4C261842 /* Security.framework in Frameworks */, + 75092C6F60330AA447A66ADEB43581C6 /* StoreKit.framework in Frameworks */, + AC70F2D05DDEE9CA1E15F5FBC259E974 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E3E27D1553990F260E018F2FD31F237C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3BC5621A2DA38E302E4D3A891CAD35CE /* Foundation.framework in Frameworks */, + 647E650A08B67B558A6C1A0041544B1D /* QuartzCore.framework in Frameworks */, + B2DB66509B953232772CC24828B2A2D6 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F1E353087C983AF68F393D9A09D83CDA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AFC9F60694818B7903ED6065CA9E7E38 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1132C1F746513DE93738ED48AFAB38 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 195B7EACB9E277F950B7C1BC314BB968 /* CoreGraphics.framework in Frameworks */, + 18BA1F40271FF44B3A0508ABFD1600FF /* Foundation.framework in Frameworks */, + 805398D3248C43C8DE072375177A8354 /* MobileCoreServices.framework in Frameworks */, + 0A45B6A339543EC83754D28F87523802 /* Security.framework in Frameworks */, + 88B5193C02621657A8A1599944D7966A /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 030A5B3E44F0F6E57B1380DD185339D1 /* Support Files */ = { + isa = PBXGroup; + children = ( + E0BEF4CC671BA1E579779C38712DC769 /* FBSDKShareKit.xcconfig */, + EAA5D41EBB47944D263EB028AA677026 /* FBSDKShareKit-dummy.m */, + 7A71B1896C184DD250A8FB4EF534051E /* FBSDKShareKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/FBSDKShareKit"; + sourceTree = ""; + }; + 037C0CA694176A3C0915F62C9D20B3E6 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + B3D1D13E0C6553800746CB8FD61CF946 /* Pods */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 072B748C4ABC47FF5DD09E14AFCFA80C /* Bolts */ = { + isa = PBXGroup; + children = ( + F7647B87DD09DE1D36642AA78D579180 /* AppLinks */, + AB60DD59D35FBC4FEF669D67E4191C38 /* Support Files */, + 4380A3F473F199836A3C72502983239A /* Tasks */, + ); + path = Bolts; + sourceTree = ""; + }; + 0BFBFBF37DD4FBC676345E304C5B6CE7 /* Testing */ = { + isa = PBXGroup; + children = ( + 4C7FFDC2B7A4F0D5C315F44B0165D091 /* RKBenchmark.h */, + 4F6B679BDA82770D971194798F95DC69 /* RKBenchmark.m */, + EA4EBDCE8C9C8A5582D7231A544E96A8 /* RKConnectionTestExpectation.h */, + 7BC4913285E98A56C951839A999352AB /* RKConnectionTestExpectation.m */, + CA3CB4DD07E35F520C793BA9032F51FC /* RKMappingTest.h */, + 817589AA5C8BA17E8B2F9808EC23788B /* RKMappingTest.m */, + 10FAFCCD6FB4FC9E877FCB27902EA1F7 /* RKPropertyMappingTestExpectation.h */, + 20B291B44372ECD90FA4961CB9F9C9C4 /* RKPropertyMappingTestExpectation.m */, + 6A986FCBAFF66C34031E230F059A2DCF /* RKTestConstants.m */, + 7EE2EBDC54FDE1E50CD9A33DDF48404D /* RKTestFactory.h */, + 530B742954AE4C60876DC3128D82F154 /* RKTestFactory.m */, + D5B2F6DAB138D6C0AFB76C250456D0A9 /* RKTestFixture.h */, + BF6BCF95270D89143AE2BD11E8C58467 /* RKTestFixture.m */, + F3BB79D7E31BCBC04BA5D076D3B1A9BC /* RKTestHelpers.h */, + FF461E4535F2215F6A9DDAA832E1BC7F /* RKTestHelpers.m */, + 0EDCBE9EDEE91346EC864E690AF4D08E /* RKTestNotificationObserver.h */, + F6FB42658DA37641EE0F5D6EE5236722 /* RKTestNotificationObserver.m */, + B25EAE7B7171B287489EDA0C0A129426 /* Testing.h */, + ); + name = Testing; + sourceTree = ""; + }; + 102D02B51D25F8C5C815B69B7CB61B08 /* Support */ = { + isa = PBXGroup; + children = ( + 3C6C852E7C915FBEDD2E5B3C2CDD20A8 /* lcl_config_components_RK.h */, + 18811D86AFD569DE58C69DE2D674A00D /* lcl_config_extensions_RK.h */, + C3B87B3E4AC8A18214858CF42A599D50 /* lcl_config_logger_RK.h */, + D284CA3DDD91571D70CF7256A3C248FE /* lcl_RK.h */, + 997269FD4178F2BC0707886B0C405A8D /* lcl_RK.m */, + F2FBDEBC39B29A9DA41247E2D96331E6 /* RestKit.h */, + B5AA14CFC28475D9E28E32A363674B8F /* RKDictionaryUtilities.h */, + 611F4CE6ED5017088CB427383A3D1445 /* RKDictionaryUtilities.m */, + F2ACCE7F5437F868E4BA7E2A0C645D43 /* RKDotNetDateFormatter.h */, + 57A42437229DCF10EA2D792B45EC0449 /* RKDotNetDateFormatter.m */, + 2E3E506FDF95C78237F089FED94DAB76 /* RKErrors.h */, + C31FC859AAD2E2012636FC6B877D6EB6 /* RKErrors.m */, + E8A3F0FA2907B71EC0DCB074D0E32D52 /* RKLog.h */, + 667F8446CCEAF60B9DCD4E68CCB9ED5E /* RKLog.m */, + EE16E8E41B610CE73E8BC061D6E6E102 /* RKLumberjackLogger.h */, + 6AFF7959F2290BD0027C49FBA305DFE5 /* RKLumberjackLogger.m */, + F09DC66B579DD76F90EDE78627D95BB3 /* RKMacros.h */, + 6AD9092DA1F9CCC04506CAA7CAD0EC83 /* RKMIMETypes.h */, + 2E4DB2AB05ABDFB2096CBD1A0D1C960A /* RKMIMETypes.m */, + 93EE612E26F15D494EE5870F082534C2 /* RKMIMETypeSerialization.h */, + DDB0E62AEBB7CEA6AAB32321B17C4DA4 /* RKMIMETypeSerialization.m */, + 8275725385A9F6C10AF8B7A642A129F8 /* RKNSJSONSerialization.h */, + 8FB19F616008A121FAA50E14B62D67A0 /* RKNSJSONSerialization.m */, + 7E668F82944D74008FA69DF68A0E96F9 /* RKOperationStateMachine.h */, + 4A3FF0A4A486E57DD176B3DF5F619173 /* RKOperationStateMachine.m */, + 4EB1F29228069356CCA0E5D8E0C8DA3C /* RKPathUtilities.h */, + F288F2786DB87278DEB0D83B15A2B5B2 /* RKPathUtilities.m */, + 5E0DB2127804727AC549721870914323 /* RKSerialization.h */, + 9766DA2E569D10FE157FA2E355CC9802 /* RKStringTokenizer.h */, + 2562927BDB580A25FD1C5DE23213DD83 /* RKStringTokenizer.m */, + 10D33DBF4C307AD2EA9D10FA2001F6E0 /* RKURLEncodedSerialization.h */, + 3F756E1A3BA52E99D6635DE49C0331CB /* RKURLEncodedSerialization.m */, + 9ADB5C6CFDD59CB906870DA9025B3B8A /* Support.h */, + ); + name = Support; + sourceTree = ""; + }; + 1ABD97751947F20E67D4F852B3655259 /* Parse */ = { + isa = PBXGroup; + children = ( + 882472CF6BA62D86D2BF8542B479D3CB /* BFTask+Private.h */, + 2F0F7C3B1D42E74B34C118D7F55D56DC /* BFTask+Private.m */, + D8C9CB701E4F6C654174000392CF24D9 /* Parse.h */, + D1B966C2A921DE73042AA8B317E629EA /* Parse.m */, + 503253CFCA3206291EBDFF00B0FDE5BF /* Parse_Private.h */, + 749A8D41E182E9883688C41D2D257554 /* ParseInternal.h */, + 23397924D53E7B536CB59C3373E47BCC /* ParseManager.h */, + 02AEBA17B69A4D55F659D4F44440127E /* ParseManager.m */, + BD6DD4F4195C174C8DC06D3C85DDF8A8 /* ParseModule.h */, + 67B4C66668FC14A61182B73575A193DE /* ParseModule.m */, + B934A04F1A258C2A0713237E8C4DB79E /* PFACL.h */, + FD8688B0EFB589FA74DDBEE72083D4A3 /* PFACL.m */, + C4DAAE6C562288FB95B1415AF6763317 /* PFACLPrivate.h */, + 95C137F2DF407C83936DE0B2BB3D6F86 /* PFACLState.h */, + 62BEED70070D14A0FF9C95200AA22741 /* PFACLState.m */, + 7B6054861B48456D5D8D1E661F92EE5D /* PFACLState_Private.h */, + 5EEF5F821C5CAF35FB96774AFF53120A /* PFAlertView.h */, + 9FBA963311C705B8BC3B0E2FC0EB8529 /* PFAlertView.m */, + D4AB7EDD51484D69712FC0BAF2EEFB20 /* PFAnalytics.h */, + D9283FF2298CF4AB76D39E0BB4601791 /* PFAnalytics.m */, + BC07203CD82FF286D245D3A0306E62C5 /* PFAnalytics_Private.h */, + 3D9C8B62E94BADCE53C2B3A336B91A66 /* PFAnalyticsController.h */, + 77DB8925A606DF13F24DBF2AD343EB8D /* PFAnalyticsController.m */, + B6CBDBFAF7E5AFEF7AE3D397FB6EE762 /* PFAnalyticsUtilities.h */, + 32584F1C40CC0FB3ACD703733332AA08 /* PFAnalyticsUtilities.m */, + 36C75B01624E2DCB9059D7ABADC2B668 /* PFAnonymousAuthenticationProvider.h */, + D46B8631F4A20A30B5C1E47D9F2A6FEB /* PFAnonymousAuthenticationProvider.m */, + 13B2A7FD3B5E9C5F68CC0E991780A0EC /* PFAnonymousUtils.h */, + 2AA9ED123D1A01B9CE0864DF21669E32 /* PFAnonymousUtils.m */, + ECE23EA20C48234573BE370B97423C3A /* PFAnonymousUtils_Private.h */, + E516EBEC7356A04879F93CDEB1C0A839 /* PFApplication.h */, + B78A7E4B40882223B829568BDECFF65F /* PFApplication.m */, + 7C7BBFE7402E447E0363B1BF78CFD3A0 /* PFAssert.h */, + 7BB5593B161ABABA1D0209ECA5074EA3 /* PFAsyncTaskQueue.h */, + 5BEC90C5581726DE80B840585A9F4174 /* PFAsyncTaskQueue.m */, + 0A7261E40A7493778EDD34738B42676E /* PFBase64Encoder.h */, + 8E39257A1062D3B3E8CA265E73AF9795 /* PFBase64Encoder.m */, + AAB9F7182025D4FEB1027A192204588E /* PFBaseState.h */, + 4CDDA61BB7A1F8AD65676757226E8A74 /* PFBaseState.m */, + 9152B5335813665EC6B08F73411A813E /* PFCachedQueryController.h */, + 2AECAEEB58E4CB5EFF8D61951BC17DB1 /* PFCachedQueryController.m */, + 1747B6933EBB45F17399984642773739 /* PFCategoryLoader.h */, + 9AA9561725BB1FB9134A92D8DC5A504B /* PFCategoryLoader.m */, + EC54205F1719C5C45D60A2253F84C5ED /* PFCloud.h */, + 37382D15DA0BBCC18167A1B61E72CD64 /* PFCloud.m */, + 74B44F24917A72CA781246EA2632A00C /* PFCloudCodeController.h */, + E758F865F37D77788EE4B4551EF1487D /* PFCloudCodeController.m */, + 36C8AD8E2390F415DC7425C9734EFAFB /* PFCommandCache.h */, + 999823937ADC925F2F63F241A5995EFE /* PFCommandCache.m */, + B8C1F1B3446748EE4B4240C0CC009D67 /* PFCommandCache_Private.h */, + 45A41F6A2E3BF848EF5F335556B27EC1 /* PFCommandResult.h */, + 6273DBD91B70BE5A81E0EF6B816A31E1 /* PFCommandResult.m */, + 5ED668482FAFCC7E2F744E4B45E21C00 /* PFCommandRunning.h */, + A94107D173054A31E231EA3E081AC080 /* PFCommandRunning.m */, + 34467D773B15C784E43F77DA67A5790C /* PFCommandRunningConstants.h */, + 26A9C85767DC8FE594E7F2DF14F867B2 /* PFCommandRunningConstants.m */, + C2DF84BAF1C49F7A7466D1F88D650A50 /* PFCommandURLRequestConstructor.h */, + 87EE4B2AFFD85E9F75C94F5661D717F2 /* PFCommandURLRequestConstructor.m */, + 2DA32C8430B17D1CEF6CC0C2F20702C6 /* PFConfig.h */, + 163A2E68515F17EBB397973CE01A2E02 /* PFConfig.m */, + 58DD77FFA76457DC7826A465EB970094 /* PFConfig_Private.h */, + 6447BB55EEB3096AE38B4D07B1F5F620 /* PFConfigController.h */, + E1F89AA6B095AAB2C7CEB2BEAC5A7F1B /* PFConfigController.m */, + 1516B2B4A8F91019AE5E4283AA8F5E5D /* PFConstants.h */, + 4F70D98B41C9E7EEBC1231E9885224AA /* PFConstants.m */, + D8EF0F918739185C24D9BE7DDED005BB /* PFCoreDataProvider.h */, + 83C5E9FB336C0917EC02E4034B2B66FE /* PFCoreManager.h */, + 0FD81CD43134464279746BA1F66D5A48 /* PFCoreManager.m */, + F19938456DF0C30C53CBE44847B3E479 /* PFCurrentConfigController.h */, + 012EA998B79C045DB5F3DF0D066F78B1 /* PFCurrentConfigController.m */, + 2572DB6B289BFC9AA6F1D1DCFF16D994 /* PFCurrentInstallationController.h */, + 40AB5DCC80577C96F4732C2FA58B903D /* PFCurrentInstallationController.m */, + 658BD9C8EBCC6CE298417312A7B194FF /* PFCurrentObjectControlling.h */, + F105D77D5F0461FECD9BAEB70A50AE87 /* PFCurrentUserController.h */, + 6FF8DA1F7EEE96CC61CEEB687513A615 /* PFCurrentUserController.m */, + D9F9A1B8EB6CBAF33BDC895542AB64E9 /* PFDataProvider.h */, + 4035095FBC067B91C5DECADD26277EB1 /* PFDateFormatter.h */, + 99B423A79E8F8A42FC5D676612B33E2F /* PFDateFormatter.m */, + E2C63AFAC34B0E794D2603EF0F27DF0E /* PFDecoder.h */, + 11575C24EBD20B38803926830ED63640 /* PFDecoder.m */, + 951E09F02C4842CACF36CAD6D5398E11 /* PFDefaultACLController.h */, + F51B8874D2E27F0F4E6BB3A745216087 /* PFDefaultACLController.m */, + DC4C06AF4A9CCA7E3F9A2C7F97FFCE87 /* PFDevice.h */, + 0BAE999CCCB6D83C2D4DFA288FE9C7BF /* PFDevice.m */, + 8837B1CB6DAF343BD8C545163EA2DA58 /* PFEncoder.h */, + 07D8A98D56E6D538D6FA0B232BBCBA03 /* PFEncoder.m */, + E5FEF8F1937676245479BD46246EE956 /* PFErrorUtilities.h */, + D4F5FFBEC5EF679476BD610B31B04B36 /* PFErrorUtilities.m */, + 7AAB2C033ACD2C5EDF5AFECCDE5BC95D /* PFEventuallyPin.h */, + 98262DA8D9F983FFA347D99C232021E5 /* PFEventuallyPin.m */, + A43A3FE9CF5B7E721E9179EB461EBDD7 /* PFEventuallyQueue.h */, + 41BB788E886BFA89367834A4426A765E /* PFEventuallyQueue.m */, + 33D917AEA2C6B3BD1FB6DE5E32B94689 /* PFEventuallyQueue_Private.h */, + 97D4677BC9F2D88DF946E204DF242D38 /* PFFieldOperation.h */, + 91E9125BDC1505BCE865985502732B9D /* PFFieldOperation.m */, + 5AAE8E50B932782D92F325DCE2EDEBBB /* PFFieldOperationDecoder.h */, + 1ABF2667D317A8E92F4DAB58CAEEB37A /* PFFieldOperationDecoder.m */, + 9CDD229A4ED63D296862C7CC3E93D079 /* PFFile.h */, + E3F194E608C0A87A1EA1DBA9B49CDFC8 /* PFFile.m */, + 6D298D539E71478D6340E3FA832E4778 /* PFFile_Private.h */, + 3FE19DF082B2711D3D79E3BDF50FA146 /* PFFileController.h */, + 39F780E56F26B16CAF1CF2F0EBC58660 /* PFFileController.m */, + 49BFECAFEA1EF171D5BA9CFAFE63B895 /* PFFileDataStream.h */, + D24D9A1393699B9007901EB5221D9018 /* PFFileDataStream.m */, + B818BE16D0901DD3F720DF4447B592B0 /* PFFileManager.h */, + C0773511F8B57D80E82BBCED6576C5D2 /* PFFileManager.m */, + FCB8001E15C66CA1A4ADC3B7AB26C08D /* PFFileStagingController.h */, + E4865AB05BFD84B7B6E65342C643E18E /* PFFileStagingController.m */, + 3F16209AB717FBAFF4C2730320EF9840 /* PFFileState.h */, + 4FD94F67395BDA44DD37B2CEBB86BB64 /* PFFileState.m */, + EC599B21BE1C0853A0234AD38F8FC07E /* PFFileState_Private.h */, + 40DC3C427F03295338C11BDDD89C3D2A /* PFGeoPoint.h */, + 6B650BB26CA49F23280F611BC06CAB7A /* PFGeoPoint.m */, + 407C402A54C0C81D42BEA7147982FA35 /* PFGeoPointPrivate.h */, + 0A1EA9C9D41AE2090A25AEB7774EFF7F /* PFHash.h */, + DA1BD0504C0DB02DE656D603F622159C /* PFHash.m */, + 209E38BB2ADFFA4C0E2497F629810AEB /* PFHTTPRequest.h */, + 5733C650048839167646DC7974A01ABA /* PFHTTPURLRequestConstructor.h */, + 3BCD0EFCBE498C67A5B0097360333011 /* PFHTTPURLRequestConstructor.m */, + A51B1A321088E7B66FD0BCAE78FD96F9 /* PFInstallation.h */, + 892F0F257D5AF973E182934E5D03C911 /* PFInstallation.m */, + DCDABFE826ADB96F79D0DFB7BF9C4259 /* PFInstallationConstants.h */, + 22F77D342CCB58DBAA7457C6289C028C /* PFInstallationConstants.m */, + BC16505461748776619D43C6BDC6A703 /* PFInstallationController.h */, + 19393B003CB10D5DCBF525994DDE8462 /* PFInstallationController.m */, + 1FC50F7EF899B70145D9D7DB1F55E927 /* PFInstallationIdentifierStore.h */, + 79A12CFC76EC1B0BF26367E0922426FD /* PFInstallationIdentifierStore.m */, + F0E8603DBA1064D73E0E7EB92BED0DA0 /* PFInstallationIdentifierStore_Private.h */, + 9ABAB9B040DE06F9C8CAD85CCC2D4A4D /* PFInstallationPrivate.h */, + A3FBF62848DF8B263E30542353335091 /* PFInternalUtils.h */, + B16892D13DE46A8E0F04B376575D7B5C /* PFInternalUtils.m */, + 4BF07391CA6A2181CE0A3C3765B8F4BF /* PFJSONSerialization.h */, + 4F93FF0560F945FADCA311FD06CA31D3 /* PFJSONSerialization.m */, + 4C08FCA3A865F9181B3EAED5D081E6DB /* PFKeychainStore.h */, + 6674B326B12A30BE2A6BCDFC2F890324 /* PFKeychainStore.m */, + 7B754CD741EB603D2A92BACC3F38A430 /* PFKeyValueCache.h */, + E22A1C7E80FE2BA8CE59C7C924410D0E /* PFKeyValueCache.m */, + E043164BEB509D5E2D2B9698903390E7 /* PFKeyValueCache_Private.h */, + 0B0314DD062570E8416F2523D03B9EF6 /* PFLocationManager.h */, + 1804AEAE0A042ABB0AB0F3B3CCD54B2A /* PFLocationManager.m */, + F9C6A17A0DB2E5C15C0B38508DC16669 /* PFLogger.h */, + AEA3B8A0B629E223E8AD2FFCA8C65F21 /* PFLogger.m */, + B92B54D733F8824AD766092F58A3F50C /* PFLogging.h */, + 96EB5396864F3EE4D9E7D3994DBD1015 /* PFMacros.h */, + 6BBAD9DCAFF06BB669E8D77482B04BDB /* PFMulticastDelegate.h */, + 4FE71002F43E4EE07FF4CEB964FE6D44 /* PFMulticastDelegate.m */, + 4A5BA6A301883961C6DA165D6089A985 /* PFMultiProcessFileLock.h */, + 8F8116D4E8780C6E74C186A8402C69F9 /* PFMultiProcessFileLock.m */, + 5404656CDC7518E20D0C557EF9C53B63 /* PFMultiProcessFileLockController.h */, + 04E79E027951925EA1691B4B8E395973 /* PFMultiProcessFileLockController.m */, + 7E3480D6C7EF4C1D5B97238AFFE8D127 /* PFMutableACLState.h */, + 24B58875AADE4ED78AB3942781E1AECC /* PFMutableACLState.m */, + B93B968FDB3F20E1EB2FA742FA119F61 /* PFMutableFileState.h */, + 800204DFA7DE3E6060355FB89A24FEB1 /* PFMutableFileState.m */, + 924EED608166B7F9A30865D80A87407F /* PFMutableObjectState.h */, + B5D03113C677A7DDA961E0D9E46E949A /* PFMutableObjectState.m */, + 240CCFABDE66FE6ADE38A4B02CB89687 /* PFMutablePushState.h */, + 6DC8BFB1DFE3D689F572296A0DA6E236 /* PFMutablePushState.m */, + AA02D2B63E8F9A35484FF74BB175EDCF /* PFMutableQueryState.h */, + 4F9A3C84F3CC18CABCD97E1DFB774A49 /* PFMutableQueryState.m */, + 1B162D277A2037FD2A114DD8C9CB5922 /* PFMutableRelationState.h */, + 3ED50EE6CEF264393D61B359E4FD13BB /* PFMutableRelationState.m */, + 6D052546B61C8CA0E3EB34475BFB60D0 /* PFMutableUserState.h */, + 9E5A00420D365F9C27CF6F943E8EB990 /* PFMutableUserState.m */, + ADC8E7B23140B59FA2BE5667DEC580B9 /* PFNetworkActivityIndicatorManager.h */, + 9FE38696DEEE3653F1AF4FB0CA7BC07F /* PFNetworkActivityIndicatorManager.m */, + C303ED3A2C18CE2AAADCC69948039080 /* PFNetworkCommand.h */, + B27AB7689D28F34F8A9D466ACAB162DA /* PFNullability.h */, + C5363E7D4FF99528A9F857EE9F2DF437 /* PFObject.h */, + A12B03B24DC7C654F172A6A53E9C7603 /* PFObject.m */, + D1361066E091AA4FB6E9B94B50118177 /* PFObject+Subclass.h */, + ADBEDE77334D88F47F1AD897ECEFAC8D /* PFObjectBatchController.h */, + BC451FC53B248606339FEF2A083812CA /* PFObjectBatchController.m */, + 936E7B213612ECBF1630386CE6D7B1D2 /* PFObjectConstants.h */, + D0E010198F9F57F3C1F5251591AC52B6 /* PFObjectConstants.m */, + 8F8334729245B982D2786A77F61C281C /* PFObjectController.h */, + F9F517D67552371A385D10A6D780C46C /* PFObjectController.m */, + 10475FA9B1F63748681C1D95ED038819 /* PFObjectController_Private.h */, + 20512742319C64711FFF5148A7214E8D /* PFObjectControlling.h */, + EFC29774AABC76F1B26B97B146F2A1C9 /* PFObjectEstimatedData.h */, + 4DC337098F42B8A25439D02AF67102E7 /* PFObjectEstimatedData.m */, + ACE07B046AA72822B46EAC882E565640 /* PFObjectFileCoder.h */, + 45C1F3D82C36D976C5759677F623553F /* PFObjectFileCoder.m */, + 5E44BCC5A1A8313C135B429B4AA92FE8 /* PFObjectFileCodingLogic.h */, + 6FF111BF52B8C1648F8023FC642FF2C8 /* PFObjectFileCodingLogic.m */, + 1906627F9057BDB4DC26FC8D67A0AD0D /* PFObjectFilePersistenceController.h */, + 39D2341AC19A6B3AD747ABBF9D3A13E5 /* PFObjectFilePersistenceController.m */, + 7C114A540E5318937EFA769F5D2A5372 /* PFObjectLocalIdStore.h */, + 6426FFE9B7D5877E4580324A76A08178 /* PFObjectLocalIdStore.m */, + 31AE16032795BC110759FE0D71DD7F32 /* PFObjectPrivate.h */, + 81E010F8251FD4453C9DDE44ED09C4F4 /* PFObjectState.h */, + DC865D74F3C01339E7A0C969FDED834E /* PFObjectState.m */, + E37BF385DA04A9EDE7E17A3AD82FB48D /* PFObjectState_Private.h */, + FE58183D7C1721963488765C5C8C2AC5 /* PFObjectSubclassInfo.h */, + A7AAF29A747A53F757B1A76CF477460A /* PFObjectSubclassInfo.m */, + 6F2BB3EBFE218C47714938D29CF23EF9 /* PFObjectSubclassingController.h */, + F9E40B348CF74929CFC2ED015A0099CE /* PFObjectSubclassingController.m */, + D65E69134BE531C727A15EAC5D6BD404 /* PFObjectUtilities.h */, + C78765A1425D0F41319511A796357B1F /* PFObjectUtilities.m */, + 129476AE26D881F46C3F727D95A2D8EE /* PFOfflineObjectController.h */, + E53C7B0A7D27C453923DDE2311E75A27 /* PFOfflineObjectController.m */, + B6D4806630F08E4A693BB13FD80E2B85 /* PFOfflineQueryController.h */, + 136503C1BC94CD505033988EB9C16090 /* PFOfflineQueryController.m */, + 4EA63193596C0C6A36407E53BE350DC2 /* PFOfflineQueryLogic.h */, + 778D8D7F4CD22FFBC60450393224961A /* PFOfflineQueryLogic.m */, + C1D9153F43B4ABADD58C382A1292332B /* PFOfflineStore.h */, + 632C18854DE2E319E9B6834A93514CC5 /* PFOfflineStore.m */, + F918BC0806DF4B41E1EF8762440B3FAF /* PFOperationSet.h */, + 108401CAD15D4703C0D17F39835C74AE /* PFOperationSet.m */, + 60D3C2480A1362A32E373ED42790BD7C /* PFPaymentTransactionObserver.h */, + 1B6241CE08565BB6864AEF668F68FA18 /* PFPaymentTransactionObserver.m */, + 305A419FED9C718C8ACAE5D2F9173F27 /* PFPaymentTransactionObserver_Private.h */, + B3AE7C57230B414B51B418F0B88252FB /* PFPin.h */, + DAB59734D65B77DD76ADC6A7069BEFCA /* PFPin.m */, + A7540E284803A52212B2DE3FD4678F87 /* PFPinningEventuallyQueue.h */, + 131783F296EC8FE80CA0ACE2C3C056CC /* PFPinningEventuallyQueue.m */, + B70778A88E35241FD05E8017A5D78CFD /* PFPinningObjectStore.h */, + 82EA1A7E2F5B25D7DECB8BE35B3072F0 /* PFPinningObjectStore.m */, + 4920838C7C35EE540CFF086D92C435AC /* PFProduct.h */, + 5076A61842278BC01BD246CD9F6A6831 /* PFProduct.m */, + 4D18572FD7945CECB627B25FAFC28DF5 /* PFProduct+Private.h */, + E7909E9598E022C3C0A3969A59F14279 /* PFProductsRequestHandler.h */, + 2246103381BDCE264B43C19253CCF7C6 /* PFProductsRequestHandler.m */, + 2E051BB78BF5591341C31848B9AE0E0B /* PFPropertyInfo.h */, + 5F8A42FF495AB8897D09E00CAD01440B /* PFPropertyInfo.m */, + B4A9DBE857C85DBC4FCF8511B67E7FF3 /* PFPropertyInfo_Private.h */, + F29DD5432F60CE09614541D4BE9A4FB8 /* PFPropertyInfo_Runtime.h */, + C52117BAFED1734D3269D56FE3D842E0 /* PFPropertyInfo_Runtime.m */, + BF0336CCD7C95A339E279331D898870E /* PFPurchase.h */, + 01A50C2394596A1AAF49C7A2877C776E /* PFPurchase.m */, + A0DE6D1F31DEFED040F4E85B6631177D /* PFPurchaseController.h */, + 0648A7B89F8F0C429E649E87FBFBD699 /* PFPurchaseController.m */, + FE71E48A323238BEC2BB8D62940ED886 /* PFPush.h */, + CBF4F2328A16C47BFD1BCF837B76EB35 /* PFPush.m */, + DAE43287C4A621BABEBFD4D7ACA4D0CB /* PFPushChannelsController.h */, + FB90E78B06FCB922FD3083DB6AFE5ECA /* PFPushChannelsController.m */, + 10C11BD85333AB6363CF6EC82E870605 /* PFPushController.h */, + 13E16ED5531463D4705B39EE950AF115 /* PFPushController.m */, + 368A5760A18AE27F46F5243BA3BFD13C /* PFPushManager.h */, + AFDCBEB6665886D2633CB5495726E387 /* PFPushManager.m */, + 5B791C6AA6D3B48C2C1AA9496E0790AD /* PFPushPrivate.h */, + AB87FFD2A22D9F8F81F29DD24782E89A /* PFPushState.h */, + 939D831BAB14BEA5394F15D3E348976C /* PFPushState.m */, + 6C3843CD6AEFE5F515E6142799F801CA /* PFPushState_Private.h */, + 4235B0900E27A7ECBA96EAFDECF2D5A0 /* PFPushUtilities.h */, + A3152B830DE11B9029E12D3C5B928C17 /* PFPushUtilities.m */, + 616A0DE1DAFFD10BF5A8DD300548447E /* PFQuery.h */, + F19CD8D613E04AF9291C97EC57B1C08D /* PFQuery.m */, + 137AE6FE411D32FD166221B1257A8D27 /* PFQueryController.h */, + ABE4BA05E14673159DDEE660B13A5B00 /* PFQueryController.m */, + D18B76D6F749D3B45BAA4E3B0F2EFFD1 /* PFQueryPrivate.h */, + BD91B010ED73759E99DB85B7CA9FA867 /* PFQueryState.h */, + DD4E641A4F7583F57A2818E33113A0CF /* PFQueryState.m */, + A6D705A7C393E18FCFACEC1D2F07D098 /* PFQueryState_Private.h */, + 76EDBE5B4444693672560F0B38D5C4D3 /* PFQueryUtilities.h */, + 512FA3A57C3C25DEB20BFDE24938517B /* PFQueryUtilities.m */, + 5B799574EF27A1E8D4FD50ADAA42EC77 /* PFReachability.h */, + 20FCD32AE2B10221B23EC19A5B380953 /* PFReachability.m */, + AC8C608A0D3BE700536D0C6D4011931A /* PFRelation.h */, + 25EF987A717711C8CEAE29DFF3C12EA0 /* PFRelation.m */, + B5439DB8932AAF79667AED53097CC2C9 /* PFRelationPrivate.h */, + 9441797DDFA8DBDB595E9BA19BE1342D /* PFRelationState.h */, + 468C80083455F41B26E5C3D366E6F467 /* PFRelationState.m */, + CD4D52B14CF2360DE429DCB655B00642 /* PFRelationState_Private.h */, + B9E911ACAAECA0172448CD4E62137AF4 /* PFRESTAnalyticsCommand.h */, + FB1CFA906E2A5ECA69FDBCAC00497F72 /* PFRESTAnalyticsCommand.m */, + 8B1E4C81276B30550CB3CDA51070D862 /* PFRESTCloudCommand.h */, + CAEFED956777B69C5958C0E809EC11BB /* PFRESTCloudCommand.m */, + 3C9A888CC23B37A508B946C18FBA51D5 /* PFRESTCommand.h */, + 3962BED4A779536F2E41B1C36D6285AB /* PFRESTCommand.m */, + 37F7E3AF617E0BF5874DE052CCFF4A53 /* PFRESTCommand_Private.h */, + 3E03D377B70A81B7EE7DF0A8F510E529 /* PFRESTConfigCommand.h */, + 2E4BCF2AF417571FAAD5D3A0AF5FFB93 /* PFRESTConfigCommand.m */, + A1F131A4365C559659FC1FBB194A13E9 /* PFRESTFileCommand.h */, + D5F29001AB83C450101AC6122BCC4EA0 /* PFRESTFileCommand.m */, + 1635AF96EB71FB3FEBEE52A4395CFA1B /* PFRESTObjectBatchCommand.h */, + DAF50A43880E07D46E8A97B575A92405 /* PFRESTObjectBatchCommand.m */, + F1B5BCEFFE5D1ED352C01484C83D6924 /* PFRESTObjectCommand.h */, + E0650188B522893BF764569662B5E542 /* PFRESTObjectCommand.m */, + EBC06CCF32BA9A3FEE34142E70D19588 /* PFRESTPushCommand.h */, + 47C5EB9BE6709541AB17E0F38FB1BB1A /* PFRESTPushCommand.m */, + 118B70D2949B865CA76511460D9D0C92 /* PFRESTQueryCommand.h */, + 0842DD1DCDFD9683C89B6A9078E9D0FC /* PFRESTQueryCommand.m */, + F8B8D967E928682C85109A85124DEEC4 /* PFRESTSessionCommand.h */, + 030B329DF20766AE685434CD734BC3B2 /* PFRESTSessionCommand.m */, + D3AD3AB61D09EFC9C322C57F9239AFF8 /* PFRESTUserCommand.h */, + 9F097273140B23B664D84C6DF75EE2D1 /* PFRESTUserCommand.m */, + 409EF16B93600F84E2CC3287F2C35D7E /* PFRole.h */, + 66754BB67AA131A94D10F42D109E8523 /* PFRole.m */, + B0AF344F89667D8F50F4A22C146ACF21 /* PFSession.h */, + A7780E3BA6732D798F3374CA43890F7C /* PFSession.m */, + B03B11C4675A010812829BDD0481A90F /* PFSession_Private.h */, + 1375129BA8E11876FE8F3530124E4FF9 /* PFSessionController.h */, + 73136CB5DF8D9FDC9C0B3FF336E53790 /* PFSessionController.m */, + A4B28BD09271EAECA8D4D7EE69556765 /* PFSessionUtilities.h */, + 72C1FA5A8BDBCEC19E41771957BEB9E3 /* PFSessionUtilities.m */, + 7AD029CD6F8ADD2E864E5FE1699BB70D /* PFSQLiteDatabase.h */, + 255D43CCCFDFD52C9090EF3B8972D72C /* PFSQLiteDatabase.m */, + 31EC6AF4DEA7F85F68A5CE8C3ECA3280 /* PFSQLiteDatabase_Private.h */, + 19397C043A357D696BBA9A55EFD5B167 /* PFSQLiteDatabaseController.h */, + 97044BE056C705C44778E090F30A538B /* PFSQLiteDatabaseController.m */, + EAA88DECC60605475F4AA3869B36A8FB /* PFSQLiteDatabaseResult.h */, + C60BCCB74CDC88B04B7014C507F2D137 /* PFSQLiteDatabaseResult.m */, + 4788A28C6827C4BF85BEB5920CADFEE4 /* PFSQLiteStatement.h */, + 06FB17807D8F9BB90C006F1AA1422EEB /* PFSQLiteStatement.m */, + 4C8E5BBEB36882FAEA0C74B322ADC266 /* PFSubclassing.h */, + 1CE3CC21857556B51CB17BCFCF1EE7B1 /* PFTaskQueue.h */, + 79A805E2776C2CC27AB7764874C93173 /* PFTaskQueue.m */, + 909C0AD7538FB9457B86EC3AC7D973FD /* PFThreadsafety.h */, + 1BDC71820826E3AC85B7BE2E689790EA /* PFThreadsafety.m */, + 55DFDBF9FA07FC6282738752A376B991 /* PFURLConstructor.h */, + FF57BE3A8EF2D78A282E7FEE79783DB3 /* PFURLConstructor.m */, + 7981192FA1E3FF14D8C9EBA4511FD33B /* PFURLSession.h */, + 24851AC75A717461DF249C574A7E59B5 /* PFURLSession.m */, + F9A0A5F9F3C3457E2ECD91932E225F1F /* PFURLSession_Private.h */, + 327724504C5129C28E647306963F3042 /* PFURLSessionCommandRunner.h */, + 0D0B957E23560E8729AFBC541E7F0401 /* PFURLSessionCommandRunner.m */, + 55116A6D2C15718DE59AF5A2B7B5C7F2 /* PFURLSessionCommandRunner_Private.h */, + 701190361150FF2EEDEF10D05ABE7065 /* PFURLSessionDataTaskDelegate.h */, + 22E1D8AA11E50E9A37281052037D86FF /* PFURLSessionDataTaskDelegate.m */, + 42CBEF54F1256217E4780DB8ABBF5AC3 /* PFURLSessionDataTaskDelegate_Private.h */, + 7DFC97B9CEA18DDABF91F38573337059 /* PFURLSessionFileDownloadTaskDelegate.h */, + 423887AF6686942102218A073BC526E2 /* PFURLSessionFileDownloadTaskDelegate.m */, + 3198F91D01D488AAEE2E37C91C36109C /* PFURLSessionJSONDataTaskDelegate.h */, + B1126558A8CA869CAE3169CD0485A400 /* PFURLSessionJSONDataTaskDelegate.m */, + 0EB6E9BC99D4CE39BCEA9AB574501691 /* PFURLSessionUploadTaskDelegate.h */, + F129E4F0636DB79526F8F6270198B942 /* PFURLSessionUploadTaskDelegate.m */, + FCDD09913DC7F28BA260222EED8670BE /* PFUser.h */, + DE726D284DFE5BC0144139D8575114FE /* PFUser.m */, + A36C3225AB6FDE49BE8F8859C30A7D7D /* PFUserAuthenticationController.h */, + 16AA732281290E4169524C7073D0E8C9 /* PFUserAuthenticationController.m */, + 40E39D31FE7DC01DD03AA4AF8530EC8D /* PFUserAuthenticationDelegate.h */, + 616C83AFE6D3B13DB326EFFDA4E56218 /* PFUserConstants.h */, + 5CA0A29FC7FC84E10BBE7CB9F915C818 /* PFUserConstants.m */, + 092AA11ADB8FDDCC538A0ABDD75F38E8 /* PFUserController.h */, + C1A37998F9BF6B81FA68488F9A55BC50 /* PFUserController.m */, + B3AC4F0EFC27421FCDFE376464524DBB /* PFUserFileCodingLogic.h */, + D605FE4F41A283271B93F93C8E0C5932 /* PFUserFileCodingLogic.m */, + 6EBA7EC1BD2D3653F709A5C97063B990 /* PFUserPrivate.h */, + 099E673F2FD9E7D461C9590B6D38BA1F /* PFUserState.h */, + C4FAEDC2711A67FEFF48FE305A9A04C6 /* PFUserState.m */, + 138471689F57812BFA9933C75A79A7D5 /* PFUserState_Private.h */, + 205214C203BF751A124F1153AD9CBA8E /* PFWeakValue.h */, + 03C91AECE7686A27F9032A4DCC43165E /* PFWeakValue.m */, + 622C8AD332559FDD50912FB3F2114FD2 /* Resources */, + 558DF5C9649361A2C6A16D52D1F75A0A /* Support Files */, + ); + path = Parse; + sourceTree = ""; + }; + 25510258318D770B38C09C4CA0D2DC7C /* Support Files */ = { + isa = PBXGroup; + children = ( + EB97CD8D9BDC16D9E1CE5F863965790B /* pop.xcconfig */, + C03EC589275AA21D375F405EB48AB374 /* pop-dummy.m */, + EBF45573BC8D86EF53B4B16396F99411 /* pop-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/pop"; + sourceTree = ""; + }; + 2612628171849F4DEDE2DDD5C2B94566 /* Support Files */ = { + isa = PBXGroup; + children = ( + 556F7F390D364FD2B3DA48C98E500E2C /* TransitionKit.xcconfig */, + 83319D45D8AE5D8BF57D365983A41750 /* TransitionKit-dummy.m */, + CF09A05A7A248669395E6778DD2838AE /* TransitionKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/TransitionKit"; + sourceTree = ""; + }; + 2935474A12329277E07A08BD4241480F /* Support Files */ = { + isa = PBXGroup; + children = ( + 3BF16968FBC656E49A7B643EED4B84F6 /* ISO8601DateFormatterValueTransformer.xcconfig */, + A0C95D96D102F597D4543F77E2DBE642 /* ISO8601DateFormatterValueTransformer-dummy.m */, + 6AE20D46FEA8C73D4CD5828D72E4D47B /* ISO8601DateFormatterValueTransformer-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/ISO8601DateFormatterValueTransformer"; + sourceTree = ""; + }; + 328D5BB5F21E344E9FBB7B9C794DCDBE /* FBSDKLoginKit */ = { + isa = PBXGroup; + children = ( + 6D540B5BA940B77762F525759CD9E2F7 /* _FBSDKLoginRecoveryAttempter.h */, + C5C2B2C9BECEC9F64477D3C8051CFDB5 /* _FBSDKLoginRecoveryAttempter.m */, + 8A6E4A459DD6D5E686E59DC08B4D07F1 /* FBSDKLoginButton.h */, + DD91926B9C031018B2F9CB9019718F3E /* FBSDKLoginButton.m */, + 763D59D54C57DA2AAFAD336EE912908D /* FBSDKLoginCompletion.h */, + BBB5809E48E2B4BEFFDD671C03A673A1 /* FBSDKLoginCompletion.m */, + 517FE5FCB5C6241B8A66BE083CA1AAE6 /* FBSDKLoginCompletion+Internal.h */, + 25070753B1B37A1665F1F5332C0EF515 /* FBSDKLoginConstants.h */, + E160D14CDAB0E17CC1D0024A8673A34C /* FBSDKLoginConstants.m */, + 044941FE89AB594A010087B94F17D923 /* FBSDKLoginError.h */, + 6E2D1B4FCC4918686DEAF9094B908917 /* FBSDKLoginError.m */, + AEB4D0E3F5DD747BCD44340E26E9755F /* FBSDKLoginKit.h */, + B3362FF57BC5AE2D2552F6F4C4ACD2C9 /* FBSDKLoginKit+Internal.h */, + 59EAFD88B92A3912D4951328AF334D28 /* FBSDKLoginManager.h */, + 03549C9A2FD883CD12D063617A47E0D3 /* FBSDKLoginManager.m */, + 20B8F6A2F2E484CD2E09B61345C563A0 /* FBSDKLoginManager+Internal.h */, + EF79FDCF0AF41A384FB770643D79F0E6 /* FBSDKLoginManagerLogger.h */, + C45478301558D880893FA55C99879E3C /* FBSDKLoginManagerLogger.m */, + 826C988F437410449787F4BDCE07E6B7 /* FBSDKLoginManagerLoginResult.h */, + 5F5D256457EA109A0FD3C2B7F2AFFFD8 /* FBSDKLoginManagerLoginResult.m */, + C737DBF986FE1FF02706679384A58608 /* FBSDKLoginManagerLoginResult+Internal.h */, + 87C33535E86A40250BA126A6209213CC /* FBSDKLoginTooltipView.h */, + 335A3DE810AEDFE589A9325169A59E46 /* FBSDKLoginTooltipView.m */, + 957013533FBA66B6F24FF31441FF1EC3 /* FBSDKLoginUtility.h */, + DB72A1AC246E5FC4E81A0DBB8B1F0737 /* FBSDKLoginUtility.m */, + DF3BBA8D585F58897AE3BA414EDE35C2 /* FBSDKTooltipView.h */, + BFBDACDD0805704D189CA36FE17373B8 /* FBSDKTooltipView.m */, + 4B78A7C79EF8E74431E1D08F13B47675 /* Support Files */, + ); + path = FBSDKLoginKit; + sourceTree = ""; + }; + 36F3E3D009A33DE3EB27FA31CBCE358C /* iOS */ = { + isa = PBXGroup; + children = ( + 3849FCCD9604B569E0277015CC30071D /* AudioToolbox.framework */, + 733D51F628A8649F5A0790296BA3E42A /* CFNetwork.framework */, + EEBA4E2BFC884C1F4B170F5BC7DE8B77 /* CoreGraphics.framework */, + 1E3783F1A59CCE93EEF653593AFAD5B5 /* CoreLocation.framework */, + FC8F8CB8538044AF0B76C816D7CAF811 /* Foundation.framework */, + E62E80C06B8D2394C56D10220D1CCB6F /* MobileCoreServices.framework */, + B0F29E0D66F63131F371330D93CB4583 /* QuartzCore.framework */, + 6114EBA3A5CB7CB8ECE0A9BEFA6DB026 /* Security.framework */, + C758B84874FBB01F1E2CE355BEA77660 /* StoreKit.framework */, + 16621039C0E3312C216165BEF8D567DE /* SystemConfiguration.framework */, + B6FDEF44D035ECEB171CF49BE68D54D0 /* UIKit.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 4380A3F473F199836A3C72502983239A /* Tasks */ = { + isa = PBXGroup; + children = ( + 9EB6FC1B35894D58DCAA447BFB3BB370 /* BFCancellationToken.h */, + D340DC8D2BC61B7C8A044A46F47ED4D0 /* BFCancellationToken.m */, + F22636EFE5E1A5651E0A1520C5F281E5 /* BFCancellationTokenRegistration.h */, + 1EE55AE735F6A67726031719677B1B38 /* BFCancellationTokenRegistration.m */, + D147E7F72F838ED5D3C66A4E3546EC11 /* BFCancellationTokenSource.h */, + 0B8AE15FBFEC0BE016020B8970ADE865 /* BFCancellationTokenSource.m */, + 3B1F248FA3EE75C351E1B383AB977DF7 /* BFDefines.h */, + 0D63D25E0D4B1B1573FC3216A3041E64 /* BFExecutor.h */, + 2775CBEED05B03B513848BE46301ECA6 /* BFExecutor.m */, + D2A208C22FB8BC1DAFD34F05A88E7349 /* BFTask.h */, + BE404DC24F62FA97CDAEF063B4413139 /* BFTask.m */, + 72766C115F290B685E1C527E77EDEDEE /* BFTaskCompletionSource.h */, + F6F4C2DDD2D3755D276BC06E4C5B319E /* BFTaskCompletionSource.m */, + C5052DE726F89E27E1CA5D188FD32C5D /* Bolts.h */, + 20D1F9C0BECD5D6036F5F1A63383C39D /* Bolts.m */, + 29DAD99804B5BD08F3A74008FD65BAE7 /* BoltsVersion.h */, + ); + name = Tasks; + sourceTree = ""; + }; + 443FE6FAC9F77ED18F698A1F1AD2DF9E /* FoldingTabBar */ = { + isa = PBXGroup; + children = ( + 955C4C780B4D5A0582BF89B0379CB61E /* CAAnimation+YALTabBarViewAnimations.h */, + 26B6710576834D59FB5352DD3F5EB069 /* CAAnimation+YALTabBarViewAnimations.m */, + FBFE9966A9FB854C5D85375D24F936C5 /* CATransaction+TransactionWithAnimationsAndCompletion.h */, + 266541F607EB34A777991BD29D5D2556 /* CATransaction+TransactionWithAnimationsAndCompletion.m */, + 57319DCE064A4F4C9DD2D290FD88D642 /* YALAnimatingTabBarConstants.h */, + 2870EF5BFCF54FA3B58A74A16C8DEA99 /* YALAnimatingTabBarConstants.m */, + F7EEEC622363411316A89CF3A6941695 /* YALFoldingTabBar.h */, + F83D6439675ABF2D6040C5D9F2FFF217 /* YALFoldingTabBar.m */, + 352259996AE7807E58AB7D6E88FAC9F7 /* YALFoldingTabBarController.h */, + AE3ADE078ECB5E4868892A8EA3936EA5 /* YALFoldingTabBarController.m */, + B7B6A72DD28FBD988E0B1E6A930C1BCA /* YALSpringAnimation.h */, + BD5D724AF948672175ECFB8781A0F2F5 /* YALSpringAnimation.m */, + CCD58C1FE0A285B35DC39096400FF8C5 /* YALTabBarInteracting.h */, + 44A2841E1C0E28AFEE0B7288D6E47D4E /* YALTabBarItem.h */, + A75314C0637DF9AD59C4F573E3CB78C6 /* YALTabBarItem.m */, + CE2D9BA208321FEB30B86BE7BEF38787 /* Support Files */, + ); + path = FoldingTabBar; + sourceTree = ""; + }; + 4B78A7C79EF8E74431E1D08F13B47675 /* Support Files */ = { + isa = PBXGroup; + children = ( + 3F045700822563CB163FE8B3F606352C /* FBSDKLoginKit.xcconfig */, + 880C326DB82974026154DE2FEE6DF8EA /* FBSDKLoginKit-dummy.m */, + 17E73976887C42E701026CD6E8B7F4E4 /* FBSDKLoginKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/FBSDKLoginKit"; + sourceTree = ""; + }; + 558DF5C9649361A2C6A16D52D1F75A0A /* Support Files */ = { + isa = PBXGroup; + children = ( + A38DBD435D9B08BE5E3BBE4C171BB0B9 /* Parse.xcconfig */, + 9BD8C56BA64752CBF457FB1F3473747F /* Parse-dummy.m */, + CCE6CAC57669DAF95F75350ACA64D8F5 /* Parse-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/Parse"; + sourceTree = ""; + }; + 622C8AD332559FDD50912FB3F2114FD2 /* Resources */ = { + isa = PBXGroup; + children = ( + 207C347476CAA87AD1032D236FA290A2 /* en.lproj */, + ); + name = Resources; + sourceTree = ""; + }; + 6D2B535DFEFC2D59F09AAFC33373431E /* RestKit */ = { + isa = PBXGroup; + children = ( + 934AFBAB81ECCF7F631DBEAE9DF1B13A /* Network */, + 7EABF82AC8B75AB60FFA4D4094FA0800 /* ObjectMapping */, + 102D02B51D25F8C5C815B69B7CB61B08 /* Support */, + D1A12668CBBAF479BBDDE11E900C7DFB /* Support Files */, + 0BFBFBF37DD4FBC676345E304C5B6CE7 /* Testing */, + ); + path = RestKit; + sourceTree = ""; + }; + 730A0971E2B05CA436436CFBECBFAA5E /* FBSDKShareKit */ = { + isa = PBXGroup; + children = ( + 0587E0A5FA037D15DDF1E0DD7E70CD5D /* FBSDKAppGroupAddDialog.h */, + 782AF7A5FC9A3571F42003CD07FE5A3C /* FBSDKAppGroupAddDialog.m */, + 87352A5CFA4016F286A66829B0D2BFB9 /* FBSDKAppGroupContent.h */, + 3CFFE5B32D8DD018AAF9EB4733D6315B /* FBSDKAppGroupContent.m */, + 79630B324053224BBFAB6E9D26A18148 /* FBSDKAppGroupJoinDialog.h */, + 610EC8334EB48B27B2BBE37D785AF2B2 /* FBSDKAppGroupJoinDialog.m */, + BF8BD2902C2FE3B67C86F30BFEAE4A3E /* FBSDKAppInviteContent.h */, + D24F985E3661241D2C0921E8022E66C2 /* FBSDKAppInviteContent.m */, + 49293A25955435D7FC5E29D841FA4456 /* FBSDKAppInviteDialog.h */, + 3265A08CD5F3A28A6541A985B0B75664 /* FBSDKAppInviteDialog.m */, + C2E9C149FB61E88BEF76CE74D5776813 /* FBSDKCheckmarkIcon.h */, + 3E4E096EFFA1494BC822896BB3BD15AB /* FBSDKCheckmarkIcon.m */, + EFF0339213287B595E2857A1BCA7B7E8 /* FBSDKGameRequestContent.h */, + 7DAC4524798CD2351824DF502E226F2E /* FBSDKGameRequestContent.m */, + 346CED5D6B988E5318DBD8CC9C98A073 /* FBSDKGameRequestDialog.h */, + 4F609FCDD81EB1ADED68C1FE461C3594 /* FBSDKGameRequestDialog.m */, + E73D941475103F44552CBBF7A9C2578A /* FBSDKGameRequestFrictionlessRecipientCache.h */, + A99D66855595DD2F9E379F9A258C7FD4 /* FBSDKGameRequestFrictionlessRecipientCache.m */, + BFAC7C03033A9B1F15075F4565BC1328 /* FBSDKLikeActionController.h */, + ECF9B9F2BA04D70CD7253751FF94CCD5 /* FBSDKLikeActionController.m */, + 535545A6AC7290701119A0B61C887EFF /* FBSDKLikeActionControllerCache.h */, + 68133029060DA29FD5C9C26119CFA51B /* FBSDKLikeActionControllerCache.m */, + CF478811F261A5C3A4200EF18BD59E46 /* FBSDKLikeBoxBorderView.h */, + 95C0B6DA20609F0B05D9D1AB1D2FC475 /* FBSDKLikeBoxBorderView.m */, + A8710983B393BA50AECE51EA8D90E727 /* FBSDKLikeBoxView.h */, + A473E7C40F24CE11C1FE9F416C8E5EC2 /* FBSDKLikeBoxView.m */, + 9D7D382B54C6E6B265B154F079E1CDDB /* FBSDKLikeButton.h */, + 64264592576D6C230E966AC098067DAB /* FBSDKLikeButton.m */, + 7DEFDD3A6DB314308247D22FF14AFA98 /* FBSDKLikeButton+Internal.h */, + CEF0CE91FC9080D9E33E9B362D760F18 /* FBSDKLikeButtonPopWAV.h */, + F2575C28B5137ABEB1B9557B34F3448C /* FBSDKLikeButtonPopWAV.m */, + 424184F6AAB828CA2D22E450BB52A081 /* FBSDKLikeControl.h */, + 9E3DEF8E2E27C00D59DC5DE4C876E0D1 /* FBSDKLikeControl.m */, + 2BB0273CAD372752E68ECCBCD48E5842 /* FBSDKLikeControl+Internal.h */, + 9F1B1BCD1E0ECE22C24CC82032B14A95 /* FBSDKLikeDialog.h */, + 3394EE87DFC9E88439AB265D59382138 /* FBSDKLikeDialog.m */, + 4AB618D67D94F32578DF5336651E7855 /* FBSDKLikeObjectType.h */, + B8DA6BF199DF0CAB4F3B6FE8589F18F9 /* FBSDKLikeObjectType.m */, + 672B96E281A19DA7F2F22511F1093D16 /* FBSDKLiking.h */, + BF50A2188E832EC70F211B3F3932C51C /* FBSDKMessageDialog.h */, + 85F8F13323C74D0619E9E4B4BBB27CEE /* FBSDKMessageDialog.m */, + 804F2F0EDB0F2FE68B74F5D2D1ED5A94 /* FBSDKMessengerIcon.h */, + 134ACDC2444EE29856334D3196F53AC0 /* FBSDKMessengerIcon.m */, + 8039DDB4E996A03FF15AD2DF8D4D1CA9 /* FBSDKSendButton.h */, + 92D9BAF18D3C2495B07204C2404BFEEB /* FBSDKSendButton.m */, + 0FCED2B89C49FCB98FAE1186D1725F5B /* FBSDKShareAPI.h */, + ADBAF2BABA39070672917C80E4F74CBA /* FBSDKShareAPI.m */, + 8CBCFD5CCB1FD15EED54F82E909DC031 /* FBSDKShareButton.h */, + BEEE1441A35504F5C1462BCBEE30EE7F /* FBSDKShareButton.m */, + 29B13B33590257BF7A80C3602DC87B09 /* FBSDKShareConstants.h */, + B53170EBE3F4D7BAA67CDA6A2C198542 /* FBSDKShareConstants.m */, + 9B9C80D740936B42747C456E06BD4210 /* FBSDKShareDefines.h */, + A8051434722A3494196DC122D8029D34 /* FBSDKShareDialog.h */, + 6569377CC0B0AA51EBA394C782985089 /* FBSDKShareDialog.m */, + 3F3FC0B3D497637B402F51B44E5B28F5 /* FBSDKShareDialogMode.h */, + 36A9A82E6520CD02FD9422940934EACB /* FBSDKShareDialogMode.m */, + 0D612FDB5856A0B0DC71C9A83AF67537 /* FBSDKShareError.h */, + 0B843EB1DFCFEE6E5EE55AC6767E4E13 /* FBSDKShareError.m */, + 2B468DC6F25FAF7381C563D8A3A3C32E /* FBSDKShareKit.h */, + 2DE175F2297AFCBB1C62B1B16B5891F1 /* FBSDKShareKit+Internal.h */, + 3EE26090EAD13C1FFD39BB6A7C89193B /* FBSDKShareLinkContent.h */, + 864B619977C41FA41083B23778DFD471 /* FBSDKShareLinkContent.m */, + A9E08B70AB72ECE4DA87BFED9B17F956 /* FBSDKShareLinkContent+Internal.h */, + 6768924E65317D0E30521724DC081C08 /* FBSDKShareOpenGraphAction.h */, + 05D4509ED8E7E863F79C2BDF6FE4471C /* FBSDKShareOpenGraphAction.m */, + 97F4FC4FF392B72657F42F96261BBC3F /* FBSDKShareOpenGraphContent.h */, + 26576E563FF51DD9C6683E959913991D /* FBSDKShareOpenGraphContent.m */, + DA3EA52DCFB7D558F88A88501D54E2B9 /* FBSDKShareOpenGraphObject.h */, + 224595D0364E886259E4B2F44C937D02 /* FBSDKShareOpenGraphObject.m */, + 1B1BBDE1A0182E4AAFF80CDBBDF1DAB9 /* FBSDKShareOpenGraphValueContainer.h */, + 7C6CEAC74231F31EC9DDED4C3E2BBF48 /* FBSDKShareOpenGraphValueContainer.m */, + F42B1B0D93B9783D48D27AAF873BC978 /* FBSDKShareOpenGraphValueContainer+Internal.h */, + B91E34DFD041EF9B4895EC618300E024 /* FBSDKSharePhoto.h */, + 7CE70DA06AD37A88DD393A98C73C7D07 /* FBSDKSharePhoto.m */, + A7AC1819EBC907C93BA5F2B790C16D0E /* FBSDKSharePhotoContent.h */, + B16533489604D2247F7EC997C13BA975 /* FBSDKSharePhotoContent.m */, + 9E3D3427A00B557DE42EED0B4C015942 /* FBSDKShareUtility.h */, + C5934D49963F991DC729306B6D2ECA94 /* FBSDKShareUtility.m */, + 3135C42A396F109267EA88F6641A9194 /* FBSDKShareVideo.h */, + E6D171B8D3792811D774B92580727FAB /* FBSDKShareVideo.m */, + 56EDB2104DA13588CD5B4334FF77452F /* FBSDKShareVideoContent.h */, + 69B2823ABCAD80D975C9E8C29A5E869F /* FBSDKShareVideoContent.m */, + AF22BCCC30F4473554DFAAAEBC740BE7 /* FBSDKSharing.h */, + D80B172E70B3B5E8CAEA6069D1DE5D71 /* FBSDKSharingButton.h */, + 3ACEDF4D677834B067A9DD0F82954897 /* FBSDKSharingContent.h */, + 030A5B3E44F0F6E57B1380DD185339D1 /* Support Files */, + ); + path = FBSDKShareKit; + sourceTree = ""; + }; + 73C1CB09E0328129B45C632E136DEE53 /* no-arc */ = { + isa = PBXGroup; + children = ( + 8988609857673ACE16552A1C00D45091 /* FBSDKDynamicFrameworkLoader.m */, + ); + name = "no-arc"; + sourceTree = ""; + }; + 7ADA1DE4AC552D9180233F1D5A34429C /* Support Files */ = { + isa = PBXGroup; + children = ( + A28864FB7EB36A5080B6D12B1B94125F /* AFNetworking.xcconfig */, + E089DC06AFABF3AB162039B0DCA20D14 /* AFNetworking-dummy.m */, + 00867696A579EF950503FFC6BFDC74DD /* AFNetworking-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/AFNetworking"; + sourceTree = ""; + }; + 7DA921C2C956313F56FEBC0296B7C6F4 /* FBSDKCoreKit */ = { + isa = PBXGroup; + children = ( + D29F10A74F6ECD83F33B3134ECE1076E /* arc */, + 73C1CB09E0328129B45C632E136DEE53 /* no-arc */, + F46DF5AF30AF4F7D4DFAC67E03AEE55E /* Support Files */, + ); + path = FBSDKCoreKit; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */, + EB57DDB3388FBC701046A1E93218737F /* Frameworks */, + 98D46EC37B626EB861E505D9911A6B4C /* Pods */, + 8C2957D7B83B63ED6950DC1F89AD93E3 /* Products */, + 037C0CA694176A3C0915F62C9D20B3E6 /* Targets Support Files */, + ); + sourceTree = ""; + }; + 7EABF82AC8B75AB60FFA4D4094FA0800 /* ObjectMapping */ = { + isa = PBXGroup; + children = ( + C647E341C56F994FDA336B094DDC681B /* ObjectMapping.h */, + 776A46D7EBDABB85B1A452ED93BEFBF9 /* RKAttributeMapping.h */, + 2551AB6C3C2A1C521E0184550321DE02 /* RKAttributeMapping.m */, + 0D6A9F671AC5AAF2E4BDEE1D46C1A2DF /* RKDynamicMapping.h */, + 849262636C1FD7E1D283D86137BE70B8 /* RKDynamicMapping.m */, + 1EA0BB06D8B077DFC855CBF92505F74A /* RKErrorMessage.h */, + 6380D4168C668F109E1A03B20D714BBE /* RKErrorMessage.m */, + BCB59A851D792D3D60B16A08B9F07134 /* RKHTTPUtilities.h */, + 7DA6FF9AD89559AE8FE2FD106DCB87C5 /* RKHTTPUtilities.m */, + 65962B65C068EE02DAE719D8D70CA321 /* RKMapperOperation.h */, + 0803B22C601D5D4145A1B91DB87E04E3 /* RKMapperOperation.m */, + 433B51CC13747ACBE8AA93F02C6D784A /* RKMapperOperation_Private.h */, + CB3D0EFB3CB9EFB991A6BD44384669BB /* RKMapping.h */, + 40C31A1DA0DE91B3BDC70194B9B9E75B /* RKMapping.m */, + FBEB6D4BDCEFC529A9705D5228053B04 /* RKMappingErrors.h */, + FD07183D5459C1861CCC80EC5514A9AA /* RKMappingOperation.h */, + 6FE7C0F12060A4C3CEE3C5427762A616 /* RKMappingOperation.m */, + B7478D31F88F47602170505B415F4CEB /* RKMappingOperationDataSource.h */, + DECD8E5B530D5D0B9FB27660D6A00BA3 /* RKMappingResult.h */, + 903947141B4DCB4B32507DADE29354A1 /* RKMappingResult.m */, + F4EC41878B622B137CC4B622FC53F3ED /* RKObjectMapping.h */, + ADD34821324463B1C81B2802AFA7B01C /* RKObjectMapping.m */, + E5C990C91B211AE926078950B8630516 /* RKObjectMappingMatcher.h */, + C42E29EF756BB8A7BCE6151C6229BA3D /* RKObjectMappingMatcher.m */, + F25269A960ACE3EBB3FE45F44DE4D5BC /* RKObjectMappingOperationDataSource.h */, + 2DFC0AEEC2FC3F3A422A6A76F818E344 /* RKObjectMappingOperationDataSource.m */, + B037353120BA03ACEF0F5DA52B84530E /* RKObjectUtilities.h */, + 0673474C0D02C740FB04EE10B58213D9 /* RKObjectUtilities.m */, + 33A88DE3DA4EB5064A997FFAF0C23DCF /* RKPropertyInspector.h */, + CF3513EE8625253892B05EFF20F16B57 /* RKPropertyInspector.m */, + D4D4E125C0EFD510E0171C24783AD02F /* RKPropertyMapping.h */, + 8B9E4087FDB2FFD655EB8FA58B697B4E /* RKPropertyMapping.m */, + E49DAAC9A8E0D5362E749A6821734AF0 /* RKRelationshipMapping.h */, + 9A3DEC35A890AB8929D5A78F2D24DC7A /* RKRelationshipMapping.m */, + ); + name = ObjectMapping; + sourceTree = ""; + }; + 8C2957D7B83B63ED6950DC1F89AD93E3 /* Products */ = { + isa = PBXGroup; + children = ( + 6A45C57C5D3CBC79D400F49C075773AE /* libAFNetworking.a */, + BFCC23211BE47A527079FEF69772F5CE /* libBolts.a */, + E0E0D90BB11B78E84D92384725A9534E /* libFBSDKCoreKit.a */, + 9D7377386CC3EBA3E3B7C409D23C69B6 /* libFBSDKLoginKit.a */, + 979C040C22C6D7527C085E98ED8D71A0 /* libFBSDKShareKit.a */, + 80E5F5E0AE0F6B7B2757A6066BCC8612 /* libFoldingTabBar.a */, + C5F83C7A2BEAFF6FFAEAD7A6F73B7D49 /* libISO8601DateFormatterValueTransformer.a */, + 1D9362003B89F08493A37902350DA1BC /* libParse.a */, + 011534C01155F79E4047CADDE68EF6B8 /* libPods.a */, + FE3AAD9A2F31FBC9D00D7715F65FDB26 /* libpop.a */, + 80D183F090FB2841492B19FAC5CD77B6 /* libRestKit.a */, + 28ACD3CB82BEF500AB8A021A9907BF32 /* libRKValueTransformers.a */, + 34C584E3410A80115A9107E13C995E70 /* libSOCKit.a */, + F970BE5082817C3185CB918CBDAFE49B /* libTransitionKit.a */, + ); + name = Products; + sourceTree = ""; + }; + 934AFBAB81ECCF7F631DBEAE9DF1B13A /* Network */ = { + isa = PBXGroup; + children = ( + 85B4596D7B3771E5ABD20C9631F9B18A /* Network.h */, + 3DDC10303447DF4E3E657F2B4AD92925 /* RKHTTPRequestOperation.h */, + 9086156C9220E522C597B7BE572F6BFB /* RKHTTPRequestOperation.m */, + 8BECD1A40487A504B56D704C9D21E36C /* RKManagedObjectRequestOperation.h */, + 078AB2530E4CDAB1E634AE38A5545949 /* RKManagedObjectRequestOperation.m */, + A4DD5212BA2630DC90D52AB2A7B05B85 /* RKObjectManager.h */, + 114DF71DB16E01CD9902FA71F5FCB868 /* RKObjectManager.m */, + 12148D9B34DE0B074CF161C3B74EA2F9 /* RKObjectParameterization.h */, + 73C100898C88FF4043F6002195DD6293 /* RKObjectParameterization.m */, + D5B9C19265F524EBC4ED733155E3DB3B /* RKObjectRequestOperation.h */, + 8A7550A91022A017F5AFB8DF01AAFDFA /* RKObjectRequestOperation.m */, + A8E3AF8A6E915006D004A9CF92CA325D /* RKObjectRequestOperationSubclass.h */, + 55B8770724B1C27628F366C0CF2D3B85 /* RKPaginator.h */, + A0A6F3B1842359B2087C2C8FE2CDB03A /* RKPaginator.m */, + CD158942FBF8358677B8D9A4BEA9332E /* RKPathMatcher.h */, + 09BC6A273BD14FEC82E66ADE94F2D7AB /* RKPathMatcher.m */, + 4521F82969CCAF3A290F34A7DA26A9DF /* RKRequestDescriptor.h */, + F4B09A465BA0ED9168954ACE5D869AD1 /* RKRequestDescriptor.m */, + AEA43D8F8666C7D28DA8F862B304C5B8 /* RKResponseDescriptor.h */, + BA0DEBD43672CEB35AC053C3EDBD0BF9 /* RKResponseDescriptor.m */, + 033F7B99C3A65CD435C0B7A09C59F876 /* RKResponseMapperOperation.h */, + 7AC2271F01F29748BDF976CEF2EE767A /* RKResponseMapperOperation.m */, + 8C78256463C46E887FB8962C96ADF343 /* RKRoute.h */, + 58E4CECC242634F51EA5250B5A8FF795 /* RKRoute.m */, + 868CF57091A5F8B47E4CF9B82CD4715D /* RKRouter.h */, + 0A36A67D8095CA8BA88F3D9C867BF723 /* RKRouter.m */, + C7FD5D8AEF9C721E9A8B50A73398561A /* RKRouteSet.h */, + 66C350784D8C52C699FE7DD47EF906FB /* RKRouteSet.m */, + ); + name = Network; + sourceTree = ""; + }; + 98D46EC37B626EB861E505D9911A6B4C /* Pods */ = { + isa = PBXGroup; + children = ( + F3E1399D1C84A330951106CBABE88495 /* AFNetworking */, + 072B748C4ABC47FF5DD09E14AFCFA80C /* Bolts */, + 7DA921C2C956313F56FEBC0296B7C6F4 /* FBSDKCoreKit */, + 328D5BB5F21E344E9FBB7B9C794DCDBE /* FBSDKLoginKit */, + 730A0971E2B05CA436436CFBECBFAA5E /* FBSDKShareKit */, + 443FE6FAC9F77ED18F698A1F1AD2DF9E /* FoldingTabBar */, + F857921DBBA1D9C322F3F67E01AFB360 /* ISO8601DateFormatterValueTransformer */, + 1ABD97751947F20E67D4F852B3655259 /* Parse */, + B5CD2A18216E1078206AFA80363085DD /* pop */, + 6D2B535DFEFC2D59F09AAFC33373431E /* RestKit */, + A04613DD58C52E9A63CB9D94B14E2294 /* RKValueTransformers */, + E6CD57F66907DFAC966EF1CEDD16256D /* SOCKit */, + C3E971172C19A0ACC450FC8DB45F69D0 /* TransitionKit */, + ); + name = Pods; + sourceTree = ""; + }; + 99D520B74A305C5859B3ACBF3975932C /* Support Files */ = { + isa = PBXGroup; + children = ( + 655746194AED6433F130ACB5AA120F9B /* SOCKit.xcconfig */, + 3DD24718CA4BD9604C201D989FD03218 /* SOCKit-dummy.m */, + AA158698DE160B78310B78C6F5F5EEBF /* SOCKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/SOCKit"; + sourceTree = ""; + }; + 9AD6A794574889432B6393E390E643E4 /* Support Files */ = { + isa = PBXGroup; + children = ( + BF428BEC06706AA0A98B6805206833C2 /* RKValueTransformers.xcconfig */, + E8A1C16BDC310A2EF19DE55901CD5B41 /* RKValueTransformers-dummy.m */, + 1851F12158736155A52C64E33E513999 /* RKValueTransformers-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/RKValueTransformers"; + sourceTree = ""; + }; + A04613DD58C52E9A63CB9D94B14E2294 /* RKValueTransformers */ = { + isa = PBXGroup; + children = ( + 37FC535483D9258C485125E0488ED3EF /* RKValueTransformers.h */, + 5DDC6BF6D637CEFC8BEDA82F87D0A60D /* RKValueTransformers.m */, + 9AD6A794574889432B6393E390E643E4 /* Support Files */, + ); + path = RKValueTransformers; + sourceTree = ""; + }; + AB60DD59D35FBC4FEF669D67E4191C38 /* Support Files */ = { + isa = PBXGroup; + children = ( + 19FFE36E5537E1838031F0725CD641C2 /* Bolts.xcconfig */, + DA196AA463D20F7402232B546DE1EEC4 /* Bolts-dummy.m */, + 83A7B0C8AF063198C8EBF6559688D469 /* Bolts-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/Bolts"; + sourceTree = ""; + }; + B3D1D13E0C6553800746CB8FD61CF946 /* Pods */ = { + isa = PBXGroup; + children = ( + 37DB56D75062CC75FCB0966E1C6E8A8E /* Pods-acknowledgements.markdown */, + 10834806BD7B412BC24F347361FA2C8E /* Pods-acknowledgements.plist */, + 272643F56613CA0D336AE3DBF19DC404 /* Pods-dummy.m */, + 6911BECA35E7518D864239B7E898EEF3 /* Pods-frameworks.sh */, + A1A36D34413696BE466E2CA0AFF194DA /* Pods-resources.sh */, + 4E762F23EC34ED4A6FF3312D84E33A40 /* Pods.debug.xcconfig */, + 98C98CDFB3F20F2925F6CD1F141BB14F /* Pods.release.xcconfig */, + ); + name = Pods; + path = "Target Support Files/Pods"; + sourceTree = ""; + }; + B5CD2A18216E1078206AFA80363085DD /* pop */ = { + isa = PBXGroup; + children = ( + 9F7C74984ABBD35EBF1A84D46747BF45 /* FloatConversion.h */, + 78A05813E9EC11B010C6A344D9AAC05A /* POP.h */, + C70FA986190A848DD39EB171EF041F33 /* POPAction.h */, + 5FDB069FE07BA949728D658261EA3E40 /* POPAnimatableProperty.h */, + 5ADBAA054DAFCE013EB3EF9DF965F744 /* POPAnimatableProperty.mm */, + 7E0A91B803AD2D9F9BBC9C9C40485EFB /* POPAnimation.h */, + 0C43080C0B2655A28B3CE9D3DD9B32B2 /* POPAnimation.mm */, + F3D3B7CDCE9EF138FF8BB043F7239498 /* POPAnimationEvent.h */, + 996EADA337EAC02210FEC4506EB335B5 /* POPAnimationEvent.mm */, + 632D62E7B544FFB77F14C130A2EC4510 /* POPAnimationEventInternal.h */, + 325AD4A9548841B8B429CC3D00DF02E4 /* POPAnimationExtras.h */, + EF2907AA3AD4FE98405EC818A63855DA /* POPAnimationExtras.mm */, + 761DB1B71490B54C854E88186480B4EA /* POPAnimationInternal.h */, + 8707552112C343BFF840516C1AAD0D31 /* POPAnimationPrivate.h */, + 6467B92BD94142011900B81E0476CB0E /* POPAnimationRuntime.h */, + 54E5949F2C78F11D2017067D065794BD /* POPAnimationRuntime.mm */, + 5A5C02D17E47A222D470066E80F5230B /* POPAnimationTracer.h */, + 72B29870F05A80283BE95E71DEBEE1D2 /* POPAnimationTracer.mm */, + BC8D8339F84A5B54DDC0F0B6C03E6C30 /* POPAnimationTracerInternal.h */, + 11CBB787D4E85EE9F313E56D6B653B6F /* POPAnimator.h */, + 996415B7247FE7D0C37780B180517ACB /* POPAnimator.mm */, + 5251CF87DD5578A90ADED5D340FF960B /* POPAnimatorPrivate.h */, + 4CDA9E34CFAB4648EC74D9ED76EF02AC /* POPBasicAnimation.h */, + 96A6F76476CACBAADE4A258C71998683 /* POPBasicAnimation.mm */, + 280AB1BDCC3841953AE8E7E78F9326A1 /* POPBasicAnimationInternal.h */, + 09343BA3B921E20A6185A17744E53B63 /* POPCGUtils.h */, + 05A46A1CCAAB75FBBA2C67F460435143 /* POPCGUtils.mm */, + 09A74F4E5B1694ED02FEFEE3567FD5C4 /* POPCustomAnimation.h */, + 1C9E34AAA6316628D1EF4D8BC3CDCAB1 /* POPCustomAnimation.mm */, + 4659EF2651456627D2DF254CD1ABA4FB /* POPDecayAnimation.h */, + 55795C67F8572CA13753F14AC059940B /* POPDecayAnimation.mm */, + 64DFE094C387E0DA1F62DB6912006497 /* POPDecayAnimationInternal.h */, + C66092953B80DE287E77614DFA2D2FE3 /* POPDefines.h */, + 25913693021196FC72C7A8E7A937AFCC /* POPGeometry.h */, + 696513A0EDF7E7D3B1DA9E8871E05685 /* POPGeometry.mm */, + BDEF6D63702D3C9DE58BBBC7977D10BA /* POPLayerExtras.h */, + 79F07C09208B3EA7236791BBBDD1D459 /* POPLayerExtras.mm */, + A303568877AD7BACE17E962FDF4513C1 /* POPMath.h */, + 723C3B2158211623464D6751F8AB7101 /* POPMath.mm */, + 80519B32A7AC044BA72391DA03E6E140 /* POPPropertyAnimation.h */, + B53D5E1A96FE30D9B7F8D596BF9E2F80 /* POPPropertyAnimation.mm */, + 59F15D7F5CA85CC8436BD1872518AB18 /* POPPropertyAnimationInternal.h */, + BDC0554AEE7F2D9DF98C2D8FC049FD2A /* POPSpringAnimation.h */, + D3359292FE89A636801514727B628BCA /* POPSpringAnimation.mm */, + 7915DC37B74D252F701BF85B55880ACF /* POPSpringAnimationInternal.h */, + 1D50729BCCBCCC5A423CBB509507C3DC /* POPSpringSolver.h */, + 64E0C0D87C1527E39C8527751DB7D005 /* POPVector.h */, + 7F6E4B0E19B7E3633F89483FC21D852C /* POPVector.mm */, + 6A2F4083D494D045689BC3A072187C3B /* TransformationMatrix.cpp */, + DD2FCA295F0F6EC84DC796D623DC209F /* TransformationMatrix.h */, + 2CFCEB3A58ECB73BB6D930BB1A66A2DE /* UnitBezier.h */, + 25510258318D770B38C09C4CA0D2DC7C /* Support Files */, + ); + path = pop; + sourceTree = ""; + }; + C3E971172C19A0ACC450FC8DB45F69D0 /* TransitionKit */ = { + isa = PBXGroup; + children = ( + 62923837C0899ECA2BAD6224F5A7B22E /* TKEvent.h */, + FBBB3B26B24BB1791ACE441DFDA19FF2 /* TKEvent.m */, + 4DA5437028A51B95A1C0B0B8B5CB334B /* TKState.h */, + 7CB6F2CF47DB783D84FBBB6F2B1A451F /* TKState.m */, + DAD657A091CF82605FA8A0100D16E83E /* TKStateMachine.h */, + A78C310CE96FB8C96AB74FE6A10686E7 /* TKStateMachine.m */, + 76BDB3E82FE4A935AACD2F637F371589 /* TKTransition.h */, + E83EDDC94D7F78C9A89A9BBF973667B6 /* TKTransition.m */, + 7F1DA5784F757925FC9B2C359AE8F07C /* TransitionKit.h */, + 2612628171849F4DEDE2DDD5C2B94566 /* Support Files */, + ); + path = TransitionKit; + sourceTree = ""; + }; + CE2D9BA208321FEB30B86BE7BEF38787 /* Support Files */ = { + isa = PBXGroup; + children = ( + FF5B972C0D2221C57AE6060DE6C9A600 /* FoldingTabBar.xcconfig */, + FDF375C76C5BA4A7F1EA1C46DC3B142C /* FoldingTabBar-dummy.m */, + 3CE5F2F0D15646E1D82418047325DB76 /* FoldingTabBar-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/FoldingTabBar"; + sourceTree = ""; + }; + D1A12668CBBAF479BBDDE11E900C7DFB /* Support Files */ = { + isa = PBXGroup; + children = ( + 67DBA3140A542C45905BA912DF9D6D93 /* RestKit.xcconfig */, + 6D169B7683E9DA4DE1D139D6CD10D190 /* RestKit-dummy.m */, + AA2DB152E74138129BF1919667D8AA5C /* RestKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/RestKit"; + sourceTree = ""; + }; + D29F10A74F6ECD83F33B3134ECE1076E /* arc */ = { + isa = PBXGroup; + children = ( + A585F71D8045AD5FFA838F5907C9DCFE /* _FBSDKTemporaryErrorRecoveryAttempter.h */, + 19A473DF4573D2A6FDD72DA3BA1C2C04 /* _FBSDKTemporaryErrorRecoveryAttempter.m */, + C537E17C3097299FCBF860A93C47B723 /* FBSDKAccessToken.h */, + 06292442821AF9572A443AF0D949122D /* FBSDKAccessToken.m */, + BCA4ADF879DDDE1CAAA0ABFB4BC7210D /* FBSDKAccessTokenCache.h */, + 17713158760C0CE314D469EF9DAB5E98 /* FBSDKAccessTokenCache.m */, + A0356870F75E493C4A0C432FFFDF4798 /* FBSDKAccessTokenCacheV3.h */, + 80E3A4DA55D79A2A163A82080683C403 /* FBSDKAccessTokenCacheV3.m */, + D9AA4942A33D49D6BD6342E82EF21F2F /* FBSDKAccessTokenCacheV3_17.h */, + B7B30077DB15E3549CCF53E8707A36D6 /* FBSDKAccessTokenCacheV3_17.m */, + 735D8A9263762B7D4E5C5EDB816A7CB6 /* FBSDKAccessTokenCacheV3_21.h */, + BF44B45F9B1A350C1FB2F6D209A9BC4D /* FBSDKAccessTokenCacheV3_21.m */, + 8496664844E09F7B412D05544D90E123 /* FBSDKAccessTokenCacheV4.h */, + B352E84B1EE885140F4F4DC84329D6CB /* FBSDKAccessTokenCacheV4.m */, + 1FB151E5B82946D404F611FAC81C546B /* FBSDKAccessTokenCaching.h */, + 6D7387AFD498FF6D486BEF5755B9D7B3 /* FBSDKAppEvents.h */, + CA3482F3977AA386E991A54C5181BDE1 /* FBSDKAppEvents.m */, + 1EC237868E24D8CCBA8AA21DB4F43584 /* FBSDKAppEvents+Internal.h */, + C1B7244F3402CF0B20BFF0228719CDD1 /* FBSDKAppEventsDeviceInfo.h */, + 503DF747F3430012E621A5BB819767FB /* FBSDKAppEventsDeviceInfo.m */, + E75B973B4239A8C33C3DF18D0F41168D /* FBSDKAppEventsState.h */, + 3D1059A8B21D1214B8EA1A8BCF6B2CE5 /* FBSDKAppEventsState.m */, + A2FAF2092D4C51EAE9E68E2B1EB0071B /* FBSDKAppEventsStateManager.h */, + 57EA8E1B5446775F4608110823A9BF8C /* FBSDKAppEventsStateManager.m */, + A16A70655423A834331503E4979C4422 /* FBSDKAppEventsUtility.h */, + 8904DD3C8A8AC8A1A2F48DEB0DBC1B95 /* FBSDKAppEventsUtility.m */, + D8B4BCA52E13031B048A091F56EDD1FE /* FBSDKApplicationDelegate.h */, + 7558DBD1AF61B17AF39F3565B9F68601 /* FBSDKApplicationDelegate.m */, + CA018EEB50C81D92939C0E4379941FE9 /* FBSDKApplicationDelegate+Internal.h */, + 5783E79BEDB98581985EEC5EEAD67953 /* FBSDKAppLinkResolver.h */, + 0FBD3B84E14ADBD2E513A3522C2777DC /* FBSDKAppLinkResolver.m */, + C651AC06095B97EDAEF872B6D7032F4E /* FBSDKAppLinkUtility.h */, + F9DBE01AF3666AF5DF673F0B8302A852 /* FBSDKAppLinkUtility.m */, + 83831950A74E93412A274C95A90D1337 /* FBSDKAudioResourceLoader.h */, + B8046097AB97D9EBA30FEAF579C44F56 /* FBSDKAudioResourceLoader.m */, + 2784369F5F5CCA4ADE551377F245E131 /* FBSDKBase64.h */, + 56FE36E9C6BEFFC89DD1BC36E6289234 /* FBSDKBase64.m */, + 41DE8F8508C70E584E9DC322D6E30DB1 /* FBSDKBoltsMeasurementEventListener.h */, + 8030921BFF7BB8CE71AE970906855522 /* FBSDKBoltsMeasurementEventListener.m */, + 950E0A9F91ED212D2423C57E6D94CE04 /* FBSDKBridgeAPICrypto.h */, + FA60E1C8D40A78F03AAD7CA1CAE03991 /* FBSDKBridgeAPICrypto.m */, + 502875FAB22E086DDEA2AD3FB860D1A5 /* FBSDKBridgeAPIProtocol.h */, + 9CE70D7D33DCB5A7B77D431309FF7DED /* FBSDKBridgeAPIProtocolNativeV1.h */, + BC931BFEE302F10CF84316FC396B1F01 /* FBSDKBridgeAPIProtocolNativeV1.m */, + 568C2C82ED942F4F6D68EBFBDD16316F /* FBSDKBridgeAPIProtocolType.h */, + F7114C7234DA9F23563BF6C254E6458A /* FBSDKBridgeAPIProtocolWebV1.h */, + 95FF2C409A7211FB7720DA60E56153C4 /* FBSDKBridgeAPIProtocolWebV1.m */, + 2A17ADE2F078B621C983D99D2F0F0047 /* FBSDKBridgeAPIProtocolWebV2.h */, + AE15675496460EEA4051AF5F4AB4E504 /* FBSDKBridgeAPIProtocolWebV2.m */, + 6B7304E8EFDCC873E1CE3D2CA2076A74 /* FBSDKBridgeAPIRequest.h */, + F44E8E904E1CD028316E671E43453DCE /* FBSDKBridgeAPIRequest.m */, + CBA6686079E7409ED27CC9A6ADEBF36A /* FBSDKBridgeAPIRequest+Private.h */, + C01B234F69300CBE9F042A18823A2C64 /* FBSDKBridgeAPIResponse.h */, + 2E7F67EBB1F0265AF0F708FA1006B162 /* FBSDKBridgeAPIResponse.m */, + 5A840F03EBE584ACE4D413A297B04FC9 /* FBSDKButton.h */, + DA4A6D24A88D4B18ED3D60681DF68270 /* FBSDKButton.m */, + 79EE570F7AF0D238D396B8C1BD1233F8 /* FBSDKButton+Subclass.h */, + ADCF28A6ED4B159F06F12E95D86E08B2 /* FBSDKCloseIcon.h */, + 7719F6B5924888F0A267790B6E5647FD /* FBSDKCloseIcon.m */, + D68CBFCA3F276272B2040E6469C8D1DE /* FBSDKColor.h */, + 615339A2EDD3CE627A27EBB1ECFF21B3 /* FBSDKColor.m */, + 2E867F3D72745F4BA824FC362CEBFACB /* FBSDKConstants.h */, + 48C62F55A4F3241648089904B527F6D1 /* FBSDKConstants.m */, + 2AA04EC3FE92A62CDADA2A69B932DDF3 /* FBSDKContainerViewController.h */, + 4C3FA9E55331EB6F5C9D6ABE4173AF97 /* FBSDKContainerViewController.m */, + BA69ED7E54B79F2B468E042414006FC8 /* FBSDKCopying.h */, + 2423BDB586DF4DF3F1525A1B5C40C54F /* FBSDKCoreKit.h */, + 95A9E38BEC3EF5836FF1194D04DDB98F /* FBSDKCoreKit+Internal.h */, + D9C1F4F92487D9DCADCD60039710D816 /* FBSDKCrypto.h */, + 860BB3AFC2DD08EF4599D8D42484D2CC /* FBSDKCrypto.m */, + F48BCECC8EA184F5975C3532819CFFA2 /* FBSDKDialogConfiguration.h */, + E0976F3A16E6127C870E863609F006DF /* FBSDKDialogConfiguration.m */, + 74338BD705AD4CAADD5CA90BD8EF2D96 /* FBSDKDynamicFrameworkLoader.h */, + 1851DD5C5804EC9A837131EDAC8D3EDB /* FBSDKError.h */, + CD1F87198E6B2738076E71BB2C4A8C71 /* FBSDKError.m */, + 49B69C4B030D1D72B8261D35EB560A56 /* FBSDKErrorConfiguration.h */, + E436D932FA7C17E15674EB32E957ABE2 /* FBSDKErrorConfiguration.m */, + 9FE12F1A4097AA56DD490CFF1B57E4AB /* FBSDKErrorRecoveryAttempter.h */, + 1B4CFCBF40F579D60F6CA51813334980 /* FBSDKErrorRecoveryAttempter.m */, + BDA6A8C4B5B6F7C4E38F45C438720C50 /* FBSDKErrorRecoveryConfiguration.h */, + 9AE4C9BDAE4E6537716122FED10B39E1 /* FBSDKErrorRecoveryConfiguration.m */, + 405BEEF0AFD44793580DDB9D43634820 /* FBSDKGraphErrorRecoveryProcessor.h */, + 5030E7EB9027091137C392A948E0D5A8 /* FBSDKGraphErrorRecoveryProcessor.m */, + CF6DFEAD49E3B96B670A4AB662D78229 /* FBSDKGraphRequest.h */, + CC27E380BD4D02E6D8E8A25280C06A29 /* FBSDKGraphRequest.m */, + F87C75C1F03CFABBB54EC631815288C0 /* FBSDKGraphRequest+Internal.h */, + B9BAFC471A7F7E390879132FBD1B3B21 /* FBSDKGraphRequestBody.h */, + B6E7D0F10FA61E6BAC091324113D02F2 /* FBSDKGraphRequestBody.m */, + FE89E1667DF47EC79AB1E8C414DE79EB /* FBSDKGraphRequestConnection.h */, + B40775302C0516B1FB09E3523DC34D30 /* FBSDKGraphRequestConnection.m */, + 7239EC1173010662F747781299C375DA /* FBSDKGraphRequestConnection+Internal.h */, + C3743DDF0F64379FD843ED463460FF90 /* FBSDKGraphRequestDataAttachment.h */, + 45911FDD1904204B994BBBABE59D8DAA /* FBSDKGraphRequestDataAttachment.m */, + 190B3059AD121705B18018211A6B6C66 /* FBSDKGraphRequestMetadata.h */, + 370FAC093160183505C296D12A84BF0A /* FBSDKGraphRequestMetadata.m */, + 4B9BFA03B5504E854577C5000A356AFB /* FBSDKGraphRequestPiggybackManager.h */, + A473C610615EE15F20D33C59B9CC54B8 /* FBSDKGraphRequestPiggybackManager.m */, + 7BA86EF4EAFD3D4475A169859BB0B633 /* FBSDKIcon.h */, + F2D002F7CD0CB8A3551420036A594D40 /* FBSDKIcon.m */, + 20EA58DC0A0DC1E01333E2DC71658378 /* FBSDKInternalUtility.h */, + CA8D44F0BCF9802F38A1799B6EBF1407 /* FBSDKInternalUtility.m */, + 42B37BE48C6B242CC345A82EFFCA35CD /* FBSDKKeychainStore.h */, + 6BFB7F5189C7630850B466033A6828EF /* FBSDKKeychainStore.m */, + 67CF036576967715D363A2E7C16E4AAD /* FBSDKKeychainStoreViaBundleID.h */, + CC228E158C60DD94DF7B3EA5E18D8125 /* FBSDKKeychainStoreViaBundleID.m */, + 9860C0C7692D5A2C0C40448F5323C485 /* FBSDKLogger.h */, + 8D28D5F66862955E51F3A4E12B34C7A6 /* FBSDKLogger.m */, + 947DE8E91AEF7DBF7FD80A52A76B2360 /* FBSDKLogo.h */, + B80B9804F9EC77183DFB3A54E58272CF /* FBSDKLogo.m */, + 851FD672C97DC80E95B543E7678B133F /* FBSDKMacros.h */, + 9D4E7099B46D1C3E524DA77BA96A3960 /* FBSDKMaleSilhouetteIcon.h */, + 650F210D5B2E4ADBF30ED15408D730D3 /* FBSDKMaleSilhouetteIcon.m */, + E511AFB10E1282BD8E6813EEEAD607E0 /* FBSDKMath.h */, + ADAFAB54F5C5506CF7186CD16CA90EFA /* FBSDKMath.m */, + 933D9439D53FAC2493C8D8F5ADD21D74 /* FBSDKMonotonicTime.h */, + 26A9B6AD16C16524DC90D9F1759B3E86 /* FBSDKMonotonicTime.m */, + 26BE12FA64DB24FF7A1DF7937AEF98D6 /* FBSDKMutableCopying.h */, + B163A0D63692C83B09ED63F3D357CC5D /* FBSDKPaymentObserver.h */, + 98D1A4CAC7340A038BDCFECC7E0BFE95 /* FBSDKPaymentObserver.m */, + 55DBD79D6CDD908C9E0151AF56A3EFCE /* FBSDKProfile.h */, + 4C86B91E8FA37A02DFCBC13C26C5599E /* FBSDKProfile.m */, + 3C4E2E6E86AEBB3B50EE86E4B1074A32 /* FBSDKProfile+Internal.h */, + E1657F05C4EF96882F28C1692CBF05CE /* FBSDKProfilePictureView.h */, + 11A34265733816DD6719407EE51BEDD9 /* FBSDKProfilePictureView.m */, + DC702CD32C7B1F95EBB4525985776E1A /* FBSDKServerConfiguration.h */, + 473792C704D2EB34B69FD30D4C8A4195 /* FBSDKServerConfiguration.m */, + E55C935E4DD635C29A2B334C8AB06254 /* FBSDKServerConfiguration+Internal.h */, + 3B5920113D86FC36BEBC6F899C9034F7 /* FBSDKServerConfigurationManager.h */, + 21E3824444DF9349B08182DF250A028D /* FBSDKServerConfigurationManager.m */, + 8DB170D4C4F763AED7B36159D448013E /* FBSDKServerConfigurationManager+Internal.h */, + B477BB1DB6E55636C30151FED839DBEC /* FBSDKSettings.h */, + DCE8B19B5BBBF2EEE591030CB12399C6 /* FBSDKSettings.m */, + B432A363E0081BD273051415B767D749 /* FBSDKSettings+Internal.h */, + E2E5158BDE2438D1F296202C6A65CAD9 /* FBSDKSystemAccountStoreAdapter.h */, + 9C13271F07F590F5CD4297A3A11F07EA /* FBSDKSystemAccountStoreAdapter.m */, + 57B625AE6C787AB113D7EF7F05FB0637 /* FBSDKTestUsersManager.h */, + 324AAABDF5EC040480FF7DD0137ACC3A /* FBSDKTestUsersManager.m */, + 2DDC81A1F4448D392C77D59D57719404 /* FBSDKTimeSpentData.h */, + 84E5CF3BD81C4C414BE88556EB18D08F /* FBSDKTimeSpentData.m */, + 1C268AB8BD173983B11C4C2D404A9C57 /* FBSDKTriStateBOOL.h */, + 592AA9AF2651D5C86E7E8D122F958616 /* FBSDKTriStateBOOL.m */, + 220DF0DD34431D9668F2D2A15D25B3E7 /* FBSDKTypeUtility.h */, + 1488210FE220BBA6CCA5EBE2C7D73FA7 /* FBSDKTypeUtility.m */, + D849F8915909B1847A03276B640112BC /* FBSDKUIUtility.h */, + 6BD1AFE5456BC7AAC15A5D308229EC88 /* FBSDKURLConnection.h */, + 7E03B26327B08731B36701D28A33B9C9 /* FBSDKURLConnection.m */, + 68FE49164D11028318A5BFC6389C361A /* FBSDKURLOpening.h */, + A9971360D666FDBC3DDD421157793868 /* FBSDKUtility.h */, + E4528F78B1F397E3730075143FD93C99 /* FBSDKUtility.m */, + FEE6386026272731739CFEE82C813032 /* FBSDKViewImpressionTracker.h */, + CA3CDC2D78E68FD7654C42F67C29EF3A /* FBSDKViewImpressionTracker.m */, + AEB3E3D5DFF77A79169D2E7390145CE7 /* FBSDKWebDialog.h */, + 5FC2F31E95438D43C0ACB4E6B5287B8D /* FBSDKWebDialog.m */, + 8DE9B680DB183FA614D58C42EADD38D7 /* FBSDKWebDialogView.h */, + 47B246252A39D38E7CC3D6CD2C4549AA /* FBSDKWebDialogView.m */, + ); + name = arc; + sourceTree = ""; + }; + E6CD57F66907DFAC966EF1CEDD16256D /* SOCKit */ = { + isa = PBXGroup; + children = ( + 5C4081A3EAA34140F505CCBE9D98C0C8 /* SOCKit.h */, + D011D1FC8B93C93581E9C03ABF791BCF /* SOCKit.m */, + 99D520B74A305C5859B3ACBF3975932C /* Support Files */, + ); + path = SOCKit; + sourceTree = ""; + }; + EB57DDB3388FBC701046A1E93218737F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 36F3E3D009A33DE3EB27FA31CBCE358C /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + F3E1399D1C84A330951106CBABE88495 /* AFNetworking */ = { + isa = PBXGroup; + children = ( + 3C1CC5AA0EB4EDA9432A7D5463BE4901 /* AFHTTPClient.h */, + 764FFD75345B6B6A979A9D10F2D2907B /* AFHTTPClient.m */, + 7771BB9434E69A691392A0970DD10E28 /* AFHTTPRequestOperation.h */, + C544CA6F07611BFE8BFC800E9D59E5AE /* AFHTTPRequestOperation.m */, + A3794B030BCB9C4408CA8A2839964ED1 /* AFImageRequestOperation.h */, + F0414F682EAAC899BF6D1350B23F4920 /* AFImageRequestOperation.m */, + 3880A4A4324ED988B85901DAD4519018 /* AFJSONRequestOperation.h */, + 82E57F9588CEC77612BC5E9A20CCC2E5 /* AFJSONRequestOperation.m */, + CEB32A7ACC2D1268332E3ED6413E04AE /* AFNetworkActivityIndicatorManager.h */, + A2D57E341463F67AF53255008B5CAB0A /* AFNetworkActivityIndicatorManager.m */, + 6F529E412A09BF39D8AEC42AFFDF2F46 /* AFNetworking.h */, + 89CDFA61E00364C5AE6882B31CA90BB4 /* AFPropertyListRequestOperation.h */, + CC7C0590FD149B2C227C59AB38DF61DC /* AFPropertyListRequestOperation.m */, + 35CC150A7EE20543758EB2CBCB3D0D9D /* AFURLConnectionOperation.h */, + 1AF2857CEDB6464020434166DEB5A36F /* AFURLConnectionOperation.m */, + F51C083C4D1E3AAFE06A8F4BDF8EBB88 /* AFXMLRequestOperation.h */, + A9CA1C8C41256C5E7CEDBAF354C19AE5 /* AFXMLRequestOperation.m */, + FBB3B5641F66495915C56779C21569E7 /* UIImageView+AFNetworking.h */, + C345096A388C3F1F4E486E39C9D61CD4 /* UIImageView+AFNetworking.m */, + 7ADA1DE4AC552D9180233F1D5A34429C /* Support Files */, + ); + path = AFNetworking; + sourceTree = ""; + }; + F46DF5AF30AF4F7D4DFAC67E03AEE55E /* Support Files */ = { + isa = PBXGroup; + children = ( + 525A38283E17DE63638B7101EDD603A5 /* FBSDKCoreKit.xcconfig */, + 231F7C139C4CE6856490CCC6331A4BB0 /* FBSDKCoreKit-dummy.m */, + 03B64D2A236E8A41E92A66B21F198BFB /* FBSDKCoreKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/FBSDKCoreKit"; + sourceTree = ""; + }; + F7647B87DD09DE1D36642AA78D579180 /* AppLinks */ = { + isa = PBXGroup; + children = ( + 74089267A9387B60B1CE108DFAA883BC /* BFAppLink.h */, + C1C4E1C48CDDA8FCF1C074DCC0D2A656 /* BFAppLink.m */, + 5732F9BC7E2742FFFC7C3BA8F1225459 /* BFAppLink_Internal.h */, + 7FDE21F99879BAFCD8007510D41FD42B /* BFAppLinkNavigation.h */, + CFEE369DBDB3AF968FCC81B9E15BD259 /* BFAppLinkNavigation.m */, + B99772D5AE952C0693DC05AAA4538D94 /* BFAppLinkResolving.h */, + AE3D34F74057747813B67E0E716F8275 /* BFAppLinkReturnToRefererController.h */, + 91D5B36C33B97E32AFA561C868667F87 /* BFAppLinkReturnToRefererController.m */, + 5444C22939A582C105AC91CE65D666F4 /* BFAppLinkReturnToRefererView.h */, + 6E3D7476264442440AC1374D1E0418A1 /* BFAppLinkReturnToRefererView.m */, + D7AC47EB8D0E9C9582957C2869B7517D /* BFAppLinkReturnToRefererView_Internal.h */, + E362D4507FC775D8570A80D797BC3E91 /* BFAppLinkTarget.h */, + F22BFE44135812D7404BBDAF34C010E3 /* BFAppLinkTarget.m */, + E5A9EBDF50D04397C922F9D0AB7B0512 /* BFMeasurementEvent.h */, + FB3A9DED47A72521C01855CCB13A10EA /* BFMeasurementEvent.m */, + CB172E497F3C842C06931402446C2D4B /* BFMeasurementEvent_Internal.h */, + 7F63108EF1315E6D7E404F9ABF304F1A /* BFURL.h */, + 1C6681893EA2BE8AA8ED08B44B774980 /* BFURL.m */, + 44420C2483949613227FDC09A152A3F2 /* BFURL_Internal.h */, + 9045C664399C37132A893F2E170BEA3C /* BFWebViewAppLinkResolver.h */, + EED2B7513CB5A03507BE982601143DEC /* BFWebViewAppLinkResolver.m */, + ); + name = AppLinks; + sourceTree = ""; + }; + F857921DBBA1D9C322F3F67E01AFB360 /* ISO8601DateFormatterValueTransformer */ = { + isa = PBXGroup; + children = ( + DAB70DB4EE93F869DBC66617E527E62E /* ISO8601DateFormatterValueTransformer.h */, + E4C5528C376F1D824C32FC5049A22958 /* ISO8601DateFormatterValueTransformer.m */, + D68125D407CB86FE46338C7579765331 /* RKISO8601DateFormatter.h */, + 6101E1788344FEF66BFB8A3BD80CF650 /* RKISO8601DateFormatter.m */, + 2935474A12329277E07A08BD4241480F /* Support Files */, + ); + path = ISO8601DateFormatterValueTransformer; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0DDAA8E16E00423BC6858ACC657DA26B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 46A761F0B52B393302374F202159EF83 /* _FBSDKLoginRecoveryAttempter.h in Headers */, + 06D70E3ED56542E6E150732ACE707585 /* FBSDKLoginButton.h in Headers */, + 46434AF620227311479C776B81BA97F6 /* FBSDKLoginCompletion+Internal.h in Headers */, + F9A49E306CE246D7F327C43091688131 /* FBSDKLoginCompletion.h in Headers */, + B05B85B93FE4C40364989A851D0E4C95 /* FBSDKLoginConstants.h in Headers */, + 6E81F98DB0508128E08205B0290F7F66 /* FBSDKLoginError.h in Headers */, + 0524E3768D3DFCF2E4E232DCF896DC2D /* FBSDKLoginKit+Internal.h in Headers */, + ECECB6E62DA076603D8F2A805641CA27 /* FBSDKLoginKit.h in Headers */, + E65B5BAA6FD361DED892118A76ECF21E /* FBSDKLoginManager+Internal.h in Headers */, + 49F2BA3E1D32E882B51DC0A899D3C229 /* FBSDKLoginManager.h in Headers */, + 6E33ED273C645E70EF87C0C05807D1A2 /* FBSDKLoginManagerLogger.h in Headers */, + D041A6307B8BE12B6F1D2C7B11DB335F /* FBSDKLoginManagerLoginResult+Internal.h in Headers */, + BCC52FD8A4B950C4F0A918C1E7C04A8B /* FBSDKLoginManagerLoginResult.h in Headers */, + 3D91615B81BDE2505C751BD7D4FB5EDB /* FBSDKLoginTooltipView.h in Headers */, + 8EE441E5EBD7EAFFDDCCB5F247B160F6 /* FBSDKLoginUtility.h in Headers */, + A8FB9C2DF4996A5647C43D1D20B34154 /* FBSDKTooltipView.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 19C2B07A862CD221D4D5B9309876BAC3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A11240D567F7A3207F0F9882ED2AB75 /* _FBSDKTemporaryErrorRecoveryAttempter.h in Headers */, + 530AC824CCD371BAA717F8ACAB33F958 /* FBSDKAccessToken.h in Headers */, + 3E16E0BEF69F5BA97F8E9F07A617E509 /* FBSDKAccessTokenCache.h in Headers */, + B2C7E9065BD6BF8E3F3017B802865B56 /* FBSDKAccessTokenCacheV3.h in Headers */, + 85030A540670174CA31F4F4226C54C4F /* FBSDKAccessTokenCacheV3_17.h in Headers */, + BE0F6955D03D6DF536335CAC10A8CFC5 /* FBSDKAccessTokenCacheV3_21.h in Headers */, + CB7A2EB58EBA82B7CE519F8C2EEAFBC4 /* FBSDKAccessTokenCacheV4.h in Headers */, + 6F5BB8563523FEB8914557A0C379361F /* FBSDKAccessTokenCaching.h in Headers */, + CA0A64C7187BFF5B6143C3D3A7FF8D94 /* FBSDKAppEvents+Internal.h in Headers */, + 0C08BCEA5FE46370A36AEF6BEFCC41EA /* FBSDKAppEvents.h in Headers */, + A6D8B881BC31F26E99F56A4B5144F72D /* FBSDKAppEventsDeviceInfo.h in Headers */, + 216D6126C206D951C489C95FD37BD8CF /* FBSDKAppEventsState.h in Headers */, + C8E9B871537B5C88280E56A9778803A4 /* FBSDKAppEventsStateManager.h in Headers */, + AB7CAA7D0CB1D37DB84BF83644CF6E41 /* FBSDKAppEventsUtility.h in Headers */, + 4EC1B8AAA4341E02B888E2CDBED626DD /* FBSDKApplicationDelegate+Internal.h in Headers */, + 01A9C95FB174BF00024C127D94FAE9F9 /* FBSDKApplicationDelegate.h in Headers */, + 9B516F3168787E2C9732AC0C00479971 /* FBSDKAppLinkResolver.h in Headers */, + E10A2574E0EE99F47BC9CAC0AF33FC47 /* FBSDKAppLinkUtility.h in Headers */, + 81A2A1E607483054B4C595CA92987E08 /* FBSDKAudioResourceLoader.h in Headers */, + F4F96AF7AC5C83FA96E172128610B1F2 /* FBSDKBase64.h in Headers */, + 555466B7EA6454B1E1968FB7A7BD1334 /* FBSDKBoltsMeasurementEventListener.h in Headers */, + 4727F1C349747A7F96CA2EE6098BA7E6 /* FBSDKBridgeAPICrypto.h in Headers */, + 809C53B31BE1AC40886B82DFD238136D /* FBSDKBridgeAPIProtocol.h in Headers */, + 00163060B2D0C8870906DF0994834474 /* FBSDKBridgeAPIProtocolNativeV1.h in Headers */, + E7AC21B4D847D0F421132DCD478589F6 /* FBSDKBridgeAPIProtocolType.h in Headers */, + A248810839C65E5881B7B7B3F264078F /* FBSDKBridgeAPIProtocolWebV1.h in Headers */, + E0EAD57AC8EA4C3510C04CDDC9A28DE6 /* FBSDKBridgeAPIProtocolWebV2.h in Headers */, + 90F2175480DE7324ADEEF602757134D7 /* FBSDKBridgeAPIRequest+Private.h in Headers */, + 67F789F4A32CA7A82DE43CD27AEA87BD /* FBSDKBridgeAPIRequest.h in Headers */, + C8A8F4BE07EDC15A6921CD68990C0F98 /* FBSDKBridgeAPIResponse.h in Headers */, + 33808782CCEF801D53209D523D9C7358 /* FBSDKButton+Subclass.h in Headers */, + 926F1FF1ADA93F8BE4339C7AE28BD968 /* FBSDKButton.h in Headers */, + 3C0DEBB740DFB646BB292668FF187A3C /* FBSDKCloseIcon.h in Headers */, + E03421EE59E06D90EC9F0E07B93E1C2D /* FBSDKColor.h in Headers */, + 22E435D60724A7D16B950FC453C5E34C /* FBSDKConstants.h in Headers */, + 587ED101545A953414998ABFA4479B5D /* FBSDKContainerViewController.h in Headers */, + 138917EC340B4D359138CD16C4383D1D /* FBSDKCopying.h in Headers */, + 7051CE40FD16869F0BF9CD028A658782 /* FBSDKCoreKit+Internal.h in Headers */, + 156967851249D30F7710773EC47EB1F3 /* FBSDKCoreKit.h in Headers */, + 73518A8EAF46D85112E2CB85D02BF9C0 /* FBSDKCrypto.h in Headers */, + D183B6B66F20B85A64F5B7603D0A473B /* FBSDKDialogConfiguration.h in Headers */, + CF49B64886C0C73CE0EB0549FA20E21F /* FBSDKDynamicFrameworkLoader.h in Headers */, + AE279B6C3893C1BB12A7D761A8F70EA1 /* FBSDKError.h in Headers */, + E19528B349AA57299BED8F28FFCDB92D /* FBSDKErrorConfiguration.h in Headers */, + 77CF177F2CDC9BEBEF5BE1DD296E1E2C /* FBSDKErrorRecoveryAttempter.h in Headers */, + 1B732797EE1CF10C328DFDC742E866A6 /* FBSDKErrorRecoveryConfiguration.h in Headers */, + 7F35603B737B2A4B465CAE4B481C34BB /* FBSDKGraphErrorRecoveryProcessor.h in Headers */, + 62DDEB5456833B4AD3A84F7AADBE9099 /* FBSDKGraphRequest+Internal.h in Headers */, + AB8D18ED889E13CC5F738DD1A59CC510 /* FBSDKGraphRequest.h in Headers */, + 949F1878AC4A43632EFADACFC8140683 /* FBSDKGraphRequestBody.h in Headers */, + E47D4E86203EFA7643A44E5109117967 /* FBSDKGraphRequestConnection+Internal.h in Headers */, + A5E23287231B8CED31D97C44BA2702F9 /* FBSDKGraphRequestConnection.h in Headers */, + 50570F0F317C5A916AD5BE1D82F49641 /* FBSDKGraphRequestDataAttachment.h in Headers */, + 23F22339DEDBD778AB5D1DA13BFECC4F /* FBSDKGraphRequestMetadata.h in Headers */, + 4029E4F75B527907B5ADAD8E3E0264E2 /* FBSDKGraphRequestPiggybackManager.h in Headers */, + A9821C932984F979E72D5984C1E3A87E /* FBSDKIcon.h in Headers */, + 2453E44572F93FE8CFB1E9C2B07F8142 /* FBSDKInternalUtility.h in Headers */, + 31B7827480A2AD779C80D1E428F0F758 /* FBSDKKeychainStore.h in Headers */, + 8E3F310FB34E020A985BF37D34582619 /* FBSDKKeychainStoreViaBundleID.h in Headers */, + FEAB4AF7F2C57BDEFD6081038CFD20FB /* FBSDKLogger.h in Headers */, + 392F1056919E38CEDEB5A545DA4C820B /* FBSDKLogo.h in Headers */, + 307D54623092903A6C49A7C219BA3252 /* FBSDKMacros.h in Headers */, + 61BCC6DAB9276D969FCC0F848B69DB86 /* FBSDKMaleSilhouetteIcon.h in Headers */, + D1F17C848BA03A0D38CC8D8B815B75C8 /* FBSDKMath.h in Headers */, + 2617C1651BDE360A04512FF5DFEE55B1 /* FBSDKMonotonicTime.h in Headers */, + 5F2CF6350F306F78D40161C01EEDD731 /* FBSDKMutableCopying.h in Headers */, + E35FADAE8EF72A1419545CEE70610D27 /* FBSDKPaymentObserver.h in Headers */, + 9EFC61F27D88241A96D3FB13EF831E02 /* FBSDKProfile+Internal.h in Headers */, + 6B00AF25CFB12372D5281D7B9D51E3E2 /* FBSDKProfile.h in Headers */, + 78952ACEF38C155ADF7CA3B63C38A5E6 /* FBSDKProfilePictureView.h in Headers */, + 924D2586BFCD36A807E0E047454317A8 /* FBSDKServerConfiguration+Internal.h in Headers */, + DCF16A999DCFC281A8744148B305482C /* FBSDKServerConfiguration.h in Headers */, + E30BD9620B97DF000E8F31104048D432 /* FBSDKServerConfigurationManager+Internal.h in Headers */, + 444F2DDB714D8D83F59764F223E6EE70 /* FBSDKServerConfigurationManager.h in Headers */, + 210C00EF879DEDEA7EB09EC8C91A80A2 /* FBSDKSettings+Internal.h in Headers */, + 52474B3F869DBA64CC57CC8E1031F87B /* FBSDKSettings.h in Headers */, + 24FA587A203EB1838E92394C128065EA /* FBSDKSystemAccountStoreAdapter.h in Headers */, + 3C31ED01B7466FD05173FEB6F86953BA /* FBSDKTestUsersManager.h in Headers */, + 89E9143B078C3D9D56CDA6BE3AAA16D3 /* FBSDKTimeSpentData.h in Headers */, + 7569FD90D7667E15A7B67B62E4A72E5D /* FBSDKTriStateBOOL.h in Headers */, + FDF39F9BC888D9146BC087518C89A8F6 /* FBSDKTypeUtility.h in Headers */, + 1DFA8E2E3190F5321761EE4BE95C9ADC /* FBSDKUIUtility.h in Headers */, + 72DDA136310E1878B3393479B38B83F9 /* FBSDKURLConnection.h in Headers */, + 4505527808576A44D861B0A13154F425 /* FBSDKURLOpening.h in Headers */, + 1002547EB73320964BC1B10D757EAE2D /* FBSDKUtility.h in Headers */, + D2C8A050CA49DB3967B01D9B9354FC16 /* FBSDKViewImpressionTracker.h in Headers */, + C412C0A9241FD8CB88314EB3BD8E528C /* FBSDKWebDialog.h in Headers */, + A55D4E06A15BD0D7189518E2B96DB8A3 /* FBSDKWebDialogView.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 235759BBA87FE7B50D5CDEC6E14CA7A8 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5925CFB0F01031178978AF59986A8836 /* TKEvent.h in Headers */, + C9ADB5534B9078FBD0215BCB05701219 /* TKState.h in Headers */, + F6B3F611DF383CE5E1E8E62665449291 /* TKStateMachine.h in Headers */, + AF923C2C11D76B65500D200EF0BAFA33 /* TKTransition.h in Headers */, + 92CC0855895CFD948F305B30546B0414 /* TransitionKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 24CC375AC6BF6375B73651BB0872C62A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CBC28D34E7E02B4E254099B15B674080 /* BFAppLink.h in Headers */, + 336B220F124974D444746D194367422A /* BFAppLink_Internal.h in Headers */, + 96E1FE094390E35BE4E0D715675C16B0 /* BFAppLinkNavigation.h in Headers */, + 49A306F39FCE73FFB0E1A6589D331F35 /* BFAppLinkResolving.h in Headers */, + D963CE53920E664E9CAD6F4B834B315C /* BFAppLinkReturnToRefererController.h in Headers */, + E347F996B822D8480FF7B718185C46DD /* BFAppLinkReturnToRefererView.h in Headers */, + 5AF64E5EEA043722E238A8C5EE47A63A /* BFAppLinkReturnToRefererView_Internal.h in Headers */, + 5449D946ADE982013F5C2069E0BE45F0 /* BFAppLinkTarget.h in Headers */, + 06CC5B30A43EF1C3B526DEE380D8FE8A /* BFCancellationToken.h in Headers */, + E15B9B510B4BFB5AAF2F8BFAC5EBC997 /* BFCancellationTokenRegistration.h in Headers */, + FB9237E38009CB01D2D2BC136D5924B7 /* BFCancellationTokenSource.h in Headers */, + 7171DEAFC5A2F780E670B8395EF8F07B /* BFDefines.h in Headers */, + 012374FC7BF3C42864F8A6D9790C7836 /* BFExecutor.h in Headers */, + 80511BB81FC091E526BECA78607C0FC2 /* BFMeasurementEvent.h in Headers */, + 12D4BF5F8785937DA809F9D90E6FB565 /* BFMeasurementEvent_Internal.h in Headers */, + EC5F8395D48ED1C0BE2C2D7EB7D9F4B9 /* BFTask.h in Headers */, + 6D2E47E46AED98D49CD7E1D7DCA449B3 /* BFTaskCompletionSource.h in Headers */, + 2FBCC263A4CF83AF299AAC0CEE750AD6 /* BFURL.h in Headers */, + CF6A6DAB258596DF234FDDA9F2B214CF /* BFURL_Internal.h in Headers */, + 5208CEE9E04A230A895075F81179E9C0 /* BFWebViewAppLinkResolver.h in Headers */, + 4508BEB10E935ADE1BBC8AD18BB3F581 /* Bolts.h in Headers */, + 43A7D7D1E2E0828AC2FCD3155471E59E /* BoltsVersion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3B4A9D40B5373A9E33560665CB9E94AA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E13085CB448418E957E9EB41D88F5E2 /* BFTask+Private.h in Headers */, + 37E32240C69433B8D41BF206C15BDE91 /* Parse.h in Headers */, + 27DAF03799622546C24B79D72DFF1003 /* Parse_Private.h in Headers */, + BA61EA5F3CCE71914D2E8405C76CE42A /* ParseInternal.h in Headers */, + C72DD6BF1D64A4F33EBF2D6B77A8824C /* ParseManager.h in Headers */, + 1DD387B9558E7C1759425FCA6C52D4F5 /* ParseModule.h in Headers */, + 92450C8A67B02D5312E98B29C29FE89C /* PFACL.h in Headers */, + 5B619FB7B735B3AE6E29CD79496C39C0 /* PFACLPrivate.h in Headers */, + 3B2C344B306A3FB19169E1F4AA62E103 /* PFACLState.h in Headers */, + 6765D67511A02AD8B1C22BFD59E32233 /* PFACLState_Private.h in Headers */, + 85738B1734F9BE17BEE9520D89D2D133 /* PFAlertView.h in Headers */, + BE269944FF4E5E554223D2E055E4F1A6 /* PFAnalytics.h in Headers */, + 08A92B11564DA8300821C2F9E8851DB2 /* PFAnalytics_Private.h in Headers */, + FFEDBF912F4CF43D78BC4F4331F09059 /* PFAnalyticsController.h in Headers */, + 93508BB9AD5671C0AB3E4E890FF01C95 /* PFAnalyticsUtilities.h in Headers */, + 0799DA50D0F7AB26E77782D14A4D54AF /* PFAnonymousAuthenticationProvider.h in Headers */, + 2D6AF7788EA8D30E93BEB5F0CAC89C68 /* PFAnonymousUtils.h in Headers */, + BEFC0134FE56543E669CD06873F5BB8F /* PFAnonymousUtils_Private.h in Headers */, + 36CAD613B46C6F3F7B092EDDE2BFD87B /* PFApplication.h in Headers */, + 1570AA3EA1A480ADB0757319269174D1 /* PFAssert.h in Headers */, + CD70F46AD007D42A6E7E4C03AD654B48 /* PFAsyncTaskQueue.h in Headers */, + D270E51BC7362F767D5429DF7A368E0B /* PFBase64Encoder.h in Headers */, + 00CC1284C4EC48A67C89030A464A8E22 /* PFBaseState.h in Headers */, + B60C299FB6D6C13D99621CDBF557AB27 /* PFCachedQueryController.h in Headers */, + 8BF233CF21110FBB9A78A0E9C6FCDD49 /* PFCategoryLoader.h in Headers */, + E0614739E177590ABDB7BE575E24118C /* PFCloud.h in Headers */, + 6C052D12CBAB4B9CEC3E0B97C3B0CA00 /* PFCloudCodeController.h in Headers */, + 5482BE85008ECE92916F583C9A15378B /* PFCommandCache.h in Headers */, + A1B7647A3A40381C4430FBDBF794C699 /* PFCommandCache_Private.h in Headers */, + C8650F51B96E23879C9133719B5CE14A /* PFCommandResult.h in Headers */, + D6C7199C3F4D973B0E6ACA2C6ACF5FF3 /* PFCommandRunning.h in Headers */, + B903E58329FDF7F6E815312255B967F7 /* PFCommandRunningConstants.h in Headers */, + 8EAD9F99B96C0786E0B85D4D00F096DC /* PFCommandURLRequestConstructor.h in Headers */, + CB4B0DCDDB21473382F6B2B6666EC6DC /* PFConfig.h in Headers */, + 6AAB88174D5DAE8A23C47D20961B3DDE /* PFConfig_Private.h in Headers */, + 8FA163961DCFE696DD2BA76D1B0467AF /* PFConfigController.h in Headers */, + D052ADE6387927B8A72F291AB6D821EF /* PFConstants.h in Headers */, + C938FA47C6276A28C9F0E0C1933E3E51 /* PFCoreDataProvider.h in Headers */, + 2556A6696795A705FF3AAA00CAAF1879 /* PFCoreManager.h in Headers */, + 516780FBAE8477C063977B67B0C4F64A /* PFCurrentConfigController.h in Headers */, + 81193EC84CBFB74E91526F896C9BA770 /* PFCurrentInstallationController.h in Headers */, + 62A4E5BEAC5F31E0EB99CDCB8179311B /* PFCurrentObjectControlling.h in Headers */, + CD6F43B3511A0FBF3E573962063BD5B9 /* PFCurrentUserController.h in Headers */, + 53A73625D6FFEC0A47C83977EE7CDBCC /* PFDataProvider.h in Headers */, + 808276E084690B816C4FE2938B4E3F38 /* PFDateFormatter.h in Headers */, + D83032130352AB7F72E4AF6EE0024D11 /* PFDecoder.h in Headers */, + B9A074BC3A31106AEC6667D7684FB0F6 /* PFDefaultACLController.h in Headers */, + B3777DF9804F4FD5656FF7A89A266CC3 /* PFDevice.h in Headers */, + 61C04EFBF42F1F1275B42E1DB6103AAC /* PFEncoder.h in Headers */, + FA8E3B41E8BBAC3A94F8040161250867 /* PFErrorUtilities.h in Headers */, + 506994605B778659CB416E37C461D150 /* PFEventuallyPin.h in Headers */, + A6381412CBAD67981B189C3D03FF02B6 /* PFEventuallyQueue.h in Headers */, + FB27D03B5B38BC7F5B6E70EF758693B9 /* PFEventuallyQueue_Private.h in Headers */, + 67767415823A98D8A2C93A953551A571 /* PFFieldOperation.h in Headers */, + C09CA6A4AA52E14E894A7A328C0D8178 /* PFFieldOperationDecoder.h in Headers */, + D4315EE9D6AA73520E3C28206BB12A2E /* PFFile.h in Headers */, + 598CA7FEDEDFDBF38831C0015C044596 /* PFFile_Private.h in Headers */, + 25EFA69D90204A5BFBC506669A97C683 /* PFFileController.h in Headers */, + 6A7AA0924113739F682D6E35E4B71540 /* PFFileDataStream.h in Headers */, + 9FE10640F0AED83B16480FFAD9CEA3CD /* PFFileManager.h in Headers */, + 28EBF852662F1A1004F220F004B2FB27 /* PFFileStagingController.h in Headers */, + F21561635F6B62CFBA1A70ED0D86BE5A /* PFFileState.h in Headers */, + 0E688D49284AEE76C3B651E3CFE54C94 /* PFFileState_Private.h in Headers */, + F9DC54B44C2DA79FEE1FE863F3185504 /* PFGeoPoint.h in Headers */, + 1B11A9CD89258EFE81856DDA597C2826 /* PFGeoPointPrivate.h in Headers */, + CD5054A2ECB96B3ABB0B3794A299A822 /* PFHash.h in Headers */, + 478F099B2EDD4376B8C1183745A5B4B9 /* PFHTTPRequest.h in Headers */, + 10B055EF9DE001B011240568093FE8AB /* PFHTTPURLRequestConstructor.h in Headers */, + 0ADF250658B54EA51FC500CB76783CB5 /* PFInstallation.h in Headers */, + 66F445220BAF1CCE856A11B0B7F803A4 /* PFInstallationConstants.h in Headers */, + D66BEA50BF7F894CCCA235694CF7590B /* PFInstallationController.h in Headers */, + 3F569B5B27E0603B07C858321F23FB9B /* PFInstallationIdentifierStore.h in Headers */, + D7B46B6BD03E88E70CAECBDCED8F4744 /* PFInstallationIdentifierStore_Private.h in Headers */, + B5983C745D96CF344F4DE9DEF60C5ECF /* PFInstallationPrivate.h in Headers */, + ED6B6D31DCF0E36BB88E225710AA83DB /* PFInternalUtils.h in Headers */, + 3E41E38FF7A69B85994E73EABE7FF57F /* PFJSONSerialization.h in Headers */, + A80A4BCE5F0BE99CC5D0D79ABC6EFC84 /* PFKeychainStore.h in Headers */, + 6B8F8457EE06C9B9F37CA931F439DB4A /* PFKeyValueCache.h in Headers */, + E7A1E7F0498A21036EE756DA807E34B0 /* PFKeyValueCache_Private.h in Headers */, + D2DF8F3B252BED46B455366674FC5F8D /* PFLocationManager.h in Headers */, + 9D89845489A310CB56E647F143BEA677 /* PFLogger.h in Headers */, + BFA8895521CECBF82A30964B918DDD3A /* PFLogging.h in Headers */, + 909D78EE968D364B5DDD6C8CF7E375A2 /* PFMacros.h in Headers */, + 5FBDA19530CA26D2F5E37B02FFA15D50 /* PFMulticastDelegate.h in Headers */, + 9988B7041D7B470C3F7D1938D965F654 /* PFMultiProcessFileLock.h in Headers */, + 75928CD63004AE9767341F79B565BEAC /* PFMultiProcessFileLockController.h in Headers */, + 0EA556CC3DBCD3806D56508332A5FB59 /* PFMutableACLState.h in Headers */, + 4FA4189FA17793F898C1A79920893A7D /* PFMutableFileState.h in Headers */, + 4C3A2F763EEE360861027C7097748A42 /* PFMutableObjectState.h in Headers */, + AC0D3A56A07AF56CCCB9E6A24C68C969 /* PFMutablePushState.h in Headers */, + A9F8CCF3E9E7A1F8BB906AE75CDD76A1 /* PFMutableQueryState.h in Headers */, + F7A16A60215390EB56EFF7E65F4CF803 /* PFMutableRelationState.h in Headers */, + 04C21C0C58DD5EF39D9E5A7C9E060F3C /* PFMutableUserState.h in Headers */, + 6B6E69822F96D41917A1791C1873A1D1 /* PFNetworkActivityIndicatorManager.h in Headers */, + 43EDB848BEACB773962B589EC73AA826 /* PFNetworkCommand.h in Headers */, + 6678A92E1C40BF48F96D3FCF476C03BC /* PFNullability.h in Headers */, + F2948A142B6234A6E12DF2AD5FC390CF /* PFObject+Subclass.h in Headers */, + A75FE2B82568636BBA4E284DD4E782B8 /* PFObject.h in Headers */, + 200F941DC68314422A92DECA8D213082 /* PFObjectBatchController.h in Headers */, + 5AAE55DFA2869211ADAE99C345C0192E /* PFObjectConstants.h in Headers */, + A734638E2FD9CD1F9174C76669F0DF6B /* PFObjectController.h in Headers */, + BEBFDE40361511989AD4318B1B5E578E /* PFObjectController_Private.h in Headers */, + 188C54485E358878521C5C15A0AFE626 /* PFObjectControlling.h in Headers */, + D637A12D921733D3173960A61DB8AE92 /* PFObjectEstimatedData.h in Headers */, + C15F9AD9C17E18B25E1EF6B788309E6F /* PFObjectFileCoder.h in Headers */, + F7CC6A2F5288951581078FA3B7C9A215 /* PFObjectFileCodingLogic.h in Headers */, + FF7920785C7F9A6CBCDBFB44A8C63791 /* PFObjectFilePersistenceController.h in Headers */, + 4D4A07890A079F8AA2090CF76EF82A90 /* PFObjectLocalIdStore.h in Headers */, + 134441CFC16A905CB51B70597FF4B61B /* PFObjectPrivate.h in Headers */, + A41BB882FD7A74A2F25113D6A5644F7D /* PFObjectState.h in Headers */, + BF7290A7C875C362F762B2D6C1B991B7 /* PFObjectState_Private.h in Headers */, + 8E562933760503079FD82D5E56CCCAF5 /* PFObjectSubclassInfo.h in Headers */, + 0A1E88ACE6A4D6D41EA0634DB6A94256 /* PFObjectSubclassingController.h in Headers */, + A4A05FBBDDB993E56073550A63C1727E /* PFObjectUtilities.h in Headers */, + 1C906268C5AA213F8CFCDCC95D00C718 /* PFOfflineObjectController.h in Headers */, + EF254F401AD05830A53E37EB6ED1A20D /* PFOfflineQueryController.h in Headers */, + 1BF89E326EBB865184A47A1B76EA44B6 /* PFOfflineQueryLogic.h in Headers */, + B4E61680387E0E5146734C1EB81255C5 /* PFOfflineStore.h in Headers */, + FD2A1B5A3B8F58A419B8030AB3B0C900 /* PFOperationSet.h in Headers */, + 1F85CC0A24315E41F1DB39068E4684A8 /* PFPaymentTransactionObserver.h in Headers */, + 59B602D97CE0027EE607A6D59E7FAEC4 /* PFPaymentTransactionObserver_Private.h in Headers */, + 512D2E7F3E98E29CD6338D40FC3CBEEE /* PFPin.h in Headers */, + 6CC372C70EE09A01AEC3B0C9A077B395 /* PFPinningEventuallyQueue.h in Headers */, + 2D8BA321D46E84251856DED2E84239DD /* PFPinningObjectStore.h in Headers */, + 01A64680ACA654A0CAA6A98B76A2C015 /* PFProduct+Private.h in Headers */, + 93BDA0F9D51A5F9D4EE287129BDBB99D /* PFProduct.h in Headers */, + 379BA3F1B3C1F43A72C4C17B61215FDE /* PFProductsRequestHandler.h in Headers */, + 427DD66260DDD2F6345D7196B90E3DEE /* PFPropertyInfo.h in Headers */, + C9774E7792D3CF37A4D1C7C208FD14E2 /* PFPropertyInfo_Private.h in Headers */, + 1C2AF8394E4C8C86B7F42AF545C80281 /* PFPropertyInfo_Runtime.h in Headers */, + F3F9AFABE12CF6EF4371A4A8DC5C9D46 /* PFPurchase.h in Headers */, + 397DD286C0935623C81E4AA9AE2E4C2C /* PFPurchaseController.h in Headers */, + 9DA2B0C972429DD7AD7064E9E09475C3 /* PFPush.h in Headers */, + A00E98DC15CC981738CFBE96AEB16EB6 /* PFPushChannelsController.h in Headers */, + 08D84FA7E2537052744E64C7025A84E7 /* PFPushController.h in Headers */, + 70905E1AFD8E61FF829458D67B744EB4 /* PFPushManager.h in Headers */, + A466E7239F778C5E117BA4008114B272 /* PFPushPrivate.h in Headers */, + 12824DFDC12C14097AF56D630AD2D8FB /* PFPushState.h in Headers */, + 21C13796DE839F92D14C6CA50671E5BF /* PFPushState_Private.h in Headers */, + 9CBF1E478681F7C22EC2F5B1303DBEF8 /* PFPushUtilities.h in Headers */, + D8ADDAF044D6B1B3B763D0334FD8BDAD /* PFQuery.h in Headers */, + 1708C44508662C2D5867EB8DB869B93E /* PFQueryController.h in Headers */, + 8286DA65B1C86544369DF6D387CA87DB /* PFQueryPrivate.h in Headers */, + 18128AAED9116077EDF701E1098C9954 /* PFQueryState.h in Headers */, + 2C04A25EF87B39A7378F852D3A251514 /* PFQueryState_Private.h in Headers */, + F53BB2B5B2739CED55C0738568C22BE0 /* PFQueryUtilities.h in Headers */, + 693563EF1DB59CD00D1B0B8685D0819E /* PFReachability.h in Headers */, + ADA73C3403D0DCBA9ADC9737B71F448B /* PFRelation.h in Headers */, + 81D3161E66F074CAE137695C259391D6 /* PFRelationPrivate.h in Headers */, + 847C86711AC58480F93EE157EC762827 /* PFRelationState.h in Headers */, + 0C132DF2B2F5648112EE398656EE0962 /* PFRelationState_Private.h in Headers */, + 89131DE7914EFB6BDBAF0E0BA46E0B81 /* PFRESTAnalyticsCommand.h in Headers */, + A8FFC32B766D8160348983C902A0FBCF /* PFRESTCloudCommand.h in Headers */, + BD3CB42C142417AFADFDF458A7B580E7 /* PFRESTCommand.h in Headers */, + 05606336B17E8DE7AFBE9B0AD554763D /* PFRESTCommand_Private.h in Headers */, + 99D055FF3D067DC24E05819741E06945 /* PFRESTConfigCommand.h in Headers */, + 2132812C756FB96D0AB12B601F84A802 /* PFRESTFileCommand.h in Headers */, + AB54E487727ABF1E4455A951FFEF2C82 /* PFRESTObjectBatchCommand.h in Headers */, + 8B1097E93AE1F424DE31FFB1D83C1E99 /* PFRESTObjectCommand.h in Headers */, + 05F9EB16C3ED571BD0592AE09986458D /* PFRESTPushCommand.h in Headers */, + DAD881A7C7DDA8848FF17E18DB99295C /* PFRESTQueryCommand.h in Headers */, + 46E222D8EF5404BBB0ADEC81B1DF1874 /* PFRESTSessionCommand.h in Headers */, + A03EE16F31569592C179BC824D019DC9 /* PFRESTUserCommand.h in Headers */, + 50A19E0D54B5ABC2DF718485876675BF /* PFRole.h in Headers */, + 6080A31C682280C87E76F93D3D1C7D42 /* PFSession.h in Headers */, + 1700592C1709E23CF04D2CA3F4BEC83D /* PFSession_Private.h in Headers */, + 3FBCAD82A3A69CB7850136E6D8613AD0 /* PFSessionController.h in Headers */, + CD2E86E2BA9BE8DBAA7FE88993F1E41E /* PFSessionUtilities.h in Headers */, + 9D3D9A7D232F06FADE0D0D036D96A598 /* PFSQLiteDatabase.h in Headers */, + 77D00913E6BC46EF1D8E536BA5A36A93 /* PFSQLiteDatabase_Private.h in Headers */, + 1DBC9B7D710CE712D9F4C8E497DE1E0B /* PFSQLiteDatabaseController.h in Headers */, + 083A7602FC1ED21B8878784115D662F1 /* PFSQLiteDatabaseResult.h in Headers */, + CC0225659881638027E96EFF8EE41228 /* PFSQLiteStatement.h in Headers */, + C66C913D05F70FF30EC65B1143CDC84E /* PFSubclassing.h in Headers */, + DF5A96668809AF7FF9E04130C5D9A1D2 /* PFTaskQueue.h in Headers */, + 862FE930B3C40926DC7101D0D25931B1 /* PFThreadsafety.h in Headers */, + 8A0852C94F274C951A8FF2C0E53CC203 /* PFURLConstructor.h in Headers */, + 9D8543C5F547215DBD30C9C18E525F33 /* PFURLSession.h in Headers */, + D41A41DB158B8E95575669C635CCD82D /* PFURLSession_Private.h in Headers */, + F7077CE67CBD9DAAAE91FBED372BA0CD /* PFURLSessionCommandRunner.h in Headers */, + D16EF56685DA7EE0C6F714819F926216 /* PFURLSessionCommandRunner_Private.h in Headers */, + E228987782C3CA4BC276D56CD25AA911 /* PFURLSessionDataTaskDelegate.h in Headers */, + 2C61A57B4DA38760CFE42C7F3AFF489E /* PFURLSessionDataTaskDelegate_Private.h in Headers */, + 8E576F91BE595E20B1D97319B3E40EE0 /* PFURLSessionFileDownloadTaskDelegate.h in Headers */, + E92D54EC2B8A52C24D9C34F2A37F2996 /* PFURLSessionJSONDataTaskDelegate.h in Headers */, + 5DB44075B06EAE0B3D695B29CCF444DA /* PFURLSessionUploadTaskDelegate.h in Headers */, + 1546A097DB78CBCC3268F3EB5541DE8F /* PFUser.h in Headers */, + E544AA008F4106DB432AFF71DD5B5654 /* PFUserAuthenticationController.h in Headers */, + F060AADC6126A31918F62A205D714C32 /* PFUserAuthenticationDelegate.h in Headers */, + E998F4250A20099ECF4980ECA881988E /* PFUserConstants.h in Headers */, + A1D7AF47B734259F42226B7577014F7C /* PFUserController.h in Headers */, + 9F836AA840436BDA62D7D6325F233221 /* PFUserFileCodingLogic.h in Headers */, + FBFCD80E29C5DB1702D3FB255115D1C5 /* PFUserPrivate.h in Headers */, + 82023A97B43D2DEC58CA0092A2A63835 /* PFUserState.h in Headers */, + 206B7172BAA6262F77700E4347C0F8D5 /* PFUserState_Private.h in Headers */, + 1F3D5A5A5067181846196EEC61D25961 /* PFWeakValue.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3EB13134BE830329BA711C2AA10931C8 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DA880A2094CF94108583D78E4097D554 /* FBSDKAppGroupAddDialog.h in Headers */, + 5A1CB5B72C92E43BF844377DC72DA072 /* FBSDKAppGroupContent.h in Headers */, + 1BBA57EDDB94507AC5DAA85D6489D942 /* FBSDKAppGroupJoinDialog.h in Headers */, + 54D559AFA627AFA735FB0D6D878F5D7F /* FBSDKAppInviteContent.h in Headers */, + B17336576943ADD8ABE250E808D8B72D /* FBSDKAppInviteDialog.h in Headers */, + 35599C4F9F10FC09064011AE354E20C5 /* FBSDKCheckmarkIcon.h in Headers */, + 0BB5BE4B4A8C410F2248DE8D14BB4663 /* FBSDKGameRequestContent.h in Headers */, + 74D22BA7DDF7C44219CE3E793CE0AC6F /* FBSDKGameRequestDialog.h in Headers */, + 92D14F626066984B8740E9484071B7C1 /* FBSDKGameRequestFrictionlessRecipientCache.h in Headers */, + B84F69EEEA9898307D85749FD54502D0 /* FBSDKLikeActionController.h in Headers */, + C7DCD67DF808CAC96CFFB404088D2CC5 /* FBSDKLikeActionControllerCache.h in Headers */, + F48F08F807C465B2DC535CE521E66D97 /* FBSDKLikeBoxBorderView.h in Headers */, + 20CA33378056E289649C0616BF5C5E08 /* FBSDKLikeBoxView.h in Headers */, + E346D04E3F0539B358C1194F02FB8809 /* FBSDKLikeButton+Internal.h in Headers */, + 0E089188D74319CC3ED824652B776895 /* FBSDKLikeButton.h in Headers */, + 5FCA3879482A03418CCB75CE50EEA9C1 /* FBSDKLikeButtonPopWAV.h in Headers */, + EBB6F0BB04FCFC82D12723EF3E740261 /* FBSDKLikeControl+Internal.h in Headers */, + 7B38759EF062D9FF703E7D297DAB27E6 /* FBSDKLikeControl.h in Headers */, + B25E3751AB01594311494F5E9AFC5322 /* FBSDKLikeDialog.h in Headers */, + 34FE928299E6FCBB43826BDB66144FD7 /* FBSDKLikeObjectType.h in Headers */, + 097CE360D698CD7CC46F59B370318ED1 /* FBSDKLiking.h in Headers */, + 87E208C4BC2E8A5C74E1D01087F195FF /* FBSDKMessageDialog.h in Headers */, + 2DC488DF3C90086C17087C2BB72189AA /* FBSDKMessengerIcon.h in Headers */, + 0DB80F6F97A5BEB7A1839EBAF3FCA9AF /* FBSDKSendButton.h in Headers */, + A72805273E466C273A4B10C6ACB993AA /* FBSDKShareAPI.h in Headers */, + 64BD30EF98CC4A38D8BF92656D4A6AD0 /* FBSDKShareButton.h in Headers */, + B220008A1D3DD1B6628E2AC2A64A02AA /* FBSDKShareConstants.h in Headers */, + A1FCC931AC4A1A8D148E28C4572BB307 /* FBSDKShareDefines.h in Headers */, + 10B85E5BCE0729452FFC72D7BB376F59 /* FBSDKShareDialog.h in Headers */, + 44731A7D10EF496E7DED3DCA05410767 /* FBSDKShareDialogMode.h in Headers */, + A161B6BDF507ABF1322BB74A9D437D4B /* FBSDKShareError.h in Headers */, + 8AF36C0CC65E3A5D7AF4AEA8BEA5F8DD /* FBSDKShareKit+Internal.h in Headers */, + 205E1195DEF1603010BA47F3A8A39ACA /* FBSDKShareKit.h in Headers */, + 6EA031F1089FBD5D7E5DACD68EDC2F5A /* FBSDKShareLinkContent+Internal.h in Headers */, + C50BE142E604DE751E9B8AF5DD6B0363 /* FBSDKShareLinkContent.h in Headers */, + 488F77FF13E79A72AD87E8B838E827E4 /* FBSDKShareOpenGraphAction.h in Headers */, + E2D2F28DE8D25857A0143D0C99E1264C /* FBSDKShareOpenGraphContent.h in Headers */, + 3F7A18D123E044CFAC2A0D1322E727BF /* FBSDKShareOpenGraphObject.h in Headers */, + F1B80D56445F494B2F82BB577E4CB42A /* FBSDKShareOpenGraphValueContainer+Internal.h in Headers */, + 18C091723B432584B085686061A0CEE0 /* FBSDKShareOpenGraphValueContainer.h in Headers */, + 76EACBDAB632DF356DEB855DD97A09A6 /* FBSDKSharePhoto.h in Headers */, + 435602DE03BDC37F6F724BE3A943F1AB /* FBSDKSharePhotoContent.h in Headers */, + 1AD36782B0606C9AB186A075420F1EA3 /* FBSDKShareUtility.h in Headers */, + 22080662EA8952370B284F798F16D4B2 /* FBSDKShareVideo.h in Headers */, + EDB2BA3AEA3A7A4EC735BAF9804D75D4 /* FBSDKShareVideoContent.h in Headers */, + 4E5A7BE76B5EC309DAB207FAFB7FE7FC /* FBSDKSharing.h in Headers */, + E9BBD9ED8781DB4B08B9A35068B2E0D9 /* FBSDKSharingButton.h in Headers */, + F2614C38AA4BB27104AD7BAB99E2BDD3 /* FBSDKSharingContent.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 48BE40436AC830EF2C4CB6035A80602C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 429897FA95FC01863ACF624955ED030D /* FloatConversion.h in Headers */, + B85FA9794E00DFF09C3ECB91A3D45882 /* POP.h in Headers */, + 27F8C6DBEE3149A4A1FE4682E23111A5 /* POPAction.h in Headers */, + 90A1C18005CD010BC306C9E32ED37C72 /* POPAnimatableProperty.h in Headers */, + 2EF035CF21D5D9B2F876D73D145DCBAC /* POPAnimation.h in Headers */, + A2B99500387BF0FB3062AB1D0FFD57A5 /* POPAnimationEvent.h in Headers */, + 4D07C5CE0CD51D48D58268926E71C534 /* POPAnimationEventInternal.h in Headers */, + 0CAA65756A68A9D5C473ABECAA0B50BF /* POPAnimationExtras.h in Headers */, + 1742414744E4A0DF8BB946045C2EB827 /* POPAnimationInternal.h in Headers */, + 630A23A824A9AE5B03C54172F5F9556F /* POPAnimationPrivate.h in Headers */, + 70687046EC0243F807433D9D44DB7EB1 /* POPAnimationRuntime.h in Headers */, + 15C98EE5B0B19EC8B2B69FFF3836F90A /* POPAnimationTracer.h in Headers */, + 313C10C6A642FC61680D2E00D59E5FD5 /* POPAnimationTracerInternal.h in Headers */, + 0F4202BC6561358918BED3708C095673 /* POPAnimator.h in Headers */, + 666C8261EF1AB3272F89C4CA09FC631D /* POPAnimatorPrivate.h in Headers */, + FE0C5ACB05FF0C1803B48C2A0FDBFB2D /* POPBasicAnimation.h in Headers */, + CB0C14620CFC843788BBAF4AC8A4E6DB /* POPBasicAnimationInternal.h in Headers */, + 229318A2EF0A83A1BC417DBB54FAE450 /* POPCGUtils.h in Headers */, + B7BBC12792F777B1ACF0CF3C28355EEB /* POPCustomAnimation.h in Headers */, + 8933272E50BAE580EAB845528BE0E364 /* POPDecayAnimation.h in Headers */, + 2F67C0F2B19DD7478B7C6089401D10D8 /* POPDecayAnimationInternal.h in Headers */, + D2B66E29F3D4324178B40D412922503D /* POPDefines.h in Headers */, + 2FD8DABDCB30DFD548402447EDD982B7 /* POPGeometry.h in Headers */, + 0CA55F1868EDE312E4DD0713C9AEAE99 /* POPLayerExtras.h in Headers */, + 6EFA282EB5DD6C5347CCE430844E5CAA /* POPMath.h in Headers */, + 939F928ECFFE801E912A133DB6158E86 /* POPPropertyAnimation.h in Headers */, + AEC8FB690EB9BAD0F86F1B972089BD4A /* POPPropertyAnimationInternal.h in Headers */, + 7AE92FAE0E12991264A8E657D4187884 /* POPSpringAnimation.h in Headers */, + 34139CCA6481211B5C8BC57918F8FF3B /* POPSpringAnimationInternal.h in Headers */, + 32E214F119A1BF1D749C05323F252756 /* POPSpringSolver.h in Headers */, + F3D8FC254CCC51A7FBC764EDCF823A3C /* POPVector.h in Headers */, + 467E37A4D9DFFFA4BE812456B18B5766 /* TransformationMatrix.h in Headers */, + E936CBE6114F820C4E7408AC11114C9F /* UnitBezier.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5B893C40E516471E59001046BD80B3B3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D3A10AB5D0CAECCEEDE49132B5F4330 /* AFHTTPClient.h in Headers */, + ED4ECDAC11F885A77723CE05B89A65AA /* AFHTTPRequestOperation.h in Headers */, + 8365B59553252085916A6D4ECCE383BB /* AFImageRequestOperation.h in Headers */, + 3A4A4D139CCD0A806197BF7A723800F2 /* AFJSONRequestOperation.h in Headers */, + B71F48BE352CE58652003A3A8BE5EDC2 /* AFNetworkActivityIndicatorManager.h in Headers */, + F54F01DCDD820F6EF621E915C1BF6E0D /* AFNetworking.h in Headers */, + 8D66E14F4E946CF7C4A203E9DC27E301 /* AFPropertyListRequestOperation.h in Headers */, + 0EEABB9AABDED87C8B9F585D82062063 /* AFURLConnectionOperation.h in Headers */, + C35F6A896E802A315D7EE2BB54CBEFA5 /* AFXMLRequestOperation.h in Headers */, + 791E4A4DAC2DF15F7846EBC44911F06E /* UIImageView+AFNetworking.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6BD109D1C8BF4F54CE2A7C6F7F91C5E8 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 390565C6A1B7B2060B10FCF3BCC97989 /* lcl_config_components_RK.h in Headers */, + 007D207B3BF73369E36B01A53A09538A /* lcl_config_extensions_RK.h in Headers */, + F636A430FBAA6F63A249AD7B432C57CD /* lcl_config_logger_RK.h in Headers */, + 2894A71BD9B82830C0DE27EDB9DEC7E0 /* lcl_RK.h in Headers */, + 3358C947C2329AD593909B5A55839B9C /* Network.h in Headers */, + FA3330484B355C821E59E5DE1C0BA454 /* ObjectMapping.h in Headers */, + 1F2C79C7C24FCC4784A09BF594C6F1ED /* RestKit.h in Headers */, + 03FB2588038E1FF08053127B70281205 /* RKAttributeMapping.h in Headers */, + 58597619340E5853CDA8DBC80D53D577 /* RKBenchmark.h in Headers */, + 94E9756648CDAC618994DEA3D28ECC18 /* RKConnectionTestExpectation.h in Headers */, + AD94C0E58E9E796C2461FB990370B8B9 /* RKDictionaryUtilities.h in Headers */, + 09FF1B52A8DE609DF1E2EF7378210758 /* RKDotNetDateFormatter.h in Headers */, + A51B5663618D00E23D7124EC97861DD4 /* RKDynamicMapping.h in Headers */, + 4CB1746E41309F454F4CB59CCB120634 /* RKErrorMessage.h in Headers */, + 49FB341D2B6AB6B34B968D145F42A04C /* RKErrors.h in Headers */, + A7B200E0CE52F38A4D17E432C3D5D44B /* RKHTTPRequestOperation.h in Headers */, + D3A453D5AB624E0B9703A6E8542657A0 /* RKHTTPUtilities.h in Headers */, + 231A46F0855F96400AFB1832C605FF6F /* RKLog.h in Headers */, + ADDFED5198FA5284E28022251BA98C1D /* RKLumberjackLogger.h in Headers */, + 16ADFA9976DB0641CC700CE33921E328 /* RKMacros.h in Headers */, + ED6FD3AB4D6A18C000AEA269BC8D7F29 /* RKManagedObjectRequestOperation.h in Headers */, + 40987DD554F4D5EB29B8B0948FCAC33B /* RKMapperOperation.h in Headers */, + 0D5354A9FFC479301962382BF42F5597 /* RKMapperOperation_Private.h in Headers */, + 44A5248789F660D19C2D6D8CBCCC7C13 /* RKMapping.h in Headers */, + 6713CDF473C3A1F71B852C8F354780A0 /* RKMappingErrors.h in Headers */, + 452F0DCF8F0D3525E9DC890D389684D9 /* RKMappingOperation.h in Headers */, + 696305155D2765894FA3E5EBC092A650 /* RKMappingOperationDataSource.h in Headers */, + CDD83F91D134051FA132923E3D4096DD /* RKMappingResult.h in Headers */, + E1A643D9DE8D164F5D1179CF5117F763 /* RKMappingTest.h in Headers */, + 9F6482097A50B68DAE48BE9D3CB3D28D /* RKMIMETypes.h in Headers */, + E704C533E6A5D7805AAF9761C8017D51 /* RKMIMETypeSerialization.h in Headers */, + 0C4D309AE4178F282BAD4DC9EB1E5B03 /* RKNSJSONSerialization.h in Headers */, + C419D5E278F540F1644BA4741785CC8A /* RKObjectManager.h in Headers */, + 6B980244FC648CB685E9AD30A9780D1C /* RKObjectMapping.h in Headers */, + 273413858783060A2A4F5AB76A2855CE /* RKObjectMappingMatcher.h in Headers */, + 28BA0A9D61D5B23A53B9D09A7A9896CC /* RKObjectMappingOperationDataSource.h in Headers */, + C981DB324F5A971F06590A5FDEB937F0 /* RKObjectParameterization.h in Headers */, + 434F58B870A20B1FFBF38579DF600676 /* RKObjectRequestOperation.h in Headers */, + FE44D1FCA03026E71140FBE5FE12FBAA /* RKObjectRequestOperationSubclass.h in Headers */, + 9FCAE5105CB7AB9D7B5CD6457B323B06 /* RKObjectUtilities.h in Headers */, + 2B19F33BE94964880FAA3A6B58CCE963 /* RKOperationStateMachine.h in Headers */, + EF10BDF15001F7DFC2CB2B2F898A40B9 /* RKPaginator.h in Headers */, + 92C02E7583FDE1D396BB88B19EE2831E /* RKPathMatcher.h in Headers */, + 0D6F37CCD07F22936439247F6189A056 /* RKPathUtilities.h in Headers */, + 94C8C1F85C2C32F8D8C4843B10603DF0 /* RKPropertyInspector.h in Headers */, + AECC0656F68B2EF64F2FE95EE733659A /* RKPropertyMapping.h in Headers */, + F69121DAB7F11950A7942C4D70A1B556 /* RKPropertyMappingTestExpectation.h in Headers */, + EDE804E78EDBA4011460F800C7E8F9FB /* RKRelationshipMapping.h in Headers */, + 813ADFF01E988125B016E0A604A0FCC4 /* RKRequestDescriptor.h in Headers */, + 1497B8CAE9DE252B51DC38604B76AD7A /* RKResponseDescriptor.h in Headers */, + 14545C481D346027B2C0E703B8AFDAAA /* RKResponseMapperOperation.h in Headers */, + 336A9DE5FB7C4ED8DF5B7E6EC76D0822 /* RKRoute.h in Headers */, + 0D52952BF5B3A015FA024A23981EA5BD /* RKRouter.h in Headers */, + 7D1605EE6FF513FDFB9A9827C2930B89 /* RKRouteSet.h in Headers */, + C195E761865347834BB306A41FBFD8B7 /* RKSerialization.h in Headers */, + 5621D0F1F50874AACD396E2AC5A8ED7B /* RKStringTokenizer.h in Headers */, + 4E7740FDD29E3D20879999C4584BA7E0 /* RKTestFactory.h in Headers */, + 7E50C34963B8ED1D60B79E534C5627AC /* RKTestFixture.h in Headers */, + 29A195C90E8CFB19E874DE1984AF015E /* RKTestHelpers.h in Headers */, + E459591E18120BB2457AA3AB88FD94E5 /* RKTestNotificationObserver.h in Headers */, + D985CD1702B209DE6E69F600B59751DC /* RKURLEncodedSerialization.h in Headers */, + 25C7617B2D122A04E33E3B78CA426B60 /* Support.h in Headers */, + FAE3BF2AD91A39EB7B33F722AB050FDF /* Testing.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7BAB51A16596C67D638F977F2523AD29 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + A6A403231A96C6C21C83BAEF0BB1093F /* CAAnimation+YALTabBarViewAnimations.h in Headers */, + 2086289033B670D4FFE18F8578E911F2 /* CATransaction+TransactionWithAnimationsAndCompletion.h in Headers */, + E6E0B008759D9B3D9EE25FD2FE56E715 /* YALAnimatingTabBarConstants.h in Headers */, + B50EA8AB3CF7CF9162E24421784D4BAD /* YALFoldingTabBar.h in Headers */, + 7EE9BE9884D5807EC2C980930CB99B06 /* YALFoldingTabBarController.h in Headers */, + 565365EA7F73C65562A3FC4459E770B5 /* YALSpringAnimation.h in Headers */, + 6DFB846C756551ECD366F5AC7B189C2C /* YALTabBarInteracting.h in Headers */, + E288DE93014B057EC4C1871E17F3FA89 /* YALTabBarItem.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9C2A60614E0D3502F6D764E564E1FF45 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 091B7CD914893E81C39427757E3FB0FD /* RKValueTransformers.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C49083680F8B4A2C2894B47349E1B59A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4A30A8F0DDE8E4D807E1F48C169CA7EE /* SOCKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E26EEF9536E33C04CAD5660D5465C478 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + A9514FF859C895C0BB0BCE528FF507D3 /* ISO8601DateFormatterValueTransformer.h in Headers */, + E46B5DC4D2646D5DD81881A2D4EA57F0 /* RKISO8601DateFormatter.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 05AF921757BAF218468C62708B020AA6 /* TransitionKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 776BD5F5971B32DDF8E6A10063D3C2F5 /* Build configuration list for PBXNativeTarget "TransitionKit" */; + buildPhases = ( + 8FDCE15764753ADC3473510DD6B2D8B5 /* Sources */, + 5585D11E7E0A5A702DA209671365FADF /* Frameworks */, + 235759BBA87FE7B50D5CDEC6E14CA7A8 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TransitionKit; + productName = TransitionKit; + productReference = F970BE5082817C3185CB918CBDAFE49B /* libTransitionKit.a */; + productType = "com.apple.product-type.library.static"; + }; + 080AF914A09167DB5759A733917B840F /* ISO8601DateFormatterValueTransformer */ = { + isa = PBXNativeTarget; + buildConfigurationList = D698E21AD6E8699A3BDEA8BF928C6677 /* Build configuration list for PBXNativeTarget "ISO8601DateFormatterValueTransformer" */; + buildPhases = ( + 6831413FDAC4F2DD02AF35510D60199B /* Sources */, + 8303124DDA063FE89C9AEFC94E6AB54E /* Frameworks */, + E26EEF9536E33C04CAD5660D5465C478 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + E36E70253F374409C8D0E675B83B8B9A /* PBXTargetDependency */, + ); + name = ISO8601DateFormatterValueTransformer; + productName = ISO8601DateFormatterValueTransformer; + productReference = C5F83C7A2BEAFF6FFAEAD7A6F73B7D49 /* libISO8601DateFormatterValueTransformer.a */; + productType = "com.apple.product-type.library.static"; + }; + 0EB292B9319B2DAFB20D9A12B70C9D45 /* RestKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6A3F4B905459EE391C08BBDEFCD88A2D /* Build configuration list for PBXNativeTarget "RestKit" */; + buildPhases = ( + E890AF42CB01E48E4575A2E6468A4288 /* Sources */, + 63458E103C17B332F0872EC549B57894 /* Frameworks */, + 6BD109D1C8BF4F54CE2A7C6F7F91C5E8 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + B3CB3A784EC01BD22BD2A2D7715117F4 /* PBXTargetDependency */, + 9FCD970EABEC67BFA1394916D7ED1CC9 /* PBXTargetDependency */, + 4909A8706666DFDB01A2C76C5D573D69 /* PBXTargetDependency */, + A40864DBEEF11A082B652791FA04C24C /* PBXTargetDependency */, + DC9F00594A01E8A9FF3ACFF59CDEE467 /* PBXTargetDependency */, + ); + name = RestKit; + productName = RestKit; + productReference = 80D183F090FB2841492B19FAC5CD77B6 /* libRestKit.a */; + productType = "com.apple.product-type.library.static"; + }; + 4E286D373D75563CE26E479A68203892 /* FBSDKLoginKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = D73F005C56A801E3CEDE801CC9ECFC4A /* Build configuration list for PBXNativeTarget "FBSDKLoginKit" */; + buildPhases = ( + 2347071535D409729A663A058F04F2DB /* Sources */, + 6772349FF73FC6301A658A55439FAB73 /* Frameworks */, + 0DDAA8E16E00423BC6858ACC657DA26B /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + 9A5270C4EC04E2D2E511996DDEDD58C5 /* PBXTargetDependency */, + ); + name = FBSDKLoginKit; + productName = FBSDKLoginKit; + productReference = 9D7377386CC3EBA3E3B7C409D23C69B6 /* libFBSDKLoginKit.a */; + productType = "com.apple.product-type.library.static"; + }; + 5366B7F679CF2BA31EA583EA35CA2D90 /* Parse */ = { + isa = PBXNativeTarget; + buildConfigurationList = 107C08C918B3D3433F2E017FB4FDB128 /* Build configuration list for PBXNativeTarget "Parse" */; + buildPhases = ( + 688B805CEFC0CF8022B905243A59A50E /* Sources */, + E2152948655C0A221BBD699822F629C0 /* Frameworks */, + 3B4A9D40B5373A9E33560665CB9E94AA /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + B724649E56667B1CEB768EA1EBEFD8D4 /* PBXTargetDependency */, + ); + name = Parse; + productName = Parse; + productReference = 1D9362003B89F08493A37902350DA1BC /* libParse.a */; + productType = "com.apple.product-type.library.static"; + }; + 61681BF0E677683490353B846C61A129 /* AFNetworking */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9B712D281AB5A267FCA1AC12339CC749 /* Build configuration list for PBXNativeTarget "AFNetworking" */; + buildPhases = ( + 78D1430387219E1CEECF694664B47298 /* Sources */, + FF1132C1F746513DE93738ED48AFAB38 /* Frameworks */, + 5B893C40E516471E59001046BD80B3B3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AFNetworking; + productName = AFNetworking; + productReference = 6A45C57C5D3CBC79D400F49C075773AE /* libAFNetworking.a */; + productType = "com.apple.product-type.library.static"; + }; + 81D7FE2A0FD9258247B1232874B837DA /* FBSDKCoreKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9D5140DAF776FF373AAB7D42B9292675 /* Build configuration list for PBXNativeTarget "FBSDKCoreKit" */; + buildPhases = ( + 678CA587F9F0CD82C2737EC72B7D49E6 /* Sources */, + 06397B19B46BC23B4020A7016F06E806 /* Frameworks */, + 19C2B07A862CD221D4D5B9309876BAC3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + F7688FE10814D6B183CC1B9B3F9F7B56 /* PBXTargetDependency */, + ); + name = FBSDKCoreKit; + productName = FBSDKCoreKit; + productReference = E0E0D90BB11B78E84D92384725A9534E /* libFBSDKCoreKit.a */; + productType = "com.apple.product-type.library.static"; + }; + 83077DC47C917DFA4D9F81629D0AA80C /* Pods */ = { + isa = PBXNativeTarget; + buildConfigurationList = A1C2EE2AE7BD563B4A49CDA59286CA4E /* Build configuration list for PBXNativeTarget "Pods" */; + buildPhases = ( + 626D5271FA62C2E787E92C0C06118473 /* Sources */, + 633F46B6757F8B68507D56B231750794 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + BE47033188B8D72402B90474E4F2A905 /* PBXTargetDependency */, + FC9A62FC396F057A9D3B1657CB55DC6D /* PBXTargetDependency */, + 3E4988ED810AD321E1E9DFEC13FEC872 /* PBXTargetDependency */, + C9563FCB47B04BAFDE797E98AC96E16B /* PBXTargetDependency */, + 1B3E7005E90372159541C07635478C09 /* PBXTargetDependency */, + 2E0A25F4A4A85AC834C7F15468F5B337 /* PBXTargetDependency */, + 80F8A239034C4CB916F792A309A7D049 /* PBXTargetDependency */, + 0165668441754BC1FA06647E5E8B1BC2 /* PBXTargetDependency */, + 2F5F18AEAFEBEC26EA2C13A32E9D1852 /* PBXTargetDependency */, + 311341FA67358AAF209E4F9F0C4466F3 /* PBXTargetDependency */, + 7ED5415B6800424874AAD35E3516EE07 /* PBXTargetDependency */, + 29DDDD2855AC6B907DDB5A2453363AD9 /* PBXTargetDependency */, + FAA8A8573D840D2F7E36B520A72135BF /* PBXTargetDependency */, + ); + name = Pods; + productName = Pods; + productReference = 011534C01155F79E4047CADDE68EF6B8 /* libPods.a */; + productType = "com.apple.product-type.library.static"; + }; + 9145E070690055EA2D82D264E78B0F71 /* FoldingTabBar */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3D9BA71030A144DE354FA087AE0AC89C /* Build configuration list for PBXNativeTarget "FoldingTabBar" */; + buildPhases = ( + 1B24A6DE00BF454C0B785A62F56A9B24 /* Sources */, + E3E27D1553990F260E018F2FD31F237C /* Frameworks */, + 7BAB51A16596C67D638F977F2523AD29 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = FoldingTabBar; + productName = FoldingTabBar; + productReference = 80E5F5E0AE0F6B7B2757A6066BCC8612 /* libFoldingTabBar.a */; + productType = "com.apple.product-type.library.static"; + }; + A48601FEE4437A924848DB48369BA809 /* Bolts */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA34C800AB38CCECE78A9E7D6EB38344 /* Build configuration list for PBXNativeTarget "Bolts" */; + buildPhases = ( + 020ACAA02DAD5E45B62595CFFE1CC884 /* Sources */, + 4B6FCC51F24F6991AAA4CC61597FD2DA /* Frameworks */, + 24CC375AC6BF6375B73651BB0872C62A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Bolts; + productName = Bolts; + productReference = BFCC23211BE47A527079FEF69772F5CE /* libBolts.a */; + productType = "com.apple.product-type.library.static"; + }; + C47E006176ABF4755350B88C088C3F0D /* RKValueTransformers */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F071AF9EBB9B88FCF6AD4FC486502B8 /* Build configuration list for PBXNativeTarget "RKValueTransformers" */; + buildPhases = ( + 7A32D54FA40FEF860E67B9E9E2AE0993 /* Sources */, + 4B6ED4A1B1BED7DD189B582654C25EB6 /* Frameworks */, + 9C2A60614E0D3502F6D764E564E1FF45 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RKValueTransformers; + productName = RKValueTransformers; + productReference = 28ACD3CB82BEF500AB8A021A9907BF32 /* libRKValueTransformers.a */; + productType = "com.apple.product-type.library.static"; + }; + C78CAB9013653EB1A250B2DFD3BC7666 /* FBSDKShareKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58770B39DB702F4BF658BBDB3D144297 /* Build configuration list for PBXNativeTarget "FBSDKShareKit" */; + buildPhases = ( + 6D58EE024B08316911051FCE3FA6EBDC /* Sources */, + AB6236FDABEA71A344A72311A20E9129 /* Frameworks */, + 3EB13134BE830329BA711C2AA10931C8 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + CD37FC7A32B6A7B6629457EB67E933A8 /* PBXTargetDependency */, + ); + name = FBSDKShareKit; + productName = FBSDKShareKit; + productReference = 979C040C22C6D7527C085E98ED8D71A0 /* libFBSDKShareKit.a */; + productType = "com.apple.product-type.library.static"; + }; + D8FDBC10A40DB83968987CBA76E4F7DD /* SOCKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = CB03CA1862F38085257433BFD1800B62 /* Build configuration list for PBXNativeTarget "SOCKit" */; + buildPhases = ( + 097BC0EE360EE40371D791F02C321299 /* Sources */, + F1E353087C983AF68F393D9A09D83CDA /* Frameworks */, + C49083680F8B4A2C2894B47349E1B59A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SOCKit; + productName = SOCKit; + productReference = 34C584E3410A80115A9107E13C995E70 /* libSOCKit.a */; + productType = "com.apple.product-type.library.static"; + }; + DD71C0AD634DC4E364BC189688A42294 /* pop */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3E62EC71A9D0016F784F7C6B8D081224 /* Build configuration list for PBXNativeTarget "pop" */; + buildPhases = ( + 236C57FBEE351C3C8D87B75C117C8782 /* Sources */, + AAABAAEC6D245621B8DDE1ACF9BB7918 /* Frameworks */, + 48BE40436AC830EF2C4CB6035A80602C /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pop; + productName = pop; + productReference = FE3AAD9A2F31FBC9D00D7715F65FDB26 /* libpop.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = 8C2957D7B83B63ED6950DC1F89AD93E3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 61681BF0E677683490353B846C61A129 /* AFNetworking */, + A48601FEE4437A924848DB48369BA809 /* Bolts */, + 81D7FE2A0FD9258247B1232874B837DA /* FBSDKCoreKit */, + 4E286D373D75563CE26E479A68203892 /* FBSDKLoginKit */, + C78CAB9013653EB1A250B2DFD3BC7666 /* FBSDKShareKit */, + 9145E070690055EA2D82D264E78B0F71 /* FoldingTabBar */, + 080AF914A09167DB5759A733917B840F /* ISO8601DateFormatterValueTransformer */, + 5366B7F679CF2BA31EA583EA35CA2D90 /* Parse */, + 83077DC47C917DFA4D9F81629D0AA80C /* Pods */, + DD71C0AD634DC4E364BC189688A42294 /* pop */, + 0EB292B9319B2DAFB20D9A12B70C9D45 /* RestKit */, + C47E006176ABF4755350B88C088C3F0D /* RKValueTransformers */, + D8FDBC10A40DB83968987CBA76E4F7DD /* SOCKit */, + 05AF921757BAF218468C62708B020AA6 /* TransitionKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 020ACAA02DAD5E45B62595CFFE1CC884 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 07B38C643DE61100C2471A5E2061DB6D /* BFAppLink.m in Sources */, + 58F4A4DF57C22014622BB042607EB8EE /* BFAppLinkNavigation.m in Sources */, + B1B5542A3966742AC81F380E955AA85B /* BFAppLinkReturnToRefererController.m in Sources */, + A0F75CBE72EE4F9B74838F6F01191D06 /* BFAppLinkReturnToRefererView.m in Sources */, + 1540A63B0BF8B0C782AE91A5B67FEF38 /* BFAppLinkTarget.m in Sources */, + F50BE85096146332D4C00C17546561DA /* BFCancellationToken.m in Sources */, + FCDC22BD5A90775000A728831060EDCC /* BFCancellationTokenRegistration.m in Sources */, + 196864B89AC2C8A21D31595D9A7E05A0 /* BFCancellationTokenSource.m in Sources */, + B68EF6DB36966D13E557D2247702E8C5 /* BFExecutor.m in Sources */, + 18D7A90C450EC893C4428E23D8B47E9F /* BFMeasurementEvent.m in Sources */, + D6B9D996B48B90EB489E54CDC7A9D401 /* BFTask.m in Sources */, + 0AAD3502C3D2BB1E3E7F4377C5111691 /* BFTaskCompletionSource.m in Sources */, + 4426214315E4D8313D27EE3F16CF8C13 /* BFURL.m in Sources */, + F6C1716F0805EA68532FF09E380B40D7 /* BFWebViewAppLinkResolver.m in Sources */, + 634D85A94A89FB79C887AEB085DECA60 /* Bolts-dummy.m in Sources */, + EC7025C98AE47F5E2D9CBEA4AC041890 /* Bolts.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 097BC0EE360EE40371D791F02C321299 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B60AAB7F842EAE538F42641F811DBC07 /* SOCKit-dummy.m in Sources */, + D279CC9D345EBC4120F60408E3392608 /* SOCKit.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1B24A6DE00BF454C0B785A62F56A9B24 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A5A2E68EC92D877AE2289A67BA94C9E7 /* CAAnimation+YALTabBarViewAnimations.m in Sources */, + 3BF789DD91B049645722960CC51287EB /* CATransaction+TransactionWithAnimationsAndCompletion.m in Sources */, + A5EF7E6ADB37EC0A0DE6145812D8998D /* FoldingTabBar-dummy.m in Sources */, + 00F8DED37CC833980AEAD7E7BD46C99E /* YALAnimatingTabBarConstants.m in Sources */, + 06084AD9120FF151ADF37E92A8CDBE83 /* YALFoldingTabBar.m in Sources */, + 343BA26395BFBF73CFC3F42871C03BB9 /* YALFoldingTabBarController.m in Sources */, + 2D8855CDA875AC8AD7AE0DFCC4250493 /* YALSpringAnimation.m in Sources */, + 88410794220AF1062177201E82FF9DBA /* YALTabBarItem.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2347071535D409729A663A058F04F2DB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50ED958AFAB156499B1D88CD2C0394B7 /* _FBSDKLoginRecoveryAttempter.m in Sources */, + E1B5FD2855EE2B8E7393E7DB0C494946 /* FBSDKLoginButton.m in Sources */, + EF38756A5556C26335245407A2D3C876 /* FBSDKLoginCompletion.m in Sources */, + 5322CA0A34DB0348C3603AFAD04A7DF5 /* FBSDKLoginConstants.m in Sources */, + 6B2DD9967AB4D947BDECC65AC4CCB1EE /* FBSDKLoginError.m in Sources */, + B1E2BB1A1186B0C02B35C1C6F5509D36 /* FBSDKLoginKit-dummy.m in Sources */, + 75F412B1EE494A57BC9AED52E8F28700 /* FBSDKLoginManager.m in Sources */, + 5EEB7C03214B977E5D8925797BCCF7B1 /* FBSDKLoginManagerLogger.m in Sources */, + 04562DEDFEB5549638FFF3A71A940FF3 /* FBSDKLoginManagerLoginResult.m in Sources */, + E538CE431B0B1742D219C8D91483FDEA /* FBSDKLoginTooltipView.m in Sources */, + F9814C410ADDB3A0797E70914157D3A0 /* FBSDKLoginUtility.m in Sources */, + AAEA1275B8DBCEDED978E0E5967D1440 /* FBSDKTooltipView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 236C57FBEE351C3C8D87B75C117C8782 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C003AB01A869DC27CDDCD6CCC0CACE9 /* pop-dummy.m in Sources */, + 74935B997B546A6E2D523ECE6E06E4FC /* POPAnimatableProperty.mm in Sources */, + C234A73209753EDCFE73464F05EA45E1 /* POPAnimation.mm in Sources */, + C067F0759FE44C28F074EFF6C754A11D /* POPAnimationEvent.mm in Sources */, + F751CEADDC757850DAE30E3411FD494D /* POPAnimationExtras.mm in Sources */, + B63E72E378C0C4DEBC0EF1A6EE5CAD25 /* POPAnimationRuntime.mm in Sources */, + BE695DFD8590BE457047A5B07B829199 /* POPAnimationTracer.mm in Sources */, + B16764D185993A3DA87BD56929F05480 /* POPAnimator.mm in Sources */, + 5FBB039F53D31783622E144DF3B0DC7B /* POPBasicAnimation.mm in Sources */, + A1732411203D091E1FC231EB20F5A8C7 /* POPCGUtils.mm in Sources */, + 57B1DEE062B9373E350E5EB3DC657FC8 /* POPCustomAnimation.mm in Sources */, + FF185ADF983855172EE9FA3D34A91DD6 /* POPDecayAnimation.mm in Sources */, + 916B7BBE0652142389AB4290D8E4ECB2 /* POPGeometry.mm in Sources */, + C03ACB5DC566E5F4BCC725F8A8D6F195 /* POPLayerExtras.mm in Sources */, + 862060E613DA5CEF2678D462DA797828 /* POPMath.mm in Sources */, + 954B302CD45EB32FEC37295F3EC0206C /* POPPropertyAnimation.mm in Sources */, + C46A8064365E409811A4E812177A4041 /* POPSpringAnimation.mm in Sources */, + 1005515B34A7CCF2EF97A317B71D2632 /* POPVector.mm in Sources */, + B253780C6017BCC8E3B9457E3048462C /* TransformationMatrix.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 626D5271FA62C2E787E92C0C06118473 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C13E0E83471C1104A40CB5D928C5C78 /* Pods-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 678CA587F9F0CD82C2737EC72B7D49E6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BB1151A40AE6E5AA064A5AAC684EEF46 /* _FBSDKTemporaryErrorRecoveryAttempter.m in Sources */, + D5EE317B7D0E35A376DF8328CEA3252B /* FBSDKAccessToken.m in Sources */, + 33E51CF359A60B9BF66BE9C279AB3E43 /* FBSDKAccessTokenCache.m in Sources */, + 9B7B596E21B20063D8870D27F93990BF /* FBSDKAccessTokenCacheV3.m in Sources */, + D4163483905F3CE49898DD8AAC0E0910 /* FBSDKAccessTokenCacheV3_17.m in Sources */, + 4BC610C052636A802256616F808FD2AE /* FBSDKAccessTokenCacheV3_21.m in Sources */, + E159EF1028A9794B189D47DD79C6A0CC /* FBSDKAccessTokenCacheV4.m in Sources */, + 74B1B04C2705C12FDA25D308C6F8F669 /* FBSDKAppEvents.m in Sources */, + 3B88684885F6A92894F9B1C6DF2CB127 /* FBSDKAppEventsDeviceInfo.m in Sources */, + FF6C07931C151FAE59F3FB55F032AF23 /* FBSDKAppEventsState.m in Sources */, + A9D01434F1CFFFF1277E3429A43FA1C0 /* FBSDKAppEventsStateManager.m in Sources */, + 2A2484F1773729BB256973910B7340DB /* FBSDKAppEventsUtility.m in Sources */, + 1D840EA09132B2B34413FA16BD0E1AA5 /* FBSDKApplicationDelegate.m in Sources */, + 7CE53AEEEB82A1729F0A343B85F1FA7E /* FBSDKAppLinkResolver.m in Sources */, + BC852E5C003C0E1C337D9C642F826513 /* FBSDKAppLinkUtility.m in Sources */, + BFAAE2E16A1F2007BD7CDF1DB8D2CDAD /* FBSDKAudioResourceLoader.m in Sources */, + 25C893D3F81918CA2748927B5F02A595 /* FBSDKBase64.m in Sources */, + 8D9E418F4BF4FF9ABF3F4E5932589C3D /* FBSDKBoltsMeasurementEventListener.m in Sources */, + 77B5397CB9EB225E9C0BB7318B12E949 /* FBSDKBridgeAPICrypto.m in Sources */, + 86444AC2A924F63C45BEC54A0DDB7E8E /* FBSDKBridgeAPIProtocolNativeV1.m in Sources */, + C0C7A1E73D584A4F93A286FA1753D5B1 /* FBSDKBridgeAPIProtocolWebV1.m in Sources */, + 2E87F7494BC2023ED83CCB2C93E67B69 /* FBSDKBridgeAPIProtocolWebV2.m in Sources */, + 1345483A67FB02C778D2D3639930AED7 /* FBSDKBridgeAPIRequest.m in Sources */, + E81433D0931C25789180EA53A62C940E /* FBSDKBridgeAPIResponse.m in Sources */, + 18CF81105FB6E0685A26F83F128F4E47 /* FBSDKButton.m in Sources */, + 6C6B44FB16E5ABD292E2D77D89DDFF32 /* FBSDKCloseIcon.m in Sources */, + 8392255CCB63818562D4F58555DDDB08 /* FBSDKColor.m in Sources */, + E497F7EAC903A7C28D8CC1FD0D90CCDF /* FBSDKConstants.m in Sources */, + 905D0A5FE23B08D47AA9AB3F584B626D /* FBSDKContainerViewController.m in Sources */, + A4AA61EF4E7E175383F829835B3690B6 /* FBSDKCoreKit-dummy.m in Sources */, + 9E1DFD298D2638A443CF2EA5B47BFC51 /* FBSDKCrypto.m in Sources */, + C95B6FEA0DB3899E1F52C07D40DD4DA0 /* FBSDKDialogConfiguration.m in Sources */, + 2A9CDB714501BF7551C376135E06CB77 /* FBSDKDynamicFrameworkLoader.m in Sources */, + 9D1E20F07E1C09F60E2F35F6119A0F42 /* FBSDKError.m in Sources */, + 2F4C116B777496BAB15E7D6442D221BF /* FBSDKErrorConfiguration.m in Sources */, + D466AEB0B97EDC9663AFFD5F94C04630 /* FBSDKErrorRecoveryAttempter.m in Sources */, + 3B34B9CF9A34E235FD457006303C757D /* FBSDKErrorRecoveryConfiguration.m in Sources */, + 8CDAFE25429AD7F8885827F293890076 /* FBSDKGraphErrorRecoveryProcessor.m in Sources */, + 41CCAB61BAA581E58CB30F56F9F372F4 /* FBSDKGraphRequest.m in Sources */, + 1F2BB357DDF0A1CE916761ED5DBB98D2 /* FBSDKGraphRequestBody.m in Sources */, + 9F3D3656F5864DED6AF668D1AB68975E /* FBSDKGraphRequestConnection.m in Sources */, + 361A366D11CECA15C3B45FC3ACEDA050 /* FBSDKGraphRequestDataAttachment.m in Sources */, + 591FE63D036F4A539784293BCAD97493 /* FBSDKGraphRequestMetadata.m in Sources */, + E6D6A687F8FD1088F5EBB283308B0DC2 /* FBSDKGraphRequestPiggybackManager.m in Sources */, + A661008071892B0148336A0636FC59A1 /* FBSDKIcon.m in Sources */, + A18206D679C80B4AFF6654B5677DBFDB /* FBSDKInternalUtility.m in Sources */, + 41DDB4BD2A89F44F733C82B65BE76ACA /* FBSDKKeychainStore.m in Sources */, + D3CBA0C9A2F20A2AE8D9E8FA5F2326DA /* FBSDKKeychainStoreViaBundleID.m in Sources */, + 774E19492156820F5CC848D34D9AA4A6 /* FBSDKLogger.m in Sources */, + 25435509864D8830160361E72AA5E31F /* FBSDKLogo.m in Sources */, + 83C5AD87D4B7BF94A4B000FC4C254798 /* FBSDKMaleSilhouetteIcon.m in Sources */, + 97996933B25E24DAF9D18F8E188B03CA /* FBSDKMath.m in Sources */, + FA27E23894DFC2F77A0EA14C2D1A3DD4 /* FBSDKMonotonicTime.m in Sources */, + E97B61F439BAE5B0BC4AE0382AF6E4B3 /* FBSDKPaymentObserver.m in Sources */, + EE76A64B08255C079A379BC77864B85F /* FBSDKProfile.m in Sources */, + DA96A28C136407B16A3F0C70656042AF /* FBSDKProfilePictureView.m in Sources */, + 42F787E07A69C27C09E049303C8E8530 /* FBSDKServerConfiguration.m in Sources */, + E461DC7FBE41300801EE6D160AE29860 /* FBSDKServerConfigurationManager.m in Sources */, + 82360B32AC1B887E85DC592D62CB046F /* FBSDKSettings.m in Sources */, + D97FDB91BBA6D010CA658A611FC4A9A1 /* FBSDKSystemAccountStoreAdapter.m in Sources */, + 264457704BDD888C92CAAEBE20E709FC /* FBSDKTestUsersManager.m in Sources */, + 1D66DABAD4D2C36AAF8062BE3D55C7DB /* FBSDKTimeSpentData.m in Sources */, + EA3208DE2E2A3C5B240A0C832A77DDCF /* FBSDKTriStateBOOL.m in Sources */, + 5E1AB8EC72407D7A56EE8074AC99F4AC /* FBSDKTypeUtility.m in Sources */, + DDAB1F17EC68C8B719BA8C80FB5DC317 /* FBSDKURLConnection.m in Sources */, + 69F828062553D0A5623207630EB9FB21 /* FBSDKUtility.m in Sources */, + 9AB561BA236CB930E21B38DE886155A6 /* FBSDKViewImpressionTracker.m in Sources */, + 578485DD86226126B8E08842D826D2DC /* FBSDKWebDialog.m in Sources */, + 899C1F6FEAF906667F0E67D51EDA44FD /* FBSDKWebDialogView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6831413FDAC4F2DD02AF35510D60199B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7491B632AA9E26DA9BC69374DE8BF0FA /* ISO8601DateFormatterValueTransformer-dummy.m in Sources */, + 9CF9ABEBAA86E37078F793BAF2C4F18B /* ISO8601DateFormatterValueTransformer.m in Sources */, + CF61365D13FDC0E6A145C012AB9B98AE /* RKISO8601DateFormatter.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 688B805CEFC0CF8022B905243A59A50E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C5FC139D9A229EC782BD8D26071C29E /* BFTask+Private.m in Sources */, + AFD33F9C5B99DD2201D2F07DBB808E79 /* Parse-dummy.m in Sources */, + C0575A904CA77375C3DC6B600B99CEAD /* Parse.m in Sources */, + B3539900ACA90E11ED43DD92C1AC3C8C /* ParseManager.m in Sources */, + BAB82247B24428DCAC2A4F4E9207F60A /* ParseModule.m in Sources */, + 9BFBEB3B8ABB7F24555374DAFDEE5A43 /* PFACL.m in Sources */, + E7C91F488C152026DF77891E905E49BC /* PFACLState.m in Sources */, + A721709FC277E75DE5C95BB094C3D554 /* PFAlertView.m in Sources */, + DA957B3EC09252118B3E9ABE033421A5 /* PFAnalytics.m in Sources */, + BD8A5E25C13BF645294D97EB1ED09CA0 /* PFAnalyticsController.m in Sources */, + 2E8782D39FA5B415D526EBE5C8AFA32E /* PFAnalyticsUtilities.m in Sources */, + 1BFCFA4856B9BE43C5FB24EA58662689 /* PFAnonymousAuthenticationProvider.m in Sources */, + AA196672E44A737889F2795FEA012F6D /* PFAnonymousUtils.m in Sources */, + F7DD4882D66BDDF093E01A1050E60F2E /* PFApplication.m in Sources */, + 7E6125121D979F1802CAD8FB88B66E4C /* PFAsyncTaskQueue.m in Sources */, + 05E1825A084B452E32D6063463B3FDDB /* PFBase64Encoder.m in Sources */, + D224C6471A4DA408043B4E72EA97721E /* PFBaseState.m in Sources */, + CCF1CD4428BA2944666A829E767A6C15 /* PFCachedQueryController.m in Sources */, + 81BBD301442755592686C551DE726C06 /* PFCategoryLoader.m in Sources */, + 9F309454D3B0FA1C2701DD3226C97074 /* PFCloud.m in Sources */, + 2D7129239566598FD9FC8204D9D26793 /* PFCloudCodeController.m in Sources */, + 35A2D271C4A91DC464251B9245103DB5 /* PFCommandCache.m in Sources */, + C0CA4956B32616DC4919F00A7EC9B92C /* PFCommandResult.m in Sources */, + 0AD287666FAFC490CAD4CBFBF47431AE /* PFCommandRunning.m in Sources */, + 2E29ABDC3BF7E6B7FF03C02FDD08B45F /* PFCommandRunningConstants.m in Sources */, + 2FC94CCAED9DD09203580A70DECF2A4A /* PFCommandURLRequestConstructor.m in Sources */, + 3CCACCF079947A68FE7E62AF0303CAC3 /* PFConfig.m in Sources */, + 0E47EB82346F3A93F6FC3AF3AEA778E3 /* PFConfigController.m in Sources */, + 86201505E0AE8888C1DE7E594A2D17E9 /* PFConstants.m in Sources */, + 95D14872174A30E8C238C5334ED744D4 /* PFCoreManager.m in Sources */, + 577FB11637F9A3CF218053ADC3A5F10E /* PFCurrentConfigController.m in Sources */, + 5557E69BD0A14921486F9974F746737C /* PFCurrentInstallationController.m in Sources */, + A1752CBBCEED5A344FDA136B0EF771A5 /* PFCurrentUserController.m in Sources */, + 1DD3895D39730377AEA9BEA6D66767CA /* PFDateFormatter.m in Sources */, + 89564402FD876B2472994636049AC191 /* PFDecoder.m in Sources */, + DCA33BB2A983A45F3617A576ACBC26E1 /* PFDefaultACLController.m in Sources */, + 227CE567B059758E1C977990BFAD75AF /* PFDevice.m in Sources */, + 6D1ED30B474D96450E7B0D1E548CDC60 /* PFEncoder.m in Sources */, + 94812F8C5A752C24A9B6D7635CB77A89 /* PFErrorUtilities.m in Sources */, + 087E876A250108F964ABA6E268BE5846 /* PFEventuallyPin.m in Sources */, + 7E7AB5CD972320B0ADA45CD3A96BF892 /* PFEventuallyQueue.m in Sources */, + 2DE0A008B557C991779E119572071163 /* PFFieldOperation.m in Sources */, + 63B17895BA064D712385A40C63BD7EA2 /* PFFieldOperationDecoder.m in Sources */, + 86043DABC677904AEAAD37E3C8981439 /* PFFile.m in Sources */, + ABBA98083D66AA8745D3CE85508A4B54 /* PFFileController.m in Sources */, + AD0387E79E49576C00BEAED9E903F6B9 /* PFFileDataStream.m in Sources */, + 438CA2F1118781D63B470E41E4C7889C /* PFFileManager.m in Sources */, + D5DE272410B216A538955743C7C9574F /* PFFileStagingController.m in Sources */, + 9634B50A041722E070888114E161E4EE /* PFFileState.m in Sources */, + B072A694A0A46131BB3A56636471FAE1 /* PFGeoPoint.m in Sources */, + 8E5C4F9E02DA0CE1FB4656E19A803A23 /* PFHash.m in Sources */, + 74EB4B274B8CF5543B9DB2B77394CC60 /* PFHTTPURLRequestConstructor.m in Sources */, + 267A29AA34A9D757450EBE41A4A5F40B /* PFInstallation.m in Sources */, + 4BABB36619011AA0B6039422203CFC5E /* PFInstallationConstants.m in Sources */, + 4D2FE3A028403C4E9545B01159BBE9CB /* PFInstallationController.m in Sources */, + 857C325B0A6E76A01EACF737B6D4FD1A /* PFInstallationIdentifierStore.m in Sources */, + 082462DCFDC7A19F595743F10C8EC7EB /* PFInternalUtils.m in Sources */, + F6439BF34231EC9F4CBB3F01C862CEFA /* PFJSONSerialization.m in Sources */, + 5DD4705F866F09E0FA008D068DD31F48 /* PFKeychainStore.m in Sources */, + 2ADFEB8C12A6F30CE83BC5AB3316C6E4 /* PFKeyValueCache.m in Sources */, + 22C38A31A84F31B9EF5B40892497DA44 /* PFLocationManager.m in Sources */, + DF6FA2E0FCB935C5FF9824699BF32C2F /* PFLogger.m in Sources */, + B91DBAED5B544D03577FAFF5722F865E /* PFMulticastDelegate.m in Sources */, + 80AC86A7716C9D9FE484C461CECF64A5 /* PFMultiProcessFileLock.m in Sources */, + F728C30DC692908961A286369C3A5D56 /* PFMultiProcessFileLockController.m in Sources */, + EC988E57B95BF4C3D8D67B5A3B382A8C /* PFMutableACLState.m in Sources */, + 37C6195201D97353994A4B323BD7EC39 /* PFMutableFileState.m in Sources */, + 824F558CFBB6BFD7FC2D2E9FB1FCA5B3 /* PFMutableObjectState.m in Sources */, + 86EF71FE1E8C350F37E45235765F15F4 /* PFMutablePushState.m in Sources */, + 269ABC30C8CD9E74E46491F5B6FB9D17 /* PFMutableQueryState.m in Sources */, + 893E921270F96758F3799A3949DECB9E /* PFMutableRelationState.m in Sources */, + 580B7575D5092F73CADB0DC057A8DD20 /* PFMutableUserState.m in Sources */, + 7C9D94C465AE6FEED19A76EF32EE9DB0 /* PFNetworkActivityIndicatorManager.m in Sources */, + 1DA6669105771BA38E2C69FDC90286A6 /* PFObject.m in Sources */, + 8A96BC7922311E4546CA119B3CF1249D /* PFObjectBatchController.m in Sources */, + 7DAD345A47688CC2FF5EEF4E6576DA9D /* PFObjectConstants.m in Sources */, + AF896EF80A89E677C2FEAD7D25B5CA13 /* PFObjectController.m in Sources */, + 8A9D36221679B9C6AF86158044A8AB80 /* PFObjectEstimatedData.m in Sources */, + 14D6E494E0D7E904AD960AE602238451 /* PFObjectFileCoder.m in Sources */, + 8C62414E0ABD89DD5A595B207B4F3DA8 /* PFObjectFileCodingLogic.m in Sources */, + 854828D77E6CD3D9B82D9498EF24E92E /* PFObjectFilePersistenceController.m in Sources */, + 641656C3A17793081B0B55EF4183369C /* PFObjectLocalIdStore.m in Sources */, + EE0DAF5E510D971C9A34D617DA2438EC /* PFObjectState.m in Sources */, + 1B3FD4504118844C3450B1F75C2EC2B1 /* PFObjectSubclassInfo.m in Sources */, + 02A63183E1CD64A36C6C93A5A33A2CC8 /* PFObjectSubclassingController.m in Sources */, + 17D0DD03C923128099A9737F317E5D29 /* PFObjectUtilities.m in Sources */, + 5A3E09336161889373CC89326260ADE5 /* PFOfflineObjectController.m in Sources */, + CD714C0FC030441A7466E26DE9A3AC29 /* PFOfflineQueryController.m in Sources */, + 324B462950BF05B9CF8C8B4E1556D1A3 /* PFOfflineQueryLogic.m in Sources */, + AB61AD540531ED95F49168BD4C8C1936 /* PFOfflineStore.m in Sources */, + D1E16869A350E851F31AE83FAB93361B /* PFOperationSet.m in Sources */, + C7ADD9A2DC3411145922D13FE552AD20 /* PFPaymentTransactionObserver.m in Sources */, + 5624B5B3EB50D43FB54BACDDB45228AD /* PFPin.m in Sources */, + 2BE316C68D11EAF02F9288B25FEFF2B8 /* PFPinningEventuallyQueue.m in Sources */, + B2ECB596CD8B0A8925E2221C87668493 /* PFPinningObjectStore.m in Sources */, + 4075B036E32B6718E9B9523BC0059DF2 /* PFProduct.m in Sources */, + F1FB40054787172F5817A61DF16AA000 /* PFProductsRequestHandler.m in Sources */, + D6027C66071A9702E15C8A733DBF6FF6 /* PFPropertyInfo.m in Sources */, + 8CDA43D636A5808F5E87A816EB9F0D78 /* PFPropertyInfo_Runtime.m in Sources */, + 1961C4A9AD59A951688C260E91482AA0 /* PFPurchase.m in Sources */, + 4FC468A52568F12ED267007F0AD753FC /* PFPurchaseController.m in Sources */, + 91D8984FCF7711FFFA4E5A8795A49B19 /* PFPush.m in Sources */, + 150FD95BCF7C18E9717A863C6B645DC6 /* PFPushChannelsController.m in Sources */, + D808382848DE98DF7860D36066C0B58B /* PFPushController.m in Sources */, + 07ED5D3AADD2C1C41BD215C19C4E48C6 /* PFPushManager.m in Sources */, + E06A12A765D316CFB2E9E26FB48C3AC1 /* PFPushState.m in Sources */, + 9F04CB08F3037EDF755036F82BCC418F /* PFPushUtilities.m in Sources */, + 560BB49A70689476862EE5E1F179D36A /* PFQuery.m in Sources */, + 658F5F398CDC2959D9D80E71D58CF261 /* PFQueryController.m in Sources */, + 946BB4E027BBEDA5EC360607902B1EB0 /* PFQueryState.m in Sources */, + 5D8F8D57EC3D51CD74969DAA5BFBC15C /* PFQueryUtilities.m in Sources */, + BA9C553426A8678957BAED9B891E4B96 /* PFReachability.m in Sources */, + 0301C8C6C03DB444A51A086E29571535 /* PFRelation.m in Sources */, + 55F36BBE4FE82BCCD0C9A4E06DC26BEF /* PFRelationState.m in Sources */, + 1A8EA6EABBDB4F9D5170BBC9F31E9FB9 /* PFRESTAnalyticsCommand.m in Sources */, + 4348B4727F59DB738A1A33721BB29AA8 /* PFRESTCloudCommand.m in Sources */, + 62D812F2EF8DA118C618FF5349055C57 /* PFRESTCommand.m in Sources */, + 7A67EA6F03AFFE55FAA759B11890E468 /* PFRESTConfigCommand.m in Sources */, + DD60532519B073DDC5A56E7426B983B4 /* PFRESTFileCommand.m in Sources */, + 1CE911A8315F4C7A5844415DC9933260 /* PFRESTObjectBatchCommand.m in Sources */, + 2F8A6D5D298FE5F63CFA909D0A63D26B /* PFRESTObjectCommand.m in Sources */, + 864CF85CA92D5D4313B0A57692C45881 /* PFRESTPushCommand.m in Sources */, + 2D4F9228E33B7CB031B9344EA22E3AE7 /* PFRESTQueryCommand.m in Sources */, + 0DA197860573F04B990BB55CED47EB2F /* PFRESTSessionCommand.m in Sources */, + DB8CE9C5C660790137E0C7B7364E8E82 /* PFRESTUserCommand.m in Sources */, + E0E49C694EE64CD46539BAD3D4F08AC9 /* PFRole.m in Sources */, + CF49D485A500B363E1DDEF68072F9F36 /* PFSession.m in Sources */, + 57BDE2372BC4BBC34CAB643A2A95E416 /* PFSessionController.m in Sources */, + E0724D062B05BEC513826196D0DF36F2 /* PFSessionUtilities.m in Sources */, + 2E74D36D8D8BAD8D55380944015FD120 /* PFSQLiteDatabase.m in Sources */, + 716A44DCF2417118DDAEAD57B69029BA /* PFSQLiteDatabaseController.m in Sources */, + A3353245628DEA268387441F4EF31877 /* PFSQLiteDatabaseResult.m in Sources */, + B00E930CCC7EF81612BF8392339E17A8 /* PFSQLiteStatement.m in Sources */, + C63F51531975AE0BE6BC871568A6475D /* PFTaskQueue.m in Sources */, + EFB0AF9D9768F6BD8723FFCB40AD7D39 /* PFThreadsafety.m in Sources */, + C8DF39D35A8ACF9F10F8392AF8C407A0 /* PFURLConstructor.m in Sources */, + D33E2DE9B21F540B2BF1812B90F33155 /* PFURLSession.m in Sources */, + 0ECA745830D272585C68ECDF8C5569D7 /* PFURLSessionCommandRunner.m in Sources */, + 36CB170B89C0B4642CB663616BC47E5B /* PFURLSessionDataTaskDelegate.m in Sources */, + E0DEC8F4B52DC0BDAD4F633262232B7D /* PFURLSessionFileDownloadTaskDelegate.m in Sources */, + 5774AA430101105FF0F41887984D6011 /* PFURLSessionJSONDataTaskDelegate.m in Sources */, + A56E60590F48B3C632A71A0B970F8E90 /* PFURLSessionUploadTaskDelegate.m in Sources */, + 93511A4AF61BEA29A4FD4EEE7157E023 /* PFUser.m in Sources */, + F743978153F2A7013B2066B1B306E5F5 /* PFUserAuthenticationController.m in Sources */, + 9934291C79A7EBE51544EDDB2193FD01 /* PFUserConstants.m in Sources */, + 3515249853196B72457D26E35A75A0D5 /* PFUserController.m in Sources */, + 2CC921A632237030D7C642FF4D3E2216 /* PFUserFileCodingLogic.m in Sources */, + 02551F124693A0300B457431E75E3AF0 /* PFUserState.m in Sources */, + E5BE3915A6A2859B581A8300E69A2B8E /* PFWeakValue.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6D58EE024B08316911051FCE3FA6EBDC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DE479B83E277F9913E9A6CBE17BD6B3E /* FBSDKAppGroupAddDialog.m in Sources */, + 18EAF4167A160D50758673E49250402C /* FBSDKAppGroupContent.m in Sources */, + CFFAEE251FC130E14DF2831B504F748D /* FBSDKAppGroupJoinDialog.m in Sources */, + 0A6A5BA0942FF096A2D641E8F49C0F79 /* FBSDKAppInviteContent.m in Sources */, + CEF61BB75902C8E0148259A5DF63854E /* FBSDKAppInviteDialog.m in Sources */, + 3053488EEEBCD0385576315DBE9EC11E /* FBSDKCheckmarkIcon.m in Sources */, + 8071A999E075ED48380A5AAACDA0E0E9 /* FBSDKGameRequestContent.m in Sources */, + 8C66B8A503EE7CDAF2C8B843D7839113 /* FBSDKGameRequestDialog.m in Sources */, + 3C6DF2FA1EA6BE60192A77E7270D6212 /* FBSDKGameRequestFrictionlessRecipientCache.m in Sources */, + F10CE2BA1CE785FB8EC2CE0595A7FBBE /* FBSDKLikeActionController.m in Sources */, + 2FB0531893E490ACEC556B0F43C44591 /* FBSDKLikeActionControllerCache.m in Sources */, + EED88C9780961006A6F988AFECD7BED3 /* FBSDKLikeBoxBorderView.m in Sources */, + F7E42776080FF0BDBE07365A2AFE2834 /* FBSDKLikeBoxView.m in Sources */, + F9198070ED60C8E1F3AF0910B05EA446 /* FBSDKLikeButton.m in Sources */, + 796EC3DD53C2C28010D03E1E323A1DDB /* FBSDKLikeButtonPopWAV.m in Sources */, + 3DDFA2D0FCEE1978143B685D1C3A9D7A /* FBSDKLikeControl.m in Sources */, + 21E2ED6EFD8559848B98705909DEA010 /* FBSDKLikeDialog.m in Sources */, + B28E7BE90D0898F34164A3649D16E978 /* FBSDKLikeObjectType.m in Sources */, + 081F6FAFE0FC8BD6EFC6A517B0ADB614 /* FBSDKMessageDialog.m in Sources */, + 4A7FBB52488D368CFDFDB1B6516C2CE4 /* FBSDKMessengerIcon.m in Sources */, + B4035BD0031BD154E70AF698B10B48A7 /* FBSDKSendButton.m in Sources */, + 1E8874FFFC0B19D20C001681F1942855 /* FBSDKShareAPI.m in Sources */, + 34B1786FA4EBC179AC660B83CF1A4F82 /* FBSDKShareButton.m in Sources */, + 4458C6C127D3030A17A791B3BA9A0CE0 /* FBSDKShareConstants.m in Sources */, + 4A4CF9C7D69DC9049FD677165FADA59E /* FBSDKShareDialog.m in Sources */, + 827A9685D68B9BD092DD85970625C1F2 /* FBSDKShareDialogMode.m in Sources */, + 98350E1EE789CEB57D91ADF6F225D62E /* FBSDKShareError.m in Sources */, + 2BFE426FBB2EF7A91EAC0893828A3F5C /* FBSDKShareKit-dummy.m in Sources */, + 16E3CEBF59A2D8E5A9B04AF979FDF14A /* FBSDKShareLinkContent.m in Sources */, + BAF2CCC3F6782690F1534565B877278F /* FBSDKShareOpenGraphAction.m in Sources */, + A31552A8B1F14534DDBA1DFC4E09C195 /* FBSDKShareOpenGraphContent.m in Sources */, + EBE1D926D326775167E082772E23D000 /* FBSDKShareOpenGraphObject.m in Sources */, + 51F742896037EA588D6157B105922B77 /* FBSDKShareOpenGraphValueContainer.m in Sources */, + 2763640E3F9F25BCE1BC36B60364A740 /* FBSDKSharePhoto.m in Sources */, + 2B868B020F9C681F76C506EF6BC9A801 /* FBSDKSharePhotoContent.m in Sources */, + 29E9B7D045DD5219B0D17A1289A1E228 /* FBSDKShareUtility.m in Sources */, + E571D44B22235633760C6FB955906D99 /* FBSDKShareVideo.m in Sources */, + 57503516957EEFAFFAD7A789730E7B9C /* FBSDKShareVideoContent.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 78D1430387219E1CEECF694664B47298 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 168754543C69B5763F69864E4180CA20 /* AFHTTPClient.m in Sources */, + 6E7A504266921DE5FEDD84D1A38F473F /* AFHTTPRequestOperation.m in Sources */, + A71645666E899BA6FCD0A105BCF4554D /* AFImageRequestOperation.m in Sources */, + 977939FF92D57042F939439588EB0E6F /* AFJSONRequestOperation.m in Sources */, + 28E0C7D4EAB83F94E8BED7A8A6588F17 /* AFNetworkActivityIndicatorManager.m in Sources */, + 9EFD8B6E9A0DFB23D0458D0071283130 /* AFNetworking-dummy.m in Sources */, + 958CCFDA315803AE6E8B769C3985BF57 /* AFPropertyListRequestOperation.m in Sources */, + C920759127C01FDD99644BB6806F24FC /* AFURLConnectionOperation.m in Sources */, + 6D3FD8968A8524A1D88687C9861581B7 /* AFXMLRequestOperation.m in Sources */, + 3EC6C51767337E859A4F15C5FBC1770E /* UIImageView+AFNetworking.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7A32D54FA40FEF860E67B9E9E2AE0993 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FB1E08557D01F434CD5C340084CC4AE1 /* RKValueTransformers-dummy.m in Sources */, + 0EF3F474C4F968CC78351909F0C76A70 /* RKValueTransformers.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8FDCE15764753ADC3473510DD6B2D8B5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A48B34E8A4056CAF37BF815D80F851FB /* TKEvent.m in Sources */, + 16A0D1D260C2A0C9456093033B7B2704 /* TKState.m in Sources */, + 3618426AB7A42805D853A084743D6138 /* TKStateMachine.m in Sources */, + 9DC8CA8457330A93C4CCC547F530F6A0 /* TKTransition.m in Sources */, + F935343777FB6C7405A086E0FA59F28C /* TransitionKit-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E890AF42CB01E48E4575A2E6468A4288 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9519538BB8C70220B80F280767FD1CE4 /* lcl_RK.m in Sources */, + 04885DFC809E60B33C73D0262CCD3D7B /* RestKit-dummy.m in Sources */, + 0601A5D463502C68B57F87216DC01E47 /* RKAttributeMapping.m in Sources */, + C674B4D84DEE46658392F9A5C6CE6429 /* RKBenchmark.m in Sources */, + BAF2D4F797832511A4718AE2F9D4C9E2 /* RKConnectionTestExpectation.m in Sources */, + 6370111F8E53B9FCB359DE67FB0A5768 /* RKDictionaryUtilities.m in Sources */, + 558CA36485EBAAE1ACFC94ECF26A4C13 /* RKDotNetDateFormatter.m in Sources */, + 1E37A7B04ECBE439CE8A683823B663B7 /* RKDynamicMapping.m in Sources */, + D9CF728584EBF7AD231EF28A2BB2F158 /* RKErrorMessage.m in Sources */, + B1864DAD1E71AE119D92AD90D4075B44 /* RKErrors.m in Sources */, + FD60C452AEB7A05724E5BC76D389C794 /* RKHTTPRequestOperation.m in Sources */, + 3E00A40C8893EE63BA63D4A9008594A7 /* RKHTTPUtilities.m in Sources */, + 591282C08F383491158606060CF4799A /* RKLog.m in Sources */, + 5290E96A370ECE9B13F91391BFECE059 /* RKLumberjackLogger.m in Sources */, + ED6709D08D9B015AB6FC3F9A6B207DD3 /* RKManagedObjectRequestOperation.m in Sources */, + 329EEBF461254C9F4C4F7DFF196498F3 /* RKMapperOperation.m in Sources */, + AABB7281DE92C99CC47D5985438FFAF8 /* RKMapping.m in Sources */, + 1B3C45012DD6C877AF2B3757B48D2CEA /* RKMappingOperation.m in Sources */, + 8F8BE93BB0467F675822961A702D55F1 /* RKMappingResult.m in Sources */, + 83A32D0DCD7B1179BE18D0B98A61B20D /* RKMappingTest.m in Sources */, + 8173E2EA7A6ED5AF96950F1C983E7D8E /* RKMIMETypes.m in Sources */, + 37623963889357DF56CD5A4023A293D0 /* RKMIMETypeSerialization.m in Sources */, + E10ED2683F83860B93799B1241CE8C22 /* RKNSJSONSerialization.m in Sources */, + 1B7C3D5167896D20FDA7AD2B99B9B442 /* RKObjectManager.m in Sources */, + E2360651E2E5A293C9E59863EC157308 /* RKObjectMapping.m in Sources */, + 51A4B3F64553C8AF7DAD4F16035044C7 /* RKObjectMappingMatcher.m in Sources */, + 0B96F448CA70A5E1B7389BD7015EFE01 /* RKObjectMappingOperationDataSource.m in Sources */, + BADD59CEDAC52C54651BF484D6490C67 /* RKObjectParameterization.m in Sources */, + 562CF85B86D5B01C4F9A7B9ADB016D2C /* RKObjectRequestOperation.m in Sources */, + 798D21067BF1C22C12D8A94001BF5A59 /* RKObjectUtilities.m in Sources */, + F7B6B5468F0E365CBF4AC5F003E17684 /* RKOperationStateMachine.m in Sources */, + CF027C0D4F7C6873C8BEA392044BE467 /* RKPaginator.m in Sources */, + B4AECD7B0079602334FD0CA11106AC3F /* RKPathMatcher.m in Sources */, + AFCC73E1C178EA83628FBECB44C75A50 /* RKPathUtilities.m in Sources */, + 872A4C2396A30AA64CF2786166CB6562 /* RKPropertyInspector.m in Sources */, + 5BAB981C0B0E5CA4456C701E0D4C8C3D /* RKPropertyMapping.m in Sources */, + 4864EC253C572D7696B5849BB72291D0 /* RKPropertyMappingTestExpectation.m in Sources */, + 6239684B7D89D4F446BF5B4383804BFE /* RKRelationshipMapping.m in Sources */, + 609CCC1A9F655B5B7E6F6D3FF89E80D5 /* RKRequestDescriptor.m in Sources */, + 440457C5E92E83101E8970FFC6086762 /* RKResponseDescriptor.m in Sources */, + 22BB0A3493753E3DE40426F8E2A8D98F /* RKResponseMapperOperation.m in Sources */, + 52D0E5B4BE2960D5264CA76B3287BA53 /* RKRoute.m in Sources */, + B0C1C3993C766809A801540862C105E2 /* RKRouter.m in Sources */, + 5F51961B26B43B74BC1F3504C2AA68ED /* RKRouteSet.m in Sources */, + 13F6C4E6B73C633E8D58029DEB14DF5A /* RKStringTokenizer.m in Sources */, + 0059AAF7BDA07F6056221CE7D55CFE28 /* RKTestConstants.m in Sources */, + 01CEDCC7CB1512AB0E0F3D84C2F12918 /* RKTestFactory.m in Sources */, + 451A0964C7CDBD5043BBD97DD3BB59EF /* RKTestFixture.m in Sources */, + A3F739BF4CBFB653314B4737DABB5E7B /* RKTestHelpers.m in Sources */, + 275BF668E4B40AEBF35F411A56F05B6D /* RKTestNotificationObserver.m in Sources */, + FCAB2361E009734F6BE467ED760F2E00 /* RKURLEncodedSerialization.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0165668441754BC1FA06647E5E8B1BC2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Parse; + target = 5366B7F679CF2BA31EA583EA35CA2D90 /* Parse */; + targetProxy = E06E7B292C6EE211982F723016ADBF4B /* PBXContainerItemProxy */; + }; + 1B3E7005E90372159541C07635478C09 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FBSDKShareKit; + target = C78CAB9013653EB1A250B2DFD3BC7666 /* FBSDKShareKit */; + targetProxy = 276A34C32823D237C256532097A068EB /* PBXContainerItemProxy */; + }; + 29DDDD2855AC6B907DDB5A2453363AD9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = TransitionKit; + target = 05AF921757BAF218468C62708B020AA6 /* TransitionKit */; + targetProxy = D1818ED7610953D782FE1124E1218D77 /* PBXContainerItemProxy */; + }; + 2E0A25F4A4A85AC834C7F15468F5B337 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FoldingTabBar; + target = 9145E070690055EA2D82D264E78B0F71 /* FoldingTabBar */; + targetProxy = FAD9FE9F58E1BE6A32DD807949F6E4A4 /* PBXContainerItemProxy */; + }; + 2F5F18AEAFEBEC26EA2C13A32E9D1852 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = C47E006176ABF4755350B88C088C3F0D /* RKValueTransformers */; + targetProxy = D0849CD3CF9A05520CE20A883B2B4F39 /* PBXContainerItemProxy */; + }; + 311341FA67358AAF209E4F9F0C4466F3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RestKit; + target = 0EB292B9319B2DAFB20D9A12B70C9D45 /* RestKit */; + targetProxy = AF0BFB883EC6A98CD8AE8E24C8F426B1 /* PBXContainerItemProxy */; + }; + 3E4988ED810AD321E1E9DFEC13FEC872 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FBSDKCoreKit; + target = 81D7FE2A0FD9258247B1232874B837DA /* FBSDKCoreKit */; + targetProxy = 302ED64CEF8BCEB768A5A5686F9E9202 /* PBXContainerItemProxy */; + }; + 4909A8706666DFDB01A2C76C5D573D69 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = C47E006176ABF4755350B88C088C3F0D /* RKValueTransformers */; + targetProxy = 4201516B1237D71DE5D182C3E05A7889 /* PBXContainerItemProxy */; + }; + 7ED5415B6800424874AAD35E3516EE07 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SOCKit; + target = D8FDBC10A40DB83968987CBA76E4F7DD /* SOCKit */; + targetProxy = FE69D65D7B77276503ADD40689F26FD5 /* PBXContainerItemProxy */; + }; + 80F8A239034C4CB916F792A309A7D049 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ISO8601DateFormatterValueTransformer; + target = 080AF914A09167DB5759A733917B840F /* ISO8601DateFormatterValueTransformer */; + targetProxy = A909E61D233546F6A1FB381F7E377CA7 /* PBXContainerItemProxy */; + }; + 9A5270C4EC04E2D2E511996DDEDD58C5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FBSDKCoreKit; + target = 81D7FE2A0FD9258247B1232874B837DA /* FBSDKCoreKit */; + targetProxy = D38BE89B6FB2301AC09AD26156B819E8 /* PBXContainerItemProxy */; + }; + 9FCD970EABEC67BFA1394916D7ED1CC9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ISO8601DateFormatterValueTransformer; + target = 080AF914A09167DB5759A733917B840F /* ISO8601DateFormatterValueTransformer */; + targetProxy = B1A299548977B6ABB67A7B67B42367D6 /* PBXContainerItemProxy */; + }; + A40864DBEEF11A082B652791FA04C24C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SOCKit; + target = D8FDBC10A40DB83968987CBA76E4F7DD /* SOCKit */; + targetProxy = E92B930C85A1D208110782E0EDC04E3C /* PBXContainerItemProxy */; + }; + B3CB3A784EC01BD22BD2A2D7715117F4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = AFNetworking; + target = 61681BF0E677683490353B846C61A129 /* AFNetworking */; + targetProxy = BAACCA3BC071717750DC231D62B73AD2 /* PBXContainerItemProxy */; + }; + B724649E56667B1CEB768EA1EBEFD8D4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Bolts; + target = A48601FEE4437A924848DB48369BA809 /* Bolts */; + targetProxy = A94178143C22B923AD7FB31DE66228B0 /* PBXContainerItemProxy */; + }; + BE47033188B8D72402B90474E4F2A905 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = AFNetworking; + target = 61681BF0E677683490353B846C61A129 /* AFNetworking */; + targetProxy = FDFB1A8326188F82A80CD07E5ACA2D87 /* PBXContainerItemProxy */; + }; + C9563FCB47B04BAFDE797E98AC96E16B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FBSDKLoginKit; + target = 4E286D373D75563CE26E479A68203892 /* FBSDKLoginKit */; + targetProxy = 675BFDC98D3AE67CA01D558BDCB9A6B7 /* PBXContainerItemProxy */; + }; + CD37FC7A32B6A7B6629457EB67E933A8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FBSDKCoreKit; + target = 81D7FE2A0FD9258247B1232874B837DA /* FBSDKCoreKit */; + targetProxy = F2525FB3B5405DC4B1BAF37F01F4D2AB /* PBXContainerItemProxy */; + }; + DC9F00594A01E8A9FF3ACFF59CDEE467 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = TransitionKit; + target = 05AF921757BAF218468C62708B020AA6 /* TransitionKit */; + targetProxy = B523CD37BCE78A7AE1C6DB51DA33B0C8 /* PBXContainerItemProxy */; + }; + E36E70253F374409C8D0E675B83B8B9A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = C47E006176ABF4755350B88C088C3F0D /* RKValueTransformers */; + targetProxy = 7FC4D59C7661F1F90B9637A4AA76565C /* PBXContainerItemProxy */; + }; + F7688FE10814D6B183CC1B9B3F9F7B56 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Bolts; + target = A48601FEE4437A924848DB48369BA809 /* Bolts */; + targetProxy = 5F9ACE740BBE74B9EF18ED10D402EBFB /* PBXContainerItemProxy */; + }; + FAA8A8573D840D2F7E36B520A72135BF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = pop; + target = DD71C0AD634DC4E364BC189688A42294 /* pop */; + targetProxy = E530D725F329BCA4799A9262ABCAE598 /* PBXContainerItemProxy */; + }; + FC9A62FC396F057A9D3B1657CB55DC6D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Bolts; + target = A48601FEE4437A924848DB48369BA809 /* Bolts */; + targetProxy = 0AF81BBB1D00CE9364E007A09C3C2829 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 075D18FF81784FE54E8A3A866A441FC2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3F045700822563CB163FE8B3F606352C /* FBSDKLoginKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKLoginKit/FBSDKLoginKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 0BEB7BFC34D620410E8215AD748D2773 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 525A38283E17DE63638B7101EDD603A5 /* FBSDKCoreKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKCoreKit/FBSDKCoreKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 0FA2BBAFEC75EEB3BB81C9E2C428F353 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A38DBD435D9B08BE5E3BBE4C171BB0B9 /* Parse.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Parse/Parse-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 19F3A60D9C6B93D07B9511478DCE6908 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 655746194AED6433F130ACB5AA120F9B /* SOCKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/SOCKit/SOCKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 209E94899E6B4FE507E0CF7D788E0268 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E0BEF4CC671BA1E579779C38712DC769 /* FBSDKShareKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKShareKit/FBSDKShareKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 2917FD7E4C82E84F9EC674674E45ACE0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 98C98CDFB3F20F2925F6CD1F141BB14F /* Pods.release.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 2A2525A28950F774C68E99A4ADD025E0 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF5B972C0D2221C57AE6060DE6C9A600 /* FoldingTabBar.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FoldingTabBar/FoldingTabBar-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 33B47AD17A7B9B8939CA59D91757B215 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BF428BEC06706AA0A98B6805206833C2 /* RKValueTransformers.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 3CDB0026CDE3D1B62A37670AE864CD4D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3BF16968FBC656E49A7B643EED4B84F6 /* ISO8601DateFormatterValueTransformer.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 4B27AC8BA944D996C0A841E604EAB6EE /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 655746194AED6433F130ACB5AA120F9B /* SOCKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/SOCKit/SOCKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4EAEE715E42BF14B7FC62DCAFFF4CB80 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB97CD8D9BDC16D9E1CE5F863965790B /* pop.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/pop/pop-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 50A7216646F9DE949301F8230EBDF91C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 67DBA3140A542C45905BA912DF9D6D93 /* RestKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RestKit/RestKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 5CE5176205D06FF3FFE3DDDA9291E44B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + ONLY_ACTIVE_ARCH = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 658C1A12EF15301743B29B1908F2C375 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 525A38283E17DE63638B7101EDD603A5 /* FBSDKCoreKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKCoreKit/FBSDKCoreKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 704A9D1ACE8BE44C524946CD091EF5F4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A38DBD435D9B08BE5E3BBE4C171BB0B9 /* Parse.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Parse/Parse-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 74857149DC1E0D599B8A01A78349A926 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8EAB94A02D205E4A7347D989269FA52D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3BF16968FBC656E49A7B643EED4B84F6 /* ISO8601DateFormatterValueTransformer.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 8FB2FB45C292505173E27DB11AAAB26B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3F045700822563CB163FE8B3F606352C /* FBSDKLoginKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKLoginKit/FBSDKLoginKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 97E881AEE973FC07B2D5CDF1BFA633EE /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 67DBA3140A542C45905BA912DF9D6D93 /* RestKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RestKit/RestKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + AE9DDACFB9BFED8AC09071B4DB675BEA /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 556F7F390D364FD2B3DA48C98E500E2C /* TransitionKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/TransitionKit/TransitionKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + C8703C001541D98EBDDB5A3A2B8B0852 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FF5B972C0D2221C57AE6060DE6C9A600 /* FoldingTabBar.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FoldingTabBar/FoldingTabBar-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + CA0E04A18B30F1C108D0F841BF1407CE /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A28864FB7EB36A5080B6D12B1B94125F /* AFNetworking.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/AFNetworking/AFNetworking-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + CE7040F2AD1B940DD8D73BF7BFFCA65A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A28864FB7EB36A5080B6D12B1B94125F /* AFNetworking.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/AFNetworking/AFNetworking-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + D2F8E494AB4D6A0498F75F99A59F171D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BF428BEC06706AA0A98B6805206833C2 /* RKValueTransformers.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + D5CF7EA2CB7125B4F2BDA5C1713C5096 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4E762F23EC34ED4A6FF3312D84E33A40 /* Pods.debug.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MACH_O_TYPE = staticlib; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + D9F08FB4D97391272615BECB95956C38 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 556F7F390D364FD2B3DA48C98E500E2C /* TransitionKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/TransitionKit/TransitionKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + E6F99486C4730AA5797898005863FB56 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E0BEF4CC671BA1E579779C38712DC769 /* FBSDKShareKit.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/FBSDKShareKit/FBSDKShareKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + E8E3ABDAF12C8378694EE61A9091F787 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 19FFE36E5537E1838031F0725CD641C2 /* Bolts.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F5526807BF2C14D6BD59E488B888E604 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 19FFE36E5537E1838031F0725CD641C2 /* Bolts.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + FFB28E6E15EB6C5874FE8AB400E94E49 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB97CD8D9BDC16D9E1CE5F863965790B /* pop.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/pop/pop-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = ""; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 107C08C918B3D3433F2E017FB4FDB128 /* Build configuration list for PBXNativeTarget "Parse" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 704A9D1ACE8BE44C524946CD091EF5F4 /* Debug */, + 0FA2BBAFEC75EEB3BB81C9E2C428F353 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5CE5176205D06FF3FFE3DDDA9291E44B /* Debug */, + 74857149DC1E0D599B8A01A78349A926 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3D9BA71030A144DE354FA087AE0AC89C /* Build configuration list for PBXNativeTarget "FoldingTabBar" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2A2525A28950F774C68E99A4ADD025E0 /* Debug */, + C8703C001541D98EBDDB5A3A2B8B0852 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3E62EC71A9D0016F784F7C6B8D081224 /* Build configuration list for PBXNativeTarget "pop" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFB28E6E15EB6C5874FE8AB400E94E49 /* Debug */, + 4EAEE715E42BF14B7FC62DCAFFF4CB80 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 58770B39DB702F4BF658BBDB3D144297 /* Build configuration list for PBXNativeTarget "FBSDKShareKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E6F99486C4730AA5797898005863FB56 /* Debug */, + 209E94899E6B4FE507E0CF7D788E0268 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F071AF9EBB9B88FCF6AD4FC486502B8 /* Build configuration list for PBXNativeTarget "RKValueTransformers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D2F8E494AB4D6A0498F75F99A59F171D /* Debug */, + 33B47AD17A7B9B8939CA59D91757B215 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6A3F4B905459EE391C08BBDEFCD88A2D /* Build configuration list for PBXNativeTarget "RestKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97E881AEE973FC07B2D5CDF1BFA633EE /* Debug */, + 50A7216646F9DE949301F8230EBDF91C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 776BD5F5971B32DDF8E6A10063D3C2F5 /* Build configuration list for PBXNativeTarget "TransitionKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D9F08FB4D97391272615BECB95956C38 /* Debug */, + AE9DDACFB9BFED8AC09071B4DB675BEA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9B712D281AB5A267FCA1AC12339CC749 /* Build configuration list for PBXNativeTarget "AFNetworking" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CE7040F2AD1B940DD8D73BF7BFFCA65A /* Debug */, + CA0E04A18B30F1C108D0F841BF1407CE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9D5140DAF776FF373AAB7D42B9292675 /* Build configuration list for PBXNativeTarget "FBSDKCoreKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 658C1A12EF15301743B29B1908F2C375 /* Debug */, + 0BEB7BFC34D620410E8215AD748D2773 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A1C2EE2AE7BD563B4A49CDA59286CA4E /* Build configuration list for PBXNativeTarget "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D5CF7EA2CB7125B4F2BDA5C1713C5096 /* Debug */, + 2917FD7E4C82E84F9EC674674E45ACE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CA34C800AB38CCECE78A9E7D6EB38344 /* Build configuration list for PBXNativeTarget "Bolts" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E8E3ABDAF12C8378694EE61A9091F787 /* Debug */, + F5526807BF2C14D6BD59E488B888E604 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CB03CA1862F38085257433BFD1800B62 /* Build configuration list for PBXNativeTarget "SOCKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B27AC8BA944D996C0A841E604EAB6EE /* Debug */, + 19F3A60D9C6B93D07B9511478DCE6908 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D698E21AD6E8699A3BDEA8BF928C6677 /* Build configuration list for PBXNativeTarget "ISO8601DateFormatterValueTransformer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EAB94A02D205E4A7347D989269FA52D /* Debug */, + 3CDB0026CDE3D1B62A37670AE864CD4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D73F005C56A801E3CEDE801CC9ECFC4A /* Build configuration list for PBXNativeTarget "FBSDKLoginKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 075D18FF81784FE54E8A3A866A441FC2 /* Debug */, + 8FB2FB45C292505173E27DB11AAAB26B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.h b/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.h new file mode 100644 index 0000000..0aa6cee --- /dev/null +++ b/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.h @@ -0,0 +1,373 @@ +// +// RKValueTransformers.h +// RestKit +// +// Created by Blake Watters on 8/18/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + Objects wish to perform transformation on values as part of a RestKit object mapping operation much adopt the `RKValueTransforming` protocol. Value transformers must introspect a given input value to determine if they are capable of performing a transformation and if so, perform the transformation and assign the new value to the given pointer to an output value and return `YES` or else construct an error describing the failure and return `NO`. Value transformers may also optionally implement a validation method that enables callers to determine if a given value transformer object is capable of performing a transformation on an input value. + */ +@protocol RKValueTransforming + +@required + +/** + Transforms a given value into a new representation. + + Attempts to perform a transformation of a given value into a new representation and returns a Boolean value indicating if the transformation was successful. Transformers are responsible for introspecting their input values before attempting to perform the transformation. If the transformation cannot be performed, then the transformer must construct an `NSError` object describing the nature of the failure else a warning will be emitted. + + @param inputValue The value to be transformed. + @param outputValue A pointer to an `id` object that will be assigned to the transformed representation. May be assigned to `nil` if that is the result of the transformation. + @param outputValueClass The class of the `outputValue` variable. Specifies the expected type of a successful transformation. May be `nil` to indicate that the type is unknown or unimportant. + @param error A pointer to an `NSError` object that must be assigned to a newly constructed `NSError` object if the transformation cannot be performed. + @return A Boolean value indicating if the transformation was successful. This is used to determine whether another transformer should be given an opportunity to attempt a transformation. + */ +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error; + +@optional + +/** + Asks the transformer if it is capable of performing a transformation from a given class into a new representation of another given class. + + This is an optional method that need only be implemented by transformers that are tightly bound to values with specific types. + + @param inputValueClass The `Class` of an input value being inspected. + @param outputValueClass The `Class` of an output value being inspected. + @return `YES` if the receiver can perform a transformation between the given source and destination classes. + */ +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + The domain for errors emitted by RKValueTransformers + */ +extern NSString *const RKValueTransformersErrorDomain; + +/** + If multiple errors occur in one operation, they are collected in an array and added with this key to the "top-level error" of the operation + */ +extern NSString *const RKValueTransformersDetailedErrorsKey; + +typedef NS_ENUM(NSUInteger, RKValueTransformationError) { + RKValueTransformationErrorUntransformableInputValue = 3000, // The input value was determined to be unacceptable and no transformation was performed. + RKValueTransformationErrorUnsupportedOutputClass = 3001, // The specified class type for the output value is unsupported and no transformation was performed. + RKValueTransformationErrorTransformationFailed = 3002 // A transformation was attempted, but failed. +}; + +/** + Tests if a given input value is of an expected class and returns a failure if it is not. + + This macro is useful for quickly verifying that a transformer can work with a given input value by checking if the value is an instance of an expected class. On failure, the macro constructs an error describing the class mismatch. + + @param inputValue The input value to test. + @param expectedClass The expected class or array of classes of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + */ +#define RKValueTransformerTestInputValueIsKindOfClass(inputValue, expectedClass, error) ({ \ + id expectedArgument = (expectedClass); \ + BOOL success = NO; \ + if ([expectedArgument isKindOfClass:[NSArray class]]) { \ + for (Class supportedClass in expectedArgument) {\ + if ([inputValue isKindOfClass:supportedClass]) { \ + success = YES; \ + break; \ + } \ + } \ + } else { \ + success = [inputValue isKindOfClass:expectedArgument]; \ + } \ + if (! success) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` of type `%@`, but got a `%@`.", expectedArgument, [inputValue class]] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +/** + Tests if a given output value class is of an expected class and returns a failure if it is not. + + This macro is useful for quickly verifying that a transformer can work with a given input value by checking if the value is an instance of an expected class. On failure, the macro constructs an error describing the class mismatch. + + @param outputValueClass The input value to test. + @param expectedClass The expected class or array of classes of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + */ +#define RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, expectedClass, error) ({ \ + BOOL success = NO; \ + id expectedArgument = (expectedClass); \ + if ([expectedArgument isKindOfClass:[NSArray class]]) { \ + for (Class supportedClass in expectedArgument) {\ + if ([outputValueClass isSubclassOfClass:supportedClass]) { \ + success = YES; \ + break; \ + } \ + } \ + } else { \ + success = [outputValueClass isSubclassOfClass:expectedArgument]; \ + } \ + if (! success) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `outputValueClass` of type `%@`, but got a `%@`.", expectedArgument, outputValueClass] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUnsupportedOutputClass userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +/** + Tests a condition to evaluate the success of an attempted value transformation and returns a failure if it is not true. + + This macro is useful for quickly verifying that an attempted transformation was successful. If the condition is not true, than an error is constructed describing the failure. + + @param condition The condition to test. + @param expectedClass The expected class of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + @param ... A string describing what the failure was that occurred. This may be a format string with additional arguments. + */ +#define RKValueTransformerTestTransformation(condition, error, ...) ({ \ +if (! (condition)) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:__VA_ARGS__] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +@class RKCompoundValueTransformer; + +/** + The `RKValueTransformer` class is an abstract base class for implementing a value transformer that conforms to the `RKValueTransforming` protocol. The class is provided to enable third-party extensions of the value transformer to be implemented through subclassing. The default implementation contains no behavior and will raise an exception if an implementation of `transformValue:toValue:ofClass:error:` is not provided by the subclass. `RKValueTransformer` also exposes accessors for the default value transformer implementations that are provided with the library. + */ +@interface RKValueTransformer : NSObject + +///-------------------------------------- +/// @name Retrieving Default Transformers +///-------------------------------------- + +/** + Returns a transformer that will return the input value if it is already of the desired output class. + */ ++ (instancetype)identityValueTransformer; + +/** + Returns a transformer capable of transforming between `NSString` and `NSURL` representations. + */ ++ (instancetype)stringToURLValueTransformer; + +/** + Returns a transformer capable of transforming between `NSNumber` and `NSString` representations. + */ ++ (instancetype)numberToStringValueTransformer; + +/** + Returns a transformer capable of transforming between `NSArray` and `NSOrderedSet` representations. + */ ++ (instancetype)arrayToOrderedSetValueTransformer; + +/** + Returns a transformer capable of transforming between `NSArray` and `NSSet` representations. + */ ++ (instancetype)arrayToSetValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDecimalNumber` and `NSNumber` representations. + */ ++ (instancetype)decimalNumberToNumberValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDecimalNumber` and `NSString` representations. + */ ++ (instancetype)decimalNumberToStringValueTransformer; + +/** + Returns a transformer capable of transforming from `[NSNull null]` to `nil` representations. + */ ++ (instancetype)nullValueTransformer; + +/** + Returns a transformer capable of transforming between objects that conform to the `NSCoding` protocol and `NSData` representations by using an `NSKeyedArchiver`/`NSKeyedUnarchiver` to serialize as a property list. + */ ++ (instancetype)keyedArchivingValueTransformer; + +/** + Returns a transformer capable of transforming between `NSNumber` or `NSString` and `NSDate` representations by evaluating the input value as a time interval since the UNIX epoch (1 January 1970, GMT). + + The transformation treats numeric values as a `double` in order to provide sub-second accuracy. + */ ++ (instancetype)timeIntervalSince1970ToDateValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDate` and `NSString` representations in which the string encodes date and time information in the ISO 8601 timestamp format. + + Note that this transformer is only capable of handling a fully qualified timestamp string rather than the complete ISO 8601 format. For a more complete implementation of the ISO 8601 standard, see the []() project. + */ ++ (instancetype)iso8601TimestampToDateValueTransformer; + +/** + Returns a transformer capable of transforming any `NSObject` that implements the `stringValue` method into an `NSString` representation. + */ ++ (instancetype)stringValueTransformer; + +/** + Returns a transformer capable of enclosing any singular `NSObject` into a collection type such as `NSArray`, `NSSet`, or `NSOrderedSet` (and its mutable descendents). + */ ++ (instancetype)objectToCollectionValueTransformer; + +/** + Returns a transformer capable of transforming any object that conforms to the `NSCopying` protocol into a dictionary representation keyed by the transformed object. + */ ++ (instancetype)keyOfDictionaryValueTransformer; + +/** + Returns a transformer capable of transforming any object conforming to the `NSMutableCopying` protocol into a mutable representation of itself. + */ ++ (instancetype)mutableValueTransformer; + +/** + Returns the singleton instance of the default value transformer. The default transformer is a compound transformer that includes all the individual value transformers implemented on the `RKValueTransformer` base class as well as `NSDateFormatter` instances for the following date format strings: + + * MM/dd/yyyy + * yyyy-MM-dd + + All date formatters are configured to the use `en_US_POSIX` locale and the UTC time zone. + */ ++ (RKCompoundValueTransformer *)defaultValueTransformer; + +/** + Sets the default value transformer to a new instance. Setting the default transformer to `nil` will result in a new singleton instance with the default configuration being rebuilt. + + @param compoundValueTransformer The new default compound transformer. Passing `nil` will reset the transformer to the default configuration. + */ ++ (void)setDefaultValueTransformer:(RKCompoundValueTransformer *)compoundValueTransformer; + +@end + +/** + The `RKBlockValueTransformer` class provides a concrete implementation of the `RKValueTransforming` protocol using blocks to provide the implementation of the transformer. + */ +@interface RKBlockValueTransformer : RKValueTransformer + +///----------------------------------- +/// @name Creating a Block Transformer +///----------------------------------- + +/** + Creates and returns a new value transformer with the given validation and transformation blocks. The blocks are used to provide the implementation of the corresponding methods from the `RKValueTransforming` protocol. + + @param validationBlock A block that evaluates whether the transformer can perform a transformation between a given pair of input and output classes. + */ ++ (instancetype)valueTransformerWithValidationBlock:(BOOL (^)(Class inputValueClass, Class outputValueClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputClass, NSError **error))transformationBlock; + +/** + An optional name for the transformer. + */ +@property (nonatomic, copy) NSString *name; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + The `RKCompoundValueTransformer` class provides an implementation of the `RKValueTransforming` protocol in which a collection of underlying value transformers are assembled into a composite value transformer. Compound values transformers are ordered collections in which each underlying transformer is given the opportunity to transform a value in the order in which it appears within the receiver. Compound transformers are copyable, enumerable and support subscripted access to the underlying value transformers. + */ +@interface RKCompoundValueTransformer : NSObject + +///-------------------------------------- +/// @name Creating a Compound Transformer +///-------------------------------------- + +/** + Creates and returns a new compound transformer from an array of individual value transformers. + + @param valueTransformers An array containining an arbitrary number of objects that conform to the `RKValueTransforming` protocol. Cannot be `nil`. + @return A new compound transformer initialized with the given collection of underlying transformers. + @raises NSInvalidArgumentException Raised if `valueTransformers` is `nil` or any objects in the given collection do not conform to the `RKValueTransforming` protocol. + */ ++ (instancetype)compoundValueTransformerWithValueTransformers:(NSArray *)valueTransformers; + +///---------------------------------------------------- +/// @name Manipulating the Value Transformer Collection +///---------------------------------------------------- + +/** + Adds the given value transformer to the end of the receiver's transformer collection. + + Adding a transformer appends it to the end of the collection meaning that it will be consulted after all other transformers. + + @param valueTransformer The transformer to add to the receiver. + */ +- (void)addValueTransformer:(id)valueTransformer; + +/** + Removes the given value transformer from the receiver. + + @param valueTransformer The transformer to remove from the receiver. + */ +- (void)removeValueTransformer:(id)valueTransformer; + +/** + Inserts the given value transformer into the receiver at a specific position. If the transformer already exists within the receiver then it is moved to the specified position. + + @param valueTransformer The value transformer to be added to (or moved within) the receiver. + @param index The position at which the transformer should be consulted within the collection. An index of 0 would mean that the transformer is consulted before all other transformers. + */ +- (void)insertValueTransformer:(id)valueTransformer atIndex:(NSUInteger)index; + +/** + Returns a count of the number of value transformers in the receiver. + + @return An integer specifying the number of transformers within the receiver. + */ +- (NSUInteger)numberOfValueTransformers; + +///------------------------------------------ +/// @name Retrieving Constituent Transformers +///------------------------------------------ + +/** + Returns a new array containing a subset of the value transformers contained within the receiver that are valid for a transformation between a representation with a given input class and a given output class. + + Whether or not a given transformer is returned is determined by the invocation of the optional `RKValueTransforming` method `validateTransformationFromClass:toClass:`. Any transformer that does not respond to `validateTransformationFromClass:toClass:` will be included within the returned array. The sequencing of the transformers within the returned array is determined by their position within the receiver. + + If you wish to obtain an array containing all of the transformers contained within the receiver then pass `Nil` for both the `inputValueClass` and `outputValueClass` arguments. + + @param inputValueClass The class of input values that you wish to retrieve the transformers for. Can only be `Nil` if `outputValueClass` is also `Nil`. + @param outputValueClass The class of output values that you wish to retrieve the transformers for. Can only be `Nil` if `inputValueClass` is also `Nil`. + @raises NSInvalidArgumentException Raised if `Nil` is given exclusively for `inputValueClass` or `outputValueClass`. + */ +- (NSArray *)valueTransformersForTransformingFromClass:(Class)inputValueClass toClass:(Class)outputValueClass; + +@end + +// Adopts `RKValueTransforming` to provide transformation from `NSString` <-> `NSNumber` +@interface NSNumberFormatter (RKValueTransformers) +@end + +// Adopts `RKValueTransforming` to provide transformation from `NSString` <-> `NSDate` +@interface NSDateFormatter (RKValueTransformers) +@end diff --git a/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.m b/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.m new file mode 100644 index 0000000..9211a93 --- /dev/null +++ b/Unit-2-Journal/Pods/RKValueTransformers/Code/RKValueTransformers.m @@ -0,0 +1,912 @@ +// +// RKValueTransformers.m +// RestKit +// +// Created by Blake Watters on 8/18/13. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include +#import "RKValueTransformers.h" + +NSString *const RKValueTransformersErrorDomain = @"org.restkit.RKValueTransformers.ErrorDomain"; +NSString *const RKValueTransformersDetailedErrorsKey = @"detailedErrors"; + +static BOOL RKVTClassIsCollection(Class aClass) +{ + return (aClass && ([aClass isSubclassOfClass:[NSSet class]] || + [aClass isSubclassOfClass:[NSArray class]] || + [aClass isSubclassOfClass:[NSOrderedSet class]])); +} + +@implementation RKValueTransformer + +- (id)init +{ + if ([self class] == [RKValueTransformer class]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`%@` is abstract and cannot be directly instantiated. " + @"Instantiate a subclass implementation instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + return [super init]; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`RKValueTransformer` subclasses must provide a concrete implementation of `%@`.", + NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +#pragma mark Default Transformers + ++ (instancetype)singletonValueTransformer:(RKBlockValueTransformer * __strong *)valueTransformer + name:(NSString *)name + onceToken:(dispatch_once_t *)onceToken + validationBlock:(BOOL (^)(Class sourceClass, Class destinationClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputValueClass, NSError **error))transformationBlock +{ + dispatch_once(onceToken, ^{ + RKBlockValueTransformer *transformer = [RKBlockValueTransformer valueTransformerWithValidationBlock:validationBlock transformationBlock:transformationBlock]; + transformer.name = name; + *valueTransformer = transformer; + }); + return *valueTransformer; +} + ++ (instancetype)identityValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:nil transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + RKValueTransformerTestTransformation([inputValue isKindOfClass:outputValueClass], error, @"The given value is not already an instance of '%@'", outputValueClass); + *outputValue = inputValue; + return YES; + }]; +} + ++ (instancetype)stringToURLValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSURL class]]) || + ([sourceClass isSubclassOfClass:[NSURL class]] && [destinationClass isSubclassOfClass:[NSString class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSURL class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSURL *URL = [NSURL URLWithString:inputValue]; + RKValueTransformerTestTransformation(URL != nil, error, @"Failed transformation of '%@' to URL: the string is malformed and cannot be transformed to an `NSURL` representation.", inputValue); + *outputValue = URL; + } else if ([inputValue isKindOfClass:[NSURL class]]) { + *outputValue = [(NSURL *)inputValue absoluteString]; + } + return YES; + }]; +} + ++ (instancetype)numberToStringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[NSString class]]) || + ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + static NSSet *trueStrings; + static NSSet *booleanStrings; + static Class cfBooleanClass1; + static Class cfBooleanClass2; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSString class] ]; + trueStrings = [NSSet setWithObjects:@"true", @"t", @"yes", @"y", nil]; + booleanStrings = [trueStrings setByAddingObjectsFromSet:[NSSet setWithObjects:@"false", @"f", @"no", @"n", nil]]; + cfBooleanClass1 = NSClassFromString(@"__NSCFBoolean"); + cfBooleanClass2 = NSClassFromString(@"NSCFBoolean"); + }); + + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *lowercasedString = [inputValue lowercaseString]; + if ([booleanStrings containsObject:lowercasedString]) { + // Handle booleans encoded as Strings + *outputValue = [NSNumber numberWithBool:[trueStrings containsObject:lowercasedString]]; + } else if ([lowercasedString rangeOfString:@"." options:NSLiteralSearch].location != NSNotFound) { + // String -> Floating Point Number + // Only use floating point if needed to avoid losing precision on large integers + *outputValue = [NSNumber numberWithDouble:[lowercasedString doubleValue]]; + } else { + // String -> Signed Integer + *outputValue = [NSNumber numberWithLongLong:[lowercasedString longLongValue]]; + } + } else if ([inputValue isKindOfClass:[NSNumber class]]) { + if (cfBooleanClass1 && [inputValue isKindOfClass:cfBooleanClass1]) { + *outputValue = [inputValue boolValue] ? @"true" : @"false"; + } else if (cfBooleanClass2 && [inputValue isKindOfClass:cfBooleanClass2]) { + *outputValue = [inputValue boolValue] ? @"true" : @"false"; + } else { + *outputValue = [inputValue stringValue]; + } + } + return YES; + }]; +} + ++ (instancetype)numberToBooleanValueTransformer { + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + static dispatch_once_t booleanClassOnceToken; + static Class cfBooleanClass1; + static Class cfBooleanClass2; + + dispatch_once(&booleanClassOnceToken, ^{ + cfBooleanClass1 = NSClassFromString(@"__NSCFBoolean"); + cfBooleanClass2 = NSClassFromString(@"NSCFBoolean"); + }); + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[cfBooleanClass1 class]]) || + ([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[cfBooleanClass2 class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + + RKValueTransformerTestInputValueIsKindOfClass(inputValue, @[[NSNumber class]], error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, @[[NSNumber class]], error); + + *outputValue = inputValue; + + return YES; + }]; +} + ++ (instancetype)arrayToOrderedSetValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSArray class]] && [destinationClass isSubclassOfClass:[NSOrderedSet class]]) || + ([sourceClass isSubclassOfClass:[NSOrderedSet class]] && [destinationClass isSubclassOfClass:[NSArray class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSArray class], [NSOrderedSet class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSArray class]]) { + *outputValue = [NSOrderedSet orderedSetWithArray:inputValue]; + } else if ([inputValue isKindOfClass:[NSOrderedSet class]]) { + *outputValue = [inputValue array]; + } + return YES; + }]; +} + ++ (instancetype)arrayToSetValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSArray class]] && [destinationClass isSubclassOfClass:[NSSet class]]) || + ([sourceClass isSubclassOfClass:[NSSet class]] && [destinationClass isSubclassOfClass:[NSArray class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSSet class], [NSArray class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSArray class]]) { + if ([outputValueClass isSubclassOfClass:[NSMutableSet class]]) *outputValue = [NSMutableSet setWithArray:inputValue]; + else *outputValue = [NSSet setWithArray:inputValue]; + } else if ([inputValue isKindOfClass:[NSSet class]]) { + if ([outputValueClass isSubclassOfClass:[NSMutableArray class]]) *outputValue = [[inputValue allObjects] mutableCopy]; + else *outputValue = [inputValue allObjects]; + } + return YES; + }]; +} + ++ (instancetype)decimalNumberToStringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSDecimalNumber class]] && [destinationClass isSubclassOfClass:[NSString class]]) || + ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSDecimalNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSDecimalNumber class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:inputValue]; + RKValueTransformerTestTransformation(! [decimalNumber isEqual:[NSDecimalNumber notANumber]], error, @"Failed transformation of '%@' to `NSDecimalNumber`: the input string was transformed into Not a Number (NaN) value.", inputValue); + *outputValue = decimalNumber; + } else if ([inputValue isKindOfClass:[NSDecimalNumber class]]) { + *outputValue = [inputValue stringValue]; + } + return YES; + }]; +} + ++ (instancetype)decimalNumberToNumberValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSDecimalNumber class]] && [destinationClass isSubclassOfClass:[NSNumber class]]) || + ([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[NSDecimalNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSDecimalNumber class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [NSDecimalNumber decimalNumberWithDecimal:[inputValue decimalValue]]; + } else if ([inputValue isKindOfClass:[NSDecimalNumber class]]) { + *outputValue = inputValue; + } + return YES; + }]; +} + ++ (instancetype)nullValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:nil transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSNull class], error); + *outputValue = nil; + return YES; + }]; +} + ++ (instancetype)keyedArchivingValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([destinationClass isSubclassOfClass:[NSData class]] && [sourceClass conformsToProtocol:@protocol(NSCoding)]) || + ([sourceClass isSubclassOfClass:[NSData class]] && [destinationClass conformsToProtocol:@protocol(NSCoding)])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if ([inputValue isKindOfClass:[NSData class]]) { + id unarchivedValue = nil; + @try { + unarchivedValue = [NSKeyedUnarchiver unarchiveObjectWithData:inputValue]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"An `%@` exception was encountered while attempting to unarchive the given inputValue.", [exception name]], @"exception": exception }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + return NO; + } + if (! [unarchivedValue isKindOfClass:outputValueClass]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `outputValueClass` of type `%@`, but the unarchived object is a `%@`.", outputValueClass, [unarchivedValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + return NO; + } + *outputValue = unarchivedValue; + } else if ([inputValue conformsToProtocol:@protocol(NSCoding)]) { + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSData class], error); + *outputValue = [NSKeyedArchiver archivedDataWithRootObject:inputValue]; + } else { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` of type `NSData` or conforming to `NSCoding`, but got a `%@` which does not satisfy these expectation.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + return YES; + }]; +} + ++ (instancetype)timeIntervalSince1970ToDateValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ((([sourceClass isSubclassOfClass:[NSString class]] || [sourceClass isSubclassOfClass:[NSNumber class]]) && [destinationClass isSubclassOfClass:[NSDate class]]) || + ([sourceClass isSubclassOfClass:[NSDate class]] && ([destinationClass isSubclassOfClass:[NSNumber class]] || [destinationClass isSubclassOfClass:[NSString class]]))); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + static NSNumberFormatter *numberFormatter; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSString class], [NSDate class] ]; + numberFormatter = [NSNumberFormatter new]; + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSDate class]]) { + if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [NSDate dateWithTimeIntervalSince1970:[inputValue doubleValue]]; + } else if ([inputValue isKindOfClass:[NSString class]]) { + if ([[inputValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) { + *outputValue = nil; + return YES; + } + NSString *errorDescription = nil; + NSNumber *formattedNumber; + BOOL success = [numberFormatter getObjectValue:&formattedNumber forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + *outputValue = [NSDate dateWithTimeIntervalSince1970:[formattedNumber doubleValue]]; + } + } else if ([outputValueClass isSubclassOfClass:[NSNumber class]]) { + *outputValue = @([inputValue timeIntervalSince1970]); + } else if ([outputValueClass isSubclassOfClass:[NSString class]]) { + *outputValue = [numberFormatter stringForObjectValue:@([inputValue timeIntervalSince1970])]; + } + return YES; + }]; +} + ++ (instancetype)iso8601TimestampToDateValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSDate class]]) || + ([sourceClass isSubclassOfClass:[NSDate class]] && [destinationClass isSubclassOfClass:[NSString class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSDate class] ]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSDate class]]) { + static unsigned int const ISO_8601_MAX_LENGTH = 29; + + if ([(NSString *)inputValue length] == 0) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Cannot transform a zero length string"] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + + static NSRegularExpression *validISO8601RegularExpression = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error = nil; + static const char * REGEX_ISO8601_TIMESTAMP = + "\\A(\\d{4})-(\\d{2})-(\\d{2})[T\\s](\\d{2}):(\\d{2}):(\\d{2})" // Mandatory - YYYY-MM-DD(T|\s)hh:mm:ss + "(?:" + "[.](\\d{1,6})" // Optional - .nnnnnn + ")?" + "(?:" + "([+-])(\\d{2}):?(\\d{2})|Z" // Optional -[+-]hh:?mm or Z + ")?\\z"; + NSString *regexString = [[NSString alloc] initWithUTF8String:REGEX_ISO8601_TIMESTAMP]; + validISO8601RegularExpression = [NSRegularExpression regularExpressionWithPattern:regexString + options:NSRegularExpressionCaseInsensitive + error:&error]; + + if (! validISO8601RegularExpression) [NSException raise:NSInternalInconsistencyException format:@"The ISO 8601 validation regex failed to parse: %@", error]; + }); + + if (! [validISO8601RegularExpression numberOfMatchesInString:(NSString *)inputValue options:0 range:NSMakeRange(0, [inputValue length])]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Input value is not a valid ISO 8601 string: '%@'", inputValue] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + + /* Strip milliseconds prior to parsing */ + double milliseconds = 0.f; + if (19 < [inputValue length] && ([inputValue characterAtIndex:19] == '.' || [inputValue characterAtIndex:19] == ':')) { + NSMutableString *newInputString = [NSMutableString stringWithString:[inputValue substringToIndex:19]]; + NSMutableString *millisecondsString = [NSMutableString new]; + + NSUInteger index = 20; + for (; index < [inputValue length]; index++) + { + unichar digit = [inputValue characterAtIndex:index]; + if(digit >= '0' && digit <= '9') + [millisecondsString appendString:[NSString stringWithFormat:@"%C", digit]]; + else + break; + } + + if (index != 20 && index < [inputValue length]) + [newInputString appendString:[inputValue substringFromIndex:index]]; + + inputValue = [NSString stringWithString:newInputString]; + milliseconds = [millisecondsString doubleValue]/1000.f; + } + + const char *constSource = [(NSString *)inputValue cStringUsingEncoding:NSUTF8StringEncoding]; + size_t length = strlen(constSource); + + char source[ISO_8601_MAX_LENGTH]; + memcpy(source, constSource, sizeof (source)); + if (constSource[10] != 'T') + source[10] = 'T'; + + char destination[ISO_8601_MAX_LENGTH]; + if (length == 19) { + memcpy(destination, source, length); + strncpy(destination + length, "+0000\0", 6); + }else if (length == 20 && source[length - 1] == 'Z') { + memcpy(destination, source, length - 1); + strncpy(destination + length - 1, "+0000\0", 6); + } else { + memcpy(destination, source, sizeof (destination)); + if (length == 25 && source[22] == ':') { + destination[22] = destination[23]; + destination[23] = destination[24]; + destination[24] = '\0'; + } + } + + struct tm time = { + .tm_isdst = -1, + }; + + strptime_l(destination, "%FT%T%z", &time, NULL); + + time_t timeIntervalSince1970 = mktime(&time); + RKValueTransformerTestTransformation(timeIntervalSince1970 != -1, error, @"Failed transformation to date representation: time range is beyond the bounds supported by mktime"); + *outputValue = [NSDate dateWithTimeIntervalSince1970:((double)timeIntervalSince1970 + milliseconds)]; + } else if ([outputValueClass isSubclassOfClass:[NSString class]]) { + static NSDateFormatter *iso8601DateFormatter = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + iso8601DateFormatter = [[NSDateFormatter alloc] init]; + [iso8601DateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; + [iso8601DateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; + [iso8601DateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]]; + }); + *outputValue = [iso8601DateFormatter stringFromDate:(NSDate *)inputValue]; + } + return YES; + }]; +} + ++ (instancetype)stringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ([sourceClass instancesRespondToSelector:@selector(stringValue)] && [destinationClass isSubclassOfClass:[NSString class]]); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue respondsToSelector:@selector(stringValue)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Expected an `inputValue` that responds to `stringValue`, but it does not." }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSString class], error); + *outputValue = [inputValue stringValue]; + return YES; + }]; +} + ++ (instancetype)objectToCollectionValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (!RKVTClassIsCollection(sourceClass) && RKVTClassIsCollection(destinationClass)); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (RKVTClassIsCollection([inputValue class])) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` that is not a collection, but got a `%@`.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSArray class], [NSSet class], [NSOrderedSet class]]; + }); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSMutableArray class]]) *outputValue = [NSMutableArray arrayWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSMutableSet class]]) *outputValue = [NSMutableSet setWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSMutableOrderedSet class]]) *outputValue = [NSMutableOrderedSet orderedSetWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSArray class]]) *outputValue = @[ inputValue ]; + else if ([outputValueClass isSubclassOfClass:[NSSet class]]) *outputValue = [NSSet setWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSOrderedSet class]]) *outputValue = [NSOrderedSet orderedSetWithObject:inputValue]; + RKValueTransformerTestTransformation(*outputValue, error, @"Failed to transform value into collection %@", outputValueClass); + return YES; + }]; +} + ++ (instancetype)mutableValueTransformer +{ + static dispatch_once_t classesOnceToken; + static NSArray *mutableClasses; + dispatch_once(&classesOnceToken, ^{ + mutableClasses = @[ [NSMutableArray class], [NSMutableDictionary class], [NSMutableString class], [NSMutableSet class], [NSMutableOrderedSet class], [NSMutableData class], [NSMutableIndexSet class], [NSMutableString class], [NSMutableAttributedString class] ]; + }); + + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + /** + NOTE: Because of class clusters in Foundation you cannot make any assumptions about mutability based on classes. For example, given `__NSArrayI` (immutable array) and a destination class of `NSMutableArray`, `isSubClassOfClass:` will not evaluate to `YES`. If you want a mutable result, you need to invoke `mutableCopy`. + */ + return [sourceClass conformsToProtocol:@protocol(NSMutableCopying)] && [mutableClasses containsObject:destinationClass]; + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue conformsToProtocol:@protocol(NSMutableCopying)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` that conforms to `NSMutableCopying`, but `%@` objects do not.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, mutableClasses, error); + *outputValue = [inputValue mutableCopy]; + return YES; + }]; +} + ++ (instancetype)keyOfDictionaryValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ([sourceClass conformsToProtocol:@protocol(NSCopying)] && [destinationClass isSubclassOfClass:[NSDictionary class]]); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue conformsToProtocol:@protocol(NSCopying)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Expected an `inputValue` that conforms to `NSCopying`, but it does not." }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSDictionary class], error); + if ([outputValueClass isSubclassOfClass:[NSMutableDictionary class]]) { + *outputValue = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionary] forKey:inputValue]; + } else { + *outputValue = @{ inputValue: @{} }; + } + + return YES; + }]; +} + +static RKCompoundValueTransformer *RKDefaultValueTransformer; +static dispatch_once_t RKDefaultValueTransformerOnceToken; + ++ (RKCompoundValueTransformer *)defaultValueTransformer +{ + dispatch_once(&RKDefaultValueTransformerOnceToken, ^{ + if (! RKDefaultValueTransformer) { + RKDefaultValueTransformer = [RKCompoundValueTransformer compoundValueTransformerWithValueTransformers:@[ + [self identityValueTransformer], + [self stringToURLValueTransformer], + + // `NSDecimalNumber` transformers must be consulted ahead of `NSNumber` transformers because `NSDecimalNumber` is a subclass thereof + [self decimalNumberToNumberValueTransformer], + [self decimalNumberToStringValueTransformer], + + [self numberToBooleanValueTransformer], + [self numberToStringValueTransformer], + [self arrayToOrderedSetValueTransformer], + [self arrayToSetValueTransformer], + [self nullValueTransformer], + [self keyedArchivingValueTransformer], + [self stringValueTransformer], + [self objectToCollectionValueTransformer], + [self stringValueTransformer], + [self keyOfDictionaryValueTransformer], + [self mutableValueTransformer], + ]]; + + // Default date formatters + [RKDefaultValueTransformer addValueTransformer:[self iso8601TimestampToDateValueTransformer]]; + [RKDefaultValueTransformer addValueTransformer:[self timeIntervalSince1970ToDateValueTransformer]]; + + // The latter three date format strings below represent the three + // date formats specified by the HTTP/1.1 protocol. See + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + // for details + NSArray *defaultDateFormatStrings = @[ + @"MM/dd/yyyy", + @"yyyy-MM-dd", + @"EEE, dd MMM yyyy HH:mm:ss zzz", // RFC 1123 + @"EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 850 + @"EEE MMM d HH:mm:ss yyyy" // ANSI C asctime() + ]; + for (NSString *dateFormatString in defaultDateFormatStrings) { + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormatString; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + [RKDefaultValueTransformer addValueTransformer:dateFormatter]; + } + } + }); + return RKDefaultValueTransformer; +} + ++ (void)setDefaultValueTransformer:(RKCompoundValueTransformer *)compoundValueTransformer +{ + RKDefaultValueTransformerOnceToken = 0; // resets the once_token so dispatch_once will run again + RKDefaultValueTransformer = compoundValueTransformer; +} + +@end + +@interface RKBlockValueTransformer () +@property (nonatomic, copy) BOOL (^validationBlock)(Class, Class); +@property (nonatomic, copy) BOOL (^transformationBlock)(id, id *, Class, NSError **); +@end + +@implementation RKBlockValueTransformer + ++ (instancetype)valueTransformerWithValidationBlock:(BOOL (^)(Class sourceClass, Class destinationClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputClass, NSError **error))transformationBlock +{ + if (! transformationBlock) [NSException raise:NSInvalidArgumentException format:@"The `transformationBlock` cannot be `nil`."]; + RKBlockValueTransformer *valueTransformer = [self new]; + valueTransformer.validationBlock = validationBlock; + valueTransformer.transformationBlock = transformationBlock; + return valueTransformer; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + NSError *blockError = nil; + BOOL success = self.transformationBlock(inputValue, outputValue, outputValueClass, &blockError); + if (error) *error = blockError; + return success; +} + +- (BOOL)validateTransformationFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + if (self.validationBlock) return self.validationBlock(sourceClass, destinationClass); + else return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, name: %@>", NSStringFromClass([self class]), self, self.name]; +} + +@end + +@interface RKCompoundValueTransformer () +@property (nonatomic, strong) NSMutableArray *valueTransformers; +@property (nonatomic, strong) NSMutableDictionary *transformerCache; +@property (nonatomic) dispatch_queue_t cacheQueue; +@end + +@implementation RKCompoundValueTransformer + ++ (instancetype)compoundValueTransformerWithValueTransformers:(NSArray *)valueTransformers +{ + if (! valueTransformers) [NSException raise:NSInvalidArgumentException format:@"`valueTransformers` argument cannot be `nil`."]; + for (id valueTransformer in valueTransformers) { + if (! [valueTransformer conformsToProtocol:@protocol(RKValueTransforming)]) { + [NSException raise:NSInvalidArgumentException format:@"All objects in the given `valueTransformers` collection must conform to the `RKValueTransforming` protocol."]; + } + } + RKCompoundValueTransformer *valueTransformer = [self new]; + valueTransformer.valueTransformers = [valueTransformers mutableCopy]; + return valueTransformer; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.valueTransformers = [NSMutableArray new]; + self.transformerCache = [NSMutableDictionary new]; + self.cacheQueue = dispatch_queue_create("org.restkit.value-transformer.compound-cache", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_cacheQueue) dispatch_release(_cacheQueue); +#endif + _cacheQueue = NULL; +} + +- (void)invalidateCache +{ + dispatch_barrier_sync(self.cacheQueue, ^{ + [self.transformerCache removeAllObjects]; + }); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, valueTransformers=%@>", NSStringFromClass([self class]), self, self.valueTransformers]; +} + +- (void)addValueTransformer:(id)valueTransformer +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot add `nil` to a compound transformer."]; + [self.valueTransformers addObject:valueTransformer]; + [self invalidateCache]; +} + +- (void)removeValueTransformer:(id)valueTransformer +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot remove `nil` from a compound transformer."]; + [self.valueTransformers removeObject:valueTransformer]; + [self invalidateCache]; +} + +- (void)insertValueTransformer:(id)valueTransformer atIndex:(NSUInteger)index +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot insert `nil` into a compound transformer."]; + [self removeValueTransformer:valueTransformer]; + [self.valueTransformers insertObject:valueTransformer atIndex:index]; +} + +- (NSUInteger)numberOfValueTransformers +{ + return [self.valueTransformers count]; +} + +- (NSArray *)valueTransformersForTransformingFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + if (sourceClass == Nil && destinationClass == Nil) return [self.valueTransformers copy]; + else if (sourceClass == Nil || destinationClass == Nil) [NSException raise:NSInvalidArgumentException format:@"If you specify a source or destination class then you must specify both."]; + + /* See if we have cached values */ + __block NSArray *transformers; + dispatch_sync(self.cacheQueue, ^{ + transformers = [[[self transformerCache] objectForKey:(id)sourceClass] objectForKey:(id)destinationClass]; + }); + + if (transformers != nil) return transformers; + + NSMutableArray *matchingTransformers = [[NSMutableArray alloc] initWithCapacity:[self.valueTransformers count]]; + for (RKValueTransformer *valueTransformer in self) { + if (! [valueTransformer respondsToSelector:@selector(validateTransformationFromClass:toClass:)] + || [valueTransformer validateTransformationFromClass:sourceClass toClass:destinationClass]) { + [matchingTransformers addObject:valueTransformer]; + } + } + + transformers = [matchingTransformers copy]; + dispatch_barrier_sync(self.cacheQueue, ^{ + NSMutableDictionary *cache = self.transformerCache; + NSMutableDictionary *sourceDict = [cache objectForKey:sourceClass]; + if (sourceDict == nil) + { + sourceDict = [NSMutableDictionary new]; + [cache setObject:sourceDict forKey:(id)sourceClass]; + } + + [sourceDict setObject:transformers forKey:(id)destinationClass]; + }); + + return transformers; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index +{ + return [self.valueTransformers objectAtIndex:index]; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(__unsafe_unretained Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + NSArray *matchingTransformers = [self valueTransformersForTransformingFromClass:[inputValue class] toClass:outputValueClass]; + NSMutableArray *errors; + NSError *underlyingError = nil; + for (id valueTransformer in matchingTransformers) { + BOOL success = [valueTransformer transformValue:inputValue toValue:outputValue ofClass:outputValueClass error:&underlyingError]; + if (success) return YES; + if (errors == nil) errors = [NSMutableArray new]; + [errors addObject:underlyingError]; + } + + if (errors.count > 0) { + errors = errors ?: (id)[NSArray new]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Failed transformation of value '%@' to %@: none of the %lu value transformers consulted were successful.", inputValue, outputValueClass, (unsigned long)[matchingTransformers count]], RKValueTransformersDetailedErrorsKey: errors }; + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + } + return NO; +} + +- (BOOL)validateTransformationFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + return [[self valueTransformersForTransformingFromClass:sourceClass toClass:destinationClass] count] > 0; +} + +#pragma mark NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + RKCompoundValueTransformer *compoundValueTransformer = [[[self class] allocWithZone:zone] init]; + compoundValueTransformer.valueTransformers = [self.valueTransformers mutableCopy]; + return compoundValueTransformer; +} + +#pragma mark NSFastEnumeration + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len +{ + return [self.valueTransformers countByEnumeratingWithState:state objects:buffer count:len]; +} + +@end + +@implementation NSNumberFormatter (RKValueTransformers) + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSNumber class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSNumber class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSNumber class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSNumber class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [self stringFromNumber:inputValue]; + } + return YES; +} + +@end + +@implementation NSDateFormatter (RKValueTransformers) + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSDate class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSDate class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSDate class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSDate class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSDate class]]) { + *outputValue = [self stringFromDate:inputValue]; + } + return YES; +} + +@end diff --git a/Unit-2-Journal/Pods/RKValueTransformers/LICENSE b/Unit-2-Journal/Pods/RKValueTransformers/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/Unit-2-Journal/Pods/RKValueTransformers/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Unit-2-Journal/Pods/RKValueTransformers/README.md b/Unit-2-Journal/Pods/RKValueTransformers/README.md new file mode 100644 index 0000000..0480db0 --- /dev/null +++ b/Unit-2-Journal/Pods/RKValueTransformers/README.md @@ -0,0 +1,209 @@ +RKValueTransformers +=================== + +[![Build Status](http://img.shields.io/travis/RestKit/RKValueTransformers/master.svg?style=flat)](https://travis-ci.org/RestKit/RKValueTransformers) +![Pod Version](http://cocoapod-badges.herokuapp.com/v/RKValueTransformers/badge.png) +![Pod Platform](http://cocoapod-badges.herokuapp.com/p/RKValueTransformers/badge.png) + +**A simple, powerful Objective-C value transformation API extracted from RestKit** + +RKValueTransformers is a standalone library that provides a simple value transformation API in Objective-C. Value transformation is the process of converting a value between representations and is a core part of any system that requires that data be transmitted and received in a serialization format distinct from the local data model. + +In the general context of a RESTful API this means the transformation between values encoded in an XML or JSON document and local attributes of your data model. The most familiar and obvious example is the transformation of date and time data encoded as a string in a JSON document and represented locally as an `NSDate` attribute of an `NSObject` or `NSManagedObject` derived class. RKValueTransformers provides a simple, well-designed API for generalizing and simplifying the task of handling an arbitrarily complex set of value transformation requirements for your iOS or Mac OS X application. + +Value transformation is a core feature of [RestKit](http://github.com/RestKit/RestKit) and RKValueTransformers was extracted from the parent project to benefit the larger Cocoa development community. If you are looking for a comprehensive solution for your RESTful API needs then be sure to give RestKit a closer look. + +### Features + +RKValueTransformers is a "batteries included" library that ships with value transformers handling the most common transformations. The core set of transformers can be customized and new transformers are easily implemented to meet the needs of any application. + +* Includes a rich set of transformers covering the most common transformations: + * `NSString` <-> `NSURL` + * `NSNumber` <-> `NSString` + * `NSArray` <-> `NSOrderedSet` + * `NSArray` <-> `NSSet` + * `NSDecimalNumber` <-> `NSNumber` + * `NSDecimalNumber` <-> `NSString` + * `NSNull` <-> `nil` + * Any class conforming to `NSCoding` <-> `NSData` + * UNIX Time Interval encoded as `NSNumber` or `NSString` <-> `NSDate` + * ISO 8601 Timestamp strings <-> `NSDate` (Only supports complete timestamp strings. On 32 bit systems such as iOS devices pre-iPhone 5s only years < 2038 are supported) + * Any object implementing `stringValue` -> `NSString` + * Any singular object to a collection (`NSArray`, `NSSet`, `NSOrderedSet` and their mutable counterparts) + * Any object and an `NSDictionary` (object becomes a key for empty nested dictionary) + * Any class conforming to `NSMutableCoding` -> mutable representation of itself + * `NSString` <-> `NSDate` via `NSDateFormatter`. Default formats include: + * RFC 1123 format + * RFC 850 format + * ANSI C's asctime() format + * `NSString` <-> `NSNumber` via `NSNumberFormatter` +* Lightweight. Implemented in a single pair or header and implementation files. +* Fully unit tested and documented. +* Extensible by implementing the `RKValueTransforming` protocol, subclassing `RKValueTransformer` or with blocks via `RKBlockValueTransformer`. +* Multiple value transformers can be assembled into a composite transformer via the `RKCompoundValueTransformer` class. +* Transparently improves date transformation performance by providing a cache of date formatters. +* Fully integrated with RestKit. + +## Examples + +All value transformation is performed via an abstract common interface defined by the `RKValueTransforming` protocol: + +```objc +NSString *stringContainingDecimalNumber = @"3.4593895835"; +NSError *error = nil; +NSDecimalNumber *decimalNumber = nil; +BOOL success = [[RKValueTransformers decimalNumberToStringValueTransformer] transformValue:stringContainingDecimalNumber toValue:&decimalNumber ofClass:[NSDecimalNumber class] error:&error]; +``` + +The `transformValue:toValue:ofClass:error:` method is always the same regardless of the implementation details of the underlying transformation. It is guaranteed to always return a Boolean value indicating if the transformation was successful and value transformers **must** return an `NSError` in the event the transformation could not be performed. + +### Validating a Transformation + +In many cases, whether or not a given transformation can be performed can be determined entirely by the types involved in the transformation. In these cases, a value transformer may implement the optional `RKValueTransforming` method `validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass`: + +```objc +BOOL isTransformationPossible = [[RKValueTransformers arrayToSetValueTransformer] validateTransformationFromClass:[NSSet class] toClass:[NSArray class]]; +NSAssert(isTransformationPossible == YES, @"Should be `YES`"); +isTransformationPossible = [[RKValueTransformers arrayToSetValueTransformer] validateTransformationFromClass:[NSSet class] toClass:[NSData class]]; +NSAssert(isTransformationPossible == NO, @"Should be `NO`"); +``` + +Note that as this is an optional method you must check that a given instance responds to the validation selector. If it does not then the transformation cannot be validated and a transformation must be attempted to determine success or failure. + +### Compound Transformers + +Individual transformers are very convenient -- they abstract away the need to remember how to implement a given transformation and present a simple interface for transformations. But the real power of RKValueTransformers emerges when you assemble a collection of value transformers into a compound transformer via the `RKCompoundValueTransformer` class. Compound value transformers also implement the `RKValueTransforming` protocol -- but instead of providing any value transformation and validation themselves they proxy the calls to a collection of underlying value transformers in programmer defined order. This allows you to configure a set of transformers in a specific order such that the first transformer that is capable of performing a given transformation will handle it. + +Consider for example that a given application may interact with several API's that return dates as strings in several different formats. We wish to be able to transform any given string value into an `NSDate` without worrying about the details. We could configure a compound transformer to handle this task like so: + +```objc +NSArray *dateFormats = @[ @"MM/dd/yyyy", @"yyyy-MM-dd'T'HH:mm:ss'Z'", @"yyyy-MM-dd" ]; +RKCompoundValueTransformer *compoundValueTransformer = [RKCompoundValueTransformer new]; +for (NSString *dateFormat in dateFormats) { + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormat; + [compoundValueTransformer addValueTransformer:dateFormatter]; +} + +[compoundValueTransformer addValueTransformer:[RKValueTransformer timeIntervalSince1970ToDateValueTransformer]]; + +NSArray *dateStrings = @[ @"11/27/1982", @"1378767519.18176508", @"2013-11-27", @"2013-04-23T16:29:05Z" ]; +NSError *error = nil; +for (NSString *dateString in dateStrings) { + NSDate *date = nil; + BOOL success = [compoundValueTransformer transformValue:dateString toValue:&date ofClass:[NSDate class]]; + NSLog(@"Transformed value '%@' to value '%@' successfully=%@, error=%@", dateString, date, success ? @"YES" : @"NO", error); +} +``` + +### Block Value Transformers + +RKValueTransformers supports the creation of ad-hoc value transformer instances implemented via blocks. For example, one could implement a value transformer that turns all `NSString` instances into uppercase strings like so: + +```objc +RKValueTransformer *uppercaseStringTransformer = [RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + // We transform a `NSString` into another `NSString` + return ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSString class]]); +} transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + // Validate the input and output + RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSString class], error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSString class], error); + + // Perform the transformation + *outputValue = [(NSString *)inputValue uppercaseString]; + return YES; +}]; +``` + +## Installation + +RKValueTransformers is extremely lightweight and has no direct dependencies outside of the Cocoa Foundation framework. As such, the library can be trivially be installed into any Cocoa project by directly adding the source code. Despite this fact, we recommend installing via CocoaPods as it provides modularity and enables the easy installation of new value transformers that are dependent on RKValueTransformers itself. + +### Via CocoaPods + +The recommended approach for installing RKValueTransformers is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.24.0** using Git **>= 1.8.0** installed via Homebrew. + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add RKValueTransformers: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'RKValueTransformers', '~> 1.0.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +### Via Source Code + +Simply add `RKValueTransformers.h` and `RKValueTransformers.m` to your project and `#import "RKValueTransformers.h"`. + +## Design & Implementation Details + +RKValueTransformers is designed to be simple to integrate and use. The entire library consists of a single protocol, three classes, and a handful of category implementations: + +* `RKValueTransforming` - Defines the value transformation API. Adopted by any class that wishes to act as a value transformer. +* `RKValueTransformer` - An abstract base class that implements `RKValueTransforming`. The base class includes static accessors for retrieving singleton instances of the bundled value transformers. Extension libraries can subclass `RKValueTransformer` to provide new transformers. +* `RKBlockValueTransformer` - A concrete subclass of `RKValueTransformer` that enables the creation of ad-hoc value transformers defined via blocks. +* `RKCompoundValueTransformer` - A concrete implementation of `RKValueTransforming` that proxies calls to an underlying collection of value transformers and provides support for composing value transformers. + +For those implementing value transformers, a few macros are included to simplify the implementation of validation and transformation methods: + +* `RKValueTransformerTestInputValueIsKindOfClass` - Tests that a given input value is an instance of a given class or one of its subclasses. If the test evaluates negatively, then `NO` is returned and an appropriate `NSError` is emitted. +* `RKValueTransformerTestOutputValueClassIsSubclassOfClass` - Tests that a given output value class is equal to a given class or is a subclass there of. If the test evaluates negatively, then `NO` is returned an appropriate `NSError` is emitted. +* `RKValueTransformerTestTransformation` - Tests that a given transformation was successful. If the test evaluates negatively, then `NO` is returned an appropriate `NSError` is emitted. + +### Why not NSValueTransformer? + +In developing RKValueTransformers we looked closely at `NSValueTransformer` and ultimately determined that it was not a great fit for our needs. Specifically we found the following issues: + +1. `NSValueTransformer` defines a notion of 'forward' and 'reverse' transformation that doesn't map cleanly in a system primarilly concerned with type transformations. Which side do you consider forward? This gets worse when you consider transformations that can occur between more than just two types. +2. `NSValueTransformer` exposes the class of the "output" object via the class method `transformedValueClass`. This becomes annoying as you are forced to use inheritance to express type knowledge. This necessitates directly inheriting from `NSValueTransformer` or using fancy run-time hackery such as that [utilized by TransformerKit](https://github.com/mattt/TransformerKit/blob/master/TransformerKit/NSValueTransformer%2BTransformerKit.m). +3. `NSValueTransformer` exposes a single global name based registry for value transformers via the `setValueTransformer:forName:` and `valueTransformerForName:` methods. Ultimately this is not granular enough to provide necessary flexibility and requires the use of names (as opposed to type information) to look up transformers. + +Given all of the above it just made sense to go back to a clean slate and design a solution to the value transformation problem from scratch. + +## Unit Tests + +RKValueTransformers is tested using the [Expecta](https://github.com/specta/Expecta) library of unit testing matchers. In order to run the tests, you must do the following: + +1. Install the dependencies via CocoaPods: `pod install` +1. Open the workspace: `open RKValueTransformers.xcworkspace` +1. Run the specs via the **Product** menu > **Test** + +## Credits + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +Samuel E. Giddins + +- https://github.com/segiddins +- http://twitter.com/segiddins +- segiddins@segiddins.me + +## License + +RKValueTransformers is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network.h b/Unit-2-Journal/Pods/RestKit/Code/Network.h new file mode 100644 index 0000000..53d34a5 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network.h @@ -0,0 +1,34 @@ +// +// Network.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" +#import "RKRouteSet.h" +#import "RKRouter.h" +#import "RKRequestDescriptor.h" +#import "RKResponseDescriptor.h" +#import "RKObjectManager.h" +#import "RKHTTPUtilities.h" +#import "RKObjectRequestOperation.h" +#import "RKObjectParameterization.h" +#import "RKPathMatcher.h" + +#ifdef _COREDATADEFINES_H +#import "RKManagedObjectRequestOperation.h" +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h new file mode 100644 index 0000000..f18d9f2 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h @@ -0,0 +1,60 @@ +// +// RKHTTPRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/7/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "AFHTTPClient.h" +#import "AFHTTPRequestOperation.h" + +// Expose the default headers from AFNetworking's AFHTTPClient +@interface AFHTTPClient () +@property (readonly, nonatomic) NSDictionary *defaultHeaders; +@end + +/** + The `RKHTTPRequestOperation` class is a subclass of `AFHTTPRequestOperation` for HTTP or HTTPS requests made by RestKit. It provides per-instance configuration of the acceptable status codes and content types and integrates with the `RKLog` system to provide detailed requested and response logging. Instances of `RKHTTPRequest` are created by `RKObjectRequestOperation` and its subclasses to HTTP requests that will be object mapped. When used to make standalone HTTP requests, `RKHTTPRequestOperation` instance behave identically to `AFHTTPRequestOperation` with the exception of emitting logging information. + + ## Determining Request Processability + + The `RKHTTPRequestOperation` class diverges from the behavior of `AFHTTPRequestOperation` in the implementation of `canProcessRequest`, which is used to determine if a request can be processed. Because `RKHTTPRequestOperation` handles Content Type and Status Code acceptability at the instance rather than the class level, it by default returns `YES` when sent a `canProcessRequest:` method. Subclasses are encouraged to implement more specific logic if constraining the type of requests handled is desired. + */ +@interface RKHTTPRequestOperation : AFHTTPRequestOperation + +///------------------------------------------------------------ +/// @name Configuring Acceptable Status Codes and Content Types +///------------------------------------------------------------ + +/** + The set of status codes which the operation considers successful. + + When `nil`, the acceptability of status codes is deferred to the superclass implementation. + + **Default**: `nil` + */ +@property (nonatomic, strong) NSIndexSet *acceptableStatusCodes; + +/** + The set of content types which the operation considers successful. + + The set may contain `NSString` or `NSRegularExpression` objects. When `nil`, the acceptability of content types is deferred to the superclass implementation. + + **Default**: `nil` + */ +@property (nonatomic, strong) NSSet *acceptableContentTypes; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m new file mode 100644 index 0000000..8b6f6af --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m @@ -0,0 +1,139 @@ +// +// RKHTTPRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/7/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKLog.h" +#import "lcl_RK.h" +#import "RKHTTPUtilities.h" +#import "RKMIMETypes.h" + +extern NSString * const RKErrorDomain; + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); // Defined in RKResponseDescriptor.m + +static BOOL RKResponseRequiresContentTypeMatch(NSHTTPURLResponse *response, NSURLRequest *request) +{ + if (RKRequestMethodFromString(request.HTTPMethod) == RKRequestMethodHEAD) return NO; + if ([RKStatusCodesOfResponsesWithOptionalBodies() containsIndex:response.statusCode]) return NO; + return YES; +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@interface RKHTTPRequestOperation () +@property (readwrite, nonatomic, strong) NSError *rkHTTPError; +@end + +@implementation RKHTTPRequestOperation + ++ (BOOL)canProcessRequest:(NSURLRequest *)request +{ + return YES; +} + +// Disable class level Content/Status Code inspection in our superclass ++ (NSSet *)acceptableContentTypes +{ + return nil; +} + ++ (NSIndexSet *)acceptableStatusCodes +{ + return nil; +} + +- (BOOL)hasAcceptableStatusCode +{ + if (! self.response) return NO; + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + return self.acceptableStatusCodes ? [self.acceptableStatusCodes containsIndex:statusCode] : [super hasAcceptableStatusCode]; +} + +- (BOOL)hasAcceptableContentType +{ + if (! self.response) return NO; + if (!RKResponseRequiresContentTypeMatch(self.response, self.request)) return YES; + NSString *contentType = [self.response MIMEType] ?: @"application/octet-stream"; + return self.acceptableContentTypes ? RKMIMETypeInSet(contentType, self.acceptableContentTypes) : [super hasAcceptableContentType]; +} + +// NOTE: We reimplement this because the AFNetworking implementation keeps Acceptable Status Code/MIME Type at class level +- (NSError *)error +{ + [self.lock lock]; + + if (!self.rkHTTPError && self.response) { + if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey]; + [userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey]; + + if (![self hasAcceptableStatusCode]) { + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), RKStringFromIndexSet(self.acceptableStatusCodes ?: [NSMutableIndexSet indexSet]), statusCode] forKey:NSLocalizedDescriptionKey]; + self.rkHTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; + } else if (![self hasAcceptableContentType] && self.response.statusCode != 204) { + // NOTE: 204 responses come back as text/plain, which we don't want + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), self.acceptableContentTypes, [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; + self.rkHTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + } + + NSError *error = self.rkHTTPError ?: [super error]; + [self.lock unlock]; + return error; +} + +#pragma mark - NSURLConnectionDelegate methods + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + [super connection:connection didReceiveAuthenticationChallenge:challenge]; + + RKLogDebug(@"Received authentication challenge"); +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse +{ + if ([AFHTTPRequestOperation instancesRespondToSelector:@selector(connection:willSendRequest:redirectResponse:)]) { + NSURLRequest *returnValue = [super connection:connection willSendRequest:request redirectResponse:redirectResponse]; + if (returnValue) { + if (redirectResponse) RKLogDebug(@"Following redirect request: %@", returnValue); + return returnValue; + } else { + RKLogDebug(@"Not following redirect to %@", request); + return nil; + } + } else { + if (redirectResponse) RKLogDebug(@"Following redirect request: %@", request); + return request; + } +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h new file mode 100644 index 0000000..c677e98 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1,209 @@ +// +// RKManagedObjectRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H +#if __has_include("RKManagedObjectCaching.h") + +#import "RKObjectRequestOperation.h" +#import "RKManagedObjectCaching.h" + +/** + `RKManagedObjectRequestOperation` is a subclass of `RKObjectRequestOperation` that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation` in which the mapping targets `NSManagedObject` objects managed by Core Data. + + The `RKManagedObjectRequestOperation` class extends the basic behavior of an `RKObjectRequestOperation` to meet the constraints imposed by Core Data. In particular, managed object request operations observe the threading requirements by making use of `NSManagedObjectContext` concurrency types, leverage the support for parent/child contexts, and handle obtaining a permanent `NSManagedObjectID` for objects being mapped so that they are addressable across contexts. Object mapping is internally performed within a block provided to the target context via `performBlockAndWait:`, ensuring execution on the appropriate queue. + + Aside from providing the basic infrastructure for successful object mapping into Core Data, a number of additional Core Data specific features are provided by the `RKManagedObjectRequestOperation` class that warrant discussion in detail. + + ## Parent Context + + Every `RKManagedObjectRequestOperation` object must be assigned an `NSManagedObjectContext` in which to persist the results of the underlying object mapping operation. This context is used as the parent context for a new, private `NSManagedObjectContext` with a concurrency type of `NSPrivateQueueConcurrencyType` in which the object mapping is actually performed. The use of this parent context has a number of benefits: + + 1. If the context that was assigned to the managed object request operation has a concurrency type of `NSMainQueueConcurrencyType`, then directly mapping into the context would block the execution of the main thread for the duration of the mapping process. The use of the private child context isolates the mapping process from the main thread. + 1. In the event of an error, the private context can be discarded, leaving the state of the parent context unchanged. On successful completion, the private context is saved and 'pushes' its changes up one level into the parent context. + + ## Permanent Managed Object IDs + + One of the confounding factors when working with asycnhronous processes interacting with Core Data is the addressability of managed objects that have not been saved to the persistent store across contexts. Unpersisted `NSManagedObject` instances have an `objectID` that is temporary and unsuitable for use in uniquely addressing a given object across two managed object contexts, even if they have common ancestry and share a persistent store coordinator. To mitigate this addressability issue without requiring objects to be saved to the persistent store, managed object request operations invoke `obtainPermanentIDsForObjects:` on the operation's target object (if any) and all managed objects that were inserted into the context during the mapping process. By the time the operation finishes, all managed objects in the mapping result can be referenced by `objectID` across contexts with no further action. + + ## Identification Attributes & Managed Object Caching + + When object mapping managed objects it is necessary to differentiate between objects that already exist in the local store and those that are being created as part of the mapping process. This ensures that the local store does not become populated with duplicate records. To make this differentiation, RestKit requires that each `RKEntityMapping` be configured with one or more identification attributes. Each identification attribute must correspond to a static attribute assigned by the remote backend system. During mapping, these attributes are used to search the managed object context for an existing managed object. If one is found, the object is updated else a new object is created. Identification attributes are configured on the `[RKEntityMapping identificationAttributes]` property. + + Identification attributes are used in conjunction with the `RKManagedObjectCaching` protocol. Each managed object request operation is associated with an object conforming to the `RKManagedObjectCaching` protocol via the `managedObjectCache` proeprty. This cache is consulted during mapping to find existing objects and when establishing relationships between entities by one or more attributes. Please see the documentation accompanying `RKManagedObjectCaching` and `RKConnectionDescription` classes for more information. + + ## Deleting Managed Objects for `DELETE` requests + + `RKManagedObjectRequestOperation` adds special behavior to `DELETE` requests. Upon retrieving a successful (2xx status code) response for a `DELETE`, the operation will invoke `deleteObject:` with the operations `targetObject` on the managed object context. This will delete the target object from the local store in conjunction the successfully deleted remote representation. + + ## Fetch Request Blocks and Deleting Orphaned Objects + + A common problem when accessing remote resources representing collections of objects is the problem of deletion of remote objects. The `RKManagedObjectRequestOperation` class provides support for the cleanup of such orphaned objects. In order to utilize the functionality, the operation must be able to compare a set of reference objects to the retrieved payload in order to determine which objects exist in the local store, but are no longer being returned by the server. This reference set of objects is built by executing an `NSFetchRequest` that corresponds to the URL being loaded. Configuration of this fetch request is done via an `RKFetchRequestBlock` block object. This block takes a single `NSURL` argument and returns an `NSFetchRequest` object. An array of these blocks can be provided to the managed object request operation and the array will be searched in reverse order until a non-nil value is returned by a block. Any block that cannot build a fetch request for the given URL is expected to return `nil` to indicate that it does not match the given URL. Processing of the URL is typically performed using an `RKPathMatcher` object against the value returned from the `relativePath` or `relativeString` methods of `NSURL`. + + To illustrate this concept, please consider the following real-world example which builds a fetch request for retrieving the Terminals that exist in an Airport: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:@"http://restkit.org"]; + [manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) { + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"/airports/:airport_id/terminals.json"]; + + NSDictionary *argsDict = nil; + BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict]; + NSString *airportID; + if (match) { + airportID = [argsDict objectForKey:@"airport_id"]; + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"]; + fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = %@", @([airportID integerValue])]; // NOTE: Coerced from string to number + fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ]; + return fetchRequest; + } + + return nil; + }]; + + The above example code defines an `RKFetchRequestBlock` block object that will match an `NSURL` with a relative path matching the pattern `@"/airports/:airport_id/terminals.json"`. If a match is found, the block extracts the `airport_id` key from the matched arguments, coerces its value into a number, and uses it to construct an `NSPredicate` for the primary key attribute of `GGAirport` entity. Take note that the value of the 'airport_id' was coerced from an `NSString` to an `NSNumber` -- failure to so would result in a predicate whose value is equal to `airportID == '1234'` vs. `airportID == 1234`, which will prevent fetch requests from evaluating correctly. Once coerced, the value is used to construct a `NSFetchRequest` object for the `GGTerminal` entity that will retrieve all the managed objects with an airport ID attribute whose value is equal to `airport_id` encoded within the URL's path. + + In more concrete terms, given the URL `http://restkit.org/airports/1234/terminals.json` the block would return an `NSFetchRequest` equal to: + + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"]; + fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = 1234"]; + fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]; + + Once configured and registered with the object manager, any `RKManagedObjectRequestOperation` created through the manager will automatically consult the fetch request blocks and perform orphaned object cleanup. No cleanup is performed if no block in the `fetchRequestBlocks` property is found to match the URL of the request. + + ## Managed Object Context Save Behaviors + + The results of the operation can either be 'pushed' to the parent context or saved to the persistent store. Configuration is available via the `savesToPersistentStore` property. If an error is encountered while saving the managed object context, then the operation is considered to have failed and the `error` property will be set to the `NSError` object returned by the failed save. + + ## 304 'Not Modified' Responses + + In the event that a managed object request operation loads a 304 'Not Modified' response for an HTTP request no object mapping is performed as Core Data is assumed to contain a managed object representation of the resource requested. No object mapping is performed on the cached response body, making a cache hit for a managed object request operation a very lightweight operation. To build the mapping result returned to the caller, all of the fetch request blocks matching the request URL will be invoked and each fetch request returned is executed against the managed object context and the objects returned are added to the mapping result. Please note that all managed objects returned in the mapping result for a 'Not Modified' response will be returned under the `[NSNull null]` key path. + + Note that `NSURLConnection` supports conditional GET transparently when the cache policy is set to `NSURLRequestUseProtocolCachePolicy`. Because of this the `NSHTTPURLResponse` loaded does not have the 304 (Not Modified) status code. In order to determine if a 304 response has resulted in the loading of an existing response from `NSURLCache`, the managed object request operation evaluates the following heuristic on the response: + + 1. Before the HTTP request is loaded, a reference to any existing `NSCachedURLResponse` is obtained. + 1. When the response is loaded, the request is evaluated for cacheability. A request is considered cacheable if and only if its HTTP method is either "GET" or "HEAD" and its status code is 200, 304, 203, 300, 301, 302, 307, or 410. + 1. If the request is found to be cacheable, the Etag of the current response is matched against the reference to the existing cache entry obtained before the request was loaded. + 1. If the Etags match, the response data of the loaded response is matched against the cache entry reference. + 1. If the data is found to match, then the `userInfo` dictionary of the cache entry for the current request is checked for the existence of Boolean value under the `RKResponseHasBeenMappedCacheUserInfoKey` key. If the value of this key is `YES`, it indicates that the response was previously mapped to completion by an object request operation. + + If this heuristic evaluates positively, then the response is determined to have been loaded from the cache and no mapping or managed object deletion cleanup is performed. This optimization greatly improves performance in applications where HTTP caching is leveraged. + + ## Subclassing Notes + + This class relies on the following `RKMapperOperationDelegate` method methods to do its work: + + 1. `mapperDidFinishMapping:` + + If you subclass `RKManagedObjectRequestOperation` and implement any of the above methods then you must call the superclass implementation. + + ## Limitations and Caveats + + 1. `RKManagedObjectRequestOperation` **does NOT** support object mapping that targets an `NSManagedObjectContext` with a `concurrencyType` of `NSConfinementConcurrencyType`. + + @see `RKObjectRequestOperation` + @see `RKEntityMapping` + @see `RKManagedObjectResponseMapperOperation` + */ +@interface RKManagedObjectRequestOperation : RKObjectRequestOperation + +///---------------------------------------- +/// @name Configuring Core Data Integration +///---------------------------------------- + +/** + The managed object context associated with the managed object request operation. + + This context acts as the parent context for a private managed object context in which the object mapping is performed and changes will be saved to this context upon successful completion of the operation. + + Please see the above discussion about 'Parent Context' for details. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache associated with the managed object request operation. + + The cache is used to look up existing objects by primary key to prevent the creation of duplicate objects during mapping. Please see the above discussion of 'Managed Object Caching' for more details. + + @warning A `nil` value for the `managedObjectCache` property is valid, but may result in the creation of duplicate objects. + */ +@property (nonatomic, strong) id managedObjectCache; + +/** + An array of `RKFetchRequestBlock` block objects used to map `NSURL` objects into corresponding `NSFetchRequest` objects. + + Fetch requests corresponding to URL's are used when deleting orphaned objects and completing object request operations in which `avoidsNetworkAccess` has been set to `YES`. Please see the above discussion of 'Fetch Request Blocks' for more details. + */ +@property (nonatomic, copy) NSArray *fetchRequestBlocks; + +///------------------------------------ +/// @name Managing Completion Behaviors +///------------------------------------ + +/** + A Boolean value that determines if the receiver will delete orphaned objects upon completion of the operation. + + Please see the above discussion of 'Deleting Managed Objects for `DELETE` requests' for more details. + + **Default**: `YES` + */ +@property (nonatomic, assign) BOOL deletesOrphanedObjects; + +/** + A Boolean value that determines if the operation saves the mapping results to the persistent store upon successful completion. If the network transport or mapping portions of the operation fail the operation then this option has no effect. + + When `YES`, the receiver will invoke `saveToPersistentStore:` on its private managed object context to persist the mapping results all the way back to the persistent store coordinator. If `NO`, the private mapping context will be saved causing the mapped objects to be 'pushed' to the parent context as represented by the `managedObjectContext` property. + + **Default**: `YES` + */ +@property (nonatomic, assign) BOOL savesToPersistentStore; + +/** + Sets a block to be invoked just before the operation saves the private mapping context. + + The mapping context is saved just before the object request operation completes its work and transitions into the finished state. All managed objects mapped during the operation will have permanent object ID's. The `mappingResult` will contain managed object instances local to the context yielded to the block. The block will be invoked synchronously on the private queue of the context. After the block is executed, the save operation will take place, optionally saving the mapping results back to the persistent store. + + @param block The block to execute just before the context is saved. + */ +- (void)setWillSaveMappingContextBlock:(void (^)(NSManagedObjectContext *mappingContext))block; + +@end + +/** + A block object for returning an `NSFetchRequest` suitable for fetching the managed objects that corresponds to the contents of the resource at the given URL. It accepts a single `NSURL` argument and returns an `NSFetchRequest`. + + `RKFetchRequestBlock` objects are used to identify objects that exist in the local persistent store, but have been removed from the server-side. Such orphaned objects can optionally be auto-removed by `RKManagedObjectRequestOperation` objects. + + A block that returns `nil` is considered not to match the given URL. + + @param URL The URL object to build a fetch request for. + @return An `NSFetchRequest` object corresponding to the given URL, or nil if the URL could not be processed. + */ +typedef NSFetchRequest *(^RKFetchRequestBlock)(NSURL *URL); + +/** + Returns an array of fetch request objects from an array of `RKFetchRequestBlock` objects given a URL. + + @param fetchRequestBlocks An array of `RKFetchRequestBlock` blocks to + @param URL The URL for which to return a fetch request. + @return An array of fetch requests from all blocks that match the given URL. + */ +NSArray *RKArrayOfFetchRequestFromBlocksWithURL(NSArray *fetchRequestBlocks, NSURL *URL); + +#endif +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m new file mode 100644 index 0000000..498b157 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m @@ -0,0 +1,905 @@ +// +// RKManagedObjectRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H +#if __has_include("RKManagedObjectCaching.h") + +#import "RKManagedObjectRequestOperation.h" +#import "RKLog.h" +#import "RKHTTPUtilities.h" +#import "RKResponseMapperOperation.h" +#import "RKObjectRequestOperationSubclass.h" +#import "NSManagedObjectContext+RKAdditions.h" +#import "NSManagedObject+RKAdditions.h" +#import "RKObjectUtilities.h" + +// Graph visitor +#import "RKResponseDescriptor.h" +#import "RKEntityMapping.h" +#import "RKDynamicMapping.h" +#import "RKRelationshipMapping.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetworkCoreData + +@interface RKEntityMappingEvent : NSObject +@property (nonatomic, copy) id rootKey; +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, strong) RKEntityMapping *entityMapping; + ++ (NSArray *)entityMappingEventsForMappingInfo:(NSDictionary *)mappingInfo; ++ (instancetype)eventWithRootKey:(id)rootKey keyPath:(NSString *)keyPath entityMapping:(RKEntityMapping *)entityMapping; +@end + +@implementation RKEntityMappingEvent + ++ (NSArray *)entityMappingEventsForMappingInfo:(NSDictionary *)mappingInfo +{ + NSMutableArray *entityMappingEvents = [NSMutableArray array]; + for (id rootKey in mappingInfo) { + NSArray *mappingInfoArray = mappingInfo[rootKey]; + for (RKMappingInfo *mappingInfo in mappingInfoArray) { + [entityMappingEvents addObjectsFromArray:[self entityMappingEventsWithMappingInfo:mappingInfo rootKey:rootKey keyPath:nil]]; + } + } + return entityMappingEvents; +} + ++ (NSArray *)entityMappingEventsWithMappingInfo:(RKMappingInfo *)mappingInfo rootKey:(id)rootKey keyPath:(NSString *)keyPath +{ + NSMutableArray *entityMappingEvents = [NSMutableArray array]; + if ([mappingInfo.objectMapping isKindOfClass:[RKEntityMapping class]]) { + [entityMappingEvents addObject:[RKEntityMappingEvent eventWithRootKey:rootKey + keyPath:keyPath + entityMapping:(RKEntityMapping *)mappingInfo.objectMapping]]; + } + + for (NSString *destinationKeyPath in mappingInfo.relationshipMappingInfo) { + NSString *nestedKeyPath = keyPath ? [@[ keyPath, destinationKeyPath] componentsJoinedByString:@"."] : destinationKeyPath; + NSArray *arrayOfMappingInfoForRelationship = (mappingInfo.relationshipMappingInfo)[destinationKeyPath]; + for (RKMappingInfo *mappingInfo in arrayOfMappingInfoForRelationship) { + [entityMappingEvents addObjectsFromArray:[self entityMappingEventsWithMappingInfo:mappingInfo rootKey:rootKey keyPath:nestedKeyPath]]; + } + } + return entityMappingEvents; +} + ++ (instancetype)eventWithRootKey:(id)rootKey keyPath:(NSString *)keyPath entityMapping:(RKEntityMapping *)entityMapping +{ + RKEntityMappingEvent *event = [RKEntityMappingEvent new]; + event.rootKey = rootKey; + event.keyPath = keyPath; + event.entityMapping = entityMapping; + return event; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p rootKey=%@ keyPath=%@ entityMapping=%@>", + [self class], self, self.rootKey, self.keyPath, self.entityMapping]; +} +@end + +/** + Returns the set of keys containing the outermost nesting keypath for all children. + For example, given a set containing: 'this', 'this.that', 'another.one.test', 'another.two.test', 'another.one.test.nested' + would return: 'this, 'another.one', 'another.two' + */ +NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths); +NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths) +{ + return [setOfKeyPaths objectsPassingTest:^BOOL(NSString *keyPath, BOOL *stop) { + if ([keyPath isEqual:[NSNull null]]) return YES; // Special case the root key path + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + NSMutableSet *parentKeyPaths = [NSMutableSet set]; + for (NSUInteger index = 0; index < [keyPathComponents count] - 1; index++) { + [parentKeyPaths addObject:[[keyPathComponents subarrayWithRange:NSMakeRange(0, index + 1)] componentsJoinedByString:@"."]]; + } + for (NSString *parentKeyPath in parentKeyPaths) { + if ([setOfKeyPaths containsObject:parentKeyPath]) return NO; + } + return YES; + }]; +} + +// Precondition: Must be called from within the correct context +static NSManagedObject *RKRefetchManagedObjectInContext(NSManagedObject *managedObject, NSManagedObjectContext *managedObjectContext) +{ + NSManagedObjectID *managedObjectID = [managedObject objectID]; + if ([managedObjectID isTemporaryID]) { + RKLogWarning(@"Unable to refetch managed object %@: the object has a temporary managed object ID.", managedObject); + return managedObject; + } + NSError *error = nil; + NSManagedObject *refetchedObject = [managedObjectContext existingObjectWithID:managedObjectID error:&error]; + if (! refetchedObject) { + RKLogWarning(@"Failed to refetch managed object with ID %@: %@", managedObjectID, error); + } + return refetchedObject; +} + +static id RKRefetchedValueInManagedObjectContext(id value, NSManagedObjectContext *managedObjectContext) +{ + if (! value) { + return value; + } else if ([value isKindOfClass:[NSArray class]]) { + NSMutableArray *newValue = [[NSMutableArray alloc] initWithCapacity:[value count]]; + for (__strong id object in value) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue addObject:object]; + } + return newValue; + } else if ([value isKindOfClass:[NSSet class]]) { + NSMutableSet *newValue = [[NSMutableSet alloc] initWithCapacity:[value count]]; + for (__strong id object in value) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue addObject:object]; + } + return newValue; + } else if ([value isKindOfClass:[NSOrderedSet class]]) { + NSMutableOrderedSet *newValue = [NSMutableOrderedSet orderedSet]; + [(NSOrderedSet *)value enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue setObject:object atIndex:index]; + }]; + return newValue; + } else if ([value isKindOfClass:[NSManagedObject class]]) { + return RKRefetchManagedObjectInContext(value, managedObjectContext); + } + + return value; +} + +/** + This is an NSProxy object that stands in for the mapping result and provides support for refetching the results on demand. This enables us to defer the refetching until someone accesses the results directly. For managed object request operations that do not use the mapping result (such as those used in conjunction with a NSFetchedResultsController), the refetching will be skipped entirely. + */ +@interface RKRefetchingMappingResult : NSProxy + +- (instancetype)initWithMappingResult:(RKMappingResult *)mappingResult + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + mappingInfo:(NSDictionary *)mappingInfo; +@end + +@interface RKRefetchingMappingResult () +@property (nonatomic, strong) RKMappingResult *mappingResult; +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSDictionary *mappingInfo; +@property (nonatomic, assign) BOOL refetched; +@end + +@implementation RKRefetchingMappingResult + ++ (NSString *)description +{ + return [[super description] stringByAppendingString:@"_RKRefetchingMappingResult"]; +} + +/** + Add explicit ordering of deallocations to fight `cxx_destruct` crashes + */ +- (void)dealloc +{ + _mappingResult = nil; + _mappingInfo = nil; + _managedObjectContext = nil; +} + +- (instancetype)initWithMappingResult:(RKMappingResult *)mappingResult + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + mappingInfo:(NSDictionary *)mappingInfo; +{ + self.mappingResult = mappingResult; + self.managedObjectContext = managedObjectContext; + self.mappingInfo = mappingInfo; + return self; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector +{ + return [self.mappingResult methodSignatureForSelector:selector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + if (! self.refetched) { + self.mappingResult = [self refetchedMappingResult]; + self.refetched = YES; + } + [invocation invokeWithTarget:self.mappingResult]; +} + +- (NSString *)description +{ + return [self.mappingResult description]; +} + +- (NSUInteger)count +{ + return [self.mappingResult count]; +} + +- (RKMappingResult *)refetchedMappingResult +{ + NSAssert(!self.refetched, @"Mapping result should only be refetched once"); + if (! [self.mappingResult count]) return self.mappingResult; + + NSMutableDictionary *newDictionary = [self.mappingResult.dictionary mutableCopy]; + [self.managedObjectContext performBlockAndWait:^{ + NSArray *entityMappingEvents = [RKEntityMappingEvent entityMappingEventsForMappingInfo:self.mappingInfo]; + NSSet *rootKeys = [NSSet setWithArray:[entityMappingEvents valueForKey:@"rootKey"]]; + for (id rootKey in rootKeys) { + NSArray *eventsForRootKey = [entityMappingEvents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"rootKey = %@", rootKey]]; + NSSet *keyPaths = [NSSet setWithArray:[eventsForRootKey valueForKey:@"keyPath"]]; + // If keyPaths contains null, then the root object is a managed object and we only need to refetch it + NSSet *nonNestedKeyPaths = ([keyPaths containsObject:[NSNull null]]) ? [NSSet setWithObject:[NSNull null]] : RKSetByRemovingSubkeypathsFromSet(keyPaths); + + NSDictionary *mappingResultsAtRootKey = newDictionary[rootKey]; + for (NSString *keyPath in nonNestedKeyPaths) { + id value = nil; + if ([keyPath isEqual:[NSNull null]]) { + value = RKRefetchedValueInManagedObjectContext(mappingResultsAtRootKey, self.managedObjectContext); + if (value) newDictionary[rootKey] = value; + } else { + NSMutableArray *keyPathComponents = [[keyPath componentsSeparatedByString:@"."] mutableCopy]; + NSString *destinationKey = [keyPathComponents lastObject]; + [keyPathComponents removeLastObject]; + id sourceObject = [keyPathComponents count] ? [mappingResultsAtRootKey valueForKeyPath:[keyPathComponents componentsJoinedByString:@"."]] : mappingResultsAtRootKey; + if (RKObjectIsCollection(sourceObject)) { + // This is a to-many relationship, we want to refetch each item at the keyPath + for (id nestedObject in sourceObject) { + // NOTE: If this collection was mapped with a dynamic mapping then each instance may not respond to the key + if ([nestedObject respondsToSelector:NSSelectorFromString(destinationKey)]) { + NSManagedObject *managedObject = [nestedObject valueForKey:destinationKey]; + [nestedObject setValue:RKRefetchedValueInManagedObjectContext(managedObject, self.managedObjectContext) forKey:destinationKey]; + } + } + } else { + // This is a singular relationship. We want to refetch the object and set it directly. + id valueToRefetch = [sourceObject valueForKey:destinationKey]; + [sourceObject setValue:RKRefetchedValueInManagedObjectContext(valueToRefetch, self.managedObjectContext) forKey:destinationKey]; + } + } + } + } + }]; + + return [[RKMappingResult alloc] initWithDictionary:newDictionary]; +} + +@end + +NSArray *RKArrayOfFetchRequestFromBlocksWithURL(NSArray *fetchRequestBlocks, NSURL *URL) +{ + NSMutableArray *fetchRequests = [NSMutableArray array]; + NSFetchRequest *fetchRequest = nil; + for (RKFetchRequestBlock block in [fetchRequestBlocks reverseObjectEnumerator]) { + fetchRequest = block(URL); + if (fetchRequest) [fetchRequests addObject:fetchRequest]; + } + return fetchRequests; +} + +static NSSet *RKFlattenCollectionToSet(id collection) +{ + NSMutableSet *mutableSet = [NSMutableSet set]; + if ([collection conformsToProtocol:@protocol(NSFastEnumeration)]) { + for (id nestedObject in collection) { + if ([nestedObject conformsToProtocol:@protocol(NSFastEnumeration)]) { + if ([nestedObject isKindOfClass:[NSArray class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet([NSSet setWithArray:nestedObject])]; + } else if ([nestedObject isKindOfClass:[NSSet class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet(nestedObject)]; + } else if ([nestedObject isKindOfClass:[NSOrderedSet class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet([(NSOrderedSet *)nestedObject set])]; + } + } else { + [mutableSet addObject:nestedObject]; + } + } + } else if (collection) { + [mutableSet addObject:collection]; + } + + return mutableSet; +} + +static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *responseDescriptors) +{ + NSCParameterAssert(URL); + NSCParameterAssert(responseDescriptors); + NSArray *baseURLs = [responseDescriptors valueForKeyPath:@"@distinctUnionOfObjects.baseURL"]; + if ([baseURLs count] == 1) { + NSURL *baseURL = baseURLs[0]; + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(URL, baseURL); + URL = [NSURL URLWithString:pathAndQueryString relativeToURL:baseURL]; + } + + return URL; +} + +static NSSet *RKGatherManagedObjectsFromObjectWithRelationshipMapping(id object, RKRelationshipMapping *relationshipMapping) +{ + NSMutableSet *managedObjects = [NSMutableSet set]; + NSSet *relationshipValue = RKFlattenCollectionToSet([object valueForKeyPath:relationshipMapping.destinationKeyPath]); + for (id relatedObject in relationshipValue) { + if ([relatedObject isKindOfClass:[NSManagedObject class]]) [managedObjects addObject:relatedObject]; + + if ([relationshipMapping.mapping isKindOfClass:[RKObjectMapping class]]) { + for (RKRelationshipMapping *childRelationshipMapping in [(RKObjectMapping *)relationshipMapping.mapping relationshipMappings]) { + [managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping)]; + } + } else if ([relationshipMapping.mapping isKindOfClass:[RKDynamicMapping class]]) { + for (RKObjectMapping *objectMapping in [(RKDynamicMapping *)relationshipMapping.mapping objectMappings]) { + @try { + for (RKRelationshipMapping *childRelationshipMapping in objectMapping.relationshipMappings) { + [managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping)]; + } + } + @catch (NSException *exception) { + continue; + } + } + } + } + return managedObjects; +} + +static NSSet *RKManagedObjectsFromObjectWithMappingInfo(id object, RKMappingInfo *mappingInfo) +{ + NSMutableSet *managedObjects = [NSMutableSet set]; + + if ([mappingInfo.objectMapping isKindOfClass:[RKEntityMapping class]]) { + [managedObjects unionSet:RKFlattenCollectionToSet(object)]; + } + + if ([[mappingInfo propertyMappings] count] == 0) { + // This object was matched, but no changes were made. Gather all related objects + for (RKRelationshipMapping *relationshipMapping in [mappingInfo.objectMapping relationshipMappings]) { + [managedObjects unionSet:RKGatherManagedObjectsFromObjectWithRelationshipMapping(object, relationshipMapping)]; + } + } else { + for (NSString *destinationKeyPath in mappingInfo.relationshipMappingInfo) { + id relationshipValue = [object valueForKeyPath:destinationKeyPath]; + NSArray *mappingInfos = (mappingInfo.relationshipMappingInfo)[destinationKeyPath]; + for (RKMappingInfo *relationshipMappingInfo in mappingInfos) { + NSUInteger index = [mappingInfos indexOfObject:relationshipMappingInfo]; + id mappedObjectAtIndex = ([relationshipValue respondsToSelector:@selector(objectAtIndex:)]) ? [NSSet setWithObject:relationshipValue[index]] : relationshipValue; + [managedObjects unionSet:RKFlattenCollectionToSet(RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, relationshipMappingInfo))]; + } + } + } + + return ([managedObjects count]) ? managedObjects : nil; +} + +static NSSet *RKManagedObjectsFromMappingResultWithMappingInfo(RKMappingResult *mappingResult, NSDictionary *mappingInfo) +{ + NSMutableSet *managedObjectsInMappingResult = nil; + NSDictionary *mappingResultDictionary = [mappingResult dictionary]; + + for (id rootKey in mappingInfo) { + NSArray *mappingInfoArray = mappingInfo[rootKey]; + id objectsAtRoot = mappingResultDictionary[rootKey]; + for (RKMappingInfo *mappingInfo in mappingInfoArray) { + NSUInteger index = [mappingInfoArray indexOfObject:mappingInfo]; + id mappedObjectAtIndex = ([objectsAtRoot respondsToSelector:@selector(objectAtIndex:)]) ? [NSSet setWithObject:objectsAtRoot[index]] : objectsAtRoot; + + NSSet *managedObjects = RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, mappingInfo); + if (managedObjects) { + if (! managedObjectsInMappingResult) managedObjectsInMappingResult = [NSMutableSet set]; + [managedObjectsInMappingResult unionSet:managedObjects]; + } + } + }; + + return managedObjectsInMappingResult; +} + +// Defined in RKObjectManager.h +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors); + +@interface RKObjectRequestOperation () +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@end + +@interface RKManagedObjectRequestOperation () +// Core Data specific +@property (nonatomic, strong) NSManagedObjectContext *privateContext; +@property (nonatomic, copy) NSManagedObjectID *targetObjectID; +@property (nonatomic, strong) RKManagedObjectResponseMapperOperation *responseMapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody); +@property (nonatomic, strong) NSDictionary *mappingInfo; +@property (nonatomic, strong) NSCachedURLResponse *cachedResponse; +@property (nonatomic, readonly) BOOL canSkipMapping; +@property (nonatomic, assign) BOOL hasMemoizedCanSkipMapping; +@property (nonatomic, copy) void (^willSaveMappingContextBlock)(NSManagedObjectContext *mappingContext); +@end + +@implementation RKManagedObjectRequestOperation + +@dynamic willMapDeserializedResponseBlock; +@synthesize canSkipMapping = _canSkipMapping; + +// Designated initializer +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors +{ + self = [super initWithHTTPRequestOperation:requestOperation responseDescriptors:responseDescriptors]; + if (self) { + self.savesToPersistentStore = YES; + self.deletesOrphanedObjects = YES; + self.cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:requestOperation.request]; + } + return self; +} + +/** + NOTE: This dealloc implementation attempts to avoid crashes coming from Core Data due to the ordering of deallocations under ARC. If the MOC is deallocated before its managed objects, it can trigger a crash. We dispose of the mapping result and reset the private context to avoid this situation. The crash manifests itself in `cxx_destruct` + [sbw - 2/25/2013] + */ +- (void)dealloc +{ + _mappingResult = nil; + _responseMapperOperation = nil; + _privateContext = nil; +} + +- (void)setTargetObject:(id)targetObject +{ + [super setTargetObject:targetObject]; + + if ([targetObject isKindOfClass:[NSManagedObject class]]) { + if ([[targetObject objectID] isTemporaryID]) { + [[targetObject managedObjectContext] performBlockAndWait:^{ + NSError *error = nil; + BOOL success = [[targetObject managedObjectContext] obtainPermanentIDsForObjects:@[ targetObject ] error:&error]; + if (! success) RKLogWarning(@"Failed to obtain permanent objectID for targetObject: %@ (%ld)", [error localizedDescription], (long) error.code); + }]; + } + self.targetObjectID = [targetObject objectID]; + } else { + self.targetObjectID = nil; + } +} + +- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + _managedObjectContext = managedObjectContext; + + if (managedObjectContext) { + [managedObjectContext performBlockAndWait:^{ + if ([managedObjectContext hasChanges]) { + if ([managedObjectContext.insertedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didCreateObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.insertedObjects) { + [self.managedObjectCache didCreateObject:managedObject]; + } + } + + if ([managedObjectContext.updatedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didFetchObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.updatedObjects) { + [self.managedObjectCache didFetchObject:managedObject]; + } + } + + if ([managedObjectContext.deletedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didDeleteObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.deletedObjects) { + [self.managedObjectCache didDeleteObject:managedObject]; + } + } + } + }]; + + // Create a private context + NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + [privateContext setParentContext:managedObjectContext]; + [privateContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; + + self.privateContext = privateContext; + } else { + self.privateContext = nil; + } +} + +#pragma mark - RKObjectRequestOperation Overrides + +- (void)cancel +{ + [super cancel]; + [self.responseMapperOperation cancel]; +} + +// RKResponseHasBeenMappedCacheUserInfoKey is stored by RKObjectRequestOperation +- (BOOL)canSkipMapping +{ + BOOL (^shouldSkipMapping)(void) = ^{ + // Is the request cacheable + if (!self.cachedResponse) return NO; + if (!self.managedObjectCache) return NO; + NSURLRequest *request = self.HTTPRequestOperation.request; + if (! [[request HTTPMethod] isEqualToString:@"GET"] && ! [[request HTTPMethod] isEqualToString:@"HEAD"]) return NO; + NSHTTPURLResponse *response = (NSHTTPURLResponse *)self.HTTPRequestOperation.response; + if (! [RKCacheableStatusCodes() containsIndex:response.statusCode]) return NO; + + // Check if all the response descriptors are backed by Core Data + NSMutableArray *matchingResponseDescriptors = [NSMutableArray array]; + for (RKResponseDescriptor *responseDescriptor in self.responseDescriptors) { + if ([responseDescriptor matchesResponse:response]) [matchingResponseDescriptors addObject:responseDescriptor]; + } + if (! RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(matchingResponseDescriptors)) return NO; + + // Check for a change in the Etag + NSString *cachedEtag = [(NSHTTPURLResponse *)[self.cachedResponse response] allHeaderFields][@"ETag"]; + NSString *responseEtag = [response allHeaderFields][@"ETag"]; + if (!(cachedEtag && responseEtag && [cachedEtag isEqualToString:responseEtag])) return NO; + + // Response data has changed + NSData *responseData = self.HTTPRequestOperation.responseData; + if (! [responseData isEqualToData:[self.cachedResponse data]]) return NO; + + // Check that we have mapped this response previously + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + return [(cachedResponse.userInfo)[RKResponseHasBeenMappedCacheUserInfoKey] boolValue]; + }; + + if (! self.hasMemoizedCanSkipMapping) { + _canSkipMapping = shouldSkipMapping(); + self.hasMemoizedCanSkipMapping = YES; + } + return _canSkipMapping; +} + +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock +{ + NSArray *fetchRequests = [self fetchRequestsMatchingResponseURL]; + if ([fetchRequests count] && [self canSkipMapping]) { + RKLogDebug(@"Managed object mapping requested for cached response which was previously mapped: skipping..."); + NSMutableArray *managedObjects = [NSMutableArray array]; + [self.privateContext performBlockAndWait:^{ + NSError *error = nil; + for (NSFetchRequest *fetchRequest in fetchRequests) { + NSArray *fetchedObjects = [self.privateContext executeFetchRequest:fetchRequest error:&error]; + if (fetchedObjects) { + [managedObjects addObjectsFromArray:fetchedObjects]; + } else { + RKLogError(@"Failed to execute fetch request %@: %@", fetchRequest, error); + } + } + }]; + RKMappingResult *mappingResult = [[RKMappingResult alloc] initWithDictionary:@{ [NSNull null]: managedObjects }]; + completionBlock(mappingResult, nil); + return; + } + + self.responseMapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithRequest:self.HTTPRequestOperation.request + response:self.HTTPRequestOperation.response + data:self.HTTPRequestOperation.responseData + responseDescriptors:self.responseDescriptors]; + self.responseMapperOperation.mapperDelegate = self; + self.responseMapperOperation.mappingMetadata = self.mappingMetadata; + self.responseMapperOperation.targetObject = self.targetObject; + self.responseMapperOperation.targetObjectID = self.targetObjectID; + self.responseMapperOperation.managedObjectContext = self.privateContext; + self.responseMapperOperation.managedObjectCache = self.managedObjectCache; + [self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock]; + [self.responseMapperOperation setQueuePriority:[self queuePriority]]; + __weak __typeof(self)weakSelf = self; + [self.responseMapperOperation setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *responseMappingError) { + if ([weakSelf isCancelled]) return completionBlock(mappingResult, responseMappingError); + + BOOL success; + NSError *error = nil; + + // Handle any cleanup + if (weakSelf.targetObjectID + && NSLocationInRange(weakSelf.HTTPRequestOperation.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful)) + && [[[weakSelf.HTTPRequestOperation.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"]) { + success = [weakSelf deleteTargetObject:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + } + + if (!responseMappingError) { + success = [weakSelf deleteLocalObjectsMissingFromMappingResult:mappingResult error:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + + // Persist our mapped objects + success = [weakSelf obtainPermanentObjectIDsForInsertedObjects:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + + success = [weakSelf saveContext:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + } + + // Refetch all managed objects nested at key paths within the results dictionary before returning + if (mappingResult) { + RKRefetchingMappingResult *refetchingMappingResult = [[RKRefetchingMappingResult alloc] initWithMappingResult:mappingResult + managedObjectContext:weakSelf.managedObjectContext + mappingInfo:weakSelf.mappingInfo]; + return completionBlock((RKMappingResult *)refetchingMappingResult, nil); + } + completionBlock(nil, responseMappingError); + }]; + [[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation]; +} + +- (BOOL)deleteTargetObject:(NSError **)error +{ + __block BOOL _blockSuccess = YES; + + if (self.targetObjectID) { + // 2xx/404/410 DELETE request, proceed with deletion from the MOC + __block NSError *_blockError = nil; + [self.privateContext performBlockAndWait:^{ + NSManagedObject *backgroundThreadObject = [self.privateContext existingObjectWithID:self.targetObjectID error:&_blockError]; + if (backgroundThreadObject) { + RKLogInfo(@"Deleting local object %@ due to `DELETE` request", backgroundThreadObject); + [self.privateContext deleteObject:backgroundThreadObject]; + } else { + RKLogWarning(@"Unable to delete object sent with `DELETE` request: Failed to retrieve object with objectID %@", self.targetObjectID); + RKLogCoreDataError(_blockError); + _blockSuccess = NO; + *error = _blockError; + } + }]; + } + + return _blockSuccess; +} + +- (NSSet *)localObjectsFromFetchRequests:(NSArray *)fetchRequests matchingRequestURL:(NSError **)error +{ + NSMutableSet *localObjects = [NSMutableSet set]; + __block NSError *_blockError; + __block NSArray *_blockObjects; + + for (NSFetchRequest *fetchRequest in fetchRequests) { + [self.privateContext performBlockAndWait:^{ + _blockObjects = [self.privateContext executeFetchRequest:fetchRequest error:&_blockError]; + }]; + + if (_blockObjects == nil) { + if (error) *error = _blockError; + return nil; + } + RKLogTrace(@"Fetched local objects matching URL with fetch request '%@': %@", fetchRequest, _blockObjects); + [localObjects addObjectsFromArray:_blockObjects]; + + } + + return localObjects; +} + +- (NSArray *)fetchRequestsMatchingResponseURL +{ + // Pass the fetch request blocks a relative `NSURL` object if possible + NSMutableArray *fetchRequests = [NSMutableArray array]; + NSURL *URL = RKRelativeURLFromURLAndResponseDescriptors(self.HTTPRequestOperation.response.URL, self.responseDescriptors); + for (RKFetchRequestBlock fetchRequestBlock in [self.fetchRequestBlocks reverseObjectEnumerator]) { + NSFetchRequest *fetchRequest = fetchRequestBlock(URL); + if (fetchRequest) { + // Workaround for iOS 5 -- The log statement crashes if the entity is not assigned before logging + [fetchRequest setEntity:[[[self.privateContext persistentStoreCoordinator] managedObjectModel] entitiesByName][[fetchRequest entityName]]]; + RKLogDebug(@"Found fetch request matching URL '%@': %@", URL, fetchRequest); + [fetchRequests addObject:fetchRequest]; + } + } + return fetchRequests; +} + +- (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)mappingResult error:(NSError **)error +{ + if (! self.deletesOrphanedObjects) { + RKLogDebug(@"Skipping deletion of orphaned objects: disabled as deletesOrphanedObjects=NO"); + return YES; + } + + if (! [[self.HTTPRequestOperation.request.HTTPMethod uppercaseString] isEqualToString:@"GET"]) { + RKLogDebug(@"Skipping deletion of orphaned objects: only performed for GET requests."); + return YES; + } + + if ([self canSkipMapping]) { + RKLogDebug(@"Skipping deletion of orphaned objects: 304 (Not Modified) status code encountered"); + return YES; + } + + // Determine if there are any fetch request blocks to use for orphaned object cleanup + NSArray *fetchRequests = [self fetchRequestsMatchingResponseURL]; + if (! [fetchRequests count]) return YES; + + // Proceed with cleanup + NSSet *managedObjectsInMappingResult = RKManagedObjectsFromMappingResultWithMappingInfo(mappingResult, self.mappingInfo) ?: [NSSet set]; + NSSet *localObjects = [self localObjectsFromFetchRequests:fetchRequests matchingRequestURL:error]; + if (! localObjects) { + RKLogError(@"Failed when attempting to fetch local candidate objects for orphan cleanup: %@", error ? *error : nil); + return NO; + } + RKLogDebug(@"Checking mappings result of %ld objects for %ld potentially orphaned local objects...", (long) [managedObjectsInMappingResult count], (long) [localObjects count]); + + NSMutableSet *orphanedObjects = [localObjects mutableCopy]; + [orphanedObjects minusSet:managedObjectsInMappingResult]; + RKLogDebug(@"Deleting %lu orphaned objects found in local database, but missing from mapping result", (unsigned long) [orphanedObjects count]); + + if ([orphanedObjects count]) { + [self.privateContext performBlockAndWait:^{ + for (NSManagedObject *orphanedObject in orphanedObjects) { + [self.privateContext deleteObject:orphanedObject]; + } + }]; + } + + return YES; +} + +/** + NOTE: This is more or less a direct port of the functionality provided by `[NSManagedObjectContext saveToPersistentStore:]` in the `RKAdditions` category. We have duplicated the logic here to add in support for checking if the operation has been cancelled since we began cascading up the MOC chain. Because each `performBlockAndWait:` invocation essentially jumps threads and is subject to the availability of the context, it is very possible for the operation to be cancelled during this part of the operation's lifecycle. + */ +- (BOOL)saveContextToPersistentStore:(NSManagedObjectContext *)contextToSave error:(NSError **)error +{ + __block NSError *localError = nil; + while (contextToSave) { + __block BOOL success; + [contextToSave performBlockAndWait:^{ + if (! [self isCancelled]) { + success = [contextToSave save:&localError]; + if (! success && localError == nil) RKLogWarning(@"Saving of managed object context failed, but a `nil` value for the `error` argument was returned. This typically indicates an invalid implementation of a key-value validation method exists within your model. This violation of the API contract may result in the save operation being mis-interpretted by callers that rely on the availability of the error."); + } else { + // We have been cancelled while the save is in progress -- bail + success = NO; + } + }]; + + if (! success) { + if (error) *error = localError; + return NO; + } + + if (! contextToSave.parentContext && contextToSave.persistentStoreCoordinator == nil) { + RKLogWarning(@"Reached the end of the chain of nested managed object contexts without encountering a persistent store coordinator. Objects are not fully persisted."); + return NO; + } + contextToSave = contextToSave.parentContext; + } + + return YES; +} + +- (BOOL)saveContext:(NSManagedObjectContext *)context error:(NSError **)error +{ + __block BOOL success = YES; + __block NSError *localError = nil; + if (self.savesToPersistentStore) { + success = [self saveContextToPersistentStore:context error:&localError]; + } else { + [context performBlockAndWait:^{ + success = ([self isCancelled]) ? NO : [context save:&localError]; + }]; + } + if (success) { + if ([self.targetObject isKindOfClass:[NSManagedObject class]]) { + [self.managedObjectContext performBlock:^{ + RKLogDebug(@"Refreshing mapped target object %@ in context %@", self.targetObject, self.managedObjectContext); + if (! [self isCancelled]) [self.managedObjectContext refreshObject:self.targetObject mergeChanges:YES]; + }]; + } + } else { + if (error) *error = localError; + RKLogError(@"Failed saving managed object context %@ %@: %@", (self.savesToPersistentStore ? @"to the persistent store" : @""), context, localError); + RKLogCoreDataError(localError); + } + + return success; +} + +- (BOOL)saveContext:(NSError **)error +{ + if (self.willSaveMappingContextBlock) { + self.mappingResult = _responseMapperOperation.mappingResult; + [self.privateContext performBlockAndWait:^{ + self.willSaveMappingContextBlock(self.privateContext); + }]; + } + + __block BOOL hasChanges; + [self.privateContext performBlockAndWait:^{ + hasChanges = [self.privateContext hasChanges]; + }]; + if (hasChanges) { + return [self saveContext:self.privateContext error:error]; + } else if ([self.targetObject isKindOfClass:[NSManagedObject class]]) { + NSManagedObjectContext *context = [(NSManagedObject *)self.targetObject managedObjectContext]; + __block BOOL isNew = NO; + [context performBlockAndWait:^{ + isNew = [(NSManagedObject *)self.targetObject isNew]; + }]; + // Object was like POST'd in an unsaved state and we wish to persist + if (isNew) [self saveContext:context error:error]; + } + + return YES; +} + +- (BOOL)obtainPermanentObjectIDsForInsertedObjects:(NSError **)error +{ + __block BOOL _blockSuccess = YES; + __block NSError *localError = nil; + [self.privateContext performBlockAndWait:^{ + NSArray *insertedObjects = [[self.privateContext insertedObjects] allObjects]; + RKLogDebug(@"Obtaining permanent ID's for %ld managed objects", (unsigned long) [insertedObjects count]); + _blockSuccess = [self.privateContext obtainPermanentIDsForObjects:insertedObjects error:&localError]; + }]; + if (!_blockSuccess && error) *error = localError; + + return _blockSuccess;; +} + +- (void)mapperDidFinishMapping:(RKMapperOperation *)mapper +{ + self.mappingInfo = mapper.mappingInfo; +} + +- (void)willFinish +{ + NSMutableIndexSet *deleteableStatusCodes = [NSMutableIndexSet indexSet]; + [deleteableStatusCodes addIndex:404]; // Not Found + [deleteableStatusCodes addIndex:410]; // Gone + if (self.error && self.targetObjectID + && [[[self.HTTPRequestOperation.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"] + && [deleteableStatusCodes containsIndex:self.HTTPRequestOperation.response.statusCode]) { + NSError *error = nil; + if (! [self deleteTargetObject:&error]) { + RKLogWarning(@"Secondary error encountered while attempting to delete target object in response to 404 (Not Found) or 410 (Gone) status code: %@", error); + self.error = error; + } else { + if (! [self saveContext:&error]) { + + } else { + // All good, clear any errors + self.error = nil; + } + } + } +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + RKManagedObjectRequestOperation *operation = (RKManagedObjectRequestOperation *)[super copyWithZone:zone]; + operation.managedObjectContext = self.managedObjectContext; + operation.managedObjectCache = self.managedObjectCache; + operation.fetchRequestBlocks = self.fetchRequestBlocks; + operation.deletesOrphanedObjects = self.deletesOrphanedObjects; + operation.savesToPersistentStore = self.savesToPersistentStore; + + return operation; +} + +@end + +#endif +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.h new file mode 100644 index 0000000..a1cd3ed --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.h @@ -0,0 +1,892 @@ +// +// RKObjectManager.h +// RestKit +// +// Created by Jeremy Ellison on 8/14/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouter.h" +#import "RKPaginator.h" +#import "RKMacros.h" +#import "AFNetworking.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#endif +#endif + +@protocol RKSerialization; +@class RKManagedObjectStore, RKObjectRequestOperation, RKManagedObjectRequestOperation, +RKMappingResult, RKRequestDescriptor, RKResponseDescriptor; + +/** + The `RKObjectManager` class provides a centralized interface for performing object mapping based HTTP request and response operations. It encapsulates common configuration such as request/response descriptors and routing, provides for the creation of `NSURLRequest` and `RKObjectRequestOperation` objects, and one-line methods to enqueue object request operations for the basic HTTP request methods (GET, POST, PUT, DELETE, etc). + + ## Object Request Operations + + Object request operations model the lifecycle of an object mapped HTTP request from start to finish. They are initialized with a fully configured `NSURLRequest` object and a set of `RKResponseDescriptor` objects that specify how an HTTP response is to be mapped into local domain objects. Object request operations may be constructed as standalone objects, but are often constructed through an `RKObjectManager` object. The object request operation encapsulates the functionality of two underlying operations that perform the bulk of the work. The HTTP request and response loading is handled by an `RKHTTPRequestOperation`, which is responsible for the HTTP transport details. Once a response has been successfully loaded, the object request operation starts an `RKResponseMapperOperation` that is responsible for handling the mapping of the response body. When working with Core Data, the `RKManagedObjectRequestOperation` class is used. The object manager encapsulates the Core Data configuration details and provides an interface that will return the appropriate object request operation for a request through the `appropriateObjectRequestOperationWithObject:method:path:parameters:` method. + + ## Base URL, Relative Paths and Path Patterns + + Each object manager is configured with a base URL that defines the URL that all request sent through the manager will be relative to. The base URL is configured directly through the `managerWithBaseURL:` method or is inherited from an AFNetworking `AFHTTPClient` object if the manager is initialized via the `initWithHTTPClient:` method. The base URL can point directly at the root of a URL or may include a path. + + Many of the methods of the object manager accept a path argument, either directly or in the form of a path pattern. Whenever a path is provided to the object manager directly, as part of a request or response descriptor (see "Request and Response Descriptors"), or via a route (see the "Routing" section), the path is used to construct an `NSURL` object with `[NSURL URLWithString:relativeToURL:]`. The rules for the evaluation of a relative URL can at times be surprising and many configuration errors result from incorrectly configuring the `baseURL` and relative paths thereof. For reference, here are some examples borrowed from the AFNetworking documentation detailing how base URL's and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Keep these rules in mind when providing relative paths to the object manager. + + Path patterns are a common unit of abstraction in RestKit for describing the path portion of URL's. When working with API's, there is typically one or more dynamic portions of the URL that correspond to primary keys or other identifying resource attributes. For example, a blogging application may represent articles in a URL structure such as '/articles/1234' and comments about an article might appear at '/articles/1234/comments'. These path structures could be represented as the path patterns '/articles/:articleID' and '/articles/:articleID/comments', substituing the dynamic key ':articleID' in place of the primary key of in the path. These keys can be used to interpolate a path with an object's property values using key-value coding or be used to match a string. + + Path patterns appear throughout RestKit, but the most fundamental uses are for the dynamic generation of URL paths from objects and the matching of request and response URLs for mapping configuration. When generating a URL, a path pattern is interpolated with the value of an object. Consider this example: + + // Set object attributes + RKArticle *article = [RKArticle new]; + article.articleID = @12345; + + // Interpolate with the object + NSString *path = RKPathFromPatternWithObject(@"/articles/:articleID", article); + NSLog(@"The path is %@", path); // prints /articles/12345 + + This may at first glance appear to provide only a small syntactic improvement over using `[NSString stringWithFormat:]`, but it becomes more interesting once you consider that the dynamic key can include key path: + + RKCategory *category = [RKCategory new]; + comment.name = @"RestKit; + article.category = category; + + NSString *path = RKPathFromPatternWithObject(@"/categories/:comment.name/articles/:articleID/comments/", article); + NSLog(@"The path is %@", path); // prints /categories/RestKit/articles/12345 + + These path patterns can then be registered with the manager via an `RKRoute` object (discussed in detail below), enabling one to perform object request operations like so: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + [manager.router.routeSet addRoute:[RKRoute routeWithClass:[RKArticle class] pathPattern:@"/categories/:comment.name/articles/:articleID/comments/" method:RKRequestMethodGET]]; + + // Now GET our article object... sending a GET to '/categories/RestKit/articles/12345' + [manager getObject:article path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"Loading mapping result: %@", result); + } failure:nil]; + + Once a path pattern has been registered via the routing system, the manager can automatically build full request URL's when given nothing but the object to be sent. + + The second use case of path patterns is in the matching of path into a dictionary of attributes. In this case, the path pattern is evaluatd against a string and used to construct an `NSDictionary` object containing the matched key paths, optionally including the values of a query string. This functionality is provided via the `RKPathMatcher` class and is discussed in detail in the accompanying documentation. + + ### Escaping Path Patterns + + Note that path patterns will by default interpret anything prefixed with a period that follows a dynamic path segment as a key path. This can cause an issue if you have a dynamic path segment that is followed by a file extension. For example, a path pattern of '/categories/:categoryID.json' would be erroneously interpretted as containing a dynamic path segment whose value is interpolated from the 'categoryID.json' key path. This key path evaluation behavior can be suppressed by escaping the period preceding the non-dynamic part of the pattern with two leading slashes, as in '/categories/:categoryID\\.json'. + + ## Request and Response Descriptors + + RestKit centralizes configuration for object mapping configurations into the object manager through `RKRequestDescriptor` and `RKResponseDescriptor` objects. A collection of each of these object types are maintained by the manager and used to initialize all `RKObjectRequestOperation` objects created by the manager. + + Request descriptors describe how `NSURLRequest` objects constructed by the manager will be built by specifying how the attributes and relationships for a given class will be object mapped to construct request parameters and what, if any, root key path the parameters will be nested under. Request descriptor objects can also be used with the `RKObjectParameterization` class to map an object into an `NSDictionary` representation that is suitable for use as the parameters of a request. + + Response descriptors describe how `NSHTTPURLResponse` objects loaded by object request operations sent by the manager are to be object mapped into local domain objects. Response descriptors are matched against a given response via URL path matching, parsed content key path matching, or both. The `RKMapping` object associated from a matched `RKResponseDescriptor` is given to an instance of `RKMapperOperation` with the parsed response body to perform object mapping on the response. + + To better illustrate these concepts, consider the following example for an imaginary Wiki client application: + + @interface RKWikiPage : NSObject + @property (nonatomic, copy) NSString *title; + @property (nonatomic, copy) NSString *body; + @end + + // Construct a request mapping for our class + RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; + [requestMapping addAttributeMappingsFromDictionary:@{ @"title": @"title", @"body": @"body" }]; + + // We wish to generate parameters of the format: + // @{ @"page": @{ @"title": @"An Example Page", @"body": @"Some example content" } } + RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:mapping + objectClass:[RKWikiPage class] + rootKeyPath:@"page"]; + + // Construct an object mapping for the response + // We are expecting JSON in the format: + // {"page": {"title": "", "body": "<body value>"} + RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[RKWikiPage class]]; + [responseMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]]; + + // Construct a response descriptor that matches any URL (the pathPattern is nil), when the response payload + // contains content nested under the `@"page"` key path, if the response status code is 200 (OK) + RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping + pathPattern:nil + keyPath:@"page" + statusCodes:[NSIndexSet indexSetWithIndex:200]]; + + // Register our descriptors with a manager + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org/"]]; + [manager addRequestDescriptor:requestDescriptor]; + [manager addResponseDescriptor:responseDescriptor]; + + // Work with the object + RKWikiPage *page = [RKWikiPage new]; + page.title = @"An Example Page"; + page.body = @"Some example content"; + + // POST the parameterized representation of the `page` object to `/posts` and map the response + [manager postObject:page path:@"/pages" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"We object mapped the response with the following result: %@", result); + } failure:nil]; + + In the above example, request and response mapping configurations were described for a simple data model and then used to perform a basic POST operation and map the results. An arbitrary number of request and response descriptors may be added to the manager to accommodate your application's needs. + + ## Multi-object Parameterization + + The object manager provides support for the parameterization of multiple objects provided as an array. The `requestWithObject:method:path:parameters:` and `multipartFormRequestWithObject:method:path:parameters:constructingBodyWithBlock:` methods can parameterize an array of objects for you provided that the `RKRequestDescriptor` objects are configured in a compatible way. The rules for multi-object parameterization are simple: + + 1. If a `nil` root key path is used, then it must be used for all objects in the array. This is because the objects will be parameterized into a dictionary and then each dictionary will be added to an array. This array is then serialized for transport, so objects parameterized to a non-nil key path cannot be merged with the array. + 1. If a `nil` root key path is used to parameterize the array of objects, then you cannot provide additional parameters to be merged with the request. This is again because you cannot merge a dictionary with an array. + + If non-nil key paths are used, then each object will be set in the parameters dictionary at the specified key path. If more than one object uses the same root key path, then the parameters will be combined into an array for transport. + + ## MIME Types + + MIME Types serve an important function to the object manager. They are used to identify how content is to be serialized when constructing request bodies and also used to set the 'Accept' header for content negotiation. RestKit aspires to be content type agnostic by leveraging the pluggable `RKMIMESerialization` class to handle content serialization and deserialization. + + ## Routing + + Routing is the process of generating an `NSURL` appropriate for a particular HTTP server request interaction. Using routing instead of hard-coding paths enables centralization of configuration and allows the developer to focus on what they want done rather than the details of how to do it. Changes to the URL structure in the application can be made in one place. Routes can also be useful in testing, as they permit for the changing of paths at run-time. + + Routing interfaces are provided by the `RKRouter` class. Each object manager is in initialized with an `RKRouter` object with a baseURL equal to the baseURL of the underlying `AFHTTPClient` object. Each `RKRouter` instance maintains an `RKRouteSet` object that manages a collection of `RKRoute` objects. Routes are defined in terms of a path pattern. + + There are three types of routes currently supported: + + 1. Class Routes. Class routes are configured to target a given object class and HTTP request method. For example, we might route the HTTP `GET` for a `User` class to the path pattern `@"/users/:userID"`. + 1. Relationship Routes. Relationship routes identify the path appropriate for performing a request for an object that is related to another object. For example, each `User` may have many friends. This might be routed as a relationship route for the `User` class with the name `@"friends"` to the path pattern `@"/users/:userID/friends"`. + 1. Named Routes. Names routes bind an arbitrary name to a path. For example, there might be an action to follow another user that could be added as a named route with the name `@"follow_user"` that generates a `POST` to the path pattern `@"/users/:userID/follow"`. + + To better understand these concepts, please consider the following example code for configuring the above routing examples: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + + // Class Route + [manager.router.routeSet addRoute:[RKRoute routeWithClass:[User class] pathPattern:@"/users/:userID" method:RKRequestMethodGET]]; + + // Relationship Route + [manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"friends" objectClass:[User class] pathPattern:@"/users/:userID/friends" method:RKRequestMethodGET]]; + + // Named Route + [manager.router.routeSet addRoute:[RKRoute routeWithName:@"follow_user" pathPattern:@"/users/:userID/follow" method:RKRequestMethodPOST]]; + + Once configured, routes will be consulted by the object manager whenever the path parameter provided to a method is given as nil. For example, invoking the following code would result in a `GET` to the path `@"/users/1234"`: + + User *user = [User new]; + user.userID = 1234; + [manager getObject:user path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + // Request + } failure:nil]; + + Routes can also be explicitly used to construct `NSMutableURLRequest` objects and are referenced explicitly in a few object request operation methods: + + 1. `requestWithObject:method:path:parameters:` - Consults routing when path is nil. + 1. `multipartFormRequestWithObject:method:path:parameters:constructingBodyWithBlock:` - Consults routing when path is nil. + 1. `requestWithPathForRouteNamed:object:parameters:` - Explicitly retrieves the route with the given name. + 1. `getObjectsAtPathForRelationship:ofObject:parameters:success:failure:` - Explicitly retrieves the route for the given name and object class. + 1. `getObjectsAtPathForRouteNamed:object:parameters:success:failure:` - Explicitly retrieves the route for the given name. + + Please see the documentation for `RKRouter`, `RKRouteSet`, and `RKRoute` for more details about the routing classes. + + ## Metadata Mapping + + The `RKObjectManager` class has integrated support for metadata mapping. Metdata mapping enables the object mapping of supplemental information external to the object representation loaded via an HTTP response. Object request operations constructed by the manager make the following metadata key paths available for mapping: + + 1. `@metadata.routing.parameters` - A dictionary whose keys are the key paths matched from the path pattern of the `RKRoute` object used to construct the request URL and whose values are taken by evaluating the key path against the object interpolated with the route. Only available when routing was used to construct the request URL. + 1. `@metadata.routing.route` - The route object used to construct the request URL. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + ## Core Data + + RestKit features deep integration with Apple's Core Data persistence framework. The object manager provides access to this integration by creating `RKManagedObjectRequestOperation` objects when an attempt is made to interact with a resource that has been mapped using an `RKEntityMapping`. To utilize the Core Data integration, the object manager must be provided with a fully configured `RKManagedObjectStore` object. The `RKManagedObjectStore` provides access to the `NSManagedObjectModel` and `NSManagedObjectContext` objects required to peform object mapping that targets a Core Data entity. + + Please see the documentation for `RKManagedObjectStore`, `RKEntityMapping`, and `RKManagedObjectRequestOperation` for in depth information about Core Data in RestKit. + + ## Customization & Subclassing Notes + + The object manager is designed to support subclassing. The default behaviors can be altered and tailored to the specific needs of your application easily by manipulating a few core methods: + + * `requestWithObject:method:path:parameters:` - Used to construct all `NSMutableURLRequest` objects used by the manager. + * `objectRequestOperationWithRequest:success:failure:` - Used to construct all non-managed object request operations for the manager. Provide a subclass implementation if you wish to alter the behavior of all unmanaged object request operations. + * `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` - Used to construct all managed object request operations for the manager. Provide a subclass implementation if you wish to alter the behavior of all managed object request operations. + * `appropriateObjectRequestOperationWithObject:method:path:parameters:` - Used to construct all object request operations for the manager, both managed and unmanaged. Invokes either `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` to construct the actual request. Provide a subclass implementation to alter behaviors for all object request operations constructed by the manager. + * `enqueueObjectRequestOperation:` - Invoked to enqueue all operations constructed by the manager that are to be started as soon as possible. Provide a subclass implementation if you wish to work with object request operations as they are be enqueued. + + If you wish to more specifically customize the behavior of the lower level HTTP details, you have several options. All HTTP requests made by the `RKObjectManager` class are made with an instance of the `RKHTTPRequestOperation` class, which is a subclass of the `AFHTTPRequestOperation` class from AFNetworking. This operation class implements the `NSURLConnectionDelegate` and `NSURLConnectionDataDelegate` protocols and as such, has full access to all details of the HTTP request/response cycle exposed by `NSURLConnection`. You can provide the object manager with your own custom subclass of `RKHTTPRequestOperation` to the manager via the `registerRequestOperationClass:` method and all HTTP requests made through the manager will pass through your operation. + + You can also customize the HTTP details at the AFNetworking level by subclassing `AFHTTPClient` and using an instance of your subclassed client to initialize the manager. + + @warning Note that when subclassing `AFHTTPClient` to change object manager behaviors it is not possible to alter the paramters of requests that are constructed on behalf of the manager. This is because the object manager handles its own serialization and construction of the request body, but defers to the `AFHTTPClient` for all other details (such as default HTTP headers, etc). + + @see `RKObjectRequestOperation` + @see `RKRouter` + @see `RKPathMatcher` + @see `RKMIMETypeSerialization` + */ +@interface RKObjectManager : NSObject + +///---------------------------------------------- +/// @name Configuring the Shared Manager Instance +///---------------------------------------------- + +/** + Return the shared instance of the object manager + + @return The shared manager instance. + */ ++ (instancetype)sharedManager; + +/** + Set the shared instance of the object manager + + @param manager The new shared manager instance. + */ ++ (void)setSharedManager:(RKObjectManager *)manager; + +///------------------------------------- +/// @name Initializing an Object Manager +///------------------------------------- + +/** + Creates and returns a new `RKObjectManager` object initialized with a new `AFHTTPClient` object that was in turn initialized with the given base URL. The RestKit defaults are applied to the object manager. + + When initialized with a base URL, the returned object manager will have a `requestSerializationMIMEType` with the value of `RKMIMETypeFormURLEncoded` and the underlying `HTTPClient` will have a default value for the 'Accept' header set to `RKMIMETypeJSON`, and the `AFJSONRequestOperation` class will be registered. + + @param baseURL The base URL with which to initialize the `AFHTTPClient` object + @return A new `RKObjectManager` initialized with an `AFHTTPClient` that was initialized with the given baseURL. + */ ++ (instancetype)managerWithBaseURL:(NSURL *)baseURL; + +/** + Initializes the receiver with the given AFNetworking HTTP client object, adopting the network configuration from the client. + + This is the designated initializer. If the `sharedManager` instance is `nil`, the receiver will be set as the `sharedManager`. The default headers and parameter encoding of the given HTTP client are adopted by the receiver to initialize the values of the `defaultHeaders` and `requestSerializationMIMEType` properties. + + @param client The AFNetworking HTTP client with which to initialize the receiver. + @return The receiver, initialized with the given client. + */ +- (instancetype)initWithHTTPClient:(AFHTTPClient *)client NS_DESIGNATED_INITIALIZER; + +///------------------------------------------ +/// @name Accessing Object Manager Properties +///------------------------------------------ + +/** + The AFNetworking HTTP client with which the receiver makes requests. + */ +@property (nonatomic, strong, readwrite) AFHTTPClient *HTTPClient; + +/** + The base URL of the underlying HTTP client. + */ +@property (nonatomic, readonly) NSURL *baseURL; + +/** + The default HTTP headers for all `NSURLRequest` objects constructed by the object manager. + + The returned dictionary contains all of the default headers set on the underlying `AFHTTPClient` object and the value of the 'Accept' header set on the object manager, if any. + + @see `setAcceptHeaderWithMIMEType:` + */ +@property (nonatomic, readonly) NSDictionary *defaultHeaders; + +/** + The operation queue which manages operations enqueued by the object manager. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +/** + The router used to generate URL objects for routable requests created by the manager. + + @see `RKRouter` + @see `RKRoute` + */ +@property (nonatomic, strong) RKRouter *router; + +///-------------------------------------------------- +/// @name Configuring Request and Response MIME Types +///-------------------------------------------------- + +/** + The MIME Type to serialize request parameters into when constructing request objects. + + The value of the `requestSerializationMIMEType` is used to obtain an appropriate `RKSerialization` conforming class from the `RKMIMESerialization` interface. Parameterized objects and dictionaries of parameters are then serialized for transport using the class registered for the MIME Type. By default, the value is `RKMIMETypeFormURLEncoded` which means that the request body of all `POST`, `PUT`, and `PATCH` requests will be sent in the URL encoded format. This is analagous to submitting an HTML form via a web browser. Other common formats include `RKMIMETypeJSON`, which will cause request bodies to be encoded as JSON. + + The value given for the `requestSerializationMIMEType` must correspond to a MIME Type registered via `[RKMIMETypeSerialization registerClass:forMIMEType:]`. Implementations are provided by default for `RKMIMETypeFormURLEncoded` and `RKMIMETypeJSON`. + + **Default**: `RKMIMETypeFormURLEncoded` or the value of the parameter encoding for the underlying `AFHTTPClient`. + */ +@property (nonatomic, strong) NSString *requestSerializationMIMEType; + +/** + Sets a default header on the HTTP client for the HTTP "Accept" header to specify the preferred serialization format for retrieved data. + + This method is a convenience method whose implementation is equivalent to the following example code: + + [manager.HTTPClient setDefaultHeader:@"Accept" value:MIMEType]; + + @param MIMEType The MIME Type to set as the value for the HTTP "Accept" header. + */ +- (void)setAcceptHeaderWithMIMEType:(NSString *)MIMEType; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + Creates and returns an `NSMutableURLRequest` object with a given object, method, path, and parameters. + + The manager is searched for an `RKRequestDescriptor` object with an objectClass that matches the class of the given object. If found, the matching request descriptor and object are used to build a parameterization of the object's attributes using the `RKObjectParameterization` class if the request method is a `POST`, `PUT`, or `PATCH`. The parameterized representation of the object is reverse merged with the given parameters dictionary, if any, and then serialized and set as the request body. If the HTTP method is `GET` or `DELETE`, the object will not be parameterized and the given parameters, if any, will be used to construct a url-encoded query string that is appended to the request's URL. + + If the given path is nil, the router is searched for a class route with the class of the object andthe method. The path pattern of the retrieved route is interpolated with the object and the resulting path is appended to the HTTP client's base URL and used as the request URL. + + @param object The object with which to construct the request. For the `POST`, `PUT`, and `PATCH` request methods, the object will parameterized using the `RKRequestDescriptor` for the object. + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + + @return An `NSMutableURLRequest` object. + @see RKObjectParameterization + @see RKRouter + */ +- (NSMutableURLRequest *)requestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + This method wraps the underlying `AFHTTPClient` method `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock` and adds routing and object parameterization. + + @param object The object with which to construct the request. For the `POST`, `PUT`, and `PATCH` request methods, the object will parameterized using the `RKRequestDescriptor` for the object. + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + @return An `NSMutableURLRequest` object. + @warning An exception will be raised if the specified method is not `POST`, `PUT` or `DELETE`. + @see [AFHTTPClient multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock] + */ +- (NSMutableURLRequest *)multipartFormRequestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block; + +/** + Creates an `NSMutableURLRequest` object with the `NSURL` returned by the router for the given route name and object and the given parameters. + + The implementation invokes `requestWithObject:method:path:parameters:` after constructing the path with the given route. + + @param routeName The name of the route object containing the path pattern which is to be interpolated against the given object, appended to the HTTP client's base URL and used as the request URL. + @param object The object with which to interpolate the path pattern of the named route. Can be nil. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + @return An `NSMutableRequest` object. + + @see `requestWithObject:method:path:parameters` + */ +- (NSMutableURLRequest *)requestWithPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters; +/** + Creates an `NSMutableURLRequest` object with the `NSURL` returned by the router for the relationship of the given object and the given parameters. + + The implementation invokes `requestWithObject:method:path:parameters:` after constructing the path with the given route. + + Creates an `RKObjectRequestOperation` with a `GET` request for the relationship with the given name of the given object, and enqueues it to the manager's operation queue. + + @param relationship The name of the relationship being loaded. Used to retrieve the `RKRoute` object from the router for the given object's class and the relationship name. Cannot be nil. + @param object The object for which related objects are being loaded. Evaluated against the `RKRoute` for the relationship for the object's class with the given name to compute the path. Cannot be nil. + @param method The HTTP method for the request. + @param parameters The parameters to be encoded and appended as the query string for the request URL, or parameterized and set as the request body. May be nil. + @return An `NSMutableURLRequest` object for the specified relationship. + + @raises NSInvalidArgumentException Raised if no route is configured for a relationship of the given object's class with the given name. + @see `requestWithObject:method:path:parameters` + */ +- (NSMutableURLRequest *)requestWithPathForRelationship:(NSString *)relationship + ofObject:(id)object + method:(RKRequestMethod)method + parameters:(NSDictionary *)parameters; + +///----------------------------------------- +/// @name Creating Object Request Operations +///----------------------------------------- + +/** + Attempts to register a subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation`, adding it to a list of classes that are consulted each time the receiver needs to construct an HTTP or object request operation with a URL request. + + When `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is invoked, each registered subclass is consulted to see if it can handle the request. The first class to return `YES` when sent a `+ canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + There is no guarantee that all registered classes will be consulted. The object manager will only consider direct subclasses of `RKObjectRequestOperation` when `objectRequestOperationWithRequest:success:failure` is called and will only consider subclasses of `RKManagedObjectRequestOperation` when `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called. If you wish to map a mixture of managed and unmanaged objects within the same object request operation you must register a `RKManagedObjectRequestOperation` subclass. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list. + + @param operationClass The subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` to register. + @return `YES` if the given class was registered successfully, else `NO`. The only failure condition is if `operationClass` is not a subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation`. + */ +- (BOOL)registerRequestOperationClass:(Class)operationClass; + +/** + Unregisters the specified subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` from the list of classes consulted when `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called. + + @param operationClass The subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` to unregister. + */ +- (void)unregisterRequestOperationClass:(Class)operationClass; + +/** + Creates an `RKObjectRequestOperation` operation with the given request and sets the completion block with the given success and failure blocks. + + In order to determine what kind of operation is created, each registered `RKObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + @return An `RKObjectRequestOperation` object that is ready to be sent. + + @warning Instances of `RKObjectRequestOperation` are not capable of mapping the loaded `NSHTTPURLResponse` into a Core Data entity. Use an instance of `RKManagedObjectRequestOperation` if the response is to be mapped using an `RKEntityMapping`. + */ +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKManagedObjectRequestOperation` operation with the given request and managed object context, and sets the completion block with the given success and failure blocks. + + The given managed object context given will be used as the parent context of the private managed context in which the response is mapped and will be used to fetch the results upon invocation of the success completion block. + + In order to determine what kind of operation is created, each registered `RKManagedObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param managedObjectContext The managed object context with which to associate the operation. This context will be used as the parent context of a new operation local `NSManagedObjectContext` with the `NSPrivateQueueConcurrencyType` concurrency type. Upon success, the private context will be saved and changes resulting from the object mapping will be 'pushed' to the given context. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + @return An `RKObjectRequestOperation` object that is ready to be sent. + + @see `RKManagedObjectRequestOperation` + */ +#ifdef RKCoreDataIncluded +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; +#endif + +/** + Creates and returns an object request operation of the appropriate type for the given object, request method, path, and parameters. + + The type of object request operation created is determined by evaluating the type of the object given and examining the list of `RKResponseDescriptor` objects added to the manager. + + If the given object is non-nil and inherits from `NSManagedObject`, then an instance of `RKManagedObjectRequestOperation` is returned. + + If the given object is nil, then the `RKResponseDescriptor` objects added to the manager are evaluated to determine the type of operation created. In this case, the path of the operation is used to filter the set of `RKResponseDescriptor` objects to those that may be used to map the response. If the path is nil, the router is consulted to determine an appropriate path with which to perform the matching. If the filtered array of matching response descriptors defines a mapping configuration with an `RKEntityMapping` object, then an `RKManagedObjectRequestOperation` is returned; otherwise an `RKObjectRequestOperation` is returned. + + If an `RKManagedObjectRequestOperation` operation is created, the managed object context used will be the `mainQueueManagedObjectContext` of the manager's `managedObjectStore`. + + @param object The object with which to construct the object request operation. May be nil. + @param method The request method for the request. + @param path The path to be appended to the HTTP client's baseURL and set as the URL of the request. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + + @return A newly created `RKObjectRequestOperation` or `RKManagedObjectRequest` operation as deemed appropriate by the manager for the given parameters. + @warning The given object must be a single object instance. Collections are not yet supported. + + @see `requestWithObject:method:path:parameters` + */ +- (id)appropriateObjectRequestOperationWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +///-------------------------------------------------- +/// @name Managing Enqueued Object Request Operations +///-------------------------------------------------- + +/** + Enqueues an `RKObjectRequestOperation` to the object manager's operation queue. + + @param objectRequestOperation The object request operation to be enqueued. + */ +- (void)enqueueObjectRequestOperation:(RKObjectRequestOperation *)objectRequestOperation; + +/** + Returns an array of operations in the object manager's operation queue whose requests match the specified HTTP method and path pattern. + + Paths are matches against the `path` of the `NSURL` of the `NSURLRequest` of each `RKObjectRequestOperation` contained in the receiver's operation queue using a `RKPathMatcher` object. + + @param method The HTTP method to match for the cancelled requests, such as `RKRequestMethodGET`, `RKRequestMethodPOST`, `RKRequestMethodPUT`, `RKRequestMethodPatch`, or `RKRequestMethodDELETE`. If `RKRequestMethodAny`, all object request operations with URLs matching the given path pattern will be cancelled. Multiple methods may be specified by using a bitwise OR operation. + @param pathPattern The pattern to match against the path of the request URL for executing object request operations considered for cancellation. + @return A new array containing all enqueued `RKObjectRequestOperation` objects that match the given HTTP method and path pattern. + @see `RKPathMatcher` + */ +- (NSArray *)enqueuedObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern; + +/** + Cancels all operations in the object manager's operation queue whose requests match the specified HTTP method and path pattern. + + Paths are matches against the `path` of the `NSURL` of the `NSURLRequest` of each `RKObjectRequestOperation` contained in the receiver's operation queue using a `RKPathMatcher` object. + + @param method The HTTP method to match for the cancelled requests, such as `RKRequestMethodGET`, `RKRequestMethodPOST`, `RKRequestMethodPUT`, `RKRequestMethodPatch`, or `RKRequestMethodDELETE`. If `RKRequestMethodAny`, all object request operations with URLs matching the given path pattern will be cancelled. + @param pathPattern The pattern to match against the path of the request URL for executing object request operations considered for cancellation. + + @see `RKPathMatcher` + */ +- (void)cancelAllObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern; + +///----------------------------------------- +/// @name Batching Object Request Operations +///----------------------------------------- + +/** + Creates and enqueues an `RKObjectRequestOperation` to the object manager's operation queue for each specified object into a batch. Each object request operation is built by evaluating the object against the given route to construct a request path and then invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. When each object request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @warning Note that the route type is significant in how that the object request operation is constructed. If the given route is a class route, then the `targetObject` of the operation will be set to the object for which the operation is being constructed. For named routes and relationship routes, the target object is `nil`. + + @param route The route specifying the request method and the path pattern with which to construct the request for each object object request operation in the batch. + @param objects The set of objects for which to enqueue a batch of object request operations. + @param progress A block object to be executed when an object request operation completes. This block has no return value and takes two arguments: the number of finished operations and the total number of operations initially executed. + @param completion A block object to be executed when the object request operations complete. This block has no return value and takes one argument: the list of operations executed. + + @see `[RKObjectManager enqueueBatchOfObjectRequestOperations:progress:completion]` + @see `RKRoute` + */ +- (void)enqueueBatchOfObjectRequestOperationsWithRoute:(RKRoute *)route + objects:(NSArray *)objects + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion; + +/** + Enqueues a set of `RKObjectRequestOperation` to the object manager's operation queue. + + @param operations The set of object request operations to be enqueued. + @param progress A block object to be executed when an object request operation completes. This block has no return value and takes two arguments: the number of finished operations and the total number of operations initially executed. + @param completion A block object to be executed when the object request operations complete. This block has no return value and takes one argument: the list of operations executed. + + */ +- (void)enqueueBatchOfObjectRequestOperations:(NSArray *)operations + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion; + +///------------------------------------- +/// @name Making Object Requests by Path +///------------------------------------- + +/** + Creates an `RKObjectRequestOperation` with a `GET` request with a URL for the given path, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the relationship with the given name of the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param relationshipName The name of the relationship being loaded. Used to retrieve the `RKRoute` object from the router for the given object's class and the relationship name. Cannot be nil. + @param object The object for which related objects are being loaded. Evaluated against the `RKRoute` for the relationship for the object's class with the given name to compute the path. Cannot be nil. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the mapped result created from object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @raises NSInvalidArgumentException Raised if no route is configured for a relationship of the given object's class with the given name. + @see [RKRouter URLForRelationship:ofObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPathForRelationship:(NSString *)relationshipName + ofObject:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the URL returned by the router for the given route name, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param routeName The name of the route being loaded. Used to retrieve the `RKRoute` object from the router with the given name. Cannot be nil. + @param object The object to be interpolated against the path pattern of the `RKRoute` object retrieved with the given name. Used to compute the path to be appended to the HTTP client's base URL and used as the request URL. May be nil. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the mapped result created from object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @raises NSInvalidArgumentException Raised if no route is configured with the given name or the route returned specifies an HTTP method other than `GET`. + @see [RKRouter URLForRouteNamed:method:object:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +///------------------------------------------- +/// @name Making Object Requests for an Object +///------------------------------------------- + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodGET` request method. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `POST` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPOST` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)postObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `PUT` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPUT` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)putObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `PATCH` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPATCH` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)patchObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `DELETE` request for the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodDELETE` request method. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)deleteObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +///------------------------------------------------ +/// @name Managing Request and Response Descriptors +///------------------------------------------------ + +/** + Returns an array containing the `RKRequestDescriptor` objects added to the manager. + + @return An array containing the request descriptors of the receiver. The elements of the array are instances of `RKRequestDescriptor`. + + @see RKRequestDescriptor + */ +@property (nonatomic, readonly) NSArray *requestDescriptors; + +/** + Adds a request descriptor to the manager. + + @param requestDescriptor The request descriptor object to the be added to the manager. + */ +- (void)addRequestDescriptor:(RKRequestDescriptor *)requestDescriptor; + +/** + Adds the `RKRequestDescriptor` objects contained in a given array to the manager. + + @param requestDescriptors An array of `RKRequestDescriptor` objects to be added to the manager. + @exception NSInvalidArgumentException Raised if any element of the given array is not an `RKRequestDescriptor` object. + */ +- (void)addRequestDescriptorsFromArray:(NSArray *)requestDescriptors; + +/** + Removes a given request descriptor from the manager. + + @param requestDescriptor An `RKRequestDescriptor` object to be removed from the manager. + */ +- (void)removeRequestDescriptor:(RKRequestDescriptor *)requestDescriptor; + +/** + Returns an array containing the `RKResponseDescriptor` objects added to the manager. + + @return An array containing the request descriptors of the receiver. The elements of the array are instances of `RKRequestDescriptor`. + + @see RKResponseDescriptor + */ +@property (nonatomic, readonly) NSArray *responseDescriptors; + +/** + Adds a response descriptor to the manager. + + Adding a response descriptor to the manager sets the `baseURL` of the descriptor to the `baseURL` of the manager, causing it to evaluate URL objects relatively. + + @param responseDescriptor The response descriptor object to the be added to the manager. + */ +- (void)addResponseDescriptor:(RKResponseDescriptor *)responseDescriptor; + +/** + Adds the `RKResponseDescriptor` objects contained in a given array to the manager. + + @param responseDescriptors An array of `RKResponseDescriptor` objects to be added to the manager. + @exception NSInvalidArgumentException Raised if any element of the given array is not an `RKResponseDescriptor` object. + */ +- (void)addResponseDescriptorsFromArray:(NSArray *)responseDescriptors; + +/** + Removes a given response descriptor from the manager. + + @param responseDescriptor An `RKResponseDescriptor` object to be removed from the manager. + */ +- (void)removeResponseDescriptor:(RKResponseDescriptor *)responseDescriptor; + +///---------------------------------------- +/// @name Configuring Core Data Integration +///---------------------------------------- + +#ifdef RKCoreDataIncluded +/** + A Core Data backed object store for persisting objects that have been fetched from the Web + */ +@property (nonatomic, strong) RKManagedObjectStore *managedObjectStore; + +/** + An array of `RKFetchRequestBlock` blocks used to map `NSURL` objects into corresponding `NSFetchRequest` objects. + + When searched, the blocks are iterated in the reverse-order of their registration and the first block with a non-nil return value halts the search. + */ +@property (nonatomic, readonly) NSArray *fetchRequestBlocks; + +/** + Adds the given `RKFetchRequestBlock` block to the manager. + + @param block A block object to be executed when constructing an `NSFetchRequest` object from a given `NSURL`. The block has a return type of `NSFetchRequest` and accepts a single `NSURL` argument. + */ +- (void)addFetchRequestBlock:(NSFetchRequest *(^)(NSURL *URL))block; +#endif + +///------------------------------------ +/// @name Accessing Paginated Resources +///------------------------------------ + +/** + The object mapping describing how to map pagination metadata from paginated responses. + + The object mapping must have an object class of `RKPaginator`. + + @see [RKPaginator initWithRequest:paginationMapping:responseDescriptors] + */ +@property (nonatomic, strong) RKObjectMapping *paginationMapping; + +/** + Creates and returns a paginator object configured to paginate the collection resource accessible at the specified path pattern. + + The paginator instantiated will be initialized with a URL built by appending the given pathPattern to the baseURL of the client. The response descriptors and Core Data configuration, if any, are inherited from the receiver. + + @param pathPattern A patterned URL fragment to be appended to the baseURL of the receiver in order to construct the pattern URL with which to access the paginated collection. + @return The newly created paginator instance. + @see RKPaginator + @warning Will raise an exception if the value of the `paginationMapping` property is nil. + */ +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern; + +/** + Creates and returns a paginator object configured to paginate the collection resource accessible at the specified path pattern and the given parameters. + + The paginator instantiated will be initialized with a URL built by appending the given pathPattern to the baseURL of the client and the given parameters if any. The response descriptors and Core Data configuration, if any, are inherited from the receiver. + + @param pathPattern A patterned URL fragment to be appended to the baseURL of the receiver in order to construct the pattern URL with which to access the paginated collection. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @return The newly created paginator instance. + @see RKPaginator + @warning Will raise an exception if the value of the `paginationMapping` property is nil. + */ +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters; + +@end + +#ifdef _SYSTEMCONFIGURATION_H +/** + Returns a string description of the given network status. + + @param networkReachabilityStatus The network reachability status. + @return A string describing the reachability status. + */ +NSString *RKStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus networkReachabilityStatus); +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.m new file mode 100644 index 0000000..800f84e --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectManager.m @@ -0,0 +1,1018 @@ +// +// RKObjectManager.m +// RestKit +// +// Created by Jeremy Ellison on 8/14/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKObjectManager.h" +#import "RKObjectParameterization.h" +#import "RKRequestDescriptor.h" +#import "RKResponseDescriptor.h" +#import "RKDictionaryUtilities.h" +#import "RKMIMETypes.h" +#import "RKLog.h" +#import "RKMIMETypeSerialization.h" +#import "RKPathMatcher.h" +#import "RKMappingErrors.h" +#import "RKPaginator.h" +#import "RKDynamicMapping.h" +#import "RKRelationshipMapping.h" +#import "RKObjectRequestOperation.h" +#import "RKRouter.h" +#import "RKRoute.h" +#import "RKRouteSet.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectStore.h" +#import "RKManagedObjectRequestOperation.h" +#endif +#endif + +#if !__has_feature(objc_arc) +#error RestKit must be built with ARC. +// You can turn on ARC for only RestKit files by adding "-fobjc-arc" to the build phase for each of its files. +#endif + +////////////////////////////////// +// Shared Instance + +static RKObjectManager *sharedManager = nil; + +////////////////////////////////// +// Utility Functions + +/** + Returns the subset of the given array of `RKResponseDescriptor` objects that match the given path. + + @param responseDescriptors An array of `RKResponseDescriptor` objects. + @param path The path for which to select matching response descriptors. + @param method The method for which to select matching response descriptors. + @return An `NSArray` object whose elements are `RKResponseDescriptor` objects matching the given path and method. + */ +#ifdef RKCoreDataIncluded +static NSArray *RKFilteredArrayOfResponseDescriptorsMatchingPathAndMethod(NSArray *responseDescriptors, NSString *path, RKRequestMethod method) +{ + NSIndexSet *indexSet = [responseDescriptors indexesOfObjectsPassingTest:^BOOL(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + return [responseDescriptor matchesPath:path] && (method & responseDescriptor.method); + }]; + return [responseDescriptors objectsAtIndexes:indexSet]; +} +#endif + +/** + Returns the first `RKRequestDescriptor` object from the given array that matches the given object. + + @param requestDescriptors An array of `RKRequestDescriptor` objects. + @param object The object to find a matching request descriptor for. + @return An `RKRequestDescriptor` object matching the given object, or `nil` if none could be found. + */ +RKRequestDescriptor *RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(NSArray *requestDescriptors, id object, RKRequestMethod requestMethod); +RKRequestDescriptor *RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(NSArray *requestDescriptors, id object, RKRequestMethod requestMethod) +{ + Class searchClass = [object class]; + do { + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + if ([requestDescriptor.objectClass isEqual:searchClass] && (requestMethod == requestDescriptor.method)) return requestDescriptor; + } + + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + if ([requestDescriptor.objectClass isEqual:searchClass] && (requestMethod & requestDescriptor.method)) return requestDescriptor; + } + searchClass = [searchClass superclass]; + } while (searchClass); + + return nil; +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKObjectParameters : NSObject + +@property (nonatomic, strong) NSMutableDictionary *parameters; +- (void)addParameters:(NSDictionary *)serialization atRootKeyPath:(NSString *)rootKeyPath inArray:(BOOL)inArray; + +@end + +@implementation RKObjectParameters + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.parameters = [NSMutableDictionary new]; + } + return self; +} + +- (void)addParameters:(NSDictionary *)parameters atRootKeyPath:(NSString *)rootKeyPath inArray:(BOOL)inArray +{ + id rootKey = rootKeyPath ?: [NSNull null]; + id nonNestedParameters = rootKeyPath ? parameters[rootKeyPath] : parameters; + id value = (self.parameters)[rootKey]; + if (value) { + if ([value isKindOfClass:[NSMutableArray class]]) { + [value addObject:nonNestedParameters]; + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:value, nonNestedParameters, nil]; + (self.parameters)[rootKey] = mutableArray; + } else { + [NSException raise:NSInvalidArgumentException format:@"Unexpected argument of type '%@': expected an NSDictionary or NSArray.", [value class]]; + } + } else { + (self.parameters)[rootKey] = (inArray ? @[ nonNestedParameters ] : nonNestedParameters); + } +} + +- (id)requestParameters +{ + if ([self.parameters count] == 0) return nil; + id valueAtNullKey = (self.parameters)[[NSNull null]]; + if (valueAtNullKey) { + if ([self.parameters count] == 1) return valueAtNullKey; + + // If we have values at `[NSNull null]` and other key paths, we have an invalid configuration + [NSException raise:NSInvalidArgumentException format:@"Invalid request descriptor configuration: The request descriptors specify that multiple objects be serialized at incompatible key paths. Cannot serialize objects at the `nil` root key path in the same request as objects with a non-nil root key path. Please check your request descriptors and try again."]; + } + return self.parameters; +} + +@end + +/** + Visits all mappings accessible via relationships or dynamic mapping in an object graph starting from a given mapping. + */ +@interface RKMappingGraphVisitor : NSObject + +@property (nonatomic, readonly) NSSet *mappings; + +- (instancetype)initWithMapping:(RKMapping *)mapping NS_DESIGNATED_INITIALIZER; + +@end + +@interface RKMappingGraphVisitor () +@property (nonatomic, readwrite) NSMutableSet *mutableMappings; +@end + +@implementation RKMappingGraphVisitor + +- (instancetype)initWithMapping:(RKMapping *)mapping +{ + self = [super init]; + if (self) { + self.mutableMappings = [NSMutableSet set]; + [self visitMapping:mapping]; + } + return self; +} + +- (NSSet *)mappings +{ + return self.mutableMappings; +} + +- (void)visitMapping:(RKMapping *)mapping +{ + if ([self.mappings containsObject:mapping]) return; + [self.mutableMappings addObject:mapping]; + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + for (RKMapping *nestedMapping in dynamicMapping.objectMappings) { + [self visitMapping:nestedMapping]; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + RKObjectMapping *objectMapping = (RKObjectMapping *)mapping; + for (RKRelationshipMapping *relationshipMapping in objectMapping.relationshipMappings) { + [self visitMapping:relationshipMapping.mapping]; + } + } +} + +@end + +/** + Returns `YES` if the given array of `RKResponseDescriptor` objects contains an `RKEntityMapping` anywhere in its object graph. + + @param responseDescriptors An array of `RKResponseDescriptor` objects. + @return `YES` if the `mapping` property of any of the response descriptor objects in the given array is an instance of `RKEntityMapping`, else `NO`. + */ +#ifdef RKCoreDataIncluded +static BOOL RKDoesArrayOfResponseDescriptorsContainEntityMapping(NSArray *responseDescriptors) +{ + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + // Enumerate all mappings and search for an `RKEntityMapping` + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKEntityMapping class]]) { + return YES; + } + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + if ([dynamicMapping.objectMappings count] == 0) { + // Likely means that there is a representation block, assume `YES` + return YES; + } + } + } + + return NO; +} +#endif + +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors); +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors) +{ +#ifdef RKCoreDataIncluded + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + NSMutableSet *mappingClasses = [NSMutableSet set]; + // Enumerate all mappings and search for an `RKEntityMapping` + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + [mappingClasses addObjectsFromArray:[[(RKDynamicMapping *)mapping objectMappings] valueForKey:@"class"]]; + } else { + [mappingClasses addObject:mapping.class]; + } + } + + if ([mappingClasses count]) { + for (Class mappingClass in mappingClasses) { + if (! [mappingClass isSubclassOfClass:[RKEntityMapping class]]) { + return NO; + } + } + return YES; + } +#endif + + return NO; +} + +static BOOL RKDoesArrayOfResponseDescriptorsContainMappingForClass(NSArray *responseDescriptors, Class classToBeMapped) +{ + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + // Enumerate all mappings and search for a mapping matching the class + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKObjectMapping class]]) { + if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES; + } + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + for (RKObjectMapping *mapping in dynamicMapping.objectMappings) { + if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES; + } + } + } + + return NO; +} + +static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParameterEncoding encoding) +{ + switch (encoding) { + case AFFormURLParameterEncoding: + return RKMIMETypeFormURLEncoded; + break; + + case AFJSONParameterEncoding: + return RKMIMETypeJSON; + break; + + case AFPropertyListParameterEncoding: + break; + + default: + RKLogWarning(@"RestKit is unable to infer the appropriate request serialization MIME Type from an `AFHTTPClientParameterEncoding` value of %d: defaulting to `RKMIMETypeFormURLEncoded`", encoding); + break; + } + + return RKMIMETypeFormURLEncoded; +} + +@interface AFHTTPClient () +@property (readonly, nonatomic, strong) NSURLCredential *defaultCredential; +@end + +/////////////////////////////////// + +@interface RKObjectManager () +@property (nonatomic, strong) NSMutableArray *mutableRequestDescriptors; +@property (nonatomic, strong) NSMutableArray *mutableResponseDescriptors; +@property (nonatomic, strong) NSMutableArray *mutableFetchRequestBlocks; +@property (nonatomic, strong) NSMutableArray *registeredHTTPRequestOperationClasses; +@property (nonatomic, strong) NSMutableArray *registeredObjectRequestOperationClasses; +@property (nonatomic, strong) NSMutableArray *registeredManagedObjectRequestOperationClasses; + +@end + +@implementation RKObjectManager + +- (instancetype)initWithHTTPClient:(AFHTTPClient *)client +{ + self = [super init]; + if (self) { + self.HTTPClient = client; + self.router = [[RKRouter alloc] initWithBaseURL:client.baseURL]; + self.operationQueue = [NSOperationQueue new]; + self.mutableRequestDescriptors = [NSMutableArray new]; + self.mutableResponseDescriptors = [NSMutableArray new]; + self.mutableFetchRequestBlocks = [NSMutableArray new]; + self.registeredHTTPRequestOperationClasses = [NSMutableArray new]; + self.registeredManagedObjectRequestOperationClasses = [NSMutableArray new]; + self.registeredObjectRequestOperationClasses = [NSMutableArray new]; + self.requestSerializationMIMEType = RKMIMETypeFromAFHTTPClientParameterEncoding(client.parameterEncoding); + + // Set shared manager if nil + if (nil == sharedManager) { + [RKObjectManager setSharedManager:self]; + } + } + + return self; +} + ++ (instancetype)sharedManager +{ + return sharedManager; +} + ++ (void)setSharedManager:(RKObjectManager *)manager +{ + sharedManager = manager; +} + ++ (RKObjectManager *)managerWithBaseURL:(NSURL *)baseURL +{ + RKObjectManager *manager = [[self alloc] initWithHTTPClient:[AFHTTPClient clientWithBaseURL:baseURL]]; + [manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; + [manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; + manager.requestSerializationMIMEType = RKMIMETypeFormURLEncoded; + return manager; +} + +- (void)setAcceptHeaderWithMIMEType:(NSString *)MIMEType; +{ + [self.HTTPClient setDefaultHeader:@"Accept" value:MIMEType]; +} + +- (NSURL *)baseURL +{ + return self.HTTPClient.baseURL; +} + +- (NSDictionary *)defaultHeaders +{ + return self.HTTPClient.defaultHeaders; +} + +#pragma mark - Building Requests + +/** + This method is the `RKObjectManager` analog for the method of the same name on `AFHTTPClient`. + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + NSMutableURLRequest* request; + if (parameters && !([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"])) { + // NOTE: If the HTTP client has been subclasses, then the developer may be trying to perform signing on the request + NSDictionary *parametersForClient = [self.HTTPClient isMemberOfClass:[AFHTTPClient class]] ? nil : parameters; + request = [self.HTTPClient requestWithMethod:method path:path parameters:parametersForClient]; + + NSError *error = nil; + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.HTTPClient.stringEncoding)); + [request setValue:[NSString stringWithFormat:@"%@; charset=%@", self.requestSerializationMIMEType, charset] forHTTPHeaderField:@"Content-Type"]; + NSData *requestBody = [RKMIMETypeSerialization dataFromObject:parameters MIMEType:self.requestSerializationMIMEType error:&error]; + [request setHTTPBody:requestBody]; + } else { + request = [self.HTTPClient requestWithMethod:method path:path parameters:parameters]; + } + + return request; +} + +- (NSMutableURLRequest *)requestWithPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters +{ + RKRequestMethod method; + NSURL *URL = [self.router URLForRouteNamed:routeName method:&method object:object]; + NSAssert(URL, @"No route found named '%@'", routeName); + return [self requestWithMethod:RKStringFromRequestMethod(method) path:[URL relativeString] parameters:parameters]; +} + +- (NSMutableURLRequest *)requestWithPathForRelationship:(NSString *)relationship + ofObject:(id)object + method:(RKRequestMethod)method + parameters:(NSDictionary *)parameters +{ + NSURL *URL = [self.router URLForRelationship:relationship ofObject:object method:method]; + NSAssert(URL, @"No relationship route found for the '%@' class with the name '%@'", NSStringFromClass([object class]), relationship); + return [self requestWithMethod:RKStringFromRequestMethod(method) path:[URL relativeString] parameters:parameters]; +} + +- (id)mergedParametersWithObject:(id)object method:(RKRequestMethod)method parameters:(NSDictionary *)parameters +{ + NSArray *objectsToParameterize = ([object isKindOfClass:[NSArray class]] || object == nil) ? object : @[ object ]; + RKObjectParameters *objectParameters = [RKObjectParameters new]; + for (id objectToParameterize in objectsToParameterize) { + RKRequestDescriptor *requestDescriptor = RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(self.requestDescriptors, objectToParameterize, method); + if ((method != RKRequestMethodGET && method != RKRequestMethodDELETE) && requestDescriptor) { + NSError *error = nil; + NSDictionary *parametersForObject = [RKObjectParameterization parametersWithObject:objectToParameterize requestDescriptor:requestDescriptor error:&error]; + if (error) { + RKLogError(@"Object parameterization failed while building %@ request for object '%@': %@", RKStringFromRequestMethod(method), objectToParameterize, error); + return nil; + } + // Ensure that a single object inputted as an array is emitted as an array when serialized + BOOL inArray = ([object isKindOfClass:[NSArray class]] && [object count] == 1); + [objectParameters addParameters:parametersForObject atRootKeyPath:requestDescriptor.rootKeyPath inArray:inArray]; + } + } + id requestParameters = [objectParameters requestParameters]; + + // Merge the extra parameters if possible + if ([requestParameters isKindOfClass:[NSArray class]] && parameters) { + [NSException raise:NSInvalidArgumentException format:@"Cannot merge parameters with array of object representations serialized with a nil root key path."]; + } else if (requestParameters && parameters) { + requestParameters = RKDictionaryByMergingDictionaryWithDictionary(requestParameters, parameters); + } else if (parameters && !requestParameters) { + requestParameters = parameters; + } + + return requestParameters; +} + +- (NSMutableURLRequest *)requestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; +{ + NSString *requestPath = (path) ? path : [[self.router URLForObject:object method:method] relativeString]; + id requestParameters = [self mergedParametersWithObject:object method:method parameters:parameters]; + return [self requestWithMethod:RKStringFromRequestMethod(method) path:requestPath parameters:requestParameters]; +} + +- (NSMutableURLRequest *)multipartFormRequestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block +{ + NSString *requestPath = (path) ? path : [[self.router URLForObject:object method:method] relativeString]; + id requestParameters = [self mergedParametersWithObject:object method:method parameters:parameters]; + NSMutableURLRequest *multipartRequest = [self.HTTPClient multipartFormRequestWithMethod:RKStringFromRequestMethod(method) + path:requestPath + parameters:requestParameters + constructingBodyWithBlock:block]; + return multipartRequest; +} + +#pragma mark - Registering Subclasses + +- (BOOL)registerRequestOperationClass:(Class)operationClass +{ + Class managedObjectRequestOperationClass = NSClassFromString(@"RKManagedObjectRequestOperation"); + if (managedObjectRequestOperationClass && [operationClass isSubclassOfClass:managedObjectRequestOperationClass]) { + [self.registeredManagedObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredManagedObjectRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } else if ([operationClass isSubclassOfClass:[RKObjectRequestOperation class]]) { + [self.registeredObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredObjectRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } else if ([operationClass isSubclassOfClass:[RKHTTPRequestOperation class]]) { + [self.registeredHTTPRequestOperationClasses removeObject:operationClass]; + [self.registeredHTTPRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } + + return NO; +} + +- (void)unregisterRequestOperationClass:(Class)operationClass +{ + [self.registeredHTTPRequestOperationClasses removeObject:operationClass]; + [self.registeredObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredManagedObjectRequestOperationClasses removeObject:operationClass]; +} + +- (Class)requestOperationClassForRequest:(NSURLRequest *)request fromRegisteredClasses:(NSArray *)registeredClasses +{ + Class requestOperationClass = nil; + NSEnumerator *enumerator = [registeredClasses reverseObjectEnumerator]; + while (requestOperationClass = [enumerator nextObject]) { + if ([requestOperationClass canProcessRequest:request]) break; + requestOperationClass = nil; + } + return requestOperationClass; +} + +#pragma mark - Object Request Operations + +- (void)copyStateFromHTTPClientToHTTPRequestOperation:(AFHTTPRequestOperation *)operation +{ + operation.credential = self.HTTPClient.defaultCredential; + operation.allowsInvalidSSLCertificate = self.HTTPClient.allowsInvalidSSLCertificate; +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ + operation.SSLPinningMode = self.HTTPClient.defaultSSLPinningMode; +#endif +} + +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + return [self objectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors success:success failure:failure]; +} + +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + responseDescriptors:(NSArray *)responseDescriptors + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + Class HTTPRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses] ?: [RKHTTPRequestOperation class]; + RKHTTPRequestOperation *HTTPRequestOperation = [[HTTPRequestOperationClass alloc] initWithRequest:request]; + [self copyStateFromHTTPClientToHTTPRequestOperation:HTTPRequestOperation]; + Class objectRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredObjectRequestOperationClasses] ?: [RKObjectRequestOperation class]; + RKObjectRequestOperation *operation = [[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + return operation; +} + +#ifdef RKCoreDataIncluded +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + return [self managedObjectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors managedObjectContext:managedObjectContext success:success failure:failure]; +} + +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + responseDescriptors:(NSArray *)responseDescriptors + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + Class HTTPRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses] ?: [RKHTTPRequestOperation class]; + RKHTTPRequestOperation *HTTPRequestOperation = [[HTTPRequestOperationClass alloc] initWithRequest:request]; + [self copyStateFromHTTPClientToHTTPRequestOperation:HTTPRequestOperation]; + Class objectRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredManagedObjectRequestOperationClasses] ?: [RKManagedObjectRequestOperation class]; + RKManagedObjectRequestOperation *operation = (RKManagedObjectRequestOperation *)[[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + operation.managedObjectContext = managedObjectContext ?: self.managedObjectStore.mainQueueManagedObjectContext; + operation.managedObjectCache = self.managedObjectStore.managedObjectCache; + operation.fetchRequestBlocks = self.fetchRequestBlocks; + return operation; +} +#endif + +- (id)appropriateObjectRequestOperationWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + RKObjectRequestOperation *operation = nil; + NSURLRequest *request = [self requestWithObject:object method:method path:path parameters:parameters]; + NSDictionary *routingMetadata = nil; + if (! path) { + RKRoute *route = [self.router.routeSet routeForObject:object method:method]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + if (! URL) { + RKLogError(@"Failed to construct a URL from the provided object. Returning nil."); + return operation; + } + path = [URL relativeString]; + + routingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + } else if (parameters) { + routingMetadata = @{ @"query": @{ @"parameters": parameters } }; + } + +#ifdef RKCoreDataIncluded + NSArray *matchingDescriptors = RKFilteredArrayOfResponseDescriptorsMatchingPathAndMethod(self.responseDescriptors, path, method); + BOOL containsEntityMapping = RKDoesArrayOfResponseDescriptorsContainEntityMapping(matchingDescriptors); + BOOL isManagedObjectRequestOperation = (containsEntityMapping || [object isKindOfClass:[NSManagedObject class]]); + + if (isManagedObjectRequestOperation && !self.managedObjectStore) RKLogWarning(@"Asked to create an `RKManagedObjectRequestOperation` object, but managedObjectStore is nil."); + if (isManagedObjectRequestOperation && self.managedObjectStore) { + // Construct a Core Data operation + NSManagedObjectContext *managedObjectContext = [object respondsToSelector:@selector(managedObjectContext)] ? [object managedObjectContext] : self.managedObjectStore.mainQueueManagedObjectContext; + operation = [self managedObjectRequestOperationWithRequest:request responseDescriptors:matchingDescriptors managedObjectContext:managedObjectContext success:nil failure:nil]; + + if ([object isKindOfClass:[NSManagedObject class]]) { + static NSPredicate *temporaryObjectsPredicate = nil; + if (! temporaryObjectsPredicate) temporaryObjectsPredicate = [NSPredicate predicateWithFormat:@"objectID.isTemporaryID == YES"]; + NSSet *temporaryObjects = [[managedObjectContext insertedObjects] filteredSetUsingPredicate:temporaryObjectsPredicate]; + if ([temporaryObjects count]) { + RKLogInfo(@"Asked to perform object request for NSManagedObject with temporary object IDs: Obtaining permanent ID before proceeding."); + __block BOOL _blockSuccess; + __block NSError *_blockError; + + [[object managedObjectContext] performBlockAndWait:^{ + _blockSuccess = [[object managedObjectContext] obtainPermanentIDsForObjects:[temporaryObjects allObjects] error:&_blockError]; + }]; + if (! _blockSuccess) RKLogWarning(@"Failed to obtain permanent ID for object %@: %@", object, _blockError); + } + } + } else { + // Non-Core Data operation + operation = [self objectRequestOperationWithRequest:request responseDescriptors:matchingDescriptors success:nil failure:nil]; + } +#else + // Non-Core Data operation + operation = [self objectRequestOperationWithRequest:request success:nil failure:nil]; +#endif + + if (RKDoesArrayOfResponseDescriptorsContainMappingForClass(self.responseDescriptors, [object class])) operation.targetObject = object; + operation.mappingMetadata = routingMetadata; + return operation; +} + +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object interpolatedParameters:(NSDictionary **)interpolatedParameters +{ + NSString *path = nil; + if (object) { + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:route.pathPattern]; + path = [pathMatcher pathFromObject:object addingEscapes:route.shouldEscapePath interpolatedParameters:interpolatedParameters]; + } else { + // When there is no object, the path pattern is our complete path + path = route.pathPattern; + if (interpolatedParameters) *interpolatedParameters = @{}; + } + return [NSURL URLWithString:path relativeToURL:self.baseURL]; +} + +- (void)getObjectsAtPathForRelationship:(NSString *)relationshipName + ofObject:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + RKRoute *route = [self.router.routeSet routeForRelationship:relationshipName ofClass:[object class] method:RKRequestMethodGET]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"Failed to generate URL for relationship named '%@' for object: %@", relationshipName, object); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[URL relativeString] parameters:parameters]; + + operation.mappingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObjectsAtPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSParameterAssert(routeName); + RKRoute *route = [self.router.routeSet routeForName:routeName]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"No route found named '%@'", routeName); + NSAssert(route.method & RKRequestMethodGET, @"Expected route named '%@' to specify a GET, but it does not", routeName); + + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[URL relativeString] parameters:parameters]; + + operation.mappingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObjectsAtPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSParameterAssert(path); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodGET path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)postObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPOST path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)putObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPUT path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)patchObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPATCH path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)deleteObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodDELETE path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern +{ + return [self paginatorWithPathPattern:pathPattern parameters:nil]; +} + +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters +{ + NSAssert(self.paginationMapping, @"Cannot instantiate a paginator when `paginationMapping` is nil."); + NSMutableURLRequest *request = [self requestWithMethod:@"GET" path:pathPattern parameters:parameters]; + RKPaginator *paginator = [[self.paginationMapping.objectClass alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:self.responseDescriptors]; +#ifdef RKCoreDataIncluded + paginator.managedObjectContext = self.managedObjectStore.mainQueueManagedObjectContext; + paginator.managedObjectCache = self.managedObjectStore.managedObjectCache; + paginator.fetchRequestBlocks = self.fetchRequestBlocks; +#endif + paginator.operationQueue = self.operationQueue; + Class HTTPOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses]; + if (HTTPOperationClass) [paginator setHTTPOperationClass:HTTPOperationClass]; + return paginator; +} + +#pragma mark - Request & Response Descriptors + +- (NSArray *)requestDescriptors +{ + return [NSArray arrayWithArray:self.mutableRequestDescriptors]; +} + +- (void)addRequestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(requestDescriptor); + if ([self.requestDescriptors containsObject:requestDescriptor]) return; + NSAssert([requestDescriptor isKindOfClass:[RKRequestDescriptor class]], @"Expected an object of type RKRequestDescriptor, got '%@'", [requestDescriptor class]); + [self.requestDescriptors enumerateObjectsUsingBlock:^(RKRequestDescriptor *registeredDescriptor, NSUInteger idx, BOOL *stop) { + NSAssert(!([registeredDescriptor.objectClass isEqual:requestDescriptor.objectClass] && (requestDescriptor.method == registeredDescriptor.method)), @"Cannot add request descriptor: An existing descriptor is already registered for the class '%@' and HTTP method'%@'.", requestDescriptor.objectClass, RKStringDescribingRequestMethod(requestDescriptor.method)); + }]; + [self.mutableRequestDescriptors addObject:requestDescriptor]; +} + +- (void)addRequestDescriptorsFromArray:(NSArray *)requestDescriptors +{ + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + [self addRequestDescriptor:requestDescriptor]; + } +} + +- (void)removeRequestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(requestDescriptor); + NSAssert([requestDescriptor isKindOfClass:[RKRequestDescriptor class]], @"Expected an object of type RKRequestDescriptor, got '%@'", [requestDescriptor class]); + [self.mutableRequestDescriptors removeObject:requestDescriptor]; +} + +- (NSArray *)responseDescriptors +{ + return [NSArray arrayWithArray:self.mutableResponseDescriptors]; +} + +- (void)addResponseDescriptor:(RKResponseDescriptor *)responseDescriptor +{ + NSParameterAssert(responseDescriptor); + NSAssert([responseDescriptor isKindOfClass:[RKResponseDescriptor class]], @"Expected an object of type RKResponseDescriptor, got '%@'", [responseDescriptor class]); + responseDescriptor.baseURL = self.baseURL; + [self.mutableResponseDescriptors addObject:responseDescriptor]; +} + +- (void)addResponseDescriptorsFromArray:(NSArray *)responseDescriptors +{ + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + [self addResponseDescriptor:responseDescriptor]; + } +} + +- (void)removeResponseDescriptor:(RKResponseDescriptor *)responseDescriptor +{ + NSParameterAssert(responseDescriptor); + NSAssert([responseDescriptor isKindOfClass:[RKResponseDescriptor class]], @"Expected an object of type RKResponseDescriptor, got '%@'", [responseDescriptor class]); + [self.mutableResponseDescriptors removeObject:responseDescriptor]; +} + +#pragma mark - Fetch Request Blocks + +#ifdef RKCoreDataIncluded + +- (NSArray *)fetchRequestBlocks +{ + return [NSArray arrayWithArray:self.mutableFetchRequestBlocks]; +} + +- (void)addFetchRequestBlock:(NSFetchRequest *(^)(NSURL *URL))block +{ + NSParameterAssert(block); + [self.mutableFetchRequestBlocks addObject:block]; +} + +#endif + +#pragma mark - Queue Management + +- (void)enqueueObjectRequestOperation:(RKObjectRequestOperation *)objectRequestOperation +{ + [self.operationQueue addOperation:objectRequestOperation]; +} + +- (NSArray *)enqueuedObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern +{ + NSMutableArray *matches = [NSMutableArray array]; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + for (NSOperation *operation in [self.operationQueue operations]) { + if (![operation isKindOfClass:[RKObjectRequestOperation class]]) { + continue; + } + NSURLRequest *request = [(RKObjectRequestOperation *)operation HTTPRequestOperation].request; + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL([request URL], self.baseURL); + + RKRequestMethod operationMethod = RKRequestMethodFromString([request HTTPMethod]); + if ((method & operationMethod) && [pathMatcher matchesPath:pathAndQueryString tokenizeQueryStrings:NO parsedArguments:nil]) { + [matches addObject:operation]; + } + } + return [matches copy]; +} + +- (void)cancelAllObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern +{ + for (RKObjectRequestOperation *operation in [self enqueuedObjectRequestOperationsWithMethod:method matchingPathPattern:pathPattern]) { + [operation cancel]; + } +} + +- (void)enqueueBatchOfObjectRequestOperationsWithRoute:(RKRoute *)route + objects:(NSArray *)objects + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion { + NSMutableArray *operations = [[NSMutableArray alloc] initWithCapacity:objects.count]; + for (id object in objects) { + RKObjectRequestOperation *operation = nil; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"Failed to generate URL for route %@ with object %@", route, object); + if ([route isClassRoute]) { + operation = [self appropriateObjectRequestOperationWithObject:object method:route.method path:[URL relativeString] parameters:nil]; + } else { + operation = [self appropriateObjectRequestOperationWithObject:nil method:route.method path:[URL relativeString] parameters:nil]; + } + operation.mappingMetadata = @{ @"routing": interpolatedParameters, @"route": route }; + [operations addObject:operation]; + } + return [self enqueueBatchOfObjectRequestOperations:operations progress:progress completion:completion]; +} + +- (void)enqueueBatchOfObjectRequestOperations:(NSArray *)operations + progress:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion { + + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completion) { + completion(operations); + } + }); +#if !OS_OBJECT_USE_OBJC + dispatch_release(dispatchGroup); +#endif + }]; + + for (RKObjectRequestOperation *operation in operations) { + void (^originalCompletionBlock)(void) = [operation.completionBlock copy]; + __weak RKObjectRequestOperation *weakOperation = operation; + [operation setCompletionBlock:^{ + dispatch_queue_t queue = weakOperation.successCallbackQueue ?: dispatch_get_main_queue(); + dispatch_group_async(dispatchGroup, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + __block NSUInteger numberOfFinishedOperations = 0; + [operations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([(NSOperation *)obj isFinished]) { + numberOfFinishedOperations++; + } + }]; + + if (progress) { + progress(numberOfFinishedOperations, [operations count]); + } + + dispatch_group_leave(dispatchGroup); + }); + }]; + + dispatch_group_enter(dispatchGroup); + [batchedOperation addDependency:operation]; + + [self enqueueObjectRequestOperation:operation]; + } + [self.operationQueue addOperation:batchedOperation]; +} + +@end + +#ifdef _SYSTEMCONFIGURATION_H +NSString *RKStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus networkReachabilityStatus) +{ + switch (networkReachabilityStatus) { + case AFNetworkReachabilityStatusNotReachable: return @"Not Reachable"; + case AFNetworkReachabilityStatusReachableViaWiFi: return @"Reachable via WiFi"; + case AFNetworkReachabilityStatusReachableViaWWAN: return @"Reachable via WWAN"; + case AFNetworkReachabilityStatusUnknown: return @"Reachability Unknown"; + default: break; + } + return nil; +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.h new file mode 100644 index 0000000..5e9c68f --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.h @@ -0,0 +1,44 @@ +// +// RKObjectParameterization.h +// RestKit +// +// Created by Blake Watters on 5/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRequestDescriptor.h" + +/** + The `RKObjectParameterization` class provides an interface for mapping a local domain object into an `NSDictionary` representation suitable for use as the parameters of an HTTP request. + */ +@interface RKObjectParameterization : NSObject + +///------------------------------- +/// @name Parameterizing an Object +///------------------------------- + +/** + Returns a dictionary representation of the given object by performing object mapping using the mapping + from the given request descriptor. If the request descriptor specifies a root key path, the mapped parameters + will be nested within the dictionary under the specified root key path. + + @param object The object to be parameterized. + @param requestDescriptor The request descriptor describing how the object is to be mapped into an `NSDictionary` of parameters. + @param error If there is a problem mapping the parameters, upon return contains a pointer to an instance of `NSError` that describes the problem. + @return A new dictionary containing the mapped parameters or nil if an error has occurred. + */ ++ (NSDictionary *)parametersWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor error:(NSError **)error; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.m new file mode 100644 index 0000000..857c81a --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectParameterization.m @@ -0,0 +1,151 @@ +// +// RKObjectParameterization.m +// RestKit +// +// Created by Blake Watters on 5/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" +#import "RKSerialization.h" +#import "RKObjectParameterization.h" +#import "RKMIMETypeSerialization.h" +#import "RKLog.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" +#import "RKMappingErrors.h" +#import "RKPropertyInspector.h" +#import "RKValueTransformers.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +@interface RKObjectParameterization () <RKMappingOperationDelegate> +@property (nonatomic, strong) id object; +@property (nonatomic, strong) RKRequestDescriptor *requestDescriptor; + +- (instancetype)initWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor; +- (NSDictionary *)mapObjectToParameters:(NSError **)error; + +// Convenience methods +@property (nonatomic, readonly) RKObjectMapping *mapping; +@property (nonatomic, readonly) NSString *rootKeyPath; +@end + +@implementation RKObjectParameterization + ++ (NSDictionary *)parametersWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor error:(NSError **)error +{ + RKObjectParameterization *parameterization = [[self alloc] initWithObject:object requestDescriptor:requestDescriptor]; + return [parameterization mapObjectToParameters:error]; +} + +- (instancetype)initWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(object); + NSParameterAssert(requestDescriptor); + + self = [super init]; + if (self) { + self.object = object; + self.requestDescriptor = requestDescriptor; + } + return self; +} + +- (RKMapping *)mapping +{ + return self.requestDescriptor.mapping; +} + +- (NSString *)rootKeyPath +{ + return self.requestDescriptor.rootKeyPath; +} + +- (NSDictionary *)mapObjectToParameters:(NSError **)error +{ + RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:self.object destinationObject:dictionary mapping:self.mapping]; + operation.dataSource = dataSource; + operation.delegate = self; + [operation start]; + if (operation.error) { + if (operation.error.code == RKMappingErrorUnmappableRepresentation) { + // If the mapped object is empty, return an empty dictionary and no error + return self.rootKeyPath ? @{ self.rootKeyPath: @{} } : @{}; + } + + if (error) *error = operation.error; + return nil; + } + + // Optionally enclose the serialized object within a container... + return self.rootKeyPath ? [NSMutableDictionary dictionaryWithObject:dictionary forKey:self.rootKeyPath] : dictionary; +} + +#pragma mark - RKMappingOperationDelegate + +- (void)mappingOperation:(RKMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKAttributeMapping *)mapping +{ + id transformedValue = nil; + if (value == nil) { + if (mapping.objectMapping.assignsDefaultValueForMissingAttributes) { + // Serialize nil values as null + transformedValue = [NSNull null]; + } + } else if ([value isKindOfClass:[NSDate class]]) { + [mapping.valueTransformer transformValue:value toValue:&transformedValue ofClass:[NSString class] error:nil]; + } else if ([value isKindOfClass:[NSDecimalNumber class]]) { + // Precision numbers are serialized as strings to work around Javascript notation limits + transformedValue = [(NSDecimalNumber *)value stringValue]; + } else if ([value isKindOfClass:[NSSet class]]) { + // NSSets are not natively serializable, so let's just turn it into an NSArray + transformedValue = [value allObjects]; + } else if ([value isKindOfClass:[NSOrderedSet class]]) { + // NSOrderedSets are not natively serializable, so let's just turn it into an NSArray + transformedValue = [value array]; + } else { + Class propertyClass = RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(mapping.sourceKeyPath, operation.sourceObject); + if ([propertyClass isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")] || [propertyClass isSubclassOfClass:NSClassFromString(@"NSCFBoolean")]) { + transformedValue = @([value boolValue]); + } + } + + if (transformedValue) { + RKLogDebug(@"Serialized %@ value at keyPath to %@ (%@)", NSStringFromClass([value class]), NSStringFromClass([transformedValue class]), value); + [operation.destinationObject setValue:transformedValue forKeyPath:keyPath]; + } +} + +- (BOOL)mappingOperation:(RKMappingOperation *)operation shouldSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping +{ + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + id currentValue = operation.destinationObject; + for (NSString *key in keyPathComponents) { + id value = [currentValue valueForKey:key]; + if (value == nil) { + value = [NSMutableDictionary new]; + [currentValue setValue:value forKey:key]; + } + currentValue = value; + } + return YES; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.h new file mode 100644 index 0000000..ea0d17b --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.h @@ -0,0 +1,238 @@ +// +// RKObjectRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKMappingResult.h" +#import "RKMapperOperation.h" + +/** + The key for a Boolean NSNumber value that indicates if a `NSCachedURLResponse` stored in the `NSURLCache` has been object mapped to completion. This key is stored on the `userInfo` of the cached response, if any, just before an `RKObjectRequestOperation` transitions to the finished state. + */ +extern NSString * const RKResponseHasBeenMappedCacheUserInfoKey; + +/** + `RKObjectRequestOperation` is an `NSOperation` subclass that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation`. + + Object request operations are initialized with a fully configured `NSURLRequest` object and an array of `RKResponseDescriptor` objects. `RKObjectRequestOperation` is internally implemented as an aggregate operation that constructs and starts an `RKHTTPRequestOperation` to perform the network access and retrieve the mappable data. If an error occurs during HTTP transport, the object request operation is failed with the transport error. Once response data is loaded for the request, the object request operation creates and starts an `RKObjectResponseMapperOperation` to perform the object mapping on the response body. If the mapping operation fails, then object request operation is failed and the `error` property is set. If mapping is successful, then the `mappingResult` property is set and the operation is finished successfully. + + ## Acceptable Content Types and Status Codes + + Instances of `RKObjectRequestOperation` determine the acceptability of status codes and content types differently than is typical for `AFNetworking` derived network opertations. The `RKHTTPRequestOperation` (which is a subclass of the AFNetworking `AFHTTPRequestOperation` class) supports the dynamic assignment of acceptable status codes and content types. This facility is utilized during the configuration of the network operation for an object request operation. The set of acceptable content types is determined by consulting the `RKMIMETypeSerialization` via an invocation of `[RKMIMETypeSerialization registeredMIMETypes]`. The `registeredMIMETypes` method returns an `NSSet` containing either `NSString` or `NSRegularExpression` objects that specify the content types for which `RKSerialization` classes have been registered to handle. The set of acceptable status codes is determined by aggregating the value of the `statusCodes` property from all registered `RKResponseDescriptor` objects. + + ## Error Mapping + + If the HTTP request returned a response in the Client Error (400-499 range) or Server Error (500-599 range) class and an appropriate `RKResponseDescriptor` is provided to perform mapping on the response, then the object mapping result is considered to contain a server returned error. In this case, an `NSError` object is created in the `RKErrorDomain` with an error code of `RKMappingErrorFromMappingResult` and the object request operation is failed. In the event that an a response is returned in an error class and no `RKResponseDescriptor` has been provided to the operation to handle it, then an `NSError` object in the `AFNetworkingErrorDomain` with an error code of `NSURLErrorBadServerResponse` will be returned by the underlying `RKHTTPRequestOperation` indicating that an unexpected status code was returned. + + ## Metadata Mapping + + The `RKObjectRequestOperation` class provides support for metadata mapping via the `mappingMetadata` property. This optional dictionary of user supplied information is made available to the mapping operations executed when processing the HTTP response loaded by an object request operation. More details about the metadata mapping architecture is available on the `RKMappingOperation` documentation. + + ## Prioritization and Cancellation + + Object request operations support prioritization and cancellation of the underlying `RKHTTPRequestOperation` and `RKResponseMapperOperation` operations that perform the network transport and object mapping duties on their behalf. The queue priority of the object request operation, as set via the `[NSOperation setQueuePriority:]` method, is applied to the underlying response mapping operation when it is enqueued onto the `responseMappingQueue`. If the object request operation is cancelled, then the underlying HTTP request operation and response mapping operation are also cancelled. + + ## Caching + + Instances of `RKObjectRequestOperation` support all the HTTP caching facilities available via the `NSURLConnection` family of API's. For caching to be enabled, the remote web server that the application is communicating with must emit the appropriate `Cache-Control`, `Expires`, and/or `ETag` headers. When the response headers include the appropriate caching information, the shared `NSURLCache` instance will manage responses and transparently add conditional GET support to cachable requests. HTTP caching is a deep topic explored in depth across the web and detailed in RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + + The `RKObjectRequestOperation` class also provides support for utilizing the `NSURLCache` to satisfy requests without hitting the network. This support enables applications to display views presenting data retrieved via a cachable `GET` request without revalidating with the server and incurring any overhead. The optimization is controlled via `avoidsNetworkAccess` property. When enabled, the operation will skip the network transport portion of the object request operation and proceed directly to object mapping the cached response data. When the object request operation is an instance of `RKManagedObjectRequestOperation`, the deserialization and mapping portion of the process can be skipped entirely and the operation will fetch the appropriate object directly from Core Data, falling back to network transport once the cache entry has expired. Please refer to the documentation accompanying `RKManagedObjectRequestOperation` for more details. + + ## Core Data + + `RKObjectRequestOperation` is not able to perform object mapping that targets Core Data destination entities. Please refer to the `RKManagedObjectRequestOperation` subclass for details regarding performing a Core Data object request operation. + + ## Subclassing Notes + + The `RKObjectRequestOperation` is a non-current `NSOperation` subclass and can be extended by subclassing and providing an implementation of the `main` method. It conforms to the `RKMapperOperationDelegate` protocol, providing access to the lifecycle of the mapping process to subclasses. + + @see `RKResponseDescriptor` + @see `RKHTTPRequestOperation` + @see `RKMIMETypeSerialization` + @see `RKManagedObjectRequestOperation` + */ +@interface RKObjectRequestOperation : NSOperation <NSCopying, RKMapperOperationDelegate> { + @protected + RKMappingResult *_mappingResult; +} + +///----------------------------------------------- +/// @name Initializing an Object Request Operation +///----------------------------------------------- + +/** + Initializes an object request operation with an HTTP request operation and a set of response descriptors. + + This is the designated initializer. + + @param requestOperation The request object to be used with the underlying network operation. + @param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation. + @return The receiver, initialized with the given request and response descriptors. + */ +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors; + +/** + Initializes an object request operation with a request object and a set of response descriptors. + + This method is a convenience initializer for initializing an object request operation from a URL request with the default HTTP operation class `RKHTTPRequestOperation`. This method is functionally equivalent to the following example code: + + RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request]; + RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:responseDescriptors]; + + @param request The request object to be used with the underlying network operation. + @param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation. + @return The receiver, initialized with the given request and response descriptors. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors; + +///--------------------------------- +/// @name Configuring Object Mapping +///--------------------------------- + +/** + The array of `RKResponseDescriptor` objects that specify how the deserialized `responseData` is to be object mapped. + + The response descriptors define the acceptable HTTP Status Codes of the receiver. + */ +@property (nonatomic, strong, readonly) NSArray *responseDescriptors; + +/** + The target object for the object mapping operation. + + @see `[RKObjectResponseMapperOperation targetObject]` + */ +@property (nonatomic, strong) id targetObject; + +/** + An optional dictionary of metadata to make available to mapping operations executed while processing the HTTP response loaded by the receiver. + */ +@property (nonatomic, copy) NSDictionary *mappingMetadata; + +///---------------------------------- +/// @name Accessing Operation Results +///---------------------------------- + +/** + The mapping result returned by the underlying `RKObjectResponseMapperOperation`. + + This property is `nil` if the operation is failed due to a network transport error or no mapping was peformed on the response. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occurred during execution of the operation. + + Errors may originate during the network transport or object mapping phases of the object request operation. A `nil` error value indicates that the operation completed successfully. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///------------------------------------------- +/// @name Accessing the HTTP Request Operation +///------------------------------------------- + +/** + The underlying `RKHTTPRequestOperation` object used to manage the HTTP request/response lifecycle of the object request operation. + */ +@property (nonatomic, strong, readonly) RKHTTPRequestOperation *HTTPRequestOperation; + +///------------------------------------------------------- +/// @name Setting the Completion Block and Callback Queues +///------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the object request on completion. If `error` returns a value, which can be set during HTTP transport by the underlying `HTTPRequestOperation` or during object mapping by the `RKResponseMapperOperation` object, then `failure` is executed. If the object request operation is cancelled, then the failure block will be executed with either a `RKOperationCancelledError` or a `NSURLErrorCancelled`, depending on the internal state of the operation at time of cancellation. Otherwise, `success` is executed. + + @param success The block to be executed on the completion of a successful operation. This block has no return value and takes two arguments: the receiver operation and the mapping result from object mapping the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful operation. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the execution of the operation. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + + The queue is retained while this operation is living + */ +@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + + The queue is retained while this operation is living + */ +@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; + +/** + Sets a block to be executed before the object request operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input that will be passed to the response mapper. + + @param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP. If you do not wish to make any chances to the response body before mapping begins, the block should return the value passed in the `deserializedResponseBody` block argument. Returning `nil` will decline the mapping from proceeding and fail the operation with an error with the `RKMappingErrorMappingDeclined` code. + @see [RKResponseMapperOperation setWillMapDeserializedResponseBlock:] + @warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input. + */ +- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block; + +///----------------------------------------------------- +/// @name Determining Whether a Request Can Be Processed +///----------------------------------------------------- + +/** + Returns a Boolean value determining whether or not the class can process the specified request. + + @param request The request that is determined to be supported or not supported for this class. + */ ++ (BOOL)canProcessRequest:(NSURLRequest *)request; + +///------------------------------------------- +/// @name Accessing the Response Mapping Queue +///------------------------------------------- + +/** + Returns the operation queue used by all object request operations when object mapping the body of a response loaded via HTTP. + + By default, the response mapping queue is configured with a maximum concurrent operation count of 1, ensuring that only one HTTP response is mapped at a time. + + @return The response mapping queue. + */ ++ (NSOperationQueue *)responseMappingQueue; + +@end + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when an object request operation begin executing. + */ +extern NSString *const RKObjectRequestOperationDidStartNotification; + +/** + Posted when an object request operation finishes. + */ +extern NSString *const RKObjectRequestOperationDidFinishNotification; + +/** + The key for an `NSDate` object specifying the time at which object mapping started for object request operation. Available in the user info dictionary of an `RKObjectRequestOperationDidFinishNotification` + */ +extern NSString *const RKObjectRequestOperationMappingDidStartUserInfoKey; + +/** + The key for an `NSDate` object specifying the time at which object mapping finished for object request operation. Available in the user info dictionary of an `RKObjectRequestOperationDidFinishNotification` + */ +extern NSString *const RKObjectRequestOperationMappingDidFinishUserInfoKey; diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.m new file mode 100644 index 0000000..8fbeda8 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperation.m @@ -0,0 +1,645 @@ +// +// RKObjectRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKObjectRequestOperation.h" +#import "RKResponseMapperOperation.h" +#import "RKResponseDescriptor.h" +#import "RKMIMETypeSerialization.h" +#import "RKHTTPUtilities.h" +#import "RKLog.h" +#import "RKMappingErrors.h" +#import "RKOperationStateMachine.h" + +#import <Availability.h> + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import "AFNetworkActivityIndicatorManager.h" +#endif + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +static BOOL RKLogIsStringBlank(NSString *string) +{ + return ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0); +} + +static NSString *RKLogTruncateString(NSString *string) +{ + static NSInteger maxMessageLength; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary *envVars = [[NSProcessInfo processInfo] environment]; + maxMessageLength = RKLogIsStringBlank(envVars[@"RKLogMaxLength"]) ? NSIntegerMax : [envVars[@"RKLogMaxLength"] integerValue]; + }); + + return ([string length] <= maxMessageLength) + ? string + : [NSString stringWithFormat:@"%@... (truncated at %ld characters)", + [string substringToIndex:maxMessageLength], + (long) maxMessageLength]; +} + +@interface NSCachedURLResponse (RKLeakFix) + +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSData *rkData; + +@end + +@interface RKObjectRequestOperationLogger : NSObject + ++ (RKObjectRequestOperationLogger*)sharedLogger; + +@end + +@implementation RKObjectRequestOperationLogger + ++ (RKObjectRequestOperationLogger*)sharedLogger +{ + static RKObjectRequestOperationLogger *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + ++ (void)load +{ + @autoreleasepool { + [self sharedLogger]; + }; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(objectRequestOperationDidStart:) + name:RKObjectRequestOperationDidStartNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(objectRequestOperationDidFinish:) + name:RKObjectRequestOperationDidFinishNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(HTTPOperationDidStart:) + name:AFNetworkingOperationDidStartNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(HTTPOperationDidFinish:) + name:AFNetworkingOperationDidFinishNotification + object:nil]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +static void *RKParentObjectRequestOperation = &RKParentObjectRequestOperation; +static void *RKOperationStartDate = &RKOperationStartDate; +static void *RKOperationFinishDate = &RKOperationFinishDate; + +- (void)objectRequestOperationDidStart:(NSNotification *)notification +{ + // Weakly tag the HTTP operation with its parent object request operation + RKObjectRequestOperation *objectRequestOperation = [notification object]; + objc_setAssociatedObject(objectRequestOperation, RKOperationStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(objectRequestOperation.HTTPRequestOperation, RKParentObjectRequestOperation, objectRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (void)HTTPOperationDidStart:(NSNotification *)notification +{ + RKHTTPRequestOperation *operation = [notification object]; + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) return; + + objc_setAssociatedObject(operation, RKOperationStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + NSString *body = nil; + if ([operation.request HTTPBody]) { + body = RKLogTruncateString([[NSString alloc] initWithData:[operation.request HTTPBody] encoding:NSUTF8StringEncoding]); + } + + RKLogTrace(@"%@ '%@':\nrequest.headers=%@\nrequest.body=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], [operation.request allHTTPHeaderFields], body); + } else { + RKLogInfo(@"%@ '%@'", [operation.request HTTPMethod], [[operation.request URL] absoluteString]); + } +} + +- (void)HTTPOperationDidFinish:(NSNotification *)notification +{ + RKHTTPRequestOperation *operation = [notification object]; + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) return; + + // NOTE: if we have a parent object request operation, we'll wait it to finish to emit the logging info + RKObjectRequestOperation *parentOperation = objc_getAssociatedObject(operation, RKParentObjectRequestOperation); + objc_setAssociatedObject(operation, RKParentObjectRequestOperation, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + if (parentOperation) { + objc_setAssociatedObject(operation, RKOperationFinishDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return; + } + + NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:objc_getAssociatedObject(operation, RKOperationStartDate)]; + + NSString *statusCodeString = RKStringFromStatusCode([operation.response statusCode]); + NSString *elapsedTimeString = [NSString stringWithFormat:@"[%.04f s]", elapsedTime]; + NSString *statusCodeAndElapsedTime = statusCodeString ? [NSString stringWithFormat:@"(%ld %@) %@", (long)[operation.response statusCode], statusCodeString, elapsedTimeString] : [NSString stringWithFormat:@"(%ld) %@", (long)[operation.response statusCode], elapsedTimeString]; + if (operation.error) { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogError(@"%@ '%@' %@:\nerror=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, operation.error); + RKLogDebug(@"response.body=%@", operation.responseString); + } else { + if (operation.error.code == NSURLErrorCancelled) { + RKLogError(@"%@ '%@' %@: Cancelled", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime); + } else { + RKLogError(@"%@ '%@' %@: %@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, operation.error); + } + } + } else { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogTrace(@"%@ '%@' %@:\nresponse.headers=%@\nresponse.body=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, [operation.response allHeaderFields], RKLogTruncateString(operation.responseString)); + } else { + RKLogInfo(@"%@ '%@' %@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime); + } + } +} + +- (void)objectRequestOperationDidFinish:(NSNotification *)notification +{ + RKObjectRequestOperation *objectRequestOperation = [notification object]; + if (![objectRequestOperation isKindOfClass:[RKObjectRequestOperation class]]) return; + + RKHTTPRequestOperation *HTTPRequestOperation = objectRequestOperation.HTTPRequestOperation; + NSTimeInterval objectRequestExecutionDuration = [[NSDate date] timeIntervalSinceDate:objc_getAssociatedObject(objectRequestOperation, RKOperationStartDate)]; + NSTimeInterval httpRequestExecutionDuration = [objc_getAssociatedObject(HTTPRequestOperation, RKOperationFinishDate) timeIntervalSinceDate:objc_getAssociatedObject(HTTPRequestOperation, RKOperationStartDate)]; + NSDate *mappingDidStartTime = (notification.userInfo)[RKObjectRequestOperationMappingDidFinishUserInfoKey]; + NSTimeInterval mappingDuration = [mappingDidStartTime isEqual:[NSNull null]] ? 0.0 : [mappingDidStartTime timeIntervalSinceDate:(notification.userInfo)[RKObjectRequestOperationMappingDidStartUserInfoKey]]; + + NSString *statusCodeString = RKStringFromStatusCode([HTTPRequestOperation.response statusCode]); + NSString *statusCodeDescription = statusCodeString ? [NSString stringWithFormat:@" %@ ", statusCodeString] : @" "; + NSString *elapsedTimeString = [NSString stringWithFormat:@"[request=%.04fs mapping=%.04fs total=%.04fs]", httpRequestExecutionDuration, mappingDuration, objectRequestExecutionDuration]; + NSString *statusCodeAndElapsedTime = [NSString stringWithFormat:@"(%ld%@/ %lu objects) %@", (long)[HTTPRequestOperation.response statusCode], statusCodeDescription, (unsigned long) [objectRequestOperation.mappingResult count], elapsedTimeString]; + if (objectRequestOperation.error) { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogError(@"%@ '%@' %@:\nerror=%@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, objectRequestOperation.error); + RKLogDebug(@"response.body=%@", HTTPRequestOperation.responseString); + } else { + if (objectRequestOperation.error.code == NSURLErrorCancelled) { + RKLogError(@"%@ '%@' %@: Cancelled", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime); + } else { + RKLogError(@"%@ '%@' %@: %@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, objectRequestOperation.error); + } + } + } else { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogTrace(@"%@ '%@' %@:\nresponse.headers=%@\nresponse.body=%@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, [HTTPRequestOperation.response allHeaderFields], RKLogTruncateString(HTTPRequestOperation.responseString)); + } else { + RKLogInfo(@"%@ '%@' %@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime); + } + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +NSString *const RKObjectRequestOperationDidStartNotification = @"RKObjectRequestOperationDidStartNotification"; +NSString *const RKObjectRequestOperationDidFinishNotification = @"RKObjectRequestOperationDidFinishNotification"; +NSString *const RKResponseHasBeenMappedCacheUserInfoKey = @"RKResponseHasBeenMapped"; +NSString *const RKObjectRequestOperationMappingDidStartUserInfoKey = @"mappingStartedAt"; +NSString *const RKObjectRequestOperationMappingDidFinishUserInfoKey = @"mappingFinishedAt"; + +static void RKIncrementNetworkActivityIndicator() +{ + #if __IPHONE_OS_VERSION_MIN_REQUIRED + [[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount]; + #endif +} + +static void RKDecrementNetworkAcitivityIndicator() +{ + #if __IPHONE_OS_VERSION_MIN_REQUIRED + [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount]; + #endif +} + +static NSIndexSet *RKAcceptableStatusCodesFromResponseDescriptors(NSArray *responseDescriptors) +{ + // If there are no response descriptors or any descriptor matches any status code (expressed by `statusCodes` == `nil`) then we want to accept anything + if ([responseDescriptors count] == 0 || [[responseDescriptors valueForKey:@"statusCodes"] containsObject:[NSNull null]]) return nil; + + NSMutableIndexSet *acceptableStatusCodes = [NSMutableIndexSet indexSet]; + [responseDescriptors enumerateObjectsUsingBlock:^(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + [acceptableStatusCodes addIndexes:responseDescriptor.statusCodes]; + }]; + return acceptableStatusCodes; +} + +static NSString *RKStringForStateOfObjectRequestOperation(RKObjectRequestOperation *operation) +{ + if ([operation isExecuting]) { + return @"Executing"; + } else if ([operation isFinished]) { + if (operation.error) { + return @"Failed"; + } else { + return @"Successful"; + } + } else { + return @"Ready"; + } +} + +static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response, NSData *data) +{ + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; + return [NSString stringWithFormat:@"<%@: %p statusCode=%ld MIMEType=%@ length=%ld>", [response class], response, (long) [HTTPResponse statusCode], [HTTPResponse MIMEType], (long) [data length]]; + } else { + return [response description]; + } +} + +@interface RKObjectRequestOperation () +@property (nonatomic, strong) RKOperationStateMachine *stateMachine; +@property (nonatomic, strong, readwrite) RKHTTPRequestOperation *HTTPRequestOperation; +@property (nonatomic, strong, readwrite) NSArray *responseDescriptors; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong) RKObjectResponseMapperOperation *responseMapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody); +@property (nonatomic, strong) NSDate *mappingDidStartDate; +@property (nonatomic, strong) NSDate *mappingDidFinishDate; +@property (nonatomic, copy) void (^successBlock)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult); +@property (nonatomic, copy) void (^failureBlock)(RKObjectRequestOperation *operation, NSError *error); +@end + +@implementation RKObjectRequestOperation + ++ (NSOperationQueue *)responseMappingQueue +{ + static NSOperationQueue *responseMappingQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + responseMappingQueue = [NSOperationQueue new]; + [responseMappingQueue setName:@"RKObjectRequestOperation Response Mapping Queue" ]; + [responseMappingQueue setMaxConcurrentOperationCount:1]; + }); + + return responseMappingQueue; +} + ++ (dispatch_queue_t)dispatchQueue +{ + static dispatch_queue_t dispatchQueue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dispatchQueue = dispatch_queue_create("org.restkit.network.object-request-operation-queue", DISPATCH_QUEUE_CONCURRENT); + }); + + return dispatchQueue; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request +{ + return YES; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_failureCallbackQueue) dispatch_release(_failureCallbackQueue); + if (_successCallbackQueue) dispatch_release(_successCallbackQueue); +#endif + _failureCallbackQueue = NULL; + _successCallbackQueue = NULL; +} + +// Designated initializer +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors +{ + NSParameterAssert(requestOperation); + NSParameterAssert(responseDescriptors); + + self = [self init]; + if (self) { + self.responseDescriptors = responseDescriptors; + self.HTTPRequestOperation = requestOperation; + self.HTTPRequestOperation.acceptableContentTypes = [RKMIMETypeSerialization registeredMIMETypes]; + self.HTTPRequestOperation.acceptableStatusCodes = RKAcceptableStatusCodesFromResponseDescriptors(responseDescriptors); + self.HTTPRequestOperation.successCallbackQueue = [[self class] dispatchQueue]; + self.HTTPRequestOperation.failureCallbackQueue = [[self class] dispatchQueue]; + + __weak __typeof(self)weakSelf = self; + self.stateMachine = [[RKOperationStateMachine alloc] initWithOperation:self dispatchQueue:[[self class] dispatchQueue]]; + [self.stateMachine setExecutionBlock:^{ + [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectRequestOperationDidStartNotification object:weakSelf]; + RKIncrementNetworkActivityIndicator(); + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + } else { + [weakSelf execute]; + } + }]; + [self.stateMachine setFinalizationBlock:^{ + [weakSelf willFinish]; + RKDecrementNetworkAcitivityIndicator(); + [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectRequestOperationDidFinishNotification object:weakSelf userInfo:@{ RKObjectRequestOperationMappingDidStartUserInfoKey: weakSelf.mappingDidStartDate ?: [NSNull null], RKObjectRequestOperationMappingDidFinishUserInfoKey: weakSelf.mappingDidFinishDate ?: [NSNull null] }]; + }]; + [self.stateMachine setCancellationBlock:^{ + [weakSelf.HTTPRequestOperation cancel]; + [weakSelf.responseMapperOperation cancel]; + }]; + } + + return self; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors +{ + NSParameterAssert(request); + NSParameterAssert(responseDescriptors); + return [self initWithHTTPRequestOperation:[[RKHTTPRequestOperation alloc] initWithRequest:request] responseDescriptors:responseDescriptors]; +} + +- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue +{ + if (successCallbackQueue != _successCallbackQueue) { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(successCallbackQueue); +#endif + _successCallbackQueue = successCallbackQueue; + } + } +} + +- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue +{ + if (failureCallbackQueue != _failureCallbackQueue) { + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } + + if (failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(failureCallbackQueue); +#endif + _failureCallbackQueue = failureCallbackQueue; + } + } +} + +// Adopted fix for "The Deallocation Problem" from AFN +- (void)setCompletionBlock:(void (^)(void))block +{ + if (!block) { + [super setCompletionBlock:nil]; + } else { + __unsafe_unretained id weakSelf = self; + [super setCompletionBlock:^ { + block(); + [weakSelf setCompletionBlock:nil]; + }]; + } +} + +- (void)setWillMapDeserializedResponseBlock:(id (^)(id))block +{ + if (!block) { + _willMapDeserializedResponseBlock = nil; + } else { + __unsafe_unretained id weakSelf = self; + _willMapDeserializedResponseBlock = ^id (id deserializedResponse) { + id result = block(deserializedResponse); + [weakSelf setWillMapDeserializedResponseBlock:nil]; + return result; + }; + } +} + +- (void)setCompletionBlockWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ +// See above setCompletionBlock: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + + //Keep blocks for copyWithZone + self.successBlock = success; + self.failureBlock = failure; + + self.completionBlock = ^ { + if ([self isCancelled] && !self.error) { + self.error = [NSError errorWithDomain:RKErrorDomain code:RKOperationCancelledError userInfo:nil]; + } + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, self.mappingResult); + }); + } + } + }; +#pragma clang diagnostic pop +} + +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock +{ + self.responseMapperOperation = [[RKObjectResponseMapperOperation alloc] initWithRequest:self.HTTPRequestOperation.request + response:self.HTTPRequestOperation.response + data:self.HTTPRequestOperation.responseData + responseDescriptors:self.responseDescriptors]; + self.responseMapperOperation.targetObject = self.targetObject; + self.responseMapperOperation.mappingMetadata = self.mappingMetadata; + self.responseMapperOperation.mapperDelegate = self; + [self.responseMapperOperation setQueuePriority:[self queuePriority]]; + [self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock]; + [self.responseMapperOperation setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *error) { + completionBlock(mappingResult, error); + }]; + [[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation]; +} + +- (void)execute +{ + __weak __typeof(self)weakSelf = self; + + [self.HTTPRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + return; + } + + weakSelf.mappingDidStartDate = [NSDate date]; + [weakSelf performMappingOnResponseWithCompletionBlock:^(RKMappingResult *mappingResult, NSError *error) { + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + return; + } + + // If there is no mapping result but no error, there was no mapping to be performed, + // which we do not treat as an error condition + if (error && !([weakSelf.HTTPRequestOperation.request.HTTPMethod isEqualToString:@"DELETE"] && error.code == RKMappingErrorNotFound)) { + weakSelf.error = error; + [weakSelf.stateMachine finish]; + return; + } + weakSelf.mappingResult = mappingResult; + + if (weakSelf.error) { + weakSelf.mappingResult = nil; + } else { + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:weakSelf.HTTPRequestOperation.request]; + if (cachedResponse) { + // We're all done mapping this request. Now we set a flag on the cache entry's userInfo dictionary to indicate that the request + // corresponding to the cache entry completed successfully, and we can reliably skip mapping if a subsequent request results + // in the use of this cachedResponse. + NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary]; + userInfo[RKResponseHasBeenMappedCacheUserInfoKey] = @YES; + NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.rkData userInfo:userInfo storagePolicy:cachedResponse.storagePolicy]; + [[NSURLCache sharedURLCache] storeCachedResponse:newCachedResponse forRequest:weakSelf.HTTPRequestOperation.request]; + } + } + + weakSelf.mappingDidFinishDate = [NSDate date]; + [weakSelf.stateMachine finish]; + }]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + RKLogError(@"Object request failed: Underlying HTTP request operation failed with error: %@", weakSelf.HTTPRequestOperation.error); + weakSelf.error = weakSelf.HTTPRequestOperation.error; + [weakSelf.stateMachine finish]; + }]; + + // Send the request + [self.HTTPRequestOperation start]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, isCancelled=%@, request: %@, response: %@>", + NSStringFromClass([self class]), self, RKStringForStateOfObjectRequestOperation(self), [self isCancelled] ? @"YES" : @"NO", + self.HTTPRequestOperation.request, RKStringDescribingURLResponseWithData(self.HTTPRequestOperation.response, self.HTTPRequestOperation.responseData)]; +} + +- (void)willFinish +{ + // Default implementation does nothing +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + RKObjectRequestOperation *operation = [(RKObjectRequestOperation *)[[self class] allocWithZone:zone] initWithHTTPRequestOperation:[self.HTTPRequestOperation copyWithZone:zone] responseDescriptors:self.responseDescriptors]; + operation.targetObject = self.targetObject; + operation.mappingMetadata = self.mappingMetadata; + operation.successCallbackQueue = self.successCallbackQueue; + operation.failureCallbackQueue = self.failureCallbackQueue; + operation.willMapDeserializedResponseBlock = self.willMapDeserializedResponseBlock; + [operation setCompletionBlockWithSuccess:self.successBlock failure:self.failureBlock]; + + return operation; +} + +#pragma mark - NSOperation + +- (BOOL)isConcurrent +{ + return YES; +} + +- (BOOL)isReady +{ + return [self.stateMachine isReady] && [super isReady]; +} + +- (BOOL)isExecuting +{ + return [self.stateMachine isExecuting]; +} + +- (BOOL)isFinished +{ + return [self.stateMachine isFinished]; +} + +- (void)start +{ + [self.stateMachine start]; +} + +- (void)cancel +{ + [super cancel]; + [self.stateMachine cancel]; +} + +@end + +#pragma mark - Fix for leak in iOS 5/6 "- [NSCachedURLResponse data]" message + +@implementation NSCachedURLResponse (RKLeakFix) + +- (NSData *)rkData +{ + @synchronized(self) { + NSData *result; + CFIndex count; + + @autoreleasepool { + result = [self data]; + count = CFGetRetainCount((__bridge CFTypeRef)result); + } + + if (CFGetRetainCount((__bridge CFTypeRef)result) == count) { +#ifndef __clang_analyzer__ + CFRelease((__bridge CFTypeRef)result); // Leak detected, manually release +#endif + } + + return result; + } +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h new file mode 100644 index 0000000..284df50 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1,45 @@ +// +// RKObjectRequestOperationSubclass.h +// RestKit +// +// Created by Blake Watters on 9/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/* + The extensions to the `RKObjectRequestOperation` class declared in the `ForSubclassEyesOnly` category are to be used by subclasses implementations only. Code that uses `RKObjectRequestOperation` objects must never call these methods. + */ +@interface RKObjectRequestOperation (ForSubclassEyesOnly) + +///---------------------------- +/// @name Subclassing Overrides +///---------------------------- + +/** + Performs object mapping using the `response` and `responseData` properties. + + The `RKObjectRequestOperation` superclass is responsible for the invocation of this method and the subsequent handling of the mapping result or error. + + @param error A pointer to an `NSError` object to be set in the event that the object mapping process has failed. + @return A mapping result or `nil` if an error has occurred. + */ +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock; + +/** + Invoked to tell the receiver that the object request operation is finishing its work and is about to transition into the finished state. Used to perform any necessary cleanup before the operation is finished. + */ +- (void)willFinish; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.h new file mode 100644 index 0000000..32cda58 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.h @@ -0,0 +1,280 @@ +// +// RKPaginator.h +// RestKit +// +// Created by Blake Watters on 12/29/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKObjectRequestOperation.h" +#import "RKObjectMapping.h" +#import "RKMappingResult.h" + +@protocol RKManagedObjectCaching; + +/** + Instances of `RKPaginator` retrieve paginated collections of mappable data from remote systems via HTTP. Paginators perform GET requests and use a patterned URL to construct a full URL reflecting the state of the paginator. Paginators rely on an instance of RKObjectMappingProvider to determine how to perform object mapping on the retrieved data. Paginators can load Core Data backed models provided that an instance of RKManagedObjectStore is assigned to the paginator. + + ## Configuring Pagination Mapping + + The paginator must be configured with a `paginationMapping` specifying how configuration metadata is to be mapped out of the response payload. The configured mapping must have an `objectClass` of `RKPaginator` and should include attribute mappings for the `currentPage`, `pageCount`, `perPage`, and `objectCount`. For example, given a paginated resource loaded from '/articles?page=1' with the followibg JSON: + + { "pagination": { "per_page": 10, "total_pages": 25, "total_objects": 250 }, "articles": [ // Array of articles ] } + + The pagination mapping would be configured as: + + RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]]; + [paginationMapping addAttributeMappingsFromDictionary:@{ + @"pagination.per_page": @"perPage", + @"pagination.total_pages": @"pageCount", + @"pagination.total_objects": @"objectCount", + }]; + + ## iOS 5 Compatibility Caveats + + The paginator is compatible with iOS 5.x through the use of proxy attributes. In iOS 6.0 and greater, key-value coding supports the automatic boxing and unboxing of primitive values. This enables direct mapping configuration for the `currentPage`, `pageCount`, `perPage`, and `objectCount` attributes. Under iOS 5, where autoboxing is not available, mapping configuration must target special proxy attributes instead. For each of the above properties, a private `NSNumber` property is implemented by the class. Each proxy property has 'Number' appended as a suffix to the property name: `currentPageNumber`, `pageCountNumber`, `perPageNumber`, and `objectCountNumber`. + + */ +@interface RKPaginator : NSObject + +///------------------------------------- +/// @name Initializing Paginator Objects +///------------------------------------- + +/** + Initializes a RKPaginator object with the a provided patternURL and mappingProvider. + + @param request A request with a URL containing a dynamic pattern specifying how paginated resources are to be accessed. + @param paginationMapping The pagination mapping specifying how pagination metadata is to be mapped from responses. + @param responseDescriptors An array of response descriptors describing how to map object representations loaded by object request operations dispatched by the paginator. + @return The receiver, initialized with the request, pagination mapping, and response descriptors. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request + paginationMapping:(RKObjectMapping *)paginationMapping + responseDescriptors:(NSArray *)responseDescriptors NS_DESIGNATED_INITIALIZER; + +///----------------------------- +/// @name Configuring Networking +///----------------------------- + +/** + A URL with a path pattern for building a complete URL from + which to load the paginated resource collection. The patterned resource + path will be evaluated against the state of the paginator object itself. + + For example, given a paginated collection of data at the /articles path, + the path portion of the pattern URL may look like: + + /articles?per_page=:perPage&page_number=:currentPage + + When the pattern is evaluated against the state of the paginator, this will + yield a complete path that can be used to load the specified page. Given + a paginator configured with 100 objects per page and a current page number of 3, + the path portion of the pagination URL would become: + + /articles?per_page=100&page_number=3 + */ +@property (nonatomic, readonly) NSURL *patternURL; + +/** + Returns a complete URL to the paginated resource collection by interpolating the state of the paginator object against the patternURL. + */ +@property (nonatomic, readonly) NSURL *URL; + +/** + An optional operation queue on which object request operations constructed by the paginator are to be enqueued for processing. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +/** + Returns the last object request operation used by the paginator to load a page of objects. + */ +@property (nonatomic, strong, readonly) RKObjectRequestOperation *objectRequestOperation; + +/** + Sets the `RKHTTPRequestOperation` subclass to be used when constructing HTTP request operations for requests dispatched by the paginator. + + **Default**: `[RKHTTPRequestOperation class]` + */ +- (void)setHTTPOperationClass:(Class)operationClass; + +///----------------------------------- +/// @name Setting the Completion Block +///----------------------------------- + +/** + Sets the completion block to be invoked when the paginator finishes loading a page of results. + + @param success A block to be executed upon a successful load of a page of objects. The block has no return value and takes three arguments: the paginator object, an array containing the paginated objects, and an integer indicating the page that was loaded. + @param failure A block to be exected upon a failed load. The block has no return value and takes two arguments: the paginator object and an error indicating the nature of the failure. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success + failure:(void (^)(RKPaginator *paginator, NSError *error))failure; + + +///----------------------------------- +/// @name Accessing Pagination Results +///----------------------------------- + +/** + The mapping result containing the last set of paginated objects or `nil` if an error was encountered. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occured during the last load of the paginator. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///----------------------------------- +/// @name Object Mapping Configuration +///----------------------------------- + +/** + The object mapping defining how pagination metadata is to be mapped from a paginated response onto the paginator object. + + See the documentation in the "Configuring Pagination Mapping" section for details about the pagination mapping. + + @warning The `objectClass` of the given mapping must be `RKPaginator`. + */ +@property (nonatomic, strong) RKObjectMapping *paginationMapping; + +///------------------------------ +/// @name Core Data Configuration +///------------------------------ + +#ifdef _COREDATADEFINES_H +/** + The managed object context in which paginated managed objects are to be persisted. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache used to find existing managed object instances in the persistent store. + */ +@property (nonatomic, strong) id<RKManagedObjectCaching> managedObjectCache; + +/** + An array of fetch request blocks. + */ +@property (nonatomic, copy) NSArray *fetchRequestBlocks; +#endif + +///------------------------------------ +/// @name Accessing Pagination Metadata +///------------------------------------ + +/** + The number of objects to load per page + */ +@property (nonatomic, assign) NSUInteger perPage; + +/** + A Boolean value indicating if the paginator has loaded a page of objects + + @returns YES when the paginator has loaded a page of objects + */ +@property (nonatomic, readonly, getter = isLoaded) BOOL loaded; + +/** + Returns the page number for the most recently loaded page of objects. + + @return The page number for the current page of objects. + @exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`. + */ +@property (nonatomic, readonly) NSUInteger currentPage; + +/** + Returns the offset based off the page for the most recently loaded objects. + + @return The offset for the current page of objects. + @exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`. + */ +@property (nonatomic, readonly) NSUInteger offset; + +/** + Returns the number of pages in the total resource collection. + + @return A count of the number of pages in the resource collection. + @exception NSInternalInconsistencyException Raised if `hasPageCount` is `NO`. + */ +@property (nonatomic, readonly) NSUInteger pageCount; + +/** + Returns the total number of objects in the collection + + @return A count of the number of objects in the resource collection. + @exception NSInternalInconsistencyException Raised if `hasObjectCount` is `NO`. + */ +@property (nonatomic, readonly) NSUInteger objectCount; + +/** + Returns a Boolean value indicating if the total number of pages in the collection is known by the paginator. + + @return `YES` if the paginator knows the page count, otherwise `NO`. + */ +@property (nonatomic, readonly) BOOL hasPageCount; + +/** + Returns a Boolean value indicating if the total number of objects in the collection is known by the paginator. + + @return `YES` if the paginator knows the number of objects in the paginated collection, otherwise `NO`. + */ +@property (nonatomic, readonly) BOOL hasObjectCount; + +/** + Returns a Boolean value indicating if there is a next page in the collection. + + @return `YES` if there is a next page, otherwise `NO`. + @exception NSInternalInconsistencyException Raised if isLoaded or hasPageCount is `NO`. + */ +@property (nonatomic, readonly) BOOL hasNextPage; + +/** + Returns a Boolean value indicating if there is a previous page in the collection. + + @return `YES` if there is a previous page, otherwise `NO`. + @exception NSInternalInconsistencyException Raised if isLoaded is `NO`. + */ +@property (nonatomic, readonly) BOOL hasPreviousPage; + +///------------------------ +/// @name Paginator Actions +///------------------------ + +/** + Loads the next page of data by incrementing the current page, constructing an object loader to fetch the data, and object mapping the results. + */ +- (void)loadNextPage; + +/** + Loads the previous page of data by decrementing the current page, constructing an object loader to fetch the data, and object mapping the results. + */ +- (void)loadPreviousPage; + +/** + Loads a specific page of data by mutating the current page, constructing an object loader to fetch the data, and object mapping the results. + + @param pageNumber The page of objects to load from the remote backend + */ +- (void)loadPage:(NSUInteger)pageNumber; + +/** + Cancels an in-progress pagination request. + */ +- (void)cancel; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.m new file mode 100644 index 0000000..f5ef61d --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPaginator.m @@ -0,0 +1,329 @@ +// +// RKPaginator.m +// RestKit +// +// Created by Blake Watters on 12/29/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPaginator.h" +#import "RKMappingOperation.h" +#import "SOCKit.h" +#import "RKLog.h" +#import "RKPathMatcher.h" +#import "RKHTTPUtilities.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectRequestOperation.h" +#endif +#endif + +static NSUInteger RKPaginatorDefaultPerPage = 25; + +// Private interface +@interface RKPaginator () +@property (nonatomic, copy) NSURLRequest *request; +@property (nonatomic, strong) Class HTTPOperationClass; +@property (nonatomic, copy) NSArray *responseDescriptors; +@property (nonatomic, assign, readwrite) NSUInteger currentPage; +@property (nonatomic, assign, readwrite) NSUInteger offset; +@property (nonatomic, assign, readwrite) NSUInteger pageCount; +@property (nonatomic, assign, readwrite) NSUInteger objectCount; +@property (nonatomic, assign, readwrite) BOOL loaded; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKObjectRequestOperation *objectRequestOperation; + +// iOS 5.x compatible proxy attributes +@property (nonatomic, assign, readwrite) NSNumber *perPageNumber; +@property (nonatomic, assign, readwrite) NSNumber *currentPageNumber; +@property (nonatomic, assign, readwrite) NSNumber *pageCountNumber; +@property (nonatomic, assign, readwrite) NSNumber *objectCountNumber; + +@property (nonatomic, copy) void (^successBlock)(RKPaginator *paginator, NSArray *objects, NSUInteger page); +@property (nonatomic, copy) void (^failureBlock)(RKPaginator *paginator, NSError *error); +@end + +@implementation RKPaginator + +- (instancetype)initWithRequest:(NSURLRequest *)request + paginationMapping:(RKObjectMapping *)paginationMapping + responseDescriptors:(NSArray *)responseDescriptors; +{ + NSParameterAssert(request); + NSParameterAssert(paginationMapping); + NSParameterAssert(responseDescriptors); + NSAssert([paginationMapping.objectClass isSubclassOfClass:[RKPaginator class]], @"The paginationMapping must have a target object class of `RKPaginator`"); + self = [super init]; + if (self) { + self.HTTPOperationClass = [RKHTTPRequestOperation class]; + self.request = request; + self.paginationMapping = paginationMapping; + self.responseDescriptors = responseDescriptors; + self.currentPage = NSNotFound; + self.pageCount = NSNotFound; + self.objectCount = NSNotFound; + self.offset = NSNotFound; + self.perPage = RKPaginatorDefaultPerPage; + self.loaded = NO; + } + + return self; +} + +- (void)dealloc +{ + [self.objectRequestOperation cancel]; +} + +- (NSURL *)patternURL +{ + return self.request.URL; +} + +- (NSURL *)URL +{ + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(self.patternURL, nil); + NSString *interpolatedString = RKPathFromPatternWithObject(pathAndQueryString, self); + return [NSURL URLWithString:interpolatedString relativeToURL:self.request.URL]; +} + +- (void)setHTTPOperationClass:(Class)operationClass +{ + NSAssert(operationClass == nil || [operationClass isSubclassOfClass:[RKHTTPRequestOperation class]], @"The HTTP operation class must be a subclass of `RKHTTPRequestOperation`"); + _HTTPOperationClass = operationClass; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success + failure:(void (^)(RKPaginator *paginator, NSError *error))failure +{ + self.successBlock = success; + self.failureBlock = failure; +} + +// Private. Public consumers can rely on isLoaded +- (BOOL)hasCurrentPage +{ + return _currentPage != NSNotFound; +} + +- (BOOL)hasOffset +{ + return _offset != NSNotFound; +} + +- (BOOL)hasPageCount +{ + return _pageCount != NSNotFound; +} + +- (BOOL)hasObjectCount +{ + return _objectCount != NSNotFound; +} + +- (NSUInteger)currentPage +{ + // Referenced during initial load, so we don't rely on isLoaded. + NSAssert([self hasCurrentPage], @"Current page has not been initialized."); + return _currentPage; +} + +- (NSUInteger)offset +{ + if ([self hasOffset]) return _offset; + return [self hasCurrentPage] ? ((_currentPage - 1) * _perPage) : 0; +} + +- (BOOL)hasNextPage +{ + NSAssert(self.isLoaded, @"Cannot determine hasNextPage: paginator is not loaded."); + NSAssert([self hasPageCount], @"Cannot determine hasNextPage: page count is not known."); + + return self.currentPage < self.pageCount; +} + +- (BOOL)hasPreviousPage +{ + NSAssert(self.isLoaded, @"Cannot determine hasPreviousPage: paginator is not loaded."); + return self.currentPage > 1; +} + +#pragma mark - Action methods + +- (void)loadNextPage +{ + [self loadPage:self.currentPage + 1]; +} + +- (void)loadPreviousPage +{ + [self loadPage:self.currentPage - 1]; +} + +- (void)loadPage:(NSUInteger)pageNumber +{ + if (self.objectRequestOperation.HTTPRequestOperation.response) { + // The user by calling loadPage is ready to perform the next request so invalidate objectRequestOperation + self.objectRequestOperation = nil; + } + + NSAssert(self.responseDescriptors, @"Cannot perform a load with nil response descriptors."); + NSAssert(! self.objectRequestOperation, @"Cannot perform a load while one is already in progress."); + self.currentPage = pageNumber; + + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + mutableRequest.URL = self.URL; + +#ifdef RKCoreDataIncluded + if (self.managedObjectContext) { + RKHTTPRequestOperation *requestOperation = [[self.HTTPOperationClass alloc] initWithRequest:mutableRequest]; + RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:self.responseDescriptors]; + managedObjectRequestOperation.managedObjectContext = self.managedObjectContext; + managedObjectRequestOperation.managedObjectCache = self.managedObjectCache; + managedObjectRequestOperation.fetchRequestBlocks = self.fetchRequestBlocks; + managedObjectRequestOperation.deletesOrphanedObjects = NO; + + self.objectRequestOperation = managedObjectRequestOperation; + } else { + self.objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors]; + } +#else + self.objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors]; +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + [self.objectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) { + NSError *error = nil; + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:deserializedResponseBody destinationObject:self mapping:self.paginationMapping]; + BOOL success = [mappingOperation performMapping:&error]; + if (!success) { + self.pageCount = 0; + self.currentPage = 0; + RKLogError(@"Paginator didn't map info to compute page count. Assuming no pages."); + } else if (self.perPage && [self hasObjectCount]) { + float objectCountFloat = self.objectCount; + self.pageCount = ceilf(objectCountFloat / self.perPage); + RKLogInfo(@"Paginator objectCount: %ld pageCount: %ld", (long)self.objectCount, (long)self.pageCount); + } else { + RKLogError(@"Paginator perPage set is 0."); + } + + return deserializedResponseBody; + }]; + [self.objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { + [self finish]; + if (self.successBlock) { + self.successBlock(self, [mappingResult array], self.currentPage); + } + } failure:^(RKObjectRequestOperation *operation, NSError *error) { + [self finish]; + if (self.failureBlock) { + self.failureBlock(self, error); + } + }]; +#pragma clang diagnostic pop + + if (self.operationQueue) { + [self.operationQueue addOperation:self.objectRequestOperation]; + } else { + [self.objectRequestOperation start]; + } +} + +- (void)waitUntilFinished +{ + [self.objectRequestOperation waitUntilFinished]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p patternURL=%@ isLoaded=%@ perPage=%ld currentPage=%@ offset=%@ pageCount=%@ objectCount=%@>", + NSStringFromClass([self class]), self, self.patternURL, self.isLoaded ? @"YES" : @"NO", (long) self.perPage, + [self hasCurrentPage] ? @(self.currentPage) : @"???", + [self hasOffset] ? @(self.offset) : @"???", + [self hasPageCount] ? @(self.pageCount) : @"???", + [self hasObjectCount] ? @(self.objectCount) : @"???"]; +} + +- (void)finish +{ + self.loaded = (self.objectRequestOperation.mappingResult != nil); + self.mappingResult = self.objectRequestOperation.mappingResult; + self.error = self.objectRequestOperation.error; +} + +- (void)cancel +{ + [self.objectRequestOperation cancel]; + self.objectRequestOperation = nil; +} + +#pragma mark - iOS 5 proxy attributes + +- (NSNumber *)perPageNumber +{ + return @(self.perPage); +} + +- (void)setPerPageNumber:(NSNumber *)perPageNumber +{ + self.perPage = [perPageNumber unsignedIntegerValue]; +} + +- (NSNumber *)currentPageNumber +{ + return @(self.currentPage); +} + +- (void)setCurrentPageNumber:(NSNumber *)currentPageNumber +{ + self.currentPage = [currentPageNumber unsignedIntegerValue]; +} + +- (NSNumber *)pageCountNumber +{ + return @(self.pageCount); +} + +- (void)setPageCountNumber:(NSNumber *)pageCountNumber +{ + self.pageCount = [pageCountNumber unsignedIntegerValue]; +} + +- (NSNumber *)objectCountNumber +{ + return @(self.objectCount); +} + +- (void)setObjectCountNumber:(NSNumber *)objectCountNumber +{ + self.objectCount = [objectCountNumber unsignedIntegerValue]; +} + +- (NSNumber *)offsetNumber +{ + return @(self.offset); +} + +- (void)setOffsetNumber:(NSNumber *)offsetNumber +{ + self.offset = [offsetNumber unsignedIntegerValue]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.h new file mode 100644 index 0000000..fb1cee9 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.h @@ -0,0 +1,132 @@ +// +// RKPathMatcher.h +// RestKit +// +// Created by Greg Combs on 9/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +@class SOCPattern; + +/** + Convenience method for generating a path against the properties of an object. Takes an `NSString` with property names prefixed with a colon and interpolates the values of the properties specified and returns the generated path. + + For example, given an `article` object with an `articleID` property whose value is `@12345`, `RKPathFromPatternWithObject(@"articles/:articleID", article)` would return `@"articles/12345"`. + + This functionality is the basis for path generation in the `RKRouter` class. + + @param pathPattern An `SOCPattern` string containing zero or more colon-prefixed property names. + @param object The object to interpolate the properties against + @return A new `NSString` object with the values of the given object interpolated for the colon-prefixed properties name in the given pattern string. + @see `RKPathMatcher` + @see `SOCPattern` + */ +NSString *RKPathFromPatternWithObject(NSString *pathPattern, id object); + +/** + The `RKPathMatcher` class performs pattern matching and parameter parsing of strings, typically representing the path portion of an `NSURL` object. It provides much of the necessary tools to map a given path to local objects (the inverse of RKRouter's function). This makes it easier to implement the `RKManagedObjectCaching` protocol and generate `NSFetchRequest` objects from a given path. There are two means of instantiating and using a matcher object in order to provide more flexibility in implementations, and to improve efficiency by eliminating repetitive and costly pattern initializations. + + @see `RKManagedObjectCaching` + @see `RKPathFromPatternWithObject` + @see `RKRouter` + */ +@interface RKPathMatcher : NSObject <NSCopying> + +///--------------------------------- +/// @name Matching Paths to Patterns +///--------------------------------- + +/** + Creates a path match object starting from a path string. This method should be followed by `matchesPattern:tokenizeQueryStrings:parsedArguments:` + + @param pathString The string to evaluate and parse, such as `/districts/tx/upper/?apikey=GC5512354` + @return An instantiated `RKPathMatcher` without an established pattern. + */ ++ (instancetype)pathMatcherWithPath:(NSString *)pathString; + +/** + Determines if the path string matches the provided pattern, and yields a dictionary with the resulting matched key/value pairs. Use of this method should be preceded by `pathMatcherWithPath:` Pattern strings should include encoded parameter keys, delimited by a single colon at the beginning of the key name. + + *NOTE 1 *- Numerous colon-encoded parameter keys can be joined in a long pattern, but each key must be separated by at least one unmapped character. For instance, `/:key1:key2:key3/` is invalid, whereas `/:key1/:key2/:key3/` is acceptable. + + *NOTE 2 *- The pattern matcher supports KVM, so `:key1.otherKey` normally resolves as it would in any other KVM + situation, ... otherKey is a sub-key on a the object represented by key1. This presents problems in circumstances where + you might want to build a pattern like /:filename.json, where the dot isn't intended as a sub-key on the filename, but rather + part of the json static string. In these instances, you need to escape the dot with two backslashes, like so: + /:filename\\.json + + @param patternString The pattern to use for evaluating, such as `/:entityName/:stateID/:chamber/` + @param shouldTokenize If YES, any query parameters will be tokenized and inserted into the parsed argument dictionary. + @param arguments A pointer to a dictionary that contains the key/values from the pattern (and parameter) matching. + @return A boolean value indicating if the path string successfully matched the pattern. + */ +- (BOOL)matchesPattern:(NSString *)patternString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments; + +///--------------------------------- +/// @name Matching Patterns to Paths +///--------------------------------- + +/** + Creates a path matcher object starting from a pattern string. This method should be followed by `matchesPath:tokenizeQueryStrings:parsedArguments:`. Patterns should include encoded parameter keys, delimited by a single colon at the beginning of the key name. + + *NOTE 1 *- Numerous colon-encoded parameter keys can be joined in a long pattern, but each key must be separated by at least one unmapped character. For instance, `/:key1:key2:key3/` is invalid, whereas `/:key1/:key2/:key3/` is acceptable. + + *NOTE 2 *- The pattern matcher supports KVM, so `:key1.otherKey` normally resolves as it would in any other KVM situation, ... otherKey is a sub-key on a the object represented by key1. This presents problems in circumstances where you might want to build a pattern like `/:filename.json`, where the dot isn't intended as a sub-key on the filename, but rather part of the json static string. In these instances, you need to escape the dot with two backslashes, like so: `/:filename\\.json` + + @param patternString The pattern to use for evaluating, such as `/:entityName/:stateID/:chamber/` + @return An instantiated `RKPathMatcher` with an established pattern. + */ ++ (instancetype)pathMatcherWithPattern:(NSString *)patternString; + +/** + Determines if the given path string matches a pattern, and yields a dictionary with the resulting matched key/value pairs. Use of this method should be preceded by `pathMatcherWithPattern:`. + + @param pathString The string to evaluate and parse, such as `/districts/tx/upper/?apikey=GC5512354` + @param shouldTokenize If YES, any query parameters will be tokenized and inserted into the parsed argument dictionary. + @param arguments A pointer to a dictionary that contains the key/values from the pattern (and parameter) matching. + @return A boolean value indicating if the path string successfully matched the pattern. + */ +- (BOOL)matchesPath:(NSString *)pathString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments; + +///---------------------------------- +/// @name Creating Paths from Objects +///---------------------------------- + +/** + Generates a path by interpolating the properties of the 'object' argument, assuming the existence of a previously specified pattern established via `pathMatcherWithPattern:`. Otherwise, this method is identical in function to `RKPathFromPatternWithObject` (in fact it is a shortcut for this method). + + For example, given an 'article' object with an 'articleID' property value of 12345 and a code of "This/That"... + + RKPathMatcher *matcher = [RKPathMatcher pathMatcherWithPattern:@"/articles/:articleID/:code"]; + NSString *path = [matcher pathFromObject:article addingEscapes:YES interpolatedParameters:nil]; + + ... will produce a 'path' containing the string `@"/articles/12345/This%2FThat"` + + @param object The object containing the properties to interpolate. + @param addEscapes Conditionally add percent escapes to the interpolated property values + @param interpolatedParameters On input, a pointer for a dictionary object. When the path pattern of the receiver is interpolated, this pointer is set to a new dictionary object in which the keys correspond to the named parameters within the path pattern and the values are taken from the corresponding keypaths of the interpolated object . + @return A string with the object's interpolated property values inserted into the receiver's established pattern. + @see `RKRouter` + */ +- (NSString *)pathFromObject:(id)object addingEscapes:(BOOL)addEscapes interpolatedParameters:(NSDictionary **)interpolatedParameters; + +///------------------------------------------- +/// @name Accessing Tokenized Query Parameters +///------------------------------------------- + +@property (copy, readonly) NSDictionary *queryParameters; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.m new file mode 100644 index 0000000..a8ce9bc --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKPathMatcher.m @@ -0,0 +1,154 @@ +// +// RKPathMatcher.m +// RestKit +// +// Created by Greg Combs on 9/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPathMatcher.h" +#import "SOCKit.h" +#import "RKLog.h" +#import "RKDictionaryUtilities.h" + +static NSString *RKEncodeURLString(NSString *unencodedString); +extern NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding stringEncoding); + +// NSString's stringByAddingPercentEscapes doesn't do a complete job (it ignores "/?&", among others) +static NSString *RKEncodeURLString(NSString *unencodedString) +{ + NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes( + NULL, + (__bridge CFStringRef)unencodedString, + NULL, + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8)); + return encodedString; +} + +static NSUInteger RKNumberOfSlashesInString(NSString *string) +{ + static NSRegularExpression *regex = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + regex = [NSRegularExpression regularExpressionWithPattern:@"/" options:NSRegularExpressionCaseInsensitive error:nil]; + }); + return [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])]; +} + +NSString *RKPathFromPatternWithObject(NSString *pathPattern, id object) +{ + NSCAssert(object != NULL, @"Object provided is invalid; cannot create a path from a NULL object"); + RKPathMatcher *matcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + return [matcher pathFromObject:object addingEscapes:NO interpolatedParameters:nil]; +} + +@interface RKPathMatcher () +@property (nonatomic, strong) SOCPattern *socPattern; +@property (nonatomic, copy) NSString *patternString; // SOCPattern keeps it private +@property (nonatomic, copy) NSString *sourcePath; +@end + +@implementation RKPathMatcher + +- (id)copyWithZone:(NSZone *)zone +{ + RKPathMatcher *copy = [[[self class] allocWithZone:zone] init]; + copy.socPattern = self.socPattern; + copy.patternString = self.patternString; + copy.sourcePath = self.sourcePath; + return copy; +} + ++ (instancetype)pathMatcherWithPattern:(NSString *)patternString +{ + NSAssert(patternString != NULL, @"Pattern string must not be empty in order to perform pattern matching."); + RKPathMatcher *matcher = [self new]; + matcher.socPattern = [SOCPattern patternWithString:patternString]; + matcher.patternString = patternString; + return matcher; +} + ++ (instancetype)pathMatcherWithPath:(NSString *)pathString +{ + RKPathMatcher *matcher = [self new]; + matcher.sourcePath = pathString; + return matcher; +} + +- (BOOL)itMatchesAndHasParsedArguments:(NSDictionary **)arguments andPattern:(NSString*)pattern andSourcePath:(NSString*)sourcePath tokenizeQueryStrings:(BOOL)shouldTokenize +{ + NSMutableDictionary *argumentsCollection = [NSMutableDictionary dictionary]; + NSString *rootPath = [sourcePath copy]; + NSArray *components = [sourcePath componentsSeparatedByString:@"?"]; + SOCPattern *socPattern = [SOCPattern patternWithString:pattern]; + + // Bifurcate Source Path From Query Parameters + + if ([components count] > 1) { + rootPath = [components objectAtIndex:0]; + NSDictionary *queryParameters = RKQueryParametersFromStringWithEncoding([components objectAtIndex:1], NSUTF8StringEncoding); + if (shouldTokenize) { + [argumentsCollection addEntriesFromDictionary:queryParameters]; + } + } + + bool rootPathMatchesPattern = RKNumberOfSlashesInString(pattern) == RKNumberOfSlashesInString(rootPath); + + if (![socPattern stringMatches:rootPath]) return NO; + if (!arguments) return YES && rootPathMatchesPattern; + NSDictionary *extracted = [socPattern parameterDictionaryFromSourceString:rootPath]; + if (extracted) [argumentsCollection addEntriesFromDictionary:RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(extracted)]; + *arguments = argumentsCollection; + return YES && rootPathMatchesPattern; +} + +- (BOOL)matchesPattern:(NSString *)patternString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments +{ + NSAssert(self.sourcePath != NULL, @"Matcher is not configured correctly. Instantiate it using pathMatcherWithPath: to use matchesPattern:tokenizeQueryStrings:parsedArguments"); + NSAssert(patternString != NULL, @"Pattern string must not be empty in order to perform patterm matching."); + return [self itMatchesAndHasParsedArguments:arguments andPattern:patternString andSourcePath:self.sourcePath tokenizeQueryStrings:shouldTokenize]; +} + +- (BOOL)matchesPath:(NSString *)sourceString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments +{ + return [self itMatchesAndHasParsedArguments:arguments andPattern:self.patternString andSourcePath:sourceString tokenizeQueryStrings:shouldTokenize]; +} + +- (NSString *)pathFromObject:(id)object addingEscapes:(BOOL)addEscapes interpolatedParameters:(NSDictionary **)interpolatedParameters +{ + NSAssert(self.socPattern != NULL, @"Matcher has no established pattern. Instantiate it using pathMatcherWithPattern: before calling pathFromObject:"); + NSAssert(object != NULL, @"Object provided is invalid; cannot create a path from a NULL object"); + NSString *(^encoderBlock)(NSString *interpolatedString) = nil; + if (addEscapes) { + encoderBlock = ^NSString *(NSString *interpolatedString) { + return RKEncodeURLString(interpolatedString); + }; + } + NSString *path = [self.socPattern stringFromObject:object withBlock:encoderBlock]; + if (interpolatedParameters) { + NSMutableDictionary *parsedParameters = [[self.socPattern parameterDictionaryFromSourceString:path] mutableCopy]; + if (addEscapes) { + for (NSString *key in [parsedParameters allKeys]) { + NSString *unescapedParameter = [parsedParameters[key] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [parsedParameters setValue:unescapedParameter forKey:key]; + } + } + *interpolatedParameters = parsedParameters; + } + return path; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.h new file mode 100644 index 0000000..3b45e17 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.h @@ -0,0 +1,110 @@ +// +// RKRequestDescriptor.h +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKHTTPUtilities.h" + +@class RKMapping; + +/** + An `RKRequestDescriptor` object describes an object mapping configuration that is used to construct the parameters of an HTTP request for an object. Request descriptors are defined by specifying the `RKMapping` object (whose `objectClass` must be `NSMutableDictionary`) that is to be used when object mapping an object into an `NSDictionary` of parameters, the class of the type of object for which the mapping is to be applied, and an optional root key path under which the paramters are to be nested. Response descriptors are only utilized when construct parameters for an `NSURLRequest` with an HTTP method of `POST`, `PUT`, or `PATCH`. + + @see RKObjectParameterization + @see [RKObjectMapping requestMapping] + @see [RKObjectManager requestWithObject:method:path:parameters:] + */ +@interface RKRequestDescriptor : NSObject + +///------------------------------------ +/// @name Creating a Request Descriptor +///------------------------------------ + +/** + Creates and returns a new `RKRequestDescriptor` object. + + This method is deprecated. Use `+ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath + method:(RKRequestMethod)method` instead. + + @param mapping The mapping to be used when parameterizing an object using the request descriptor. Cannot be nil and must have an objectClass equal to `[NSMutableDictionary class]`. + @param objectClass The class of objects for which the request descriptor should be used. Cannot be nil. + @param rootKeyPath The root key path under which paramters constructed using the response descriptor will be nested. If nil, the parameters will not be nested and returned as a flat dictionary object. + @return A new `RKRequestDescriptor` object. + + @see [RKObjectMapping requestMapping] + @warning An exception will be raised if the objectClass of the given mapping is not `[NSMutableDictionary class]`. + */ ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath DEPRECATED_ATTRIBUTE; + +/** +Creates and returns a new `RKRequestDescriptor` object. + +@param mapping The mapping to be used when parameterizing an object using the request descriptor. Cannot be nil and must have an objectClass equal to `[NSMutableDictionary class]`. +@param objectClass The class of objects for which the request descriptor should be used. Cannot be nil. +@param rootKeyPath The root key path under which paramters constructed using the response descriptor will be nested. If nil, the parameters will not be nested and returned as a flat dictionary object. +@param method The HTTP method(s) for which the mapping is to be used. +@return A new `RKRequestDescriptor` object. + +@see [RKObjectMapping requestMapping] +@warning An exception will be raised if the objectClass of the given mapping is not `[NSMutableDictionary class]`. +*/ ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath + method:(RKRequestMethod)method; + +///----------------------------------------------------- +/// @name Getting Information About a Request Descriptor +///----------------------------------------------------- + +/** + The mapping specifying how the object being parameterized is to be mapped into an `NSDictionary` representation. The mapping must have an objectClass equal to `[NSMutableDictionary class]`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The class of objects that the request descriptor is appropriate for use in parameterizing. + */ +@property (nonatomic, strong, readonly) Class objectClass; + +/** + The root key path that the paramters for the object are to be nested under. May be nil. + */ +@property (nonatomic, copy, readonly) NSString *rootKeyPath; + +/** + The HTTP method(s) for which the mapping is to be used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +///------------------------- +/// @name Comparing Request Descriptors +///------------------------- + +/** + Returns `YES` if the receiver and the specified request descriptor are considered equivalent. + + */ +- (BOOL)isEqualToRequestDescriptor:(RKRequestDescriptor *)otherDescriptor; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.m new file mode 100644 index 0000000..0a1ddd5 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRequestDescriptor.m @@ -0,0 +1,118 @@ +// +// RKRequestDescriptor.m +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRequestDescriptor.h" +#import "RKObjectMapping.h" +#import "RKDynamicMapping.h" + +static void RKAssertValidMappingForRequestDescriptor(RKMapping *mapping) +{ + if ([mapping isKindOfClass:[RKObjectMapping class]]) { + if (! [[(RKObjectMapping *)mapping objectClass] isEqual:[NSMutableDictionary class]]) { + [NSException raise:NSInvalidArgumentException format:@"`RKRequestDescriptor` objects must be initialized with a mapping whose target class is `NSMutableDictionary`, got '%@' (see `[RKObjectMapping requestMapping]`)", [(RKObjectMapping *)mapping objectClass]]; + } + } else if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + [[(RKDynamicMapping *)mapping objectMappings] enumerateObjectsUsingBlock:^(RKObjectMapping *objectMapping, NSUInteger idx, BOOL *stop) { + if (! [objectMapping.objectClass isEqual:[NSMutableDictionary class]]) { + [NSException raise:NSInvalidArgumentException format:@"`RKRequestDescriptor` objects may only be initialized with `RKDynamicMapping` objects containing `RKObjectMapping` objects whose target class is `NSMutableDictionary`, got '%@' (see `[RKObjectMapping requestMapping]`)", objectMapping.objectClass]; + } + }]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Expected an instance of `RKObjectMapping` or `RKDynamicMapping`, instead got '%@'", [mapping class]]; + } +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKRequestDescriptor () + +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, strong, readwrite) Class objectClass; +@property (nonatomic, copy, readwrite) NSString *rootKeyPath; +@property (nonatomic, assign, readwrite) RKRequestMethod method; + +@end + +@implementation RKRequestDescriptor + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping objectClass:(Class)objectClass rootKeyPath:(NSString *)rootKeyPath +{ + return [self requestDescriptorWithMapping:mapping objectClass:objectClass rootKeyPath:rootKeyPath method:RKRequestMethodAny]; +} +#pragma clang diagnostic pop + ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping objectClass:(Class)objectClass rootKeyPath:(NSString *)rootKeyPath method:(RKRequestMethod)method +{ + NSParameterAssert(mapping); + NSParameterAssert(objectClass); + RKAssertValidMappingForRequestDescriptor(mapping); + + RKRequestDescriptor *requestDescriptor = [self new]; + requestDescriptor.mapping = mapping; + requestDescriptor.objectClass = objectClass; + requestDescriptor.rootKeyPath = rootKeyPath; + requestDescriptor.method = method; + return requestDescriptor; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p method=%@ objectClass=%@ rootKeyPath=%@ : %@>", + NSStringFromClass([self class]), self, RKStringDescribingRequestMethod(self.method), NSStringFromClass(self.objectClass), self.rootKeyPath, self.mapping]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if ([self class] != [object class]) { + return NO; + } + return [self isEqualToRequestDescriptor:object]; +} + +#define NSUINT_BIT (CHAR_BIT * sizeof(NSUInteger)) +#define NSUINTROTATE(val, howmuch) ((((NSUInteger)val) << howmuch) | (((NSUInteger)val) >> (NSUINT_BIT - howmuch))) + +- (NSUInteger)hash +{ + return NSUINTROTATE(NSUINTROTATE([self.mapping hash], NSUINT_BIT / 3) ^ [self.objectClass hash], NSUINT_BIT / 3) ^ [self.rootKeyPath hash]; +} + +- (BOOL)isEqualToRequestDescriptor:(RKRequestDescriptor *)otherDescriptor +{ + if (![otherDescriptor isKindOfClass:[RKRequestDescriptor class]]) { + return NO; + } + + return + [self.mapping isEqualToMapping:otherDescriptor.mapping] && + self.objectClass == otherDescriptor.objectClass && + self.method == otherDescriptor.method && + ((self.rootKeyPath == otherDescriptor.rootKeyPath) || [self.rootKeyPath isEqualToString:otherDescriptor.rootKeyPath]); +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.h new file mode 100644 index 0000000..d2d9928 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.h @@ -0,0 +1,181 @@ +// +// RKResponseDescriptor.h +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +@class RKMapping; + +/** + An `RKResponseDescriptor` object describes an object mapping configuration that is applicable to an HTTP response. Response descriptors are defined by specifying the `RKMapping` object that is to be used when performing object mapping on the deserialized response body and the URL path pattern, key path, and status codes for which the mapping is appropriate. The path pattern is a SOCKit `SOCPattern` string that will be matched against the URL of the request that loaded the response being mapped. If the path pattern is nil, the response descriptor is considered to be appropriate for a response loaded from any URL. The key path specifies the location of data within the deserialized response body for which the mapping is appropriate. If nil, the mapping is considered to apply to the entire response body. The status codes specify a set of HTTP response status codes for which the mapping is appropriate. It is common to constrain a response descriptor to the HTTP Successful status code class (status codes in the 200-299 range). Object mapping for error responses can be configured by configuring a response descriptor to handle the Client Error status code class (status codes in the 400-499 range). Instances of `RKResponseDescriptor` are immutable. + + @see RKPathMatcher + @see RKStatusCodeIndexSetFromClass + */ +@interface RKResponseDescriptor : NSObject + +///------------------------------------- +/// @name Creating a Response Descriptor +///------------------------------------- + +/** + Creates and returns a new `RKResponseDescriptor` object. + + This method is deprecated. Use `+ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes` instead. + + @param mapping The mapping for the response descriptor. + @param pathPattern A path pattern that matches against URLs for which the mapping should be used. + @param keyPath A key path specifying the subset of the parsed response for which the mapping is to be used. + @param statusCodes A set of HTTP status codes for which the mapping is to be used. + @return A new `RKResponseDescriptor` object. + */ ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes DEPRECATED_ATTRIBUTE; + +/** + Creates and returns a new `RKResponseDescriptor` object. + + @param mapping The mapping for the response descriptor. + @param method The HTTP method(s) for which the mapping is to be used. + @param pathPattern A path pattern that matches against URLs for which the mapping should be used. + @param keyPath A key path specifying the subset of the parsed response for which the mapping is to be used. + @param statusCodes A set of HTTP status codes for which the mapping is to be used. + @return A new `RKResponseDescriptor` object. + */ ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes; + +///------------------------------------------------------ +/// @name Getting Information About a Response Descriptor +///------------------------------------------------------ + +/** + The mapping to be used when object mapping the deserialized HTTP response body. Cannot be nil. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The HTTP method(s) for which the mapping is to be used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +/** + The path pattern to match against the request URL. If nil, the response descriptor matches any URL. + + @see `RKPathMatcher` + */ +@property (nonatomic, copy, readonly) NSString *pathPattern; + +/** + The key path to match against the deserialized response body. If nil, the response descriptor matches the entire response body. + + When evaluating a key path match, the Foundation object parsed from the response body is sent `valueForKeyPath:` with the keyPath of the receiver. If the value returned is non-nil, object mapping is performed using the response descriptor's mapping. + */ +@property (nonatomic, copy, readonly) NSString *keyPath; + +/** + The set of status codes for which response descriptor matches. If nil, the the response descriptor matches any status code. + + @see RKStatusCodeClass + */ +@property (nonatomic, copy, readonly) NSIndexSet *statusCodes; + +///--------------------------- +/// @name Setting the Base URL +///--------------------------- + +/** + The base URL that the `pathPattern` is to be evaluated relative to. + + The base URL is set to the base URL of the object manager when a response descriptor is added to an object manager. + + @see `matchesURL:` + */ +@property (nonatomic, copy) NSURL *baseURL; + +///--------------------------------- +/// @name Using Response Descriptors +///--------------------------------- + +/** + Returns a Boolean value that indicates if the receiver's path pattern matches the given path. + + Path matching is performed using an `RKPathMatcher` object. If the receiver has a `nil` path pattern or the given path is `nil`, `YES` is returned. + + @param path The path to compare with the path pattern of the receiver. + @return `YES` if the path matches the receiver's pattern, else `NO`. + @see `RKPathMatcher` + */ +- (BOOL)matchesPath:(NSString *)path; + +/** + Returns a Boolean value that indicates if the given URL object matches the base URL and path pattern of the receiver. + + This method considers both the `baseURL` and `pathPattern` of the receiver when evaluating the given URL object. The results evaluate in the following ways: + + 1. If the `baseURL` and `pathPattern` of the receiver are both `nil`, then `YES` is returned. + 1. If the `baseURL` of the receiver is `nil`, but the path pattern is not, then the entire path and query string of the given URL will be evaluated against the path pattern of the receiver using `matchesPath:`. + 1. If the `baseURL` and the `pathPattern` are both non-nil, then the given URL is first checked to verify that it is relative to the base URL using a string prefix comparison. If the absolute string value of the given URL is prefixed with the string value of the base URL, then the URL is considered relative. If the given URL is found not to be relative to the receiver's baseURL, then `NO` is returned. If the URL is found to be relative to the base URL, then the path and query string of the URL are evaluated against the path pattern of the receiver using `matchesPath:`. + + @param URL The URL to compare with the base URL and path pattern of the receiver. + @return `YES` if the URL matches the base URL and path pattern of the receiver, else `NO`. + */ +- (BOOL)matchesURL:(NSURL *)URL; + +/** + Returns a Boolean value that indicates if the given URL response object matches the receiver. + + The match is evaluated by checking if the URL of the response matches the base URL and path pattern of the receiver via the `matchesURL:` method. If the URL is found to match, then the status code of the response is checked for inclusion in the receiver's set of status codes. + + @param response The HTTP response object to compare with the base URL, path pattern, and status codes set of the receiver. + @return `YES` if the response matches the base URL, path pattern, and status codes set of the receiver, else `NO`. + @see `matchesURL:` + */ +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response; + +/** + Returns a dictionary of parsed arguments extracted from the URL of the given response object. + + @param response The HTTP response object to compare with the base URL, path pattern, and status codes set of the receiver. + @return A dictionary of parsed arguments if the response matches the base URL, path pattern, and status codes set of the receiver, else `nil`. + @see `matchesResponse:` + + */ +- (NSDictionary *)parsedArgumentsFromResponse:(NSHTTPURLResponse *)response; + +///------------------------- +/// @name Comparing Response Descriptors +///------------------------- + +/** + Returns `YES` if the receiver and the specified response descriptor are considered equivalent. + + */ +- (BOOL)isEqualToResponseDescriptor:(RKResponseDescriptor *)otherDescriptor; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.m new file mode 100644 index 0000000..9c6bc0c --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseDescriptor.m @@ -0,0 +1,211 @@ +// +// RKResponseDescriptor.m +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPathMatcher.h" +#import "RKResponseDescriptor.h" +#import "RKHTTPUtilities.h" +#import "RKMapping.h" + +// Cloned from AFStringFromIndexSet -- method should be non-static for reuse +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); +NSString *RKStringFromIndexSet(NSIndexSet *indexSet) +{ + NSCParameterAssert(indexSet); + NSMutableString *string = [NSMutableString string]; + + NSRange range = NSMakeRange([indexSet firstIndex], 1); + while (range.location != NSNotFound) { + NSUInteger nextIndex = [indexSet indexGreaterThanIndex:range.location]; + while (nextIndex == range.location + range.length) { + range.length++; + nextIndex = [indexSet indexGreaterThanIndex:nextIndex]; + } + + if (string.length) { + [string appendString:@","]; + } + + if (range.length == 1) { + [string appendFormat:@"%lu", (unsigned long) range.location]; + } else { + NSUInteger firstIndex = range.location; + NSUInteger lastIndex = firstIndex + range.length - 1; + [string appendFormat:@"%lu-%lu", (unsigned long) firstIndex, (unsigned long) lastIndex]; + } + + range.location = nextIndex; + range.length = 1; + } + + return string; +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKResponseDescriptor () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, assign, readwrite) RKRequestMethod method; +@property (nonatomic, copy, readwrite) NSString *pathPattern; +@property (nonatomic, strong, readwrite) RKPathMatcher *pathPatternMatcher; +@property (nonatomic, copy, readwrite) NSString *keyPath; +@property (nonatomic, copy, readwrite) NSIndexSet *statusCodes; +@end + +@implementation RKResponseDescriptor + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes +{ + return [self responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:pathPattern keyPath:keyPath statusCodes:statusCodes]; +} +#pragma clang diagnostic pop + ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes +{ + NSParameterAssert(mapping); + RKResponseDescriptor *mappingDescriptor = [self new]; + mappingDescriptor.mapping = mapping; + mappingDescriptor.method = method; + mappingDescriptor.pathPattern = pathPattern; + mappingDescriptor.keyPath = keyPath; + mappingDescriptor.statusCodes = statusCodes; + + return mappingDescriptor; +} + +- (void)setPathPattern:(NSString *)pathPattern +{ + _pathPattern = pathPattern; + if (pathPattern) { + self.pathPatternMatcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + } else { + self.pathPatternMatcher = nil; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p method=%@ pathPattern=%@ keyPath=%@ statusCodes=%@ : %@>", + NSStringFromClass([self class]), self, RKStringDescribingRequestMethod(self.method), self.pathPattern, self.keyPath, self.statusCodes ? RKStringFromIndexSet(self.statusCodes) : self.statusCodes, self.mapping]; +} + +- (BOOL)matchesPath:(NSString *)path +{ + return [self matchesPath:path parsedArguments:nil]; +} + +- (BOOL)matchesPath:(NSString *)path parsedArguments:(NSDictionary **)outParsedArguments +{ + if (!self.pathPattern || !path) return YES; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:self.pathPattern]; + return [pathMatcher matchesPath:path tokenizeQueryStrings:NO parsedArguments:outParsedArguments]; +} + +- (BOOL)matchesURL:(NSURL *)URL +{ + return [self matchesURL:URL parsedArguments:nil]; +} + +- (BOOL)matchesURL:(NSURL *)URL parsedArguments:(NSDictionary **)outParsedArguments +{ + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(URL, self.baseURL); + if (self.baseURL) { + if (! RKURLIsRelativeToURL(URL, self.baseURL)) return NO; + return [self matchesPath:pathAndQueryString parsedArguments:outParsedArguments]; + } else { + return [self matchesPath:pathAndQueryString parsedArguments:outParsedArguments]; + } +} + +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response +{ + return [self matchesResponse:response parsedArguments:nil]; +} + +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response parsedArguments:(NSDictionary **)outParsedArguments +{ + if (![self matchesURL:response.URL parsedArguments:outParsedArguments]) return NO; + + if (self.statusCodes) { + if (! [self.statusCodes containsIndex:response.statusCode]) { + return NO; + } + } + return YES; +} + +- (BOOL)matchesMethod:(RKRequestMethod)method +{ + return self.method & method; +} + +- (NSDictionary *)parsedArgumentsFromResponse:(NSHTTPURLResponse *)response +{ + NSDictionary *parsedArguments = nil; + if ([self matchesResponse:response parsedArguments:&parsedArguments]) + { + return parsedArguments; + } + + return nil; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if ([self class] != [object class]) { + return NO; + } + return [self isEqualToResponseDescriptor:object]; +} + +#define NSUINT_BIT (CHAR_BIT * sizeof(NSUInteger)) +#define NSUINTROTATE(val, howmuch) ((((NSUInteger)val) << howmuch) | (((NSUInteger)val) >> (NSUINT_BIT - howmuch))) + +- (NSUInteger)hash +{ + return NSUINTROTATE(NSUINTROTATE(NSUINTROTATE([self.mapping hash], NSUINT_BIT / 4) ^ [self.pathPattern hash], NSUINT_BIT / 4) ^ [self.keyPath hash], NSUINT_BIT / 4) ^ [self.statusCodes hash]; +} + +- (BOOL)isEqualToResponseDescriptor:(RKResponseDescriptor *)otherDescriptor +{ + if (![otherDescriptor isKindOfClass:[RKResponseDescriptor class]]) { + return NO; + } + + return + [self.mapping isEqualToMapping:otherDescriptor.mapping] && + self.method == otherDescriptor.method && + ((self.pathPattern == otherDescriptor.pathPattern) || [self.pathPattern isEqualToString:otherDescriptor.pathPattern]) && + ((self.keyPath == otherDescriptor.keyPath) || [self.keyPath isEqualToString:otherDescriptor.keyPath]) && + [self.statusCodes isEqualToIndexSet:otherDescriptor.statusCodes]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.h new file mode 100644 index 0000000..7fc04f2 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.h @@ -0,0 +1,265 @@ +// +// RKResponseMapperOperation.h +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingOperationDataSource.h" +#import "RKMapperOperation.h" +#import "RKMappingResult.h" + +#ifdef _COREDATADEFINES_H +@protocol RKManagedObjectCaching; +#endif + +/** + `RKResponseMapperOperation` is an `NSOperation` that provides support for performing object mapping on an `NSHTTPURLResponse` and its associated response data. + + This is an abstract base class encapsulating the common interface API for its concrete subclasses `RKObjectResponseMapperOperation` and `RKManagedObjectResponseMapperOperation`. + + The common behaviors encapsulated within `RKResponseMapperOperation` include: + + 1. **Handling Empty Responses**: Empty response data (see note below) requires special handling depending on the status code of the HTTP response. If an empty response is loaded with a status code in 4xx (Client Error) range, an `NSError` in the `RKErrorDomain` is created with the `NSURLErrorBadServerResponse` code to indicate that the response was not processable. If an empty response is loaded with a status code in 2xx (Successful) range, the interpretation of the response is dependent on the value of `treatsEmptyResponseAsSuccess`. When `YES`, empty responses result in the successful completion of the operation with an `RKMappingResult` containing the targetObject of the operation, if any. + 1. **Deserializing Response Data**: When started, the operation attempts to deserialize the response data into a Foundation object representation using the `RKMIMETypeSerialization` class. This deserialized representation is then made available to subclass implementations that perform the actual object mapping work. + + ## How 'Empty' Responses are Evaluated + + Any `nil` response or `NSData` object with a length equal to zero is considered empty. To support a common behavior of the widely deployed Ruby on Rails Framework, `RKResponseMapperOperation` also considers a response containing a single space character to be empty. This type of response is generated by Rails whe `render :nothing => true` is invoked. + + ## Metadata Mapping + + The `RKResponseMapperOperation` class integrates with the metadata mapping architecture. Clients of the response mapper can provide a dictionary of metadata via the `mappingMetadata` property and it will be made available to the underlying `RKMapperOperation` executed to process the response body. In addition to any user supplied metadata, the response mapper makes the following metadata key paths available for mapping: + + 1. `@metadata.HTTP.request.URL` - The `NSURL` object identifying the URL of the request that loaded the response. + 1. `@metadata.HTTP.request.method` - An `NSString` specifying the HTTP method of the request that loaded the response. + 1. `@metadata.HTTP.request.headers` - An `NSDictionary` object containing all HTTP headers and values for the request that loaded the response. + 1. `@metadata.HTTP.response.URL` - The `NSURL` object identifying the URL of the response. + 1. `@metadata.HTTP.response.headers` - An `NSDictionary` object containing all HTTP headers and values for the response. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + @see `RKMapperOperation` + */ +@interface RKResponseMapperOperation : NSOperation + +///------------------------------------------------ +/// @name Initializing a Response Mapping Operation +///------------------------------------------------ + +/** + Initializes and returns a newly created response mapper operation with the given request, HTTP response, response data, and an array of `RKResponseDescriptor` objects. + + @param request The request object for which the response was loaded. + @param response The HTTP response object to be used for object mapping. + @param data The data loaded for the response body. + @param responseDescriptors An array whose elements are `RKResponseDescriptor` objects specifying object mapping configurations that may be applied to the response. + @return The receiver, initialized with the response, data, and response descriptor objects. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request + response:(NSHTTPURLResponse *)response + data:(NSData *)data + responseDescriptors:(NSArray *)responseDescriptors NS_DESIGNATED_INITIALIZER; + +///----------------------------------------------- +/// @name Accessing HTTP Request and Response Data +///----------------------------------------------- + +/** + An request object for which the response was loaded. + */ +@property (nonatomic, strong, readonly) NSURLRequest *request; + +/** + The response object that loaded the data that is to be object mapped by the operation. Cannot be `nil`. + */ +@property (nonatomic, strong, readonly) NSHTTPURLResponse *response; + +/** + The response data that is to be deserialized and mapped by the operation. May be `nil`. + */ +@property (nonatomic, strong, readonly) NSData *data; + +///--------------------------------- +/// @name Configuring Object Mapping +///--------------------------------- + +/** + An array of `RKResponseDescriptor` objects that specify object mapping configurations that may be applied to the deserialized response data if they are found to match the response. + + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSArray *responseDescriptors; + +/** + The target object for the object mapping operation performed on the deserialized response data. May be `nil`. + + When object mapping is being performed against a known object, the targetObject is set to ensure that the mapping is applied to the appropriate object reference. When `nil`, the mapping operation will result in the fetching or creation of new objects as necessary to satisfy the mapping configuration. + */ +@property (nonatomic, strong) id targetObject; + +/** + The delegate for the `RKMapperOperation` created by the receiver to perform object mapping on the deserialized response data. May be `nil`. + + The delegate provides access to the details of the mapping process as it is executing. Be aware that the delegate will be invoked from the thread on which the mapping is executing. + */ +@property (nonatomic, weak) id<RKMapperOperationDelegate> mapperDelegate; + +/** + An optional dictionary of metadata to make available to mapping operations executed by the receiver. + */ +@property (nonatomic, copy) NSDictionary *mappingMetadata; + +/** + A Boolean value that indicates if the receiver should consider empty responses as being successfully mapped even though no mapping is actually performed. + + When `YES` and the response data is empty (see below), a mapping result will be returned containing the target object (if any). Otherwise, the response data will be pass through to the parser which may generate an error. + + **Default:** `YES` + + @warning To support the Ruby on Rails behavior of rendering a single space character on invocation of `render :nothing => true`, a response body's containing only a single space is treated as empty. + */ +@property (nonatomic, assign) BOOL treatsEmptyResponseAsSuccess; + +/** + Returns a dictionary of key path to `RKMapping` objects that are applicable to mapping the response. This is determined by evaluating the URL and status codes of the response against the set of `responseDescriptors`. + + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSDictionary *responseMappingsDictionary; + +/** + Returns an array containing all `RKResponseDescriptor` objects in the configured `responseDescriptors` array that were found to match the response. + + @see `responseDescriptors` + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSArray *matchingResponseDescriptors; + +///-------------------------------- +/// @name Accessing Mapping Results +///-------------------------------- + +/** + The results of performing object mapping on the deserialized response data. In the event that the operation has failed, the value will is `nil`. + + The `keyPath` of each `RKResponseDescriptor` from the `responseDescriptors` set that was successfully mapped from the response data will appear as an entry in the mapping result. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occured during execution of the operation. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///---------------------------- +/// @name Configuring Callbacks +///---------------------------- + +/** + Sets a block to be executed before the response mapper operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input before mapping begins. + + @param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP. If you do not wish to make any chances to the response body before mapping begins, the block should return the value passed in the `deserializedResponseBody` block argument. Returning `nil` will decline the mapping from proceeding and fail the operation with an error with the `RKMappingErrorMappingDeclined` code. + @warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input. + */ +- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block; + +/** + Sets a block to be executed when the response mapper operation has completed its mapping activities. This method is distinct from the `completionBlock` because it is invoked while the operation is still executing. This block is guaranteed to be called even if the receiver is cancelled before it has been started. + + @param block A block object to be executed when the response mapping is finished. The block has no return value and accepts two arguments: an `RKNappingResult` object that was mapped from the response or an `NSError` error indicating that the mapping has failed. + */ +- (void)setDidFinishMappingBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))block; + +///-------------------------------------------------------- +/// @name Registering a Mapping Operation Data Source Class +///-------------------------------------------------------- + +/** + Registers the given data source class to to be used for mapper operations constructed by instances of the receiver. + + **NOTE**: The receiver class is significant to the registration: `[RKObjectResponseMapperOperation registerMappingOperationDataSourceClass:[MyDataSourceClass class]]` registers a data source for use with instances of `RKObjectResponseMapperOperation` exclusively. When registering a data source for `RKManagedObjectResponseMapperOperation` the given class must inherit from `RKManagedObjectMappingOperationDataSource`. + + @param dataSourceClass The class conforming to the RKMappingOperationDataSource protocol to be registered for use with mapper operations. + */ ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass; + +@end + +/** + `RKObjectResponseMapperOperation` is an `RKResponseMapperOperation` subclass that provides support for performing object mapping for mappings that target `NSObject` derived classes. It does not require a data source to perform its work. + */ +@interface RKObjectResponseMapperOperation : RKResponseMapperOperation +@end + +#ifdef _COREDATADEFINES_H +/** + `RKManagedObjectResponseMapperOperation` is an `RKResponseMapperOperation` subclass that provides support for performing object mapping using `RKEntityMapping` objects that target `NSManagedObject` derived classes. It requires an `NSManagedObjectContext` and a configured `RKManagedObjectMappingOperationDataSource` data source to execute successfully. + + Performing response mapping that targets Core Data managed objects imposes some additional constraints on the process that the developer should understand thoroughly: + + 1. **Permanent Managed Object IDs**: When using managed object contexts in a parent-child configuration, it is important to obtain a permanent `NSManagedObjectID` for any existing objects that are to be mapped. Mapping that occur against objecs with temporary managedObjectID's cannot be retrieved across contexts by ID. If executing an `RKManagedObjectResponseMapperOperation` against a `NSManagedObject` targetObject with a temporary ID. + 1. **Persisting Mapped Objects**: Instances of `RKManagedObjectResponseMapperOperation` do **NOT** perform any persistence on the `NSManagedObject` in which the mapping occurs. This is by design and ensures that the operation can be used to compose higher level components that handle persistence. It is the developer's responsibility to ensure that the mapped managed objects are eventually persisted. + + @see `RKManagedObjectMappingOperationDataSource` + @see `[NSManagedObjectContext obtainPermanentIDsForObjects:error:]` + */ +@interface RKManagedObjectResponseMapperOperation : RKResponseMapperOperation + +///---------------------------- +/// @name Configuring Core Data +///---------------------------- + +/** + The managed object context in which the mapping will be performed. + + @warning The `NSManagedObjectContext` given **must** have a `concurrencyType` of either `NSPrivateQueueConcurrencyType` or `NSMainQueueConcurrencyType`. Thread confined contexts are not supported. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + An object implementing the `RKManagedObjectCaching` protocol to be used for retrieving existing `NSManagedObject` instances by identification attributes. If `nil`, existing object cannot be retrieved and new objects will be created for all mappable content within the response data, likely resulting in the creation of duplicate objects. + + @see `RKManagedObjectCaching` + */ +@property (nonatomic, weak) id<RKManagedObjectCaching> managedObjectCache; + +/** + The permanent `NSManagedObjectID` for the target object of the mapping operation. During mapping, an instance local to the `managedObjectContext` is fetched and used to perform the mapping operation. + + If `nil` and the `targetObject` is a managed object, the `objectID` of the target object will be used. + */ +@property (nonatomic, copy) NSManagedObjectID *targetObjectID; + +@end + +#endif + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a representation of a mapping result as an `NSError` value. + + The returned `NSError` object is in the `RKErrorDomain` domain and has the `RKMappingErrorFromMappingResult` code. The value for the `NSLocalizedDescriptionKey` is computed by retrieving the objects in the mapping result as an array, evaluating `valueForKeyPath:@"description"` against the array, and joining the returned error messages by comma to form a single string value. The source error objects are returned with the `NSError` in the `userInfo` dictionary under the `RKObjectMapperErrorObjectsKey` key. + + This implementation assumes that the class used to represent the response error will return a string description of the client side error when sent the `description` message. + + @return An error object representing the objects contained in the mapping result. + @see `RKErrorMessage` + */ +NSError *RKErrorFromMappingResult(RKMappingResult *mappingResult); diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.m new file mode 100644 index 0000000..6e7e016 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKResponseMapperOperation.m @@ -0,0 +1,531 @@ +// +// RKResponseMapperOperation.m +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMappingOperationDataSource.h" +#import "RKLog.h" +#import "RKResponseDescriptor.h" +#import "RKPathMatcher.h" +#import "RKHTTPUtilities.h" +#import "RKResponseMapperOperation.h" +#import "RKMappingErrors.h" +#import "RKMIMETypeSerialization.h" +#import "RKDictionaryUtilities.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectMappingOperationDataSource.h" +#endif +#endif + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +NSError *RKErrorFromMappingResult(RKMappingResult *mappingResult) +{ + NSArray *collection = [mappingResult array]; + NSString *description = nil; + if ([collection count] > 0) { + description = [[collection valueForKeyPath:@"description"] componentsJoinedByString:@", "]; + } else { + description = @"Expected mapping result to contain at least one object to construct an error"; + RKLogWarning(@"%@", description); + } + NSDictionary *userInfo = @{RKObjectMapperErrorObjectsKey: collection, + NSLocalizedDescriptionKey: description}; + + NSError *error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorFromMappingResult userInfo:userInfo]; + return error; +} + +static NSIndexSet *RKErrorStatusCodes() +{ + static NSIndexSet *errorStatusCodes = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + errorStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(400, 200)]; + }); + + return errorStatusCodes; +} + +static NSError *RKUnprocessableErrorFromResponse(NSHTTPURLResponse *response) +{ + NSCAssert([RKErrorStatusCodes() containsIndex:response.statusCode], @"Expected response status code to be in the 400-599 range, instead got %ld", (long) response.statusCode); + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:@"Loaded an unprocessable error response (%ld)", (long) response.statusCode] forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[response URL] forKey:NSURLErrorFailingURLErrorKey]; + + return [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; +} + +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); // Defined in RKResponseDescriptor.m +static NSString *RKMatchFailureDescriptionForResponseDescriptorWithResponse(RKResponseDescriptor *responseDescriptor, NSHTTPURLResponse *response) +{ + if (responseDescriptor.statusCodes && ![responseDescriptor.statusCodes containsIndex:response.statusCode]) { + return [NSString stringWithFormat:@"response status code %ld is not within the range %@", (long) response.statusCode, RKStringFromIndexSet(responseDescriptor.statusCodes)]; + } + + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(response.URL, responseDescriptor.baseURL); + if (responseDescriptor.baseURL && !RKURLIsRelativeToURL(response.URL, responseDescriptor.baseURL)) { + // Not relative to the baseURL + return [NSString stringWithFormat:@"response URL '%@' is not relative to the baseURL '%@'.", response.URL, responseDescriptor.baseURL]; + } + + // Must be a path pattern mismatch + return [NSString stringWithFormat:@"response path '%@' did not match the path pattern '%@'.", pathAndQueryString, responseDescriptor.pathPattern]; +} + +static NSString *RKFailureReasonErrorStringForResponseDescriptorsMismatchWithResponse(NSArray *responseDescriptors, NSHTTPURLResponse *response) +{ + NSMutableString *failureReason = [NSMutableString string]; + [failureReason appendFormat:@"A %ld response was loaded from the URL '%@', which failed to match all (%ld) response descriptors:", + (long) response.statusCode, response.URL, (long) [responseDescriptors count]]; + + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + [failureReason appendFormat:@"\n <RKResponseDescriptor: %p baseURL=%@ pathPattern=%@ statusCodes=%@> failed to match: %@", + responseDescriptor, responseDescriptor.baseURL, responseDescriptor.pathPattern, + responseDescriptor.statusCodes ? RKStringFromIndexSet(responseDescriptor.statusCodes) : responseDescriptor.statusCodes, + RKMatchFailureDescriptionForResponseDescriptorWithResponse(responseDescriptor, response)]; + } + + return failureReason; +} + +/** + A serial dispatch queue used for all deserialization of response bodies + */ +static dispatch_queue_t RKResponseMapperSerializationQueue() { + static dispatch_queue_t serializationQueue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + serializationQueue = dispatch_queue_create("org.restkit.response-mapper.serialization", DISPATCH_QUEUE_SERIAL); + }); + + return serializationQueue; +} + +@interface RKResponseMapperOperation () +@property (nonatomic, strong, readwrite) NSURLRequest *request; +@property (nonatomic, strong, readwrite) NSHTTPURLResponse *response; +@property (nonatomic, strong, readwrite) NSData *data; +@property (nonatomic, strong, readwrite) NSArray *responseDescriptors; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) NSArray *matchingResponseDescriptors; +@property (nonatomic, strong, readwrite) NSDictionary *responseMappingsDictionary; +@property (nonatomic, strong, readwrite) NSDictionary *responseMappingArgumentsDictionary; +@property (nonatomic, strong) RKMapperOperation *mapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id); +@property (nonatomic, copy) void(^didFinishMappingBlock)(RKMappingResult *, NSError *); +@end + +@interface RKResponseMapperOperation (ForSubclassEyesOnly) +- (id)parseResponseData:(NSError **)error; +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL hasEmptyResponse; +@end + +@implementation RKResponseMapperOperation + +#pragma mark Data Source Registration + +static NSMutableDictionary *RKRegisteredResponseMapperOperationDataSourceClasses = nil; + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + RKRegisteredResponseMapperOperationDataSourceClasses = [NSMutableDictionary new]; + }); +} + ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass +{ + if (dataSourceClass && ![(Class)dataSourceClass conformsToProtocol:@protocol(RKMappingOperationDataSource)]) { + [NSException raise:NSInvalidArgumentException format:@"Registered data source class '%@' does not conform to the `RKMappingOperationDataSource` protocol.", NSStringFromClass(dataSourceClass)]; + } + + if (dataSourceClass) { + RKRegisteredResponseMapperOperationDataSourceClasses[(id<NSCopying>)self] = dataSourceClass; + } else { + [RKRegisteredResponseMapperOperationDataSourceClasses removeObjectForKey:(id<NSCopying>)self]; + } +} + +#pragma mark + +- (instancetype)initWithRequest:(NSURLRequest *)request + response:(NSHTTPURLResponse *)response + data:(NSData *)data + responseDescriptors:(NSArray *)responseDescriptors; +{ + NSParameterAssert(request); + NSParameterAssert(response); + NSParameterAssert(responseDescriptors); + + self = [super init]; + if (self) { + self.request = request; + self.response = response; + self.data = data; + self.responseDescriptors = responseDescriptors; + self.matchingResponseDescriptors = [self buildMatchingResponseDescriptors]; + self.responseMappingsDictionary = [self buildResponseMappingsDictionary]; + self.responseMappingArgumentsDictionary = [self buildResponseMappingArgumentsDictionary]; + self.treatsEmptyResponseAsSuccess = YES; + self.mappingMetadata = @{}; // Initialize the metadata + } + + return self; +} + +- (id)parseResponseData:(NSError **)error +{ + NSString *MIMEType = [self.response MIMEType]; + __block NSError *underlyingError = nil; + __block id object; + dispatch_sync(RKResponseMapperSerializationQueue(), ^{ + object = [RKMIMETypeSerialization objectFromData:self.data MIMEType:MIMEType error:&underlyingError]; + }); + if (! object) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:@"Loaded an unprocessable response (%ld) with content type '%@'", (long) self.response.statusCode, MIMEType] + forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[self.response URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:underlyingError forKey:NSUnderlyingErrorKey]; + NSError *HTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorCannotParseResponse userInfo:userInfo]; + + if (error) *error = HTTPError; + + return nil; + } + return object; +} + +- (NSArray *)buildMatchingResponseDescriptors +{ + NSIndexSet *indexSet = [self.responseDescriptors indexesOfObjectsPassingTest:^BOOL(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + return [responseDescriptor matchesResponse:self.response] && (RKRequestMethodFromString(self.request.HTTPMethod) & responseDescriptor.method); + }]; + return [self.responseDescriptors objectsAtIndexes:indexSet]; +} + +- (NSDictionary *)buildResponseMappingsDictionary +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (RKResponseDescriptor *responseDescriptor in self.matchingResponseDescriptors) { + dictionary[(responseDescriptor.keyPath ?: [NSNull null])] = responseDescriptor.mapping; + } + + return dictionary; +} + +- (NSDictionary *)buildResponseMappingArgumentsDictionary +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (RKResponseDescriptor *responseDescriptor in self.matchingResponseDescriptors) { + + NSDictionary *arguments = [responseDescriptor parsedArgumentsFromResponse:self.response]; + if (arguments) + { + // We don't add nil keypath at an [NSNull null] key, because that causes a crash later + // in RKDictionaryByMergingDictionaryWithDictionary + if (responseDescriptor.keyPath) + { + [dictionary setObject:arguments forKey:responseDescriptor.keyPath]; + } + else + { + [dictionary addEntriesFromDictionary:arguments]; + } + } + } + + return dictionary; +} + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is an abstract operation.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (BOOL)hasEmptyResponse +{ + // NOTE: Comparison to single string whitespace character to support Ruby on Rails `render :nothing => true` + static NSData *whitespaceData = nil; + if (! whitespaceData) whitespaceData = [[NSData alloc] initWithBytes:" " length:1]; + + NSUInteger length = [self.data length]; + return (length == 0 || (length == 1 && [self.data isEqualToData:whitespaceData])); +} + +- (void)setMappingMetadata:(NSDictionary *)mappingMetadata +{ + NSDictionary *HTTPMetadata = @{ @"HTTP": @{ @"request": @{ @"URL": self.request.URL, @"method": self.request.HTTPMethod, @"headers": [self.request allHTTPHeaderFields] ?: @{} }, + @"response": @{ @"URL": self.response.URL, @"headers": [self.response allHeaderFields] ?: @{} } } }; + _mappingMetadata = RKDictionaryByMergingDictionaryWithDictionary(HTTPMetadata, mappingMetadata); + + if (self.responseMappingArgumentsDictionary) + { + NSDictionary *argumentsMetadata = @{ @"network" : @{ @"arguments" : self.responseMappingArgumentsDictionary } }; + _mappingMetadata = RKDictionaryByMergingDictionaryWithDictionary(argumentsMetadata, _mappingMetadata); + } +} + +- (void)cancel +{ + BOOL cancelledBeforeExecution = ![self isExecuting] && ![self isCancelled]; + + [super cancel]; + [self.mapperOperation cancel]; + + // NOTE: If we are cancelled before being started, then `main` and the `completionBlock` are never executed. We must ensure that we invoke `didFinishMappingBlock`, see Github issue #1494 + if (cancelledBeforeExecution) { + [self willFinish]; + } +} + +- (void)willFinish +{ + if (self.isCancelled && !self.error) self.error = [NSError errorWithDomain:RKErrorDomain code:RKOperationCancelledError userInfo:@{ NSLocalizedDescriptionKey: @"The operation was cancelled." }]; + + if (self.didFinishMappingBlock) { + if (self.error) self.didFinishMappingBlock(nil, self.error); + else self.didFinishMappingBlock(self.mappingResult, nil); + [self setDidFinishMappingBlock:nil]; + } +} + +- (void)main +{ + if (self.isCancelled) return [self willFinish]; + + BOOL isErrorStatusCode = [RKErrorStatusCodes() containsIndex:self.response.statusCode]; + + // If we are an error response and empty, we emit an error that the content is unmappable + if (isErrorStatusCode && [self hasEmptyResponse]) { + self.error = RKUnprocessableErrorFromResponse(self.response); + [self willFinish]; + return; + } + + // If we are successful and empty, we may optionally consider the response mappable (i.e. 204 response or 201 with no body) + if ([self hasEmptyResponse] && self.treatsEmptyResponseAsSuccess) { + if (self.targetObject) { + self.mappingResult = [[RKMappingResult alloc] initWithDictionary:@{[NSNull null]: self.targetObject}]; + } else { + // NOTE: For alignment with the behavior of loading an empty array or empty dictionary, if there is a nil targetObject we return a nil mappingResult. + // This informs the caller that operation succeeded, but performed no mapping. + self.mappingResult = nil; + } + + [self willFinish]; + return; + } + + // Parse the response + NSError *error; + id parsedBody = [self parseResponseData:&error]; + if (self.isCancelled) return [self willFinish]; + if (! parsedBody) { + RKLogError(@"Failed to parse response data: %@", [error localizedDescription]); + self.error = error; + [self willFinish]; + return; + } + if (self.isCancelled) return [self willFinish]; + + // Invoke the will map deserialized response block + if (self.willMapDeserializedResponseBlock) { + parsedBody = self.willMapDeserializedResponseBlock(parsedBody); + if (! parsedBody) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Mapping was declined due to a `willMapDeserializedResponseBlock` returning nil." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorMappingDeclined userInfo:userInfo]; + RKLogError(@"Failed to parse response data: %@", [error localizedDescription]); + [self willFinish]; + return; + } + } + + // Object map the response + self.mappingResult = [self performMappingWithObject:parsedBody error:&error]; + + // If the response is a client error return either the mapping error or the mapped result to the caller as the error + if (isErrorStatusCode) { + if ([self.mappingResult count] > 0) { + error = RKErrorFromMappingResult(self.mappingResult); + } else { + // We encountered a client error that we could not map, throw unprocessable error + if (! error) error = RKUnprocessableErrorFromResponse(self.response); + } + self.error = error; + [self willFinish]; + return; + } + + // Fail if no response descriptors matched + if (error.code == RKMappingErrorNotFound && [self.responseMappingsDictionary count] == 0) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"No response descriptors match the response loaded.", nil), + NSLocalizedFailureReasonErrorKey: RKFailureReasonErrorStringForResponseDescriptorsMismatchWithResponse(self.responseDescriptors, self.response), + RKMappingErrorKeyPathErrorKey: [NSNull null], + NSURLErrorFailingURLErrorKey: self.response.URL, + NSURLErrorFailingURLStringErrorKey: [self.response.URL absoluteString], + NSUnderlyingErrorKey: error}; + self.error = [[NSError alloc] initWithDomain:RKErrorDomain code:RKMappingErrorNotFound userInfo:userInfo]; + [self willFinish]; + return; + } + + if (! self.mappingResult) self.error = error; + [self willFinish]; +} + +@end + +@implementation RKObjectResponseMapperOperation + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + Class dataSourceClass = RKRegisteredResponseMapperOperationDataSourceClasses[[self class]] ?: [RKObjectMappingOperationDataSource class]; + id<RKMappingOperationDataSource> dataSource = [dataSourceClass new]; + self.mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:sourceObject mappingsDictionary:self.responseMappingsDictionary]; + self.mapperOperation.mappingOperationDataSource = dataSource; + self.mapperOperation.delegate = self.mapperDelegate; + self.mapperOperation.metadata = self.mappingMetadata; + if (NSLocationInRange(self.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))) { + self.mapperOperation.targetObject = self.targetObject; + } else { + RKLogInfo(@"Non-successful status code encountered: performing mapping with nil target object."); + } + [self.mapperOperation start]; + if (error) *error = self.mapperOperation.error; + return self.mapperOperation.mappingResult; +} + +@end + +#ifdef RKCoreDataIncluded + +static inline NSManagedObjectID *RKObjectIDFromObjectIfManaged(id object) +{ + return [object isKindOfClass:[NSManagedObject class]] ? [object objectID] : nil; +} + +@interface RKManagedObjectResponseMapperOperation () +@property (nonatomic, strong) NSOperationQueue *operationQueue; +@end + +@implementation RKManagedObjectResponseMapperOperation + ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass +{ + if (dataSourceClass && ![(Class)dataSourceClass isSubclassOfClass:[RKManagedObjectMappingOperationDataSource class]]) { + [NSException raise:NSInvalidArgumentException format:@"Registered data source class '%@' does not inherit from the `RKManagedObjectMappingOperationDataSource` class: You must subclass `RKManagedObjectMappingOperationDataSource` in order to register a data source class for `RKManagedObjectResponseMapperOperation`.", NSStringFromClass(dataSourceClass)]; + } + [super registerMappingOperationDataSourceClass:dataSourceClass]; +} + +- (void)cancel +{ + [super cancel]; + [self.operationQueue cancelAllOperations]; +} + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + NSAssert(self.managedObjectContext, @"Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = %@)", self.response.URL); + + __block NSError *blockError = nil; + __block RKMappingResult *mappingResult = nil; + self.operationQueue = [NSOperationQueue new]; + [self.managedObjectContext performBlockAndWait:^{ + // We may have been cancelled before we made it onto the MOC's queue + if ([self isCancelled]) return; + + // Configure the mapper + self.mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:sourceObject mappingsDictionary:self.responseMappingsDictionary]; + self.mapperOperation.delegate = self.mapperDelegate; + self.mapperOperation.metadata = self.mappingMetadata; + + // Configure a data source to defer execution of connection operations until mapping is complete + Class dataSourceClass = RKRegisteredResponseMapperOperationDataSourceClasses[[self class]] ?: [RKManagedObjectMappingOperationDataSource class]; + RKManagedObjectMappingOperationDataSource *dataSource = [[dataSourceClass alloc] initWithManagedObjectContext:self.managedObjectContext + cache:self.managedObjectCache]; + dataSource.operationQueue = self.operationQueue; + dataSource.parentOperation = self.mapperOperation; + + [self.operationQueue setMaxConcurrentOperationCount:1]; + [self.operationQueue setName:[NSString stringWithFormat:@"Relationship Connection Queue for '%@'", self.mapperOperation]]; + self.mapperOperation.mappingOperationDataSource = dataSource; + + if (NSLocationInRange(self.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))) { + self.mapperOperation.targetObject = self.targetObject; + + if (self.targetObjectID || self.targetObject) { + NSManagedObjectID *objectID = self.targetObjectID ?: RKObjectIDFromObjectIfManaged(self.targetObject); + if (objectID) { + if ([objectID isTemporaryID]) RKLogWarning(@"Performing object mapping to temporary target objectID. Results may not be accessible without obtaining a permanent object ID."); + NSManagedObject *localObject = [self.managedObjectContext existingObjectWithID:objectID error:&blockError]; + NSAssert(localObject == nil || localObject.managedObjectContext == nil || [localObject.managedObjectContext isEqual:self.managedObjectContext], @"Serious Core Data error: requested existing object with ID %@ in context %@, instead got an object reference in context %@. This may indicate that the objectID for your target managed object was obtained using `obtainPermanentIDsForObjects:error:` in the wrong context.", objectID, self.managedObjectContext, [localObject managedObjectContext]); + if (! localObject) { + RKLogWarning(@"Failed to retrieve existing object with ID: %@", objectID); + RKLogCoreDataError(blockError); + return; + } + self.mapperOperation.targetObject = localObject; + } else { + if (self.mapperOperation.targetObject) RKLogDebug(@"Mapping HTTP response to unmanaged target object with `RKManagedObjectResponseMapperOperation`: %@", self.mapperOperation.targetObject); + } + } else { + RKLogTrace(@"Mapping HTTP response to nil target object..."); + } + } else { + RKLogInfo(@"Non-successful status code encountered: performing mapping with nil target object."); + } + + [self.mapperOperation start]; + blockError = self.mapperOperation.error; + mappingResult = self.mapperOperation.mappingResult; + }]; + + if (self.isCancelled) return nil; + + if (! mappingResult) { + if (error) *error = blockError; + return nil; + } + + // Mapping completed without error, allow the connection operations to execute + if ([self.operationQueue operationCount]) { + RKLogTrace(@"Awaiting execution of %ld enqueued connection operations: %@", (long) [self.operationQueue operationCount], [self.operationQueue operations]); + [self.operationQueue waitUntilAllOperationsAreFinished]; + } + + return mappingResult; +} + +@end + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.h new file mode 100644 index 0000000..66f8f91 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.h @@ -0,0 +1,141 @@ +// +// RKRoute.h +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +/** + The `RKRoute` class models a single routable path pattern in use by the application. A route can be combined with an `NSURL` base URL and interpolated with an object to produce a new fully hydrated URL object. Routes are always instantiated with a path pattern and metadata to provide for the subsequent identification of the defined route. + + There are three types of routes modeled by the RKRoute class: + + 1. **Named Routes**: A named route represents a single path and optional request method within the application. The route is not affiliated with any particular class. For example, one might define a route with the name `@"airlines_list"` as a GET to the path '/airlines.json'. + 1. **Class Routes**: An class route represents a single path that is identified by object class and request method for which it is appropriate. For example, one might define a route for the class `RKArticle` for a POST to the path '/articles.json'. + 1. **Relationship Routes**: A relationship route represents a single path through which the relationship of a parent object can be manipulated. For example, given an `RKArticle` and `RKComment` class, one might define a relationship route for the `RKArticle` class's `@"comments"` relationship as pointing to a GET to the path `@"/articles/:articleID/comments". + + The RKRoute class is internally implemented as a class cluster and is not to be directly instantiated via alloc and init. + + @see RKRouter + @see RKRouteSet + */ +@interface RKRoute : NSObject + +///--------------------------- +/// @name Instantiating Routes +///--------------------------- + +/** + Creates and returns a new named route object with the given name, path pattern and method. + + @param name A unique identifying name for the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. The method given must specify a single HTTP method to be used for requests using the route. + @return A new named route object with the given name, path pattern and request method. + @raise NSInvalidArgumentException Raised if the given HTTP request method is not an exact match of the RKRequestMethod enum + */ ++ (instancetype)routeWithName:(NSString *)name pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +/** + Creates and returns a new class route object with the given object class, path pattern and method. + + @param objectClass The class that is represented by the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. More than one method may be specified via a bitwise OR. + @return A new class route object with the given object class, path pattern and request method. + */ ++ (instancetype)routeWithClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +/** + Creates and returns a new relationship route object with the given relationship name, object class, path pattern and method. + + @param name The name of the relationship represented by the route. + @param objectClass The class containing the relationship represented by the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. More than one method may be specified via a bitwise OR. + @return A new class route object with the given object class, path pattern and request method. + */ ++ (instancetype)routeWithRelationshipName:(NSString *)name objectClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +///--------------------------------- +/// @name Accessing Route Attributes +///--------------------------------- + +/** + The name of the receiver. + + The name is used to identify named and relationship routes and is always `nil` for object routes. + */ +@property (nonatomic, strong, readonly) NSString *name; + +/** + The object class of the receiver. + + Defines the class for which the route is appropriate. Always returns `nil` for named routes. + */ +@property (nonatomic, strong, readonly) Class objectClass; + +/** + The request method of the receiver. + + Appropriate for all route types. If the route is appropriate for any HTTP request method, then the `RKRequestMethodAny` value is used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +/** + The path pattern of the receiver. + + A SOCKit pattern that describes the format of the path portion of URL's generated from the receiver. Required and used by all route types. + + @see `SOCPattern` + */ +@property (nonatomic, strong, readonly) NSString *pathPattern; + +/** + A Boolean value that determines if the path pattern should be escaped when evaluated. + + *Default*: `NO` + */ +@property (nonatomic, assign) BOOL shouldEscapePath; + +///----------------------------- +/// @name Inspecting Route Types +///----------------------------- + +/** + Determines if the receiver is a named route. + + @return YES if the receiver is a named route, else NO. + */ +@property (nonatomic, getter=isNamedRoute, readonly) BOOL namedRoute; + +/** + Determines if the receiver is a class route. + + @return YES if the receiver is a class route, else NO. + */ +@property (nonatomic, getter=isClassRoute, readonly) BOOL classRoute; + +/** + Determines if the receiver is a relationship route. + + @return YES if the receiver is a relationship route, else NO. + */ +@property (nonatomic, getter=isRelationshipRoute, readonly) BOOL relationshipRoute; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.m new file mode 100644 index 0000000..8dbc9eb --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRoute.m @@ -0,0 +1,169 @@ +// +// RKRoute.m +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" + +NSString *RKStringDescribingRequestMethod(RKRequestMethod method); +NSString *RKStringDescribingRequestMethod(RKRequestMethod method) +{ + if (method == RKRequestMethodAny) return @"*"; + NSMutableArray *methods = [NSMutableArray array]; + if (method & RKRequestMethodGET) [methods addObject:@"GET"]; + if (method & RKRequestMethodPOST) [methods addObject:@"POST"]; + if (method & RKRequestMethodPUT) [methods addObject:@"PUT"]; + if (method & RKRequestMethodDELETE) [methods addObject:@"DELETE"]; + if (method & RKRequestMethodHEAD) [methods addObject:@"HEAD"]; + if (method & RKRequestMethodPATCH) [methods addObject:@"PATCH"]; + if (method & RKRequestMethodOPTIONS) [methods addObject:@"OPTIONS"]; + return [NSString stringWithFormat:@"(%@)", [methods componentsJoinedByString:@"|"]]; +} + +@interface RKRoute () +@property (nonatomic, strong, readwrite) NSString *name; +@property (nonatomic, strong, readwrite) Class objectClass; +@property (nonatomic, assign, readwrite) RKRequestMethod method; +@property (nonatomic, strong, readwrite) NSString *pathPattern; +@end + +@interface RKNamedRoute : RKRoute +@end + +@interface RKClassRoute : RKRoute +@end + +@interface RKRelationshipRoute : RKRoute +@end + +@implementation RKRoute + ++ (instancetype)routeWithName:(NSString *)name pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(name); + NSParameterAssert(pathPattern); + if (!RKIsSpecificRequestMethod(method)) [NSException raise:NSInvalidArgumentException format:@"The `method` parameter must specify a single, non-ambiguous HTTP method. Bitmask values and `RKRequestMethodAny` are invalid arguments."]; + RKNamedRoute *route = [RKNamedRoute new]; + route.name = name; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + ++ (instancetype)routeWithClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(objectClass); + NSParameterAssert(pathPattern); + RKClassRoute *route = [RKClassRoute new]; + route.objectClass = objectClass; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + ++ (instancetype)routeWithRelationshipName:(NSString *)relationshipName objectClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(relationshipName); + NSParameterAssert(objectClass); + NSParameterAssert(pathPattern); + RKRelationshipRoute *route = [RKRelationshipRoute new]; + route.name = relationshipName; + route.objectClass = objectClass; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + if ([self isMemberOfClass:[RKRoute class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is not meant to be directly instantiated. Use one of the initializer methods instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + } + + return self; +} + +- (BOOL)isNamedRoute +{ + return NO; +} + +- (BOOL)isClassRoute +{ + return NO; +} + +- (BOOL)isRelationshipRoute +{ + return NO; +} + +@end + +@implementation RKNamedRoute + +- (BOOL)isNamedRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p name=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, self.name, RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end + +@implementation RKClassRoute + +- (BOOL)isClassRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p objectClass=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, NSStringFromClass(self.objectClass), + RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end + +@implementation RKRelationshipRoute + +- (BOOL)isRelationshipRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p relationshipName=%@ objectClass=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, self.name, NSStringFromClass(self.objectClass), + RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.h new file mode 100644 index 0000000..6cb3502 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.h @@ -0,0 +1,159 @@ +// +// RKRouteSet.h +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" + +/** + The `RKRouteSet` class provides for the storage and retrieval of `RKRoute` objects. Route objects are added and removed the route set to manipulate the routing table of the application. + + @see `RKRouter` + */ +@interface RKRouteSet : NSObject + +///--------------------------------- +/// @name Adding and Removing Routes +///--------------------------------- + +/** + Adds a route to the receiver. + + @param route The route to be added. + @raises NSInvalidArgumentException Raised if the route already exists in the receiver or overlaps an existing name. + */ +- (void)addRoute:(RKRoute *)route; + +/** + Adds all routes from the given array to the receiver. All objects within the given array must be an instance of `RKRoute` or else an `NSInvalidArgumentException` will be raised. + + @param routes An array of `RKRoute` objects to be added to the receiver. + */ +- (void)addRoutes:(NSArray *)routes; + +/** + Removes a route from the receiver. + + @param route The route to be removed. + @raises NSInvalidArgumentException Raised if the route does not exist in the receiver. + */ +- (void)removeRoute:(RKRoute *)route; + +///--------------------------- +/// @name Querying a Route Set +///--------------------------- + +/** + Determines if a given route exists within the receiver. + + @param route The route to be tested for containement. + @return `YES` if the route is contained within the route set, else `NO`. + */ +- (BOOL)containsRoute:(RKRoute *)route; + +/** + Returns all routes from the receiver in an array. + + @return An array containing all the routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *allRoutes; + +/** + Returns all named routes from the receiver in an array. + + @return An array containing all the named routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *namedRoutes; + +/** + Returns all class routes from the receiver in an array. + + @return An array containing all the class routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *classRoutes; + +/** + Returns all relationship routes from the receiver in an array. + + @return An array containing all the relationship routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *relationshipRoutes; + +/** + Retrieves a route with the given name. + + @param name The name of the named route to be found. + @return A route with the given name or nil if none was found. + */ +- (RKRoute *)routeForName:(NSString *)name; + +/** + Retrieves a route for the given object class and request method. + + @param objectClass The object class of the route to be retrieved. + @param method The request method of the route to be retrieved. + @return A route with the given object class and method or nil if none was found. + */ +- (RKRoute *)routeForClass:(Class)objectClass method:(RKRequestMethod)method; + +/** + Retrieves a route for a given relationship of a class with a given request method. + + @param relationship The name of the relationship of the route to be retrieved. + @param method The request method of the route to be retrieved. + @return A route with the given relationship name, object class and method or nil if none was found. + */ +- (RKRoute *)routeForRelationship:(NSString *)relationship ofClass:(Class)objectClass method:(RKRequestMethod)method; + +/** + Retrieves all class routes with a given object class. + + Class matches are determined by direct comparison of the class objects. The inheritance hierarchy is not consulted. + + @param objectClass The object class of the routes to be retrieved. + @return An array containing all class routes with the given class. + */ +- (NSArray *)routesForClass:(Class)objectClass; + +/** + Retrieves all object routes for a given object. + + All object routes are searched and returned if they target a class or superclass of the given object (using `- [NSObject isKindOfClass:]`). + + @param object An object for which all object routes are to be retrieved. + @return An array containing all object routes where the target class is included in the given object's class hierarchy. + */ +- (NSArray *)routesForObject:(id)object; + +/** + Retrieves all routes for a given relationship name and object class. + + @param relationshipName The name of the relationship of the routes to be retrieved. + @param objectClass The object class of the routes to be retrieved. + @return An array containing all relationship routes with the given relationship name and object class. + */ +- (NSArray *)routesForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass; + +/** + Retrieves a route for a given object and request method. + + The object routes are first searched for an exact match with the given object's class and request method. If no exact match is found for the given request method, but a route is found for the `RKRequestMethodAny` method, it is returned. If neither are found, the search process begins again and traverses up the inheritance hierarchy. + */ +- (RKRoute *)routeForObject:(id)object method:(RKRequestMethod)method; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.m new file mode 100644 index 0000000..1038b61 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouteSet.m @@ -0,0 +1,212 @@ +// +// RKRouteSet.m +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouteSet.h" +#import "RKPathMatcher.h" + +@interface RKRouteSet () + +@property (nonatomic, strong) NSMutableArray *routes; + +@end + +@implementation RKRouteSet + + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.routes = [NSMutableArray array]; + } + + return self; +} + + +- (NSArray *)allRoutes +{ + return [NSArray arrayWithArray:self.routes]; +} + +- (NSArray *)namedRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isNamedRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)classRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isClassRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)relationshipRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isRelationshipRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (void)addRoute:(RKRoute *)route +{ + NSAssert(![self containsRoute:route], @"Cannot add a route that is already added to the router."); + NSAssert(![route isNamedRoute] || [self routeForName:route.name] == nil, @"Cannot add a route with the same name as an existing route."); + if ([route isClassRoute]) { + RKRoute *existingRoute = [self routeForClass:route.objectClass method:route.method]; + if (! (existingRoute == nil || (existingRoute.method == RKRequestMethodAny && route.method != RKRequestMethodAny) || (route.method == RKRequestMethodAny && existingRoute.method != RKRequestMethodAny))) [NSException raise:NSInternalInconsistencyException format:@"Cannot add a route with the same class and method as an existing route."]; + } else if ([route isRelationshipRoute]) { + NSArray *routes = [self routesForRelationship:route.name ofClass:route.objectClass]; + for (RKRoute *existingRoute in routes) { + NSAssert(existingRoute.method != route.method, @"Cannot add a relationship route with the same name and class as an existing route."); + (void)existingRoute; + } + } + [self.routes addObject:route]; +} + +- (void)addRoutes:(NSArray *)routes +{ + for (RKRoute *route in routes) { + if (! [route isKindOfClass:[RKRoute class]]) [NSException raise:NSInvalidArgumentException format:@"Unexpected object of type `%@` encountered in array of routes.", [route class]]; + [self addRoute:route]; + } +} + +- (void)removeRoute:(RKRoute *)route +{ + NSAssert([self containsRoute:route], @"Cannot remove a route that is not added to the router."); + [self.routes removeObject:route]; +} + +- (BOOL)containsRoute:(RKRoute *)route +{ + return [self.routes containsObject:route]; +} + +- (RKRoute *)routeForName:(NSString *)name +{ + for (RKRoute *route in [self namedRoutes]) { + if ([route.name isEqualToString:name]) { + return route; + } + } + + return nil; +} + +- (RKRoute *)routeForClass:(Class)objectClass method:(RKRequestMethod)method +{ + // Check for an exact match + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass] && (route.method != RKRequestMethodAny && route.method & method)) { + return route; + } + } + + // Check for wildcard match + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass] && route.method == RKRequestMethodAny) { + return route; + } + } + + return nil; +} + +- (RKRoute *)routeForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass method:(RKRequestMethod)method +{ + for (RKRoute *route in [self relationshipRoutes]) { + if ([route.name isEqualToString:relationshipName] && [route.objectClass isEqual:objectClass] && (route.method == method || route.method == RKRequestMethodAny)) { + return route; + } + } + + return nil; +} + +- (NSArray *)routesForClass:(Class)objectClass +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass]) { + [routes addObject:route]; + } + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)routesForObject:(id)object +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in [self classRoutes]) { + if ([object isKindOfClass:route.objectClass]) { + [routes addObject:route]; + } + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)routesForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass +{ + NSIndexSet *indexes = [self.relationshipRoutes indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return [[(RKRoute *)obj objectClass] isEqual:objectClass] && [[(RKRoute *)obj name] isEqualToString:relationshipName]; + }]; + + return [self.relationshipRoutes objectsAtIndexes:indexes]; +} + +- (RKRoute *)routeForObject:(id)object method:(RKRequestMethod)method +{ + Class searchClass = [object class]; + while (searchClass) { + NSArray *routes = [self routesForClass:searchClass]; + RKRoute *wildcardRoute = nil; + RKRoute *bitMaskMatch = nil; + for (RKRoute *route in routes) { + if (route.method == method) return route; + + // We want to favor bitmask matches separate from the Any wildcard match + if (route.method == RKRequestMethodAny) wildcardRoute = route; + else if (route.method & method) bitMaskMatch = route; + } + + if (bitMaskMatch) return bitMaskMatch; + if (wildcardRoute) return wildcardRoute; + searchClass = [searchClass superclass]; + } + + return nil; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.h b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.h new file mode 100644 index 0000000..f8f7221 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.h @@ -0,0 +1,118 @@ +// +// RKRouter.h +// RestKit +// +// Created by Blake Watters on 6/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +@class RKRouteSet; +@class RKRoute; + +/** + An `RKRouter` instance is responsible for generating `NSURL` objects with a given base URL and a route set. It is used to centralize the knowledge about the URL's that are used by the application. + + ## Route Generation + + URL's can be generated by the router in three ways: + + 1. **By name**. Named routes link a symbolic name with a path and an HTTP request method. (see `URLForRouteNamed:method:object:`) + 2. **By object**. Routes can be defined by class and HTTP request method. When a URL is requested from the router for an object, the router will identify the most appropriate route for the object and instantiate an `NSURL` with the route's path pattern and interpolate it against the object. (see `URLForObject:method:`) + 3. **By object relationship**. Routes can be defined for relationships to other objects. When a URL is requested from the router for a relationship, the router will retrieve the appropriate route for the relationship from the route set and interpolate the route's path pattern against the source object. (see `URLForRelationship:ofObject:method:`) + + @see `RKRoute` + @see `RKRouteSet` + */ +@interface RKRouter : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithBaseURL: instead."))); + +///---------------------------- +/// @name Initializing a Router +///---------------------------- + +/** + Initializes a router with a given base URL. + + @param baseURL The base URL with which to initialize the receiver. + @return The receiver, initialized with the given base URL. + */ +- (instancetype)initWithBaseURL:(NSURL *)baseURL NS_DESIGNATED_INITIALIZER; + +///---------------------- +/// @name Generating URLs +///---------------------- + +/** + Generates a URL for the route with the given name. + + The route set is searched for a route with the given name and a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, optionally interpolated with a given object. If a pointer to an `RKRequestMethod` variable is provided, the HTTP method for the route will be assigned to the reference. + + @param routeName The name of the route for which a URL is to be generated. + @param method A pointer to an `RKRequestMethod` variable in which to store the HTTP method associated with the named route. May be nil. + @param object An optional object against which to interpolate the path pattern. + @return A new `NSURL` object constructed by appending the path pattern to the baseURL of the receiver and interpolating against a given object; or nil if no route was found with the given name. + */ +- (NSURL *)URLForRouteNamed:(NSString *)routeName method:(out RKRequestMethod *)method object:(id)object; + +/** + Generates a URL for a given object and HTTP method. + + The route set is searched for a route that matches the HTTP method and class of the object being routed. If there is not an exact match for the object's class, the inheritance hierarchy is searched until a match is found or all possible routes are exhausted. Exact HTTP request matches are favored over the wildcard method (`RKRequestMethodAny`). Once the appropriate route is identified, a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, interpolated against the object being routed. + + @param object The object for which a URL is to be generated. + @param method The HTTP method for which the URL is to be generated. + @return A new URL object constructed by appending the path pattern of the route for the object an HTTP method to the baseURL of the receiver, interpolated against the routed object; or nil if no route was found for the given object and HTTP method. + */ +- (NSURL *)URLForObject:(id)object method:(RKRequestMethod)method; + +/** + Generates a URL for a relationship of a given object with a given HTTP method. + + The route set is searched for a route that matches the relationship of the given object's class and the given HTTP method. If a matching route is found, a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, interpolated against the object being routed. + + @param relationshipName The name of the relationship for which a URL is to be generated. + @param object The object for which the URL is to be generated. + @param method The HTTP method for which the URL is to be generated. + @return A new URL object constructed by appending the path pattern of the route for the given object's relationship and HTTP method to the baseURL of the receiver, interpolated against the routed object; or nil if no route was found for the given relationship, object and HTTP method. + */ +- (NSURL *)URLForRelationship:(NSString *)relationshipName ofObject:(id)object method:(RKRequestMethod)method; + +/** + Generates a URL with a given route and object. + + @param route The route to generate the URL with. + @param object The object with which to interpolate the path pattern of the given route. + @return A new URL object constructed by interpolating the path pattern of the given route with the given object to construct a path and constructing an `NSURL` object relative to the `baseURL` of the receiver. + */ +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object; + +///--------------------------------------------- +/// @name Configuring the Base URL and Route Set +///--------------------------------------------- + +/** + The base URL that all URLs constructed by the receiver are relative to. + */ +@property (nonatomic, strong, readwrite) NSURL *baseURL; + +/** + A route set defining all the routes addressable through the receiver. + */ +@property (nonatomic, strong, readonly) RKRouteSet *routeSet; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.m b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.m new file mode 100644 index 0000000..2d5565f --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Network/RKRouter.m @@ -0,0 +1,85 @@ +// +// RKRouter.m +// RestKit +// +// Created by Blake Watters on 6/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouter.h" +#import "RKRouteSet.h" +#import "RKRoute.h" +#import "RKPathMatcher.h" +#import <objc/runtime.h> + +@interface RKRouter () +@property (nonatomic, strong, readwrite) RKRouteSet *routeSet; +@end + +@implementation RKRouter + +- (instancetype)initWithBaseURL:(NSURL *)baseURL +{ + self = [super init]; + if (self) { + NSParameterAssert(baseURL); + self.baseURL = baseURL; + self.routeSet = [[RKRouteSet alloc] init]; + } + + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithBaseURL: instead.", NSStringFromClass([self class])] + userInfo:nil]; +} + +- (NSURL *)URLForRouteNamed:(NSString *)routeName method:(out RKRequestMethod *)method object:(id)object +{ + RKRoute *route = [self.routeSet routeForName:routeName]; + if (method) *method = route.method; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLForObject:(id)object method:(RKRequestMethod)method +{ + RKRoute *route = [self.routeSet routeForObject:object method:method]; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLForRelationship:(NSString *)relationshipName ofObject:(id)object method:(RKRequestMethod)method +{ + RKRoute *route = [self.routeSet routeForRelationship:relationshipName ofClass:[object class] method:method]; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object +{ + NSParameterAssert(route); + NSURL *URL = [NSURL URLWithString:[self pathFromRoute:route forObject:object] relativeToURL:self.baseURL]; + return URL; +} + +- (NSString *)pathFromRoute:(RKRoute *)route forObject:(id)object +{ + if (! object) return route.pathPattern; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:route.pathPattern]; + return [pathMatcher pathFromObject:object addingEscapes:route.shouldEscapePath interpolatedParameters:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping.h new file mode 100644 index 0000000..54c84df --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping.h @@ -0,0 +1,28 @@ +// +// ObjectMapping.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMapping.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKValueTransformers.h" +#import "RKMappingResult.h" +#import "RKMapperOperation.h" +#import "RKDynamicMapping.h" +#import "RKErrorMessage.h" diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h new file mode 100644 index 0000000..6d08f96 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1,60 @@ +// +// RKAttributeMapping.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" + +/** + Instances of `RKAttributeMapping` define a transformation of data between an attribute value on source object and an attribute value on a destination object within an object mapping. + */ +@interface RKAttributeMapping : RKPropertyMapping + +/** + Creates and returns a new attribute mapping specifying that data is to be read from a given key path on a source object + and set to a given key path on a destination object. + + Attribute mappings define transformation between key paths in the source and destination object beings mapped. In the simplest + case, an attribute mapping may simply specify that data from one object is to be copied to another. A common example of this + type of transformation is copying the `name` key from a JSON payload onto a local object. In this case, the source and + destination key paths are identical, as are the source and destination types (`NSString`), so a simple get and set operation + has been defined. + + The next most common use-case is the transformation of identical data between two different key paths in the + source and destination objects. This is typically encountered when you wish to transform inbound data to conform with the naming + conventions of the platform or the data model of your application. An example of this type of transformation would be from the + source key path of `first_name` to the destination key path of `firstName`. In this transformation, the key paths have diverged + but both sides of the mapping correspond to NSString properties. + + The final type of transformation to be specified via an attribute mapping involves the transformation between types in the mapping. + By far, the most common example of this use-case is the transformation of a inbound string or numeric property into a date on + the target object. For example, consider a backend system that returns the creation date of a piece of content in a JSON payload. + This data might be returned in JSON as `{"created_on": "2012-08-27"}`. In a given application, the developer may wish to model this + data as an NSDate `createdOn` property on the target object. An attribute mapping to support this mapping would specify a source + key path of `created_on` and a destination key path of `createdOn`. On the destination object, the `createdOn` property would be defined + as `@property (nonatomic, strong) NSDate *createdOn;`. At mapping time, the mapping operation inspects the type of the content being + mapped and attempts to transform the source content into the type of the desination property specified by the mapping. In this case, + an NSDateFormatter object would be used to process the inbound `NSString` into an outbound `NSDate` object. + + @param sourceKeyPath The key path on the source object from which to read the data being mapped. If `nil`, then the entire source object representation is mapped to the specified destination attribute. + @param destinationKeyPath The key path on the destination object on which to set the mapped data. + @return A newly created attribute mapping object that is ready to be added to an object mapping. + */ ++ (instancetype)attributeMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m new file mode 100644 index 0000000..6d83f06 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m @@ -0,0 +1,39 @@ +// +// RKAttributeMapping.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKAttributeMapping.h" + +@interface RKPropertyMapping () +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@implementation RKAttributeMapping + ++ (instancetype)attributeMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath +{ + NSAssert(sourceKeyPath || destinationKeyPath, @"Both the source and destination key paths cannot be nil"); + RKAttributeMapping *attributeMapping = [self new]; + attributeMapping.sourceKeyPath = sourceKeyPath; + attributeMapping.destinationKeyPath = destinationKeyPath; + return attributeMapping; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h new file mode 100644 index 0000000..ba60aca --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1,115 @@ +// +// RKDynamicMapping.h +// RestKit +// +// Created by Blake Watters on 7/28/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMapping.h" +#import "RKObjectMappingMatcher.h" + +/** + The `RKDynamicMapping` class is an `RKMapping` subclass that provides an interface for deferring the decision about how a given object representation is to be mapped until run time. This enables many interesting mapping strategies, such as mapping similarly structured data differently and constructing object mappings at run time by examining the data being mapped. + + ## Configuring Mapping Selection + + Dynamic mappings support the selection of the concrete object mapping in one of two ways: + + 1. Through the use of a mapping selection block configured by `setObjectMappingForRepresentationBlock:`. When configured, the block is called with a reference to the current object representation being mapped and is expected to return an `RKObjectMapping` object. Returning `nil` declines the mapping of the representation. + 1. Through the configuration of one of more `RKObjectMappingMatcher` objects. The matchers are consulted in registration order and the first matcher to return an object mapping is used to map the matched representation. + + When both a mapping selection block and matchers are configured on a `RKDynamicMapping` object, the matcher objects are consulted first and if none match, the selection block is invoked. + + ## Using Matcher Objects + + The `RKObjectMappingMatcher` class provides an interface for evaluating a key path or predicate based match and returning an appropriate object mapping. Matchers can be added to the `RKDynamicMapping` objects to declaratively describe a particular mapping strategy. + + For example, suppose that we have a JSON fragment for a person that we want to map differently based on the gender of the person. When the gender is 'male', we want to use the Boy class and when then the gender is 'female' we want to use the Girl class. The JSON might look something like this: + + [ { "name": "Blake", "gender": "male" }, { "name": "Sarah", "gender": "female" } ] + + We might define configure the dynamic mapping like so: + + RKDynamicMapping *mapping = [RKDynamicMapping new]; + RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; + RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; + [mapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"gender" expectedValue:@"male" objectMapping:boyMapping]]; + [mapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"gender" expectedValue:@"female" objectMapping:girlMapping]]; + + When evaluated, the matchers will invoke `valueForKeyPath:@"gender"` against each dictionary in the array of object representations and apply the appropriate object mapping for each representation. This would return a mapping result containing an array of two objects, one an instance of the `Boy` class and the other an instance of the `Girl` class. + + ## HTTP Integration + + Dynamic mappings can be used to map HTTP requests and responses by adding them to an `RKRequestDescriptor` or `RKResponseDescriptor` objects. + */ +@interface RKDynamicMapping : RKMapping + +///------------------------------------------ +/// @name Configuring Block Mapping Selection +///------------------------------------------ + +/** + Sets a block to be invoked to determine the appropriate concrete object mapping with which to map an object representation. + + @param block The block object to invoke to select the object mapping with which to map the given object representation. The block returns an object mapping and accepts a single parameter: the object representation being mapped. + */ +- (void)setObjectMappingForRepresentationBlock:(RKObjectMapping *(^)(id representation))block; + +/** + Returns the array of matchers objects added to the receiver. + */ +@property (nonatomic, strong, readonly) NSArray *matchers; + +/** + Adds a matcher to the receiver. + + If the matcher has already been added to the receiver, then adding it again moves it to the top of the matcher stack. + + @param matcher The matcher to add to the receiver. + */ +- (void)addMatcher:(RKObjectMappingMatcher *)matcher; + +/** + Removes a matcher from the receiver. + + If the matcher has already been added to the receiver, then adding it again moves it to the top of the matcher stack. + + @param matcher The matcher to remove from the receiver. + */ +- (void)removeMatcher:(RKObjectMappingMatcher *)matcher; + +/** + Returns an array of object mappings that have been registered with the receiver. + + @return An array of `RKObjectMapping` objects registered with the receiver. + */ +@property (nonatomic, readonly) NSArray *objectMappings; + +///----------------------------------------------------------------- +/// @name Retrieving the Object Mapping for an Object Representation +///----------------------------------------------------------------- + +/** + Invoked by the `RKMapperOperation` and `RKMappingOperation` to determine the appropriate `RKObjectMapping` to use when mapping the given object representation. + + This method searches the stack of registered matchers and then executes the block, if any, set by `setObjectMappingForRepresentationBlock:`. If `nil` is returned, then mapping for the representation is declined and it will not be mapped. + + @param representation The object representation that being mapped dynamically for which to determine the appropriate concrete mapping. + @return The object mapping to be used to map the given object representation. + */ +- (RKObjectMapping *)objectMappingForRepresentation:(id)representation; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m new file mode 100644 index 0000000..f7138ba --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m @@ -0,0 +1,119 @@ +// +// RKDynamicMapping.m +// RestKit +// +// Created by Blake Watters on 7/28/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKDynamicMapping.h" +#import "RKObjectMappingMatcher.h" +#import "RKLog.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +@interface RKDynamicMapping () +@property (nonatomic, strong) NSMutableArray *mutableMatchers; +@property (nonatomic, strong) NSArray *possibleObjectMappings; +@property (nonatomic, copy) RKObjectMapping *(^objectMappingForRepresentationBlock)(id representation); +@end + +@implementation RKDynamicMapping + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.mutableMatchers = [NSMutableArray new]; + self.possibleObjectMappings = [NSArray new]; + } + + return self; +} + +- (NSArray *)matchers +{ + return [self.mutableMatchers copy]; +} + +- (NSArray *)objectMappings +{ + return self.possibleObjectMappings; +} + +- (void)addMatcher:(RKObjectMappingMatcher *)matcher +{ + NSParameterAssert(matcher); + if ([self.mutableMatchers containsObject:matcher]) { + [self.mutableMatchers removeObject:matcher]; + [self.mutableMatchers insertObject:matcher atIndex:0]; + } else { + [self.mutableMatchers addObject:matcher]; + + NSArray *newPossibleMappings = [matcher possibleObjectMappings]; + if (newPossibleMappings.count > 0) { + self.possibleObjectMappings = [self.possibleObjectMappings arrayByAddingObjectsFromArray:newPossibleMappings]; + } + } +} + +- (void)removeMatcher:(RKObjectMappingMatcher *)matcher +{ + NSParameterAssert(matcher); + + if ([self.mutableMatchers containsObject:matcher]) { + NSMutableArray *mappings = [self.possibleObjectMappings mutableCopy]; + for (RKObjectMapping *mapping in [matcher possibleObjectMappings]) { + /* removeObject will remove *all* instances; if we have dups we just want to remove one */ + NSUInteger idx = [mappings indexOfObject:mapping]; + if (idx != NSNotFound) + [mappings removeObjectAtIndex:idx]; + } + self.possibleObjectMappings = [mappings copy]; + [self.mutableMatchers removeObject:matcher]; + } +} + +- (RKObjectMapping *)objectMappingForRepresentation:(id)representation +{ + RKObjectMapping *mapping = nil; + + RKLogTrace(@"Performing dynamic object mapping for object representation: %@", representation); + + // Consult the declarative matchers first + for (RKObjectMappingMatcher *matcher in self.mutableMatchers) { + if ([matcher matches:representation]) { + RKLogTrace(@"Found declarative match for matcher: %@.", matcher); + return matcher.objectMapping; + } + } + + // Otherwise consult the block + if (self.objectMappingForRepresentationBlock) { + mapping = self.objectMappingForRepresentationBlock(representation); + if (mapping) RKLogTrace(@"Determined concrete `RKObjectMapping` using object mapping for representation block"); + } + + return mapping; +} + +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping +{ + return (self == otherMapping); +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h new file mode 100644 index 0000000..2aea33f --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h @@ -0,0 +1,44 @@ +// +// RKError.h +// RestKit +// +// Created by Jeremy Ellison on 5/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKErrorMessage` is a simple class used for representing error messages returned by a remote backend system with which the client application is communicating. Error messages are typically returned in a response body in the Client Error class (status code 4xx range). + + @see `RKErrorFromMappingResult` + */ +@interface RKErrorMessage : NSObject + +///----------------------------------- +/// @name Accessing Errror Information +///----------------------------------- + +/** + The error message to be presented to the user. + */ +@property (nonatomic, copy) NSString *errorMessage; + +/** + A dictionary of application specific information that accompanies the error message. + */ +@property (nonatomic, copy) NSDictionary *userInfo; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m new file mode 100644 index 0000000..1a102c4 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m @@ -0,0 +1,30 @@ +// +// RKError.m +// RestKit +// +// Created by Jeremy Ellison on 5/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrorMessage.h" + +@implementation RKErrorMessage + +- (NSString *)description +{ + return self.errorMessage; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h new file mode 100644 index 0000000..b1f0553 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1,159 @@ +// +// RKHTTPUtilities.h +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + HTTP methods for requests + */ +typedef NS_OPTIONS(NSInteger, RKRequestMethod) { + RKRequestMethodGET = 1 << 0, + RKRequestMethodPOST = 1 << 1, + RKRequestMethodPUT = 1 << 2, + RKRequestMethodDELETE = 1 << 3, + RKRequestMethodHEAD = 1 << 4, + RKRequestMethodPATCH = 1 << 5, + RKRequestMethodOPTIONS = 1 << 6, + RKRequestMethodAny = (RKRequestMethodGET | + RKRequestMethodPOST | + RKRequestMethodPUT | + RKRequestMethodDELETE | + RKRequestMethodHEAD | + RKRequestMethodPATCH | + RKRequestMethodOPTIONS) +}; + +/** + Returns YES if the given HTTP request method is an exact match of the RKRequestMethod enum, and NO if it's a bit mask combination. + */ +BOOL RKIsSpecificRequestMethod(RKRequestMethod method); + +/** + Returns the corresponding string for value for a given HTTP request method. + + For example, given `RKRequestMethodGET` would return `@"GET"`. + + @param method The request method to return the corresponding string value for. The given request method must be specific. + */ +NSString *RKStringFromRequestMethod(RKRequestMethod method); + +/** + Returns the corresponding request method value for a given string. + + For example, given `@"PUT"` would return `@"RKRequestMethodPUT"` + */ +RKRequestMethod RKRequestMethodFromString(NSString *); + +/** + The HTTP status code classes + + See http://tools.ietf.org/html/rfc2616#section-10 + */ +typedef NS_ENUM(NSUInteger, RKStatusCodeClass) { + RKStatusCodeClassInformational = 100, + RKStatusCodeClassSuccessful = 200, + RKStatusCodeClassRedirection = 300, + RKStatusCodeClassClientError = 400, + RKStatusCodeClassServerError = 500 +}; + +/** + Creates a new range covering the status codes in the given class. + + @param statusCodeClass The status code class to create a range covering. + @return A new range covering the status codes in the given class. + */ +NSRange RKStatusCodeRangeForClass(RKStatusCodeClass statusCodeClass); + +/** + Creates a new index set covering the status codes in the given class. + + @param statusCodeClass The status code class to create an index set covering. + @return A new index set covering the status codes in the given class. + */ +NSIndexSet *RKStatusCodeIndexSetForClass(RKStatusCodeClass statusCodeClass); + +/** + Creates and returns a new index set including all HTTP response status codes that are cacheable. + + @return A new index set containing all cacheable status codes. + */ +NSIndexSet *RKCacheableStatusCodes(void); + +/** + Returns string representation of a given HTTP status code. + + The list of supported status codes was built from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + + @param statusCode The HTTP status code to return a string from. + @return A string representation of the given status code. + */ +NSString *RKStringFromStatusCode(NSInteger statusCode); + +/** + Parse HTTP Date: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + */ +NSDate *RKDateFromHTTPDateString(NSString *); + +/** + Returns the cache expiration data from a dictionary of HTTP response headers as appropriate for the given status code. If the status code is not cachable, `nil` is returned. + + @param headers The HTTP response headers from which to extract the cache expiration date. + @param statusCode The HTTP response status code of the response. + @return The expiration date as specified by the cache headers or `nil` if none was found. + */ +NSDate *RKHTTPCacheExpirationDateFromHeadersWithStatusCode(NSDictionary *headers, NSInteger statusCode); + +/** + Returns a Boolean value that indicates if a given URL is relative to another URL. + + This method does not rely on the `baseURL` method of `NSURL` as it only indicates a relationship between the initialization of two URL objects. The relativity of the given URL is assessed by evaluating a prefix match of the URL's absolute string value with the absolute string value of the potential base URL. + + @param URL The URL to assess the relativity of. + @param baseURL The base URL to determine if the given URL is relative to. + @return `YES` is URL is relative to the base URL, else `NO`. + */ +BOOL RKURLIsRelativeToURL(NSURL *URL, NSURL *baseURL); + +/** + Returns a string object containing the relative path and query string of a given URL object and a base URL that the given URL is relative to. + + If the given URL is found not to be relative to the baseURL, `nil` is returned. + + @param URL The URL to retrieve the relative path and query string of. + @param baseURL The base URL to be omitted from the returned path and query string. + @return A string containing the relative path and query parameters. + */ +NSString *RKPathAndQueryStringFromURLRelativeToURL(NSURL *URL, NSURL *baseURL); + +/** + * Returns an index set of the status codes with optional response bodies + * + * @return An index set of the status codes with optional response bodies + */ +NSIndexSet *RKStatusCodesOfResponsesWithOptionalBodies(void); + +#ifdef __cplusplus +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m new file mode 100644 index 0000000..e789c4b --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m @@ -0,0 +1,548 @@ +// +// RKHTTPUtilities.m +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +NSUInteger RKStatusCodeRangeLength = 100; + +NSRange RKStatusCodeRangeForClass(RKStatusCodeClass statusCodeClass) +{ + return NSMakeRange(statusCodeClass, RKStatusCodeRangeLength); +} + +NSIndexSet *RKStatusCodeIndexSetForClass(RKStatusCodeClass statusCodeClass) +{ + return [NSIndexSet indexSetWithIndexesInRange:RKStatusCodeRangeForClass(statusCodeClass)]; +} + +NSIndexSet *RKCacheableStatusCodes(void) +{ + NSMutableIndexSet *cacheableStatusCodes = [NSMutableIndexSet indexSet]; + [cacheableStatusCodes addIndex:200]; + [cacheableStatusCodes addIndex:304]; + [cacheableStatusCodes addIndex:203]; + [cacheableStatusCodes addIndex:300]; + [cacheableStatusCodes addIndex:301]; + [cacheableStatusCodes addIndex:302]; + [cacheableStatusCodes addIndex:307]; + [cacheableStatusCodes addIndex:410]; + return cacheableStatusCodes; +} + +BOOL RKIsSpecificRequestMethod(RKRequestMethod method) +{ + // check for a power of two + return !(method & (method - 1)); +} + +NSString *RKStringFromRequestMethod(RKRequestMethod method) +{ + switch (method) { + case RKRequestMethodGET: return @"GET"; + case RKRequestMethodPOST: return @"POST"; + case RKRequestMethodPUT: return @"PUT"; + case RKRequestMethodPATCH: return @"PATCH"; + case RKRequestMethodDELETE: return @"DELETE"; + case RKRequestMethodHEAD: return @"HEAD"; + case RKRequestMethodOPTIONS: return @"OPTIONS"; + default: break; + } + return nil; +} + +RKRequestMethod RKRequestMethodFromString(NSString *methodName) +{ + if ([methodName isEqualToString:@"GET"]) return RKRequestMethodGET; + else if ([methodName isEqualToString:@"POST"]) return RKRequestMethodPOST; + else if ([methodName isEqualToString:@"PUT"]) return RKRequestMethodPUT; + else if ([methodName isEqualToString:@"DELETE"]) return RKRequestMethodDELETE; + else if ([methodName isEqualToString:@"HEAD"]) return RKRequestMethodHEAD; + else if ([methodName isEqualToString:@"PATCH"]) return RKRequestMethodPATCH; + else if ([methodName isEqualToString:@"OPTIONS"]) return RKRequestMethodOPTIONS; + else @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"The given HTTP request method name `%@` does not correspond to any known request methods.", methodName] + userInfo:nil]; +} + +// Built from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes +static NSDictionary *RKStatusCodesToNamesDictionary() +{ + static NSDictionary *statusCodesToNamesDictionary = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + statusCodesToNamesDictionary = @{ + // 1xx (Informational) + @(100): @"Continue", + @(101): @"Switching Protocols", + @(102): @"Processing", + + // 2xx (Success) + @(200): @"OK", + @(201): @"Created", + @(202): @"Accepted", + @(203): @"Non-Authoritative Information", + @(204): @"No Content", + @(205): @"Reset Content", + @(206): @"Partial Content", + @(207): @"Multi-Status", + @(208): @"Already Reported", + @(226): @"IM Used", + + // 3xx (Redirection) + @(300): @"Multiple Choices", + @(301): @"Moved Permanently", + @(302): @"Found", + @(303): @"See Other", + @(304): @"Not Modified", + @(305): @"Use Proxy", + @(306): @"Switch Proxy", + @(307): @"Temporary Redirect", + @(308): @"Permanent Redirect", + + // 4xx (Client Error) + @(400): @"Bad Request", + @(401): @"Unauthorized", + @(402): @"Payment Required", + @(403): @"Forbidden", + @(404): @"Not Found", + @(405): @"Method Not Allowed", + @(406): @"Not Acceptable", + @(407): @"Proxy Authentication Required", + @(408): @"Request Timeout", + @(409): @"Conflict", + @(410): @"Gone", + @(411): @"Length Required", + @(412): @"Precondition Failed", + @(413): @"Request Entity Too Large", + @(414): @"Request-URI Too Long", + @(415): @"Unsupported Media Type", + @(416): @"Requested Range Not Satisfiable", + @(417): @"Expectation Failed", + @(418): @"I'm a teapot", + @(420): @"Enhance Your Calm", + @(422): @"Unprocessable Entity", + @(423): @"Locked", + @(424): @"Failed Dependency", + @(424): @"Method Failure", + @(425): @"Unordered Collection", + @(426): @"Upgrade Required", + @(428): @"Precondition Required", + @(429): @"Too Many Requests", + @(431): @"Request Header Fields Too Large", + @(451): @"Unavailable For Legal Reasons", + + // 5xx (Server Error) + @(500): @"Internal Server Error", + @(501): @"Not Implemented", + @(502): @"Bad Gateway", + @(503): @"Service Unavailable", + @(504): @"Gateway Timeout", + @(505): @"HTTP Version Not Supported", + @(506): @"Variant Also Negotiates", + @(507): @"Insufficient Storage", + @(508): @"Loop Detected", + @(509): @"Bandwidth Limit Exceeded", + @(510): @"Not Extended", + @(511): @"Network Authentication Required", + }; + }); + return statusCodesToNamesDictionary; +} + +NSString * RKStringFromStatusCode(NSInteger statusCode) +{ + return RKStatusCodesToNamesDictionary()[@(statusCode)]; +} + + +/** + Below is ragel source used to compile those tables. The output was polished / pretty-printed and tweaked from ragel. + As the generated code is "hard" to debug, we store the code in http-date.r1 + + shell% ragel -F1 http-date.rl + shell% gcc -o http-date http-date.c + shell% ./http-date 'Sun, 06 Nov 1994 08:49:37 GMT' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun Nov 6 08:49:37 1994' 'Sat Dec 24 14:34:26 2037' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun, 06 Nov 1994 08:49:37 GMT' + */ +static const char _httpDate_trans_keys[] = { + 0, 0, 70, 87, 114, 114, 105, 105, 32, 100, 65, 83, 112, 117, 114, 114, 32, + 32, 32, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, + 58, 58, 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 48, 57, 48, 57, 103, + 103, 101, 101, 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, + 114, 121, 111, 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 32, 32, 48, + 57, 48, 57, 32, 32, 65, 83, 112, 117, 114, 114, 32, 32, 48, 57, 48, 57, + 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58, + 58, 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101, + 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111, + 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 97, 97, 121, 121, 44, 44, + 32, 32, 48, 57, 48, 57, 45, 45, 65, 83, 112, 117, 114, 114, 45, 45, 48, + 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58, 58, + 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101, 99, + 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111, 111, + 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 111, 111, 110, 110, 97, 117, 116, + 116, 32, 117, 114, 114, 100, 100, 104, 117, 117, 117, 32, 114, 115, 115, 101, 101, + 32, 115, 101, 101, 100, 100, 32, 110, 101, 101, 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _httpDate_key_spans[] = { + 0, 18, 1, 1, 69, 19, 6, 1, 1, 26, 10, 1, 10, 10, 1, 10, 10, + 1, 10, 10, 1, 10, 10, 10, 10, 1, 1, 1, 1, 1, 21, 1, 3, 1, + 8, 1, 1, 1, 1, 1, 1, 1, 10, 10, 1, 19, 6, 1, 1, 10, 10, + 10, 10, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 21, 1, 3, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 10, 10, 1, 19, 6, 1, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1, + 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 1, 3, 1, 8, 1, + 1, 1, 1, 1, 1, 1, 1, 21, 1, 86, 1, 1, 14, 1, 83, 1, 1, + 84, 1, 1, 79, 1, 0, 0, 0 +}; + +static const short _httpDate_index_offsets[] = { + 0, 0, 19, 21, 23, 93, 113, 120, 122, 124, 151, 162, 164, 175, 186, 188, 199, + 210, 212, 223, 234, 236, 247, 258, 269, 280, 282, 284, 286, 288, 290, 312, 314, 318, + 320, 329, 331, 333, 335, 337, 339, 341, 343, 354, 365, 367, 387, 394, 396, 398, 409, + 420, 431, 442, 444, 455, 466, 468, 479, 490, 492, 503, 514, 516, 518, 520, 522, 524, + 526, 528, 530, 532, 554, 556, 560, 562, 571, 573, 575, 577, 579, 581, 583, 585, 587, + 589, 591, 602, 613, 615, 635, 642, 644, 646, 657, 668, 670, 681, 692, 694, 705, 716, + 718, 729, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 780, 782, 786, 788, 797, + 799, 801, 803, 805, 807, 809, 811, 813, 835, 837, 924, 926, 928, 943, 945, 1029, 1031, + 1033, 1118, 1120, 1122, 1202, 1204, 1205, 1206 +}; + +static const unsigned char _httpDate_indicies[] = { + 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 4, 1, 1, + 5, 1, 6, 1, 7, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 10, 1, 11, 1, 1, 12, 1, 13, 1, 1, 1, + 14, 1, 1, 15, 16, 17, 1, 1, 1, 18, 1, 19, 1, 1, 1, 1, 20, + 1, 21, 1, 22, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 1, 26, 1, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 1, 29, + 1, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 1, 32, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 1, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 1, 35, 1, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 1, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 1, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 1, 40, 1, 41, 1, 42, 1, 43, 1, 44, + 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 46, 1, 47, 1, 48, 1, 49, 1, 50, 1, 51, 1, 1, + 1, 1, 1, 1, 52, 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, + 1, 59, 1, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 1, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 1, 62, 1, 63, 1, 1, 64, 1, 65, 1, + 1, 1, 66, 1, 1, 67, 68, 69, 1, 1, 1, 70, 1, 71, 1, 1, 1, + 1, 72, 1, 73, 1, 74, 1, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 1, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 1, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 1, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 1, + 79, 1, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 1, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 1, 82, 1, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 1, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 1, 85, 1, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 1, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 1, 88, 1, 89, 1, 90, 1, 91, 1, 92, 1, 93, 1, 94, + 1, 95, 1, 96, 1, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 98, 1, 99, 1, 100, 1, 101, 1, 102, + 1, 103, 1, 1, 1, 1, 1, 1, 104, 1, 105, 1, 106, 1, 107, 1, 108, + 1, 109, 1, 110, 1, 111, 1, 112, 1, 113, 1, 114, 1, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 1, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 1, 117, 1, 118, 1, 1, 119, 1, 120, 1, 1, 1, 121, 1, 1, 122, 123, + 124, 1, 1, 1, 125, 1, 126, 1, 1, 1, 1, 127, 1, 128, 1, 129, 1, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 1, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 1, 132, 1, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 1, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 1, 135, 1, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 1, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 1, 138, 1, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 1, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 1, 141, 1, 142, 1, 143, 1, 144, 1, + 145, 1, 146, 1, 147, 1, 148, 1, 149, 1, 150, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 151, 1, 152, 1, + 153, 1, 154, 1, 155, 1, 156, 1, 1, 1, 1, 1, 1, 157, 1, 158, 1, + 159, 1, 160, 1, 161, 1, 162, 1, 163, 1, 164, 1, 7, 1, 165, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 164, 1, 166, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 167, 1, 168, 1, 10, 1, 169, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 170, 1, 171, 1, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 172, 1, 168, 1, 173, 1, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 1, 174, 1, 175, 1, + 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 172, 1, 1, 1, 1, + 0 +}; + +static const unsigned char _httpDate_trans_targs[] = { + 2, 0, 124, 126, 131, 137, 3, 4, 5, 41, 82, 6, 26, 28, 30, 33, 35, + 37, 39, 7, 25, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 141, 8, 27, 8, 29, 8, 31, 32, 8, 8, 8, 34, + 8, 8, 36, 8, 38, 8, 40, 8, 42, 43, 44, 45, 46, 67, 69, 71, 74, + 76, 78, 80, 47, 66, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 142, 48, 68, 48, 70, 48, 72, 73, 48, 48, 48, + 75, 48, 48, 77, 48, 79, 48, 81, 48, 83, 84, 85, 86, 87, 88, 89, 90, + 109, 111, 113, 116, 118, 120, 122, 91, 108, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 143, 92, 110, 92, 112, 92, 114, 115, 92, + 92, 92, 117, 92, 92, 119, 92, 121, 92, 123, 92, 125, 127, 128, 129, 130, 132, + 135, 133, 134, 136, 138, 139, 140 +}; + +static const char _httpDate_trans_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5, + 5, 0, 6, 6, 6, 6, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12, 0, + 13, 14, 0, 15, 0, 16, 0, 17, 0, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 6, 6, 6, 6, 0, 3, 3, 0, 4, 4, + 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12, + 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 18, 0, 3, 3, 0, + 4, 4, 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10, + 11, 12, 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _httpDate_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 20, 21 +}; + +static NSDate *_parseHTTPDate(const char *buf, size_t bufLen) { + const char *p = buf, *pe = p + bufLen, *eof = pe; + int parsed = 0, cs = 1; + NSDate *date = NULL; + + CFGregorianDate gdate; + memset(&gdate, 0, sizeof(CFGregorianDate)); + + { + int _slen, _trans; + const char *_keys; + const unsigned char *_inds; + if(p == pe) { goto _test_eof; } + _resume: + _keys = _httpDate_trans_keys + (cs << 1); + _inds = _httpDate_indicies + _httpDate_index_offsets[cs]; + _slen = _httpDate_key_spans[cs]; + _trans = _inds[(_slen > 0) && (_keys[0] <= (*p)) && ((*p) <= _keys[1]) ? (*p) - _keys[0] : _slen]; + cs = _httpDate_trans_targs[_trans]; + + if(_httpDate_trans_actions[_trans] == 0) { goto _again; } + + switch(_httpDate_trans_actions[_trans]) { + case 6: gdate.year = gdate.year * 10 + ((*p) - '0'); break; + case 18: gdate.year = gdate.year * 10 + ((*p) - '0'); gdate.year += 1900; break; + case 10: gdate.month = 1; break; + case 9: gdate.month = 2; break; + case 13: gdate.month = 3; break; + case 1: gdate.month = 4; break; + case 14: gdate.month = 5; break; + case 12: gdate.month = 6; break; + case 11: gdate.month = 7; break; + case 7: gdate.month = 8; break; + case 17: gdate.month = 9; break; + case 16: gdate.month = 10; break; + case 15: gdate.month = 11; break; + case 8: gdate.month = 12; break; + case 2: gdate.day = gdate.day * 10 + ((*p) - '0'); break; + case 3: gdate.hour = gdate.hour * 10 + ((*p) - '0'); break; + case 4: gdate.minute = gdate.minute * 10 + ((*p) - '0'); break; + case 5: gdate.second = gdate.second * 10.0 + ((*p) - '0'); break; + } + + _again: + if( cs == 0) { goto _out; } + if(++p != pe) { goto _resume; } + _test_eof: {} + if(p == eof) { + switch(_httpDate_eof_actions[cs]) { + case 19: parsed = 1; break; + case 20: parsed = 1; break; + case 21: parsed = 1; break; + } + } + + _out: {} + } + + static CFTimeZoneRef gmtTimeZone; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ gmtTimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); }); + + if(parsed == 1) { date = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gdate, gmtTimeZone)]; } + + return(date); +} + +/* + * Parse HTTP Date: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + */ +NSDate * RKDateFromHTTPDateString(NSString *httpDate) +{ + char stringBuffer[256]; + size_t stringLength = (size_t)CFStringGetLength((__bridge CFStringRef)httpDate); + const char *cStringPtr = (const char *)CFStringGetCStringPtr((__bridge CFStringRef)httpDate, kCFStringEncodingMacRoman); + if(cStringPtr == NULL) { + CFIndex usedBytes = 0L, convertedCount = 0L; + convertedCount = CFStringGetBytes((__bridge CFStringRef)httpDate, CFRangeMake(0L, (CFIndex)stringLength), kCFStringEncodingUTF8, '?', NO, (UInt8 *)stringBuffer, sizeof(stringBuffer) - 1L, &usedBytes); + if(((size_t)convertedCount != stringLength) || (usedBytes < 0L)) { return(NULL); } + stringBuffer[usedBytes] = '\0'; + cStringPtr = (const char *)stringBuffer; + } + return(_parseHTTPDate(cStringPtr, stringLength)); +} + +static float const kRKURLCacheLastModFraction = 0.1f; // 10% since Last-Modified suggested by RFC2616 section 13.2.4 +static float const kRKURLCacheDefault = 3600.0f; // Default cache expiration delay if none defined (1 hour) + +/* + * This method tries to determine the expiration date based on a response headers dictionary. + */ +NSDate * RKHTTPCacheExpirationDateFromHeadersWithStatusCode(NSDictionary *headers, NSInteger statusCode) +{ + if (statusCode != 200 && statusCode != 203 && statusCode != 300 && statusCode != 301 && statusCode != 302 && statusCode != 307 && statusCode != 410) { + // Uncacheable response status code + return nil; + } + + // Check Pragma: no-cache + NSString *pragma = headers[@"Pragma"]; + if (pragma && [pragma isEqualToString:@"no-cache"]) { + // Uncacheable response + return nil; + } + + // Define "now" based on the request + NSString *date = headers[@"Date"]; + // If no Date: header, define now from local clock + NSDate *now = date ? RKDateFromHTTPDateString(date) : [NSDate date]; + + // Look at info from the Cache-Control: max-age=n header + NSString *cacheControl = [headers[@"Cache-Control"] lowercaseString]; + if (cacheControl) + { + NSRange foundRange = [cacheControl rangeOfString:@"no-store"]; + if (foundRange.length > 0) { + // If no-store, the content cannot be cached at all + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2 + return nil; + } + + foundRange = [cacheControl rangeOfString:@"no-cache"]; + if (foundRange.length > 0) { + // If no-cache, we must revalidate with the origin server + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 + return nil; + } + + NSInteger maxAge; + foundRange = [cacheControl rangeOfString:@"max-age"]; + if (foundRange.length > 0) { + NSScanner *cacheControlScanner = [NSScanner scannerWithString:cacheControl]; + [cacheControlScanner setScanLocation:foundRange.location + foundRange.length]; + [cacheControlScanner scanString:@"=" intoString:nil]; + if ([cacheControlScanner scanInteger:&maxAge]) { + return maxAge > 0 ? [[NSDate alloc] initWithTimeInterval:maxAge sinceDate:now] : nil; + } + } + } + + // If not Cache-Control found, look at the Expires header + NSString *expires = headers[@"Expires"]; + if (expires) { + NSTimeInterval expirationInterval = 0; + NSDate *expirationDate = RKDateFromHTTPDateString(expires); + if (expirationDate) { + expirationInterval = [expirationDate timeIntervalSinceDate:now]; + } + if (expirationInterval > 0) { + // Convert remote expiration date to local expiration date + return [NSDate dateWithTimeIntervalSinceNow:expirationInterval]; + } + else { + // If the Expires header can't be parsed or is expired, do not cache + return nil; + } + } + + if (statusCode == 302 || statusCode == 307) { + // If not explict cache control defined, do not cache those status + return nil; + } + + // If no cache control defined, try some heristic to determine an expiration date + NSString *lastModified = headers[@"Last-Modified"]; + if (lastModified) { + NSTimeInterval age = 0; + NSDate *lastModifiedDate = RKDateFromHTTPDateString(lastModified); + if (lastModifiedDate) { + // Define the age of the document by comparing the Date header with the Last-Modified header + age = [now timeIntervalSinceDate:lastModifiedDate]; + } + return age > 0 ? [NSDate dateWithTimeIntervalSinceNow:(age * kRKURLCacheLastModFraction)] : nil; + } + + // If nothing permitted to define the cache expiration delay nor to restrict its cacheability, use a default cache expiration delay + return [[NSDate alloc] initWithTimeInterval:kRKURLCacheDefault sinceDate:now]; +} + +BOOL RKURLIsRelativeToURL(NSURL *URL, NSURL *baseURL) +{ + return [[URL absoluteString] hasPrefix:[baseURL absoluteString]]; +} + +NSString *RKPathAndQueryStringFromURLRelativeToURL(NSURL *URL, NSURL *baseURL) +{ + if (baseURL) { + if (! RKURLIsRelativeToURL(URL, baseURL)) return nil; + return [[URL absoluteString] substringFromIndex:[[baseURL absoluteString] length]]; + } else { + // NOTE: [URL relativeString] would return the same value as `absoluteString` if URL is not relative to a baseURL + NSString *query = [URL query]; + NSString *pathWithPrevervedTrailingSlash = [CFBridgingRelease(CFURLCopyPath((CFURLRef)URL)) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + return (query && [query length]) ? [NSString stringWithFormat:@"%@?%@", pathWithPrevervedTrailingSlash, query] : pathWithPrevervedTrailingSlash; + } +} + +NSIndexSet *RKStatusCodesOfResponsesWithOptionalBodies() +{ + NSMutableIndexSet *statusCodes = [NSMutableIndexSet indexSet]; + [statusCodes addIndex:201]; + [statusCodes addIndex:202]; + [statusCodes addIndex:204]; + [statusCodes addIndex:205]; + [statusCodes addIndex:304]; + return statusCodes; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h new file mode 100644 index 0000000..94489d0 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h @@ -0,0 +1,256 @@ +// +// RKMapperOperation.h +// RestKit +// +// Created by Blake Watters on 5/6/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" +#import "RKMappingResult.h" +#import "RKMappingOperationDataSource.h" +#import "RKErrors.h" + +@protocol RKMapperOperationDelegate; + +/** + `RKMapperOperation` is an `NSOperation` subclass that implements object mapping for opaque object representations. Given a dictionary or an array of dictionaries that represent objects and a dictionary describing how to map the representations, the mapper will transform the source representations into `NSObject` or `NSManagedObject` instances. Mapper operations are used to map object representations from Foundation object representations, such as those deserialized from a JSON or XML document or loaded from a file. Not all the mappings specified in the mappings dictionary are required to match content in the source object for the operation to succeed. However, if none of the mappable key paths in the mappings dictionary match the source object then the operation will fail and the `error` property will be set to an `NSError` object in the `RKErrorDomain` domain with an error code value of `RKMappingErrorNotFound`. + + `RKMapperOperation` does not actually perform any mapping work. Instead, it instantiates and starts `RKMappingOperation` objects to process the mappable object representations it encounters. + + `RKMapperOperation` is a non-concurrent operation. Execution will occur synchronously on the calling thread unless the operation is enqueued onto an `NSOperationQueue`. + + ## Mappings Dictionary + + The mappings dictionary describes how to object map the source object. The keys of the dictionary are key paths into the `representation` and the values are `RKMapping` objects describing how to map the representations at the corresponding key path. This dictionary based approach enables a single document to contain an arbitrary number of object representations that can be mapped independently. Consider the following example JSON structure: + + { "tags": [ "hacking", "phreaking" ], "authors": [ "Captain Crunch", "Emmanuel Goldstein" ], "magazine": { "title": "2600 The Hacker Quarterly" } } + + Each key in the document could be mapped independently by providing a mapping for the key paths: + + RKObjectMapping *tagMapping = [RKObjectMapping mappingForClass:[Tag class]]; + RKObjectMapping *authorMapping = [RKObjectMapping mappingForClass:[Author class]]; + RKObjectMapping *magazineMapping = [RKObjectMapping mappingForClass:[Magazine class]]; + NSDictionary *mappingsDictionary = @{ @"tag": tagMapping, @"author": authorMapping, @"magazine": magazine }; + + Note that the keys of the dictionary are **key paths**. Deeply nested content can be mapped by specifying the full key path as the key of the mappings dictionary. + + ### Mapping the Root Object Representation + + A mapping set for the key `[NSNull null]` value has special significance to the mapper operation. When a mapping is encountered with the a null key, the entire `representation` is processed using the given mapping. This provides support for mapping content that does not have an outer nesting attribute. + + Note that it is possible to map the same representation with multiple mappings, including a combination of a root key mapping and nested keypaths. + + ## Data Source + + The data source is used to instantiate new objects or find existing objects to be updated during the mapping process. The object set as the `mappingOperationDataSource` will be set as the `dataSource` for the `RKMappingOperation` objects created by the mapper. + + ## Target Object + + If a `targetObject` is configured on the mapper operation, all mapping work on the `representation` will target the specified object. For transient `NSObject` mappings, this ensures that the properties of an existing object are updated rather than an new object being created for the mapped representation. If an array of representations is being processed and a `targetObject` is provided, it must be a mutable collection object else an exception will be raised. + + ## Metadata Mapping + + The `RKMapperOperation` class provides support for metadata mapping provided to the operation via the `mappingMetadata` property. This dictionary is made available to all `RKMappingOperation` objects executed by the receiver to process the representation being mapped. In addition to any user supplied metadata, the mapper operation makes the following metadata key paths available for mapping: + + 1. `@metadata.mapping.rootKeyPath` - An object specifying the root key path at which the current representation is nested within the source representation. This will correspond to a key in the `mappingsDictionary` and is typically an `NSString`, but can be `[NSNull null]` if the representation being mapped is at the root. + 1. `@metadata.mapping.collectionIndex` - An `NSNumber` object specifying the index of the current object within a collection being mapped. This key is only available if the current representation exists within a collection. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + ## Core Data + + `RKMapperOperation` supports mapping to Core Data target entities. To do so, it must be configured with an `RKManagedObjectMappingOperationDataSource` object as the data source. + */ +@interface RKMapperOperation : NSOperation + +///-------------------------------------- +/// @name Initializing a Mapper Operation +///-------------------------------------- + +/** + Initializes the operation with a source object and a mappings dictionary. + + @param representation An `NSDictionary` or `NSArray` of `NSDictionary` object representations to be mapped into local domain objects. + @param mappingsDictionary An `NSDictionary` wherein the keys are mappable key paths in `object` and the values are `RKMapping` objects specifying how the representations at its key path are to be mapped. + @return The receiver, initialized with the given object and and dictionary of key paths to mappings. + */ +- (instancetype)initWithRepresentation:(id)representation mappingsDictionary:(NSDictionary *)mappingsDictionary NS_DESIGNATED_INITIALIZER; + +///------------------------------------------ +/// @name Accessing Mapping Result and Errors +///------------------------------------------ + +/** + The error, if any, that occurred during the mapping process. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/** + The result of the mapping process. A `nil` value indicates that no mappable object representations were found and no mapping was performed. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + Returns a dictionary containing information about the mappings applied during the execution of the operation. The keys of the dictionary are keyPaths into the `mappingResult` for values that were mapped and the values are the corresponding `RKPropertyMapping` objects used to perform the mapping. + */ +@property (nonatomic, readonly) NSDictionary *mappingInfo; + +///------------------------------------- +/// @name Managing Mapping Configuration +///------------------------------------- + +/** + The representation of one or more objects against which the mapping is performed. + + Either an `NSDictionary` or an `NSArray` of `NSDictionary` objects. + */ +@property (nonatomic, strong, readonly) id representation; + +/** + A dictionary of key paths to `RKMapping` objects specifying how object representations in the `representation` are to be mapped. + + Please see the above discussion for in-depth details about the mappings dictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *mappingsDictionary; + +/** + The target object of the mapper. When configured, all object mapping will target the specified object. + + Please see the above discussion for details about target objects. + */ +@property (nonatomic, weak) id targetObject; + +/** + The data source for the underlying `RKMappingOperation` objects that perform the mapping work configured by the mapper. + */ +@property (nonatomic, strong) id<RKMappingOperationDataSource> mappingOperationDataSource; + +/** + The delegate for the mapper operation. + */ +@property (nonatomic, weak) id<RKMapperOperationDelegate> delegate; + +/** + A dictionary of metadata that is available for mappping by any mapping operation started by the receiver. + */ +@property (nonatomic, copy) NSDictionary *metadata; + +///------------------------------ +/// @name Executing the Operation +///------------------------------ + +/** + Executes the mapper operation to completion. + + @param error A pointer to an `NSError` object to set in the event an error occurs during execution. + @return A Boolean value that indicates if the operation completed successfully. + */ +- (BOOL)execute:(NSError **)error; + +@end + +///-------------------------------- +/// @name Mapper Operation Delegate +///-------------------------------- + +/** + Objects wishing to act as the delegate for `RKMapperOperation` objects must adopt the `RKMapperOperationDelegate` protocol. The protocol provides a rich set of optional callback methods that provides insight into the lifecycle of a mapper operation. + */ +@protocol RKMapperOperationDelegate <NSObject> + +@optional + +///----------------------------- +/// @name Tracking Mapper Status +///----------------------------- + +/** + Tells the delegate that the mapper operation is about to start mapping. + + @param mapper The mapper operation that is about to start mapping. + */ +- (void)mapperWillStartMapping:(RKMapperOperation *)mapper; + +/** + Tells the delegate that the mapper has finished. + + @param mapper The mapper operation that has finished mapping. + */ +- (void)mapperDidFinishMapping:(RKMapperOperation *)mapper; + +/** + Tells the delegate that the mapper has been cancelled. + + @param mapper The mapper operation that was cancelled. + */ +- (void)mapperDidCancelMapping:(RKMapperOperation *)mapper; + +///------------------------------- +/// @name Key Path Search Messages +///------------------------------- + +/** + Tells the delegate that the mapper has found one or more mappable object representations at a key path specified in the `mappingsDictionary`. + + @param mapper The mapper operation performing the mapping. + @param dictionaryOrArrayOfDictionaries The `NSDictictionary` or `NSArray` of `NSDictionary` object representations that was found at the `keyPath`. + @param keyPath The key path that the representation was read from in the `representation`. If the `keyPath` was `[NSNull null]` in the `mappingsDictionary`, it will be given as `nil` to the delegate. + */ +- (void)mapper:(RKMapperOperation *)mapper didFindRepresentationOrArrayOfRepresentations:(id)dictionaryOrArrayOfDictionaries atKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that the mapper failed to find any mappable object representations at a key path specified in the `mappingsDictionary`. + + @param mapper The mapper operation performing the mapping. + @param keyPath The key path that was searched for a mappable object representation. + */ +- (void)mapper:(RKMapperOperation *)mapper didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:(NSString *)keyPath; + +///---------------------------------------------- +/// @name Tracking Child Mapping Operation Status +///---------------------------------------------- + +/** + Tells the delegate that the mapper is about to start a mapping operation to map a representation found in the `representation`. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that is about to be started. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + */ +- (void)mapper:(RKMapperOperation *)mapper willStartMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that a mapping operation that was started by the mapper has finished executing. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that has finished. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + */ +- (void)mapper:(RKMapperOperation *)mapper didFinishMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that a mapping operation that was started by the mapper has failed with an error. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that has failed. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + @param error The error that occurred during the execution of the mapping operation. + */ +- (void)mapper:(RKMapperOperation *)mapper didFailMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath withError:(NSError *)error; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m new file mode 100644 index 0000000..db0cdcb --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m @@ -0,0 +1,446 @@ +// +// RKMapperOperation.m +// RestKit +// +// Created by Blake Watters on 5/6/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMapperOperation.h" +#import "RKMapperOperation_Private.h" +#import "RKObjectMapping.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKMappingErrors.h" +#import "RKDynamicMapping.h" +#import "RKLog.h" +#import "RKDictionaryUtilities.h" + +NSString * const RKMappingErrorKeyPathErrorKey = @"keyPath"; + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +static NSString *RKDelegateKeyPathFromKeyPath(NSString *keyPath) +{ + return ([keyPath isEqual:[NSNull null]]) ? nil : keyPath; +} + + +static NSString *RKFailureReasonErrorStringForMappingNotFoundError(id representation, NSDictionary *mappingsDictionary) +{ + NSMutableString *failureReason = [NSMutableString string]; + [failureReason appendFormat:@"The mapping operation was unable to find any nested object representations at the key paths searched: %@", [[[mappingsDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] componentsJoinedByString:@", "]]; + if ([representation respondsToSelector:@selector(allKeys)]) { + [failureReason appendFormat:@"\nThe representation inputted to the mapper was found to contain nested object representations at the following key paths: %@", [[[representation allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] componentsJoinedByString:@", "]]; + } + [failureReason appendFormat:@"\nThis likely indicates that you have misconfigured the key paths for your mappings."]; + return failureReason; +} + +// Duplicating interface from `RKMappingOperation.m` +@interface RKMappingSourceObject : NSObject +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata; +@end + +@interface RKMappingOperation (Private) +@property (nonatomic, readwrite, getter=isNewDestinationObject) BOOL newDestinationObject; +@end + +@interface RKMapperMetadata : NSObject +@property NSUInteger collectionIndex; +@property NSString *rootKeyPath; +@end + +@implementation RKMapperMetadata +- (id)valueForUndefinedKey:(NSString *)key { return nil; } +@end + +@interface RKMapperOperation () + +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong) NSMutableArray *mappingErrors; +@property (nonatomic, strong) id representation; +@property (nonatomic, strong, readwrite) NSDictionary *mappingsDictionary; +@property (nonatomic, strong) NSMutableDictionary *mutableMappingInfo; +@end + +@implementation RKMapperOperation + +- (instancetype)initWithRepresentation:(id)representation mappingsDictionary:(NSDictionary *)mappingsDictionary; +{ + self = [super init]; + if (self) { + self.representation = representation; + self.mappingsDictionary = mappingsDictionary; + self.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; + } + + return self; +} + +- (NSDictionary *)mappingInfo +{ + return self.mutableMappingInfo; +} + +#pragma mark - Errors + +- (NSArray *)errors +{ + return [NSArray arrayWithArray:self.mappingErrors]; +} + +- (void)addError:(NSError *)error +{ + NSAssert(error, @"Cannot add a nil error"); + [self.mappingErrors addObject:error]; +} + +- (void)addErrorWithCode:(RKMappingErrorCode)errorCode message:(NSString *)errorMessage keyPath:(NSString *)keyPath userInfo:(NSDictionary *)otherInfo +{ + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + errorMessage, NSLocalizedDescriptionKey, + keyPath ? keyPath : [NSNull null], RKMappingErrorKeyPathErrorKey, + nil]; + [userInfo addEntriesFromDictionary:otherInfo]; + NSError *error = [NSError errorWithDomain:RKErrorDomain code:errorCode userInfo:userInfo]; + [self addError:error]; + self.error = error; +} + +- (void)addErrorForUnmappableKeyPath:(NSString *)keyPath +{ + NSString *errorMessage = [NSString stringWithFormat:@"Could not find an object mapping for keyPath: '%@'", keyPath]; + [self addErrorWithCode:RKMappingErrorNotFound message:errorMessage keyPath:keyPath userInfo:nil]; +} + +- (BOOL)isNullCollection:(id)object +{ + // The purpose of this method is to guard against the case where we perform valueForKeyPath: on an array + // and it returns NSNull for each element in the array. + + // We consider an empty array/dictionary mappable, but a collection that contains only NSNull + // values is unmappable + if ([object respondsToSelector:@selector(objectForKey:)]) { + return NO; + } + + if ([object respondsToSelector:@selector(countForObject:)] && [object count] > 0) { + if ([object countForObject:[NSNull null]] == [object count]) { + RKLogDebug(@"Found a collection containing only `NSNull` values, considering the collection unmappable..."); + return YES; + } + } + + return NO; +} + +#pragma mark - Mapping Primitives + +// Maps a singular object representation +- (id)mapRepresentation:(id)representation atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + NSAssert([representation respondsToSelector:@selector(setValue:forKeyPath:)], @"Expected self.object to be KVC compliant"); + id destinationObject = nil; + BOOL isNewObject = NO; + + if (self.targetObject) { + destinationObject = self.targetObject; + RKObjectMapping *objectMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)mapping; + } else { + NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); + } + + if (NO == [[self.targetObject class] isSubclassOfClass:objectMapping.objectClass]) { + if ([_mappingsDictionary count] == 1) { + NSString *errorMessage = [NSString stringWithFormat: + @"Expected an object mapping for class of type '%@', provider returned one for '%@'", + NSStringFromClass([self.targetObject class]), NSStringFromClass(objectMapping.objectClass)]; + [self addErrorWithCode:RKMappingErrorTypeMismatch message:errorMessage keyPath:keyPath userInfo:nil]; + return nil; + } else { + // There is more than one mapping present. We are likely mapping secondary key paths to new objects + destinationObject = [self objectForRepresentation:representation withMapping:mapping]; + isNewObject = YES; + } + } + } else { + destinationObject = [self objectForRepresentation:representation withMapping:mapping]; + isNewObject = YES; + } + + if (mapping && destinationObject) { + NSArray *metadataList = [NSArray arrayWithObjects:@{ @"mapping": @{ @"rootKeyPath": keyPath } }, self.metadata, nil]; + BOOL success = [self mapRepresentation:representation toObject:destinationObject isNew:isNewObject atKeyPath:keyPath usingMapping:mapping metadataList:metadataList]; + if (success) { + return destinationObject; + } + } else { + // Attempted to map an object but couldn't find a mapping for the keyPath + [self addErrorForUnmappableKeyPath:keyPath]; + return nil; + } + + return nil; +} + +// Map a collection of object representations +- (NSArray *)mapRepresentations:(id)representations atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + NSAssert(representations != nil, @"Cannot map without an collection of mappable objects"); + NSAssert(mapping != nil, @"Cannot map without a mapping to consult"); + + NSArray *objectsToMap = representations; + if (mapping.forceCollectionMapping) { + // If we have forced mapping of a dictionary, map each subdictionary + if ([representations isKindOfClass:[NSDictionary class]]) { + RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); + objectsToMap = [NSMutableArray arrayWithCapacity:[representations count]]; + for (id key in representations) { + NSDictionary *dictionaryToMap = @{key: [representations valueForKey:key]}; + [(NSMutableArray *)objectsToMap addObject:dictionaryToMap]; + } + } else { + RKLogWarning(@"Collection mapping forced but representations is of type '%@' rather than NSDictionary", NSStringFromClass([representations class])); + } + } + + RKMapperMetadata *mappingData = [RKMapperMetadata new]; + mappingData.rootKeyPath = keyPath; + NSDictionary *metadata = @{ @"mapping": mappingData }; + NSArray *metadataList = [NSArray arrayWithObjects:metadata, self.metadata, nil]; + NSMutableArray *mappedObjects = [NSMutableArray arrayWithCapacity:[representations count]]; + [objectsToMap enumerateObjectsUsingBlock:^(id mappableObject, NSUInteger index, BOOL *stop) { + id destinationObject = [self objectForRepresentation:mappableObject withMapping:mapping]; + if (destinationObject) { + mappingData.collectionIndex = index; + BOOL success = [self mapRepresentation:mappableObject toObject:destinationObject isNew:YES atKeyPath:keyPath usingMapping:mapping metadataList:metadataList]; + if (success) [mappedObjects addObject:destinationObject]; + } + *stop = [self isCancelled]; + }]; + + return mappedObjects; +} + +// The workhorse of this entire process. Emits object loading operations +- (BOOL)mapRepresentation:(id)mappableObject toObject:(id)destinationObject isNew:(BOOL)newDestination atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping metadataList:(NSArray *)metadataList +{ + NSAssert(destinationObject != nil, @"Cannot map without a target object to assign the results to"); + NSAssert(mappableObject != nil, @"Cannot map without a collection of attributes"); + NSAssert(mapping != nil, @"Cannot map without an mapping"); + + RKLogDebug(@"Asked to map source object %@ with mapping %@", mappableObject, mapping); + + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:mappableObject destinationObject:destinationObject mapping:mapping metadataList:metadataList]; + mappingOperation.dataSource = self.mappingOperationDataSource; + mappingOperation.newDestinationObject = newDestination; + if ([self.delegate respondsToSelector:@selector(mapper:willStartMappingOperation:forKeyPath:)]) { + [self.delegate mapper:self willStartMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + [mappingOperation start]; + if (mappingOperation.error) { + if ([self.delegate respondsToSelector:@selector(mapper:didFailMappingOperation:forKeyPath:withError:)]) { + [self.delegate mapper:self didFailMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath) withError:mappingOperation.error]; + } + [self addError:mappingOperation.error]; + + return NO; + } else { + if ([self.delegate respondsToSelector:@selector(mapper:didFinishMappingOperation:forKeyPath:)]) { + [self.delegate mapper:self didFinishMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + if (mappingOperation.mappingInfo) { + id infoKey = keyPath ?: [NSNull null]; + NSMutableArray *infoForKeyPath = (self.mutableMappingInfo)[infoKey]; + if (infoForKeyPath) { + [infoForKeyPath addObject:mappingOperation.mappingInfo]; + } else { + infoForKeyPath = [NSMutableArray arrayWithObject:mappingOperation.mappingInfo]; + [self.mutableMappingInfo setValue:infoForKeyPath forKey:infoKey]; + } + } + + return YES; + } +} + +- (id)objectForRepresentation:(id)representation withMapping:(RKMapping *)mapping +{ + NSAssert([mapping isKindOfClass:[RKMapping class]], @"Expected an RKMapping object"); + NSAssert(self.mappingOperationDataSource, @"Cannot find or instantiate objects without a data source"); + + RKObjectMapping *objectMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + if (! objectMapping) { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned nil objectMapping", mapping, representation); + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)mapping; + } else { + NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); + } + + if (objectMapping) { + id object = nil; + if ([self.mappingOperationDataSource respondsToSelector:@selector(mappingOperation:targetObjectForMapping:inRelationship:)]) + { + object = [self.mappingOperationDataSource mappingOperation:nil targetObjectForMapping:objectMapping inRelationship:nil]; + } + if (object == nil) + { + // Ensure that we are working with a dictionary when we call down into the data source + NSDictionary *representationDictionary = [representation isKindOfClass:[NSDictionary class]] ? representation : @{ [NSNull null]: representation }; + id mappingSourceObject = [[RKMappingSourceObject alloc] initWithObject:representationDictionary parentObject:nil rootObject:representation metadata:self.metadata? @[self.metadata] : nil]; + object = [self.mappingOperationDataSource mappingOperation:nil targetObjectForRepresentation:mappingSourceObject withMapping:objectMapping inRelationship:nil]; + } + return object; + } + + return nil; +} + +- (id)mapRepresentationOrRepresentations:(id)mappableValue atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + id mappingResult; + if (mapping.forceCollectionMapping || [mappableValue isKindOfClass:[NSArray class]] || [mappableValue isKindOfClass:[NSSet class]]) { + RKLogDebug(@"Found mappable collection at keyPath '%@': %@", keyPath, mappableValue); + mappingResult = [self mapRepresentations:mappableValue atKeyPath:keyPath usingMapping:mapping]; + } else { + RKLogDebug(@"Found mappable data at keyPath '%@': %@", keyPath, mappableValue); + mappingResult = [self mapRepresentation:mappableValue atKeyPath:keyPath usingMapping:mapping]; + } + + return mappingResult; +} + +#pragma mark - + +- (NSMutableDictionary *)mapSourceRepresentationWithMappingsDictionary:(NSDictionary *)mappingsByKeyPath +{ + BOOL foundMappable = NO; + NSMutableDictionary *results = [NSMutableDictionary dictionary]; + for (NSString *keyPath in mappingsByKeyPath) { + if ([self isCancelled]) return nil; + + @autoreleasepool { + id mappingResult = nil; + id nestedRepresentation = nil; + + RKLogTrace(@"Examining keyPath '%@' for mappable content...", keyPath); + + if ([keyPath isEqual:[NSNull null]] || [keyPath isEqualToString:@""]) { + nestedRepresentation = self.representation; + } else { + nestedRepresentation = [self.representation valueForKeyPath:keyPath]; + } + + // Not found... + if (nestedRepresentation == nil || nestedRepresentation == [NSNull null] || [self isNullCollection:nestedRepresentation]) { + RKLogDebug(@"Found unmappable value at keyPath: %@", keyPath); + + if ([self.delegate respondsToSelector:@selector(mapper:didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:)]) { + [self.delegate mapper:self didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + continue; + } + + // Found something to map + foundMappable = YES; + RKMapping *mapping = mappingsByKeyPath[keyPath]; + if ([self.delegate respondsToSelector:@selector(mapper:didFindRepresentationOrArrayOfRepresentations:atKeyPath:)]) { + [self.delegate mapper:self didFindRepresentationOrArrayOfRepresentations:nestedRepresentation atKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + mappingResult = [self mapRepresentationOrRepresentations:nestedRepresentation atKeyPath:keyPath usingMapping:mapping]; + + if (mappingResult) { + results[keyPath] = mappingResult; + } + } + } + + if (NO == foundMappable) return nil; + return results; +} + +- (void)cancel +{ + [super cancel]; + RKLogDebug(@"%@:%p received `cancel` message: cancelling mapping...", [self class], self); + + if ([self.delegate respondsToSelector:@selector(mapperDidCancelMapping:)]) { + [self.delegate mapperDidCancelMapping:self]; + } +} + +- (void)main +{ + NSAssert(self.representation != nil, @"Cannot perform object mapping without a source object to map from"); + NSAssert(self.mappingsDictionary, @"Cannot perform object mapping without a dictionary of mappings"); + + if ([self isCancelled]) return; + self.mutableMappingInfo = [NSMutableDictionary dictionary]; + self.mappingErrors = [NSMutableArray new]; + + RKLogDebug(@"Executing mapping operation for representation: %@\n and targetObject: %@", self.representation, self.targetObject); + + if ([self.delegate respondsToSelector:@selector(mapperWillStartMapping:)]) { + [self.delegate mapperWillStartMapping:self]; + } + + // Perform the mapping + BOOL foundMappable = NO; + NSMutableDictionary *results = [self mapSourceRepresentationWithMappingsDictionary:self.mappingsDictionary]; + if ([self isCancelled]) return; + foundMappable = (results != nil); + + // If we found nothing eligible for mapping in the content, add an unmappable key path error and fail mapping + // If the content is empty, we don't consider it an error + BOOL isEmpty = [self.representation respondsToSelector:@selector(count)] && ([self.representation count] == 0); + if (foundMappable == NO && !isEmpty) { + NSMutableDictionary *userInfo = [@{ NSLocalizedDescriptionKey: NSLocalizedString(@"No mappable object representations were found at the key paths searched.", nil), + NSLocalizedFailureReasonErrorKey: RKFailureReasonErrorStringForMappingNotFoundError(self.representation, self.mappingsDictionary), + RKMappingErrorKeyPathErrorKey: [NSNull null], + RKDetailedErrorsKey: self.errors} mutableCopy]; + NSError *compositeError = [[NSError alloc] initWithDomain:RKErrorDomain code:RKMappingErrorNotFound userInfo:userInfo]; + self.error = compositeError; + } else { + if (results) self.mappingResult = [[RKMappingResult alloc] initWithDictionary:results]; + } + + RKLogDebug(@"Finished performing object mapping. Results: %@", results); + if ([self.delegate respondsToSelector:@selector(mapperDidFinishMapping:)]) { + [self.delegate mapperDidFinishMapping:self]; + } +} + +- (BOOL)execute:(NSError **)error +{ + [self start]; + if (error) *error = self.error; + return self.mappingResult != nil; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h new file mode 100644 index 0000000..0804dcf --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1,28 @@ +// +// RKMapperOperation_Private.h +// RestKit +// +// Created by Blake Watters on 5/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +@interface RKMapperOperation (Private) + +- (id)mapRepresentation:(id)mappableObject atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping; +- (NSArray *)mapRepresentations:(NSArray *)mappableObjects atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping; +- (BOOL)mapRepresentation:(id)mappableObject toObject:(id)destinationObject isNew:(BOOL)isNew atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping metadataList:(NSArray *)metadata; +- (id)objectForRepresentation:(id)representation withMapping:(RKMapping *)mapping; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.h new file mode 100644 index 0000000..b3a969d --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.h @@ -0,0 +1,62 @@ +// +// RKMapping.h +// RestKit +// +// Created by Blake Watters on 7/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + `RKMapping` is an abstract class for objects defining RestKit object mappings. Its interface is common to all object mapping classes, including its concrete subclasses `RKObjectMapping` and `RKDynamicMapping`. + */ +@interface RKMapping : NSObject + +///--------------------------------- +/// @name Forcing Collection Mapping +///--------------------------------- + +/** + Forces the mapper to treat the mapped keyPath as a collection even if it does not return an array or a set of objects. This permits mapping where a dictionary identifies a collection of objects. + + When enabled, each key/value pair in the resolved dictionary will be mapped as a separate entity. This is useful when you have a JSON structure similar to: + + { "users": { + "blake": { "id": 1234, "email": "blake@restkit.org" }, + "rachit": { "id": 5678, "email": "rachit@restkit.org" } + } + } + + By enabling `forceCollectionMapping`, RestKit will map "blake" => attributes and "rachit" => attributes as independent objects. This can be combined with `mapKeyOfNestedDictionaryToAttribute:` to properly map these sorts of structures. + + @default `NO` + @see `mapKeyOfNestedDictionaryToAttribute` + */ +@property (nonatomic, assign) BOOL forceCollectionMapping; + + +///------------------------- +/// @name Comparing Mappings +///------------------------- + +/** + Returns `YES` if the receiver and the specified mapping are considered equivalent. + + **NOTE**: Must be implemented in subclass. + */ +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.m new file mode 100644 index 0000000..9f60f3b --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMapping.m @@ -0,0 +1,22 @@ +// +// RKMapping.m +// RestKit +// +// Created by Blake Watters on 2/15/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "RKMapping.h" + +@implementation RKMapping + +@synthesize forceCollectionMapping; + +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h new file mode 100644 index 0000000..794e703 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h @@ -0,0 +1,37 @@ +// +// RKMappingErrors.h +// RestKit +// +// Created by Blake Watters on 5/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrors.h" + +typedef UInt32 RKMappingErrorCode; +enum { + RKMappingErrorNotFound = 1001, // No mapping found + RKMappingErrorTypeMismatch = 1002, // Target class and object mapping are in disagreement + RKMappingErrorUnmappableRepresentation = 1003, // No values were found at the key paths of any attribute or relationship mappings in the given representation + RKMappingErrorFromMappingResult = 1004, // The error was returned from the mapping result + RKMappingErrorValidationFailure = 1005, // Generic error code for use when constructing validation errors + RKMappingErrorUnableToDetermineMapping = 1006, // The mapping operation was unable to obtain a concrete object mapping from a given dynamic mapping + RKMappingErrorNilDestinationObject = 1007, // The mapping operation failed due to a nil destination object. + RKMappingErrorNilManagedObjectCache = 1008, // A managed object cache is required to satisfy the mapping, but none was given. + RKMappingErrorMappingDeclined = 1009, // Mapping was declined by a callback. + RKMappingErrorInvalidAssignmentPolicy = 1010, // The assignment policy for the relationship is invalid. +}; + +extern NSString * const RKMappingErrorKeyPathErrorKey; // The key path the error is associated with diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h new file mode 100644 index 0000000..7c5d782 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h @@ -0,0 +1,390 @@ +// +// RKMappingOperation.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMapping.h" +#import "RKAttributeMapping.h" + +@class RKMappingOperation, RKDynamicMapping, RKConnectionDescription, RKMappingInfo; +@protocol RKMappingOperationDataSource; + +/** + Objects acting as the delegate for `RKMappingOperation` objects must adopt the `RKMappingOperationDelegate` protocol. These methods enable the delegate to be notified of events such as the application of attribute and relationship mappings during a mapping operation. + */ +@protocol RKMappingOperationDelegate <NSObject> + +///--------------------------------------- +/// @name Tracking Property Mapping Events +///--------------------------------------- + +@optional + +/** + Tells the delegate that an attribute or relationship mapping was found for a given key path within the data being mapped. + + @param operation The object mapping operation being performed. + @param keyPath The key path in the source object for which the mapping is to be applied. + @param value The value that was found at the given key path in the source object representation. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` for which the mappable value was found within the source object representation. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFindValue:(id)value forKeyPath:(NSString *)keyPath mapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that no attribute or relationships mapping was found for a given key path within the data being mapped. + + @param operation The object mapping operation being performed. + @param keyPath The key path in the source object for which no mappable value was found. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` for which no mappable value could be found within the source object representation. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didNotFindValueForKeyPath:(NSString *)keyPath mapping:(RKPropertyMapping *)propertyMapping; + +/** + Asks the delegate if the mapping operation should set a value for a given key path with an attribute or relationship mapping. This method is invoked before the value is set. If the delegate does not implement this method, then the mapping operation will determine if the value should be set by comparing the current property value with the new property value. + + @param operation The object mapping operation being performed. + @param value A new value that was set on the destination object. + @param keyPath The key path in the destination object for which a new value has been set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + @return `YES` if the operation should set the proposed value for the key path, else `NO`. + */ +- (BOOL)mappingOperation:(RKMappingOperation *)operation shouldSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has set a value for a given key path with an attribute or relationship mapping. + + @param operation The object mapping operation being performed. + @param value A new value that was set on the destination object. + @param keyPath The key path in the destination object for which a new value has been set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has declined to set a value for a given key path because the value has not changed. + + @param operation The object mapping operation being performed. + @param value A unchanged value for the key path in the destination object. + @param keyPath The key path in the destination object for which a unchanged value was not set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didNotSetUnchangedValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has failed due to an error. + + @param operation The object mapping operation that has failed. + @param error An error object indicating the reason for the failure. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFailWithError:(NSError *)error; + +///----------------------------------------- +/// @name Tracking Dynamic Mapping Selection +///----------------------------------------- + +/** + Tells the delegate that the mapping operation has selected a concrete object mapping with which to map the source object. + + Only sent if the receiver was initialized with an instance of `RKDynamicMapping` as the mapping. + + @param operation The mapping operation. + @param objectMapping The concrete object mapping with which to perform the mapping. + @param dynamicMapping The dynamic source mapping from which the object mapping was determined. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didSelectObjectMapping:(RKObjectMapping *)objectMapping forDynamicMapping:(RKDynamicMapping *)dynamicMapping; + +#ifdef _COREDATADEFINES_H + +///---------------------------------------- +/// @name Tracking Relationship Connections +///---------------------------------------- + +/** + Tells the delegate that the mapping operation has connected a relationship. + + Only sent when mapping an `RKEntityMapping` object that contains connection mappings. + + @param operation The mapping operation. + @param relationship The relationship that was connected. + @param value The value that was connected to the relationship + @param connection The connection object describing how the relationship was to be connected. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didConnectRelationship:(NSRelationshipDescription *)relationship toValue:(id)value usingConnection:(RKConnectionDescription *)connection; + +/** + Tells the delegate that the mapping operation failed to connect a relationship. + + Only sent when mapping an `RKEntityMapping` object that contains connection mappings. + + @param operation The mapping operation. + @param relationship The relationship that was connected. + @param connection The connection object describing how the relationship was to be connected. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFailToConnectRelationship:(NSRelationshipDescription *)relationship usingConnection:(RKConnectionDescription *)connection; + +#endif + +@end + +/** + Instances of `RKMappingOperation` perform transformation between object representations according to the rules expressed in `RKObjectMapping` objects. Mapping operations provide the foundation for the RestKit object mapping engine and perform the work of inspecting the attributes and relationships of a source object and determining how to map them into new representations on a destination object. + + ## Metadata Mapping + + The mapping operation provides support for mapping for a dictionary of metadata in addition to the source object. This metadata is made available by mapping key paths nested under a specially designated parent key that cannot exist in a source representation. By convention, metadata is typically nested under sub keys to effectively namespace usage between components. The object mapping engine itself reserves the 'mapping' key for its usage. Metadata is passed down through a hierarchy of mapping operations (i.e. as relationships are traversed), making a common set of ancillary information available for mapping for by any operation executed. + + To understand how metadata works, consider the following example: + + @interface RKMetadataExample : NSObject + @property (nonatomic, copy) NSString *name; + @property (nonatomic, copy) NSURL *URL; + @property (nonatomic, copy) NSDate *mappedAt; + @end + + RKMetadataExample *example = [RKMetadataExample new]; + NSDictionary *representation = @{ @"name": @"Blake Watters" }; + NSDictionary *metadata = @{ @"URL": [NSURL URLWithString:@"http://restkit.org"] }; + + RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKMetadataExample class]]; + [objectMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.URL": @"URL" }]; + + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:example mapping:objectMapping]; + mappingOperation.metadata = metadata; + + NSError *error = nil; + BOOL success = [mappingOperation execute:&error]; + + Note the use of the special key path `@"@metadata.URL"`. The `@metadata` prefix indicates that the property is to be mapped from the metadata dictionary instead of from the source object representation. If any relationships were mapped, it would have access to this same metadata information as well. + + In addition to any metadata provided to the mapping operation via the `metadata` property, the operation itself makes the following metadata key paths available for mapping: + + 1. `@metadata.mapping.collectionIndex` - An `NSNumber` object specifying the index of the current object within a collection being mapped. This key is only available if the current representation exists within a collection. + 1. `@metadata.mapping.parentObject` - The direct parent object of the object that is currently being mapped. This key is only available for objects that are mapped as relationships of a parent object. + + ## Traversing the Representation Hierarchy + + In certain mapping scenarios it can become desirable to access ancestors of the current source object. For example, consider the following example JSON: + + { + "user": { + "id": 1, + "name": "Blake Watters", + "preferences": [ + { + { + "name": "push_notifications_enabled", + "value": true, + }, + { + "name": "subscribed_to_mailing_list", + "value": false + } + } + ] + } + } + + And it's corresponding model: + + @interface RKPreferenceExample : NSObject + @property (nonatomic, strong) NSNumber *userID; + @property (nonatomic, copy) NSString *name; + @property (nonatomic, strong) id value; + @end + + Notice that `userID` is a field that we wish to model as part of our local `RKPreferenceExample` class, but its not available within the `@"preferences"` key path that our + mapping will target. In this case we'd up like to reach "up" in the parsed JSON hierarchy to access our parent node, as demonstrated in the following mapping: + + RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKPreferenceExample class]]; + [objectMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"value": @"value", @"@parent.id": @"userID" }]; + + Note the use of the `@parent` key in the final attribute mapping: this pseudo-key always points to the direct parent node of the representation being mapped (or `nil` if there is none). Parent access can be chained to traverse upward all the way to the root node of the representation. + + ### Representation Traversal Keys + + There are currently two keys provided for traversing the representation hierarchy: + + 1. `@"root"` - Returns the root node of the representation being mapped. When a large JSON document is being mapped by an instance of `RKMapperOperation` this will point to the parsed JSON document that was used to initialize the operation. + 1. `@"parent"` - Returns the direct parent node of the `sourceObject` being mapped or `nil` if the `sourceObject` is itself a root node. + */ +@interface RKMappingOperation : NSObject + +///--------------------------------------- +/// @name Initializing a Mapping Operation +///--------------------------------------- + +/** + Initializes the receiver with a source object, a destination object and an object mapping with which to perform an object mapping. + + @param sourceObject The source object to be mapped. Cannot be `nil`. + @param destinationObject The destination object the results are to be mapped onto. May be `nil`, in which case a new object target object will be obtained from the `dataSource`. + @param objectOrDynamicMapping An instance of `RKObjectMapping` or `RKDynamicMapping` defining how the mapping is to be performed. + @return The receiver, initialized with a source object, a destination object, and a mapping. + */ +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping; + +/** + Initializes the receiver with a source object, a destination object and an object mapping with which to perform an object mapping, and metadata information to be made available to the mapping. + + @param sourceObject The source object to be mapped. Cannot be `nil`. + @param destinationObject The destination object the results are to be mapped onto. May be `nil`, in which case a new object target object will be obtained from the `dataSource`. + @param objectOrDynamicMapping An instance of `RKObjectMapping` or `RKDynamicMapping` defining how the mapping is to be performed. + @param metadataList A list of objects (usually dictionaries) which provide metadata to the operation, available via the @metadata key in mapping paths. Each object should respond to -valueForKeyPath:, and return nil if the requested key path is not represented in the object (in which case the following object in the list will be consulted). + @return The receiver, initialized with a source object, a destination object, and a mapping. + */ +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping metadataList:(NSArray *)metadataList; + +///-------------------------------------- +/// @name Accessing Mapping Configuration +///-------------------------------------- + +/** + A dictionary of mappable elements containing simple values or nested object structures. + */ +@property (nonatomic, strong, readonly) id sourceObject; + +/** + The target object for this operation. Mappable values in the source object will be applied to the destination object using key-value coding. + + If initialized with a `nil` destination object, the mapping operation will attempt to find or create a destination object via the data source and will populate the value of the `destinationObject` property. + */ +@property (nonatomic, strong, readonly) id destinationObject; + +/** + Property which is `YES` when the destinationObject was provided from the data source, and `NO` when the destination object was provided externally to the operation. + */ +@property (nonatomic, readonly, getter=isNewDestinationObject) BOOL newDestinationObject; + +/** + The mapping defining how values contained in the source object should be transformed to the destination object via key-value coding. + + Will either be an instance of `RKObjectMapping` or `RKDynamicMapping`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The concrete object mapping for the operation. + + If the value of `mapping` is an `RKObjectMapping`, returns the same value as `mapping`. If `mapping` is an `RKDynamicMapping`, then returns the concrete `RKObjectMapping` object selected for mapping `sourceObject`. + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +/** + A list of metadata objects available for mapping in addition to the source object. + */ +@property (nonatomic, strong, readonly) NSArray *metadataList; + +///------------------------------------------- +/// @name Configuring Delegate and Data Source +///------------------------------------------- + +/** + The delegate to inform of interesting events during the mapping operation lifecycle. + */ +@property (nonatomic, weak) id<RKMappingOperationDelegate> delegate; + +/** + The data source is responsible for providing the mapping operation with an appropriate target object for mapping when the `destinationObject` is `nil`. + + @see `RKMappingOperationDataSource` + */ +@property (nonatomic, weak) id<RKMappingOperationDataSource> dataSource; + +///-------------------------------- +/// @name Accessing Mapping Details +///-------------------------------- + +/** + The error, if any, that occurred during the execution of the mapping operation. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/** + Returns a dictionary containing information about the mappings applied during the execution of the operation. The keys of the dictionary are key paths into the `destinationObject` for values that were mapped and the values are instances of `RKMappingDetails` that specify the object mapping and property mappings that were applied. + + Mapping info is aggregated for all child mapping operations executed for relationships. + */ +@property (nonatomic, readonly) RKMappingInfo *mappingInfo; + +/** + Property to indicate whether this operation has been cancelled or not. It will be `NO` until `-cancel` is called, after which it will return `YES`. + */ +@property (nonatomic, readonly, getter=isCancelled) BOOL cancelled; + +/** + Cancels the operation, by setting the `cancelled` property to `YES`. Various steps of the process check the `cancelled` property and will abort when it gets set. + */ +- (void)cancel; + +///------------------------- +/// @name Performing Mapping +///------------------------- + +/** + Process all mappable values from the mappable dictionary and assign them to the target object according to the rules expressed in the object mapping definition. The error properties need to be checked to see if the operation was successful. + */ +- (void)start; + +/** + Process all mappable values from the mappable dictionary and assign them to the target object according to the rules expressed in the object mapping definition. + + @param error A pointer to an `NSError` reference to capture any error that occurs during the mapping. May be `nil`. + @return A Boolean value indicating if the mapping operation was successful. + */ +- (BOOL)performMapping:(NSError **)error; + +@end + +/** + Specifies the concrete object mapping and collection of property mappings that were applied for a given key path during the execution of an `RKMappingOperation`. + */ +@interface RKMappingInfo : NSObject + +/** + The mapping that was applied. + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +/** + The dynamic mapping, if any, that was used to perform the mapping. + */ +@property (nonatomic, strong, readonly) RKDynamicMapping *dynamicMapping; + +/** + The set of property mappings that were applied from the mapping. An empty set indicates that the mapping matched the representation, but all values were unchanged and thus no properties were set. + */ +@property (nonatomic, readonly) NSSet *propertyMappings; + +/** + A dictionary whose keys are the destination key path for a mapped relationship and the value is an array of `RKMappingInfo` objects specifying the mapping details for each item within the collection. + */ +@property (nonatomic, readonly) NSDictionary *relationshipMappingInfo; + +///-------------------------------------- +/// @name Accessing Property by Subscript +///-------------------------------------- + +/** + Retrieves the property mapping with the specified destination key path. + + @param key An `NSString` object specifying the destination key path for the property that is to be retrieved. + @return The `RKPropertyMapping` with the specified destination key path or `nil` if none was found. + */ +- (id)objectForKeyedSubscript:(id)key; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m new file mode 100644 index 0000000..61b85e8 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m @@ -0,0 +1,1260 @@ +// +// RKMappingOperation.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKMappingOperation.h" +#import "RKMappingErrors.h" +#import "RKPropertyInspector.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKErrors.h" +#import "RKLog.h" +#import "RKMappingOperationDataSource.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKDynamicMapping.h" +#import "RKObjectUtilities.h" +#import "RKValueTransformers.h" +#import "RKDictionaryUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +#pragma mark - Mapping utilities + +extern NSString * const RKObjectMappingNestingAttributeKeyName; + +/** + This function ensures that attribute mappings apply cleanly to an `NSMutableDictionary` target class to support mapping to nested keyPaths. See issue #882 + */ +static void RKSetIntermediateDictionaryValuesOnObjectForKeyPath(id object, NSString *keyPath) +{ + if (! [object isKindOfClass:[NSMutableDictionary class]]) return; + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + if ([keyPathComponents count] > 1) { + for (NSUInteger index = 0; index < [keyPathComponents count] - 1; index++) { + NSString *intermediateKeyPath = [[keyPathComponents subarrayWithRange:NSMakeRange(0, index + 1)] componentsJoinedByString:@"."]; + if (! [object valueForKeyPath:intermediateKeyPath]) { + [object setValue:[NSMutableDictionary dictionary] forKeyPath:intermediateKeyPath]; + } + } + } +} + +static BOOL RKIsManagedObject(id object) +{ + Class managedObjectClass = NSClassFromString(@"NSManagedObject"); + return managedObjectClass && [object isKindOfClass:managedObjectClass]; +} + +// Returns the appropriate value for `nil` value of a primitive type +static id RKPrimitiveValueForNilValueOfClass(Class keyValueCodingClass) +{ + if ([keyValueCodingClass isSubclassOfClass:[NSNumber class]]) { + return @0; + } else { + return nil; + } +} + +// Key comes from: nestedAttributeSubstitutionKey AND nestedAttributeSubstitutionValue; +NSArray *RKApplyNestingAttributeValueToMappings(NSString *attributeName, id value, NSArray *propertyMappings); +NSArray *RKApplyNestingAttributeValueToMappings(NSString *attributeName, id value, NSArray *propertyMappings) +{ + if (!attributeName) return propertyMappings; + + NSString *searchString = [NSString stringWithFormat:@"{%@}", attributeName]; + NSString *replacementString = [NSString stringWithFormat:@"%@", value]; + NSMutableArray *nestedMappings = [NSMutableArray arrayWithCapacity:[propertyMappings count]]; + for (RKPropertyMapping *propertyMapping in propertyMappings) { + NSString *sourceKeyPath = [propertyMapping.sourceKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; + NSString *destinationKeyPath = [propertyMapping.destinationKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; + RKPropertyMapping *nestedPropertyMapping = nil; + if ([propertyMapping isKindOfClass:[RKAttributeMapping class]]) { + nestedPropertyMapping = [RKAttributeMapping attributeMappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath]; + } else if ([propertyMapping isKindOfClass:[RKRelationshipMapping class]]) { + nestedPropertyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:sourceKeyPath + toKeyPath:destinationKeyPath + withMapping:[(RKRelationshipMapping *)propertyMapping mapping]]; + } + nestedPropertyMapping.propertyValueClass = propertyMapping.propertyValueClass; + nestedPropertyMapping.valueTransformer = propertyMapping.valueTransformer; + if (nestedPropertyMapping) [nestedMappings addObject:nestedPropertyMapping]; + } + + return nestedMappings; +} + +// Returns YES if there is a value present for at least one key path in the given collection +static BOOL RKObjectContainsValueForMappings(id representation, NSArray *propertyMappings) +{ + for (RKPropertyMapping *mapping in propertyMappings) { + NSString *keyPath = mapping.sourceKeyPath; + if (keyPath && [representation valueForKeyPath:keyPath]) return YES; + } + return NO; +} + +#pragma mark - Metadata utilities + +static NSString *const RKMetadataKey = @"@metadata"; +static NSString *const RKMetadataKeyPathPrefix = @"@metadata."; +static NSString *const RKParentKey = @"@parent"; +static NSString *const RKParentKeyPathPrefix = @"@parent."; +static NSString *const RKRootKey = @"@root"; +static NSString *const RKRootKeyPathPrefix = @"@root."; +static NSString *const RKSelfKey = @"self"; +static NSString *const RKSelfKeyPathPrefix = @"self."; + +/** + Inserts up to two objects a the start of the metadata list. metadata1 will be at the front if both are provided. + */ +static NSArray *RKInsertInMetadataList(NSArray *list, id metadata1, id metadata2) +{ + if (metadata1 == nil && metadata2 == nil) + return list; + NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:list]; + if (metadata2) + [newArray insertObject:metadata2 atIndex:0]; + if (metadata1) + [newArray insertObject:metadata1 atIndex:0]; + return newArray; +} + +@interface RKMappingSourceObject : NSObject +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata; +- (id)metadataValueForKey:(NSString *)key; +- (id)metadataValueForKeyPath:(NSString *)keyPath; +@end + +/** + Class used in the single case of RKMappingSourceObject needing to return a single object + for the "@metadata" key, which a special implementation of -valueForKeyPath: + to iterate over the list of metadata dictionaries (which RKMappingSourceObject usually does). + This usually only happens from the parentObjectForRelationshipMapping: implementation, but + in case it does this class provides the implementation. + */ +@interface RKMetadataWrapper : NSObject +- (instancetype)initWithMappingSource:(RKMappingSourceObject *)source NS_DESIGNATED_INITIALIZER; +@property (nonatomic, strong) RKMappingSourceObject *mappingSource; +@end + +@implementation RKMetadataWrapper + +- (instancetype)initWithMappingSource:(RKMappingSourceObject *)source { + if (self = [super init]) { + self.mappingSource = source; + } + return self; +} + +- (id)valueForKey:(NSString *)key +{ + return [self.mappingSource metadataValueForKey:key]; +} +- (id)valueForKeyPath:(NSString *)keyPath +{ + return [self.mappingSource metadataValueForKeyPath:keyPath]; +} +@end + +/** + Class meant to represent parts of the "mapping" sub-dictionary of the "@metadata" keys, but + being more efficient to create than actual NSDictionary instances. We can add any object properties + to this class, and if non-nil that value will be used, otherwise it is a passthrough. + */ +@interface RKMappingMetadata : NSObject +@property (nonatomic) BOOL inValueForKeyPath; +@property (nonatomic) id parentObject; +@end + +@implementation RKMappingMetadata + +- (id)valueForKeyPath:(NSString *)keyPath +{ + static NSString *mappingPrefix = @"mapping."; + + /* We only allow paths with a "mapping." prefix, to simulate being a nested object */ + if ([keyPath hasPrefix:mappingPrefix]) { + self.inValueForKeyPath = YES; + id value = [super valueForKeyPath:[keyPath substringFromIndex:[mappingPrefix length]]]; + self.inValueForKeyPath = NO; + return value; + } + + return nil; +} + +/* Only return values from valueForKey: if we are being routed from valueForKeyPath:. This + avoids us from returning value values from say "@metadata.collectionIndex" without the mapping prefix. + */ +- (id)valueForKey:(NSString *)key +{ + return self.inValueForKeyPath? [super valueForKey:key] : nil; +} + +/* Return nil for any unknown keys, so the next object in the metadata list gets checked */ +- (id)valueForUndefinedKey:(NSString *)key +{ + return nil; +} + +@end + +/** + Subclass of RKMappingMetadata for use for holding the collectionIndex during a to-many mapping operation. + Needs to be a subclass since the scalar property cannot return nil from valueForKey, so this can only + be used when the collectionIndex is definitely set. + */ +@interface RKMappingIndexMetadata : RKMappingMetadata +@property (nonatomic) NSUInteger collectionIndex; +@end + +@implementation RKMappingIndexMetadata +@end + + +@interface RKMappingSourceObject () +@property (nonatomic, strong) id object; +@property (nonatomic, strong) id parentObject; +@property (nonatomic, strong) id rootObject; +@property (nonatomic, strong) NSArray *metadataList; +@end + +@implementation RKMappingSourceObject + +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata +{ + self = [self init]; + if (self) { + _object = object; + _parentObject = parentObject; + _rootObject = rootObject; + _metadataList = metadata; + } + return self; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector +{ + return [_object methodSignatureForSelector:selector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + [invocation invokeWithTarget:_object]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _object; +} + +- (id)metadataValueForKey:(NSString *)key +{ + for (NSDictionary *dict in self.metadataList) + { + id val = [dict valueForKey:key]; + if (val != nil) return val; + } + + return nil; +} + +- (id)metadataValueForKeyPath:(NSString *)keyPath +{ + for (NSDictionary *dict in self.metadataList) + { + id val = [dict valueForKeyPath:keyPath]; + if (val != nil) return val; + } + + return nil; +} + +- (id)valueForKey:(NSString *)key +{ + /* Using firstChar as a small performance enhancement -- one check can avoid several isEqual: calls */ + unichar firstChar = [key length] > 0 ? [key characterAtIndex:0] : 0; + + if (firstChar == 's' && [key isEqualToString:RKSelfKey]) { + return _object; + } else if (firstChar != '@') { + return [_object valueForKey:key]; + } else if ([key isEqualToString:RKMetadataKey]) { + return [[RKMetadataWrapper alloc] initWithMappingSource:self]; + } else if ([key isEqualToString:RKParentKey]) { + return self.parentObject; + } else if ([key isEqualToString:RKRootKey]) { + return self.rootObject; + } else { + return [_object valueForKey:key]; + } +} + +/** + NOTE: We implement `valueForKeyPath:` on the proxy instead of using `forwardInvocation:` because the OS X runtime fails to appropriately handle scalar boxing/unboxing, resulting in incorrect metadata mappings. Proxying the method directly produces the expected results on both OS X and iOS [sbw - 2/1/2012] + */ +- (id)valueForKeyPath:(NSString *)keyPath +{ + /* Using firstChar as a small performance enhancement -- one check can avoid several hasPrefix calls */ + unichar firstChar = [keyPath length] > 0 ? [keyPath characterAtIndex:0] : 0; + + if (firstChar == 's' && [keyPath hasPrefix:RKSelfKeyPathPrefix]) { + NSString *selfKeyPath = [keyPath substringFromIndex:[RKSelfKeyPathPrefix length]]; + return [_object valueForKeyPath:selfKeyPath]; + } else if (firstChar != '@') { + return [_object valueForKeyPath:keyPath]; + } else if ([keyPath hasPrefix:RKMetadataKeyPathPrefix]) { + NSString *metadataKeyPath = [keyPath substringFromIndex:[RKMetadataKeyPathPrefix length]]; + return [self metadataValueForKeyPath:metadataKeyPath]; + } else if ([keyPath hasPrefix:RKParentKeyPathPrefix]) { + NSString *parentKeyPath = [keyPath substringFromIndex:[RKParentKeyPathPrefix length]]; + return [self.parentObject valueForKeyPath:parentKeyPath]; + } else if ([keyPath hasPrefix:RKRootKeyPathPrefix]) { + NSString *rootKeyPath = [keyPath substringFromIndex:[RKRootKeyPathPrefix length]]; + return [self.rootObject valueForKeyPath:rootKeyPath]; + } else { + return [_object valueForKeyPath:keyPath]; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ (%@)", [self.object description], self.metadataList]; +} + +- (Class)class +{ + return [_object class]; +} + +- (BOOL)isKindOfClass:(Class)aClass +{ + return [_object isKindOfClass:aClass]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + return [_object respondsToSelector:aSelector]; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol +{ + return [_object conformsToProtocol:aProtocol]; +} + +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive +{ + return [_object rk_classForPropertyAtKeyPath:keyPath isPrimitive:isPrimitive]; +} + +@end + + +#pragma mark - RKMappingInfo + +@interface RKMappingInfo () +@property (nonatomic, assign, readwrite) NSUInteger collectionIndex; +@property (nonatomic, strong) NSMutableSet *mutablePropertyMappings; +@property (nonatomic, strong) NSMutableDictionary *mutableRelationshipMappingInfo; + +- (instancetype)initWithObjectMapping:(RKObjectMapping *)objectMapping dynamicMapping:(RKDynamicMapping *)dynamicMapping; +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping; +@end + +@implementation RKMappingInfo + +- (instancetype)initWithObjectMapping:(RKObjectMapping *)objectMapping dynamicMapping:(RKDynamicMapping *)dynamicMapping +{ + self = [self init]; + if (self) { + _objectMapping = objectMapping; + _dynamicMapping = dynamicMapping; + _mutablePropertyMappings = [NSMutableSet setWithCapacity:[objectMapping.propertyMappings count]]; + _mutableRelationshipMappingInfo = [NSMutableDictionary dictionaryWithCapacity:[objectMapping.relationshipMappings count]]; + } + return self; +} + +- (NSSet *)propertyMappings +{ + return [self.mutablePropertyMappings copy]; +} + +- (NSDictionary *)relationshipMappingInfo +{ + return [self.mutableRelationshipMappingInfo copy]; +} + +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping +{ + [self.mutablePropertyMappings addObject:propertyMapping]; +} + +- (void)addMappingInfo:(RKMappingInfo *)mappingInfo forRelationshipMapping:(RKRelationshipMapping *)relationshipMapping +{ + NSMutableArray *arrayOfMappingInfo = (self.mutableRelationshipMappingInfo)[relationshipMapping.destinationKeyPath]; + if (arrayOfMappingInfo) { + [arrayOfMappingInfo addObject:mappingInfo]; + } else { + arrayOfMappingInfo = [NSMutableArray arrayWithObject:mappingInfo]; + (self.mutableRelationshipMappingInfo)[relationshipMapping.destinationKeyPath] = arrayOfMappingInfo; + } +} + +- (id)objectForKeyedSubscript:(id)key +{ + for (RKPropertyMapping *propertyMapping in self.mutablePropertyMappings) { + if ([propertyMapping.destinationKeyPath isEqualToString:key]) { + return propertyMapping; + } + } + return nil; +} + +@end + +#pragma mark - RKMappingOperation + +@interface RKMappingOperation () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, strong, readwrite) id sourceObject; +@property (nonatomic, strong, readwrite) id parentSourceObject; +@property (nonatomic, strong, readwrite) id rootSourceObject; +@property (nonatomic, strong, readwrite) id destinationObject; +@property (nonatomic, strong, readwrite) NSArray *metadataList; +@property (nonatomic, strong) NSString *nestedAttributeSubstitutionKey; +@property (nonatomic, strong) id nestedAttributeSubstitutionValue; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKObjectMapping *objectMapping; // The concrete mapping +@property (nonatomic, strong) NSArray *nestedAttributeMappings; +@property (nonatomic, strong) NSArray *simpleAttributeMappings; +@property (nonatomic, strong) NSArray *keyPathAttributeMappings; +@property (nonatomic, strong) NSArray *relationshipMappings; +@property (nonatomic, strong) RKMappingInfo *mappingInfo; +@property (nonatomic, getter=isCancelled) BOOL cancelled; +@property (nonatomic) BOOL collectsMappingInfo; +@property (nonatomic) BOOL shouldSetUnchangedValues; +@property (nonatomic, readwrite, getter=isNewDestinationObject) BOOL newDestinationObject; +@end + +@implementation RKMappingOperation + +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping +{ + return [self initWithSourceObject:sourceObject destinationObject:destinationObject mapping:objectOrDynamicMapping metadataList:nil]; +} + +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping metadataList:(NSArray *)metadataList +{ + NSAssert(sourceObject != nil, @"Cannot perform a mapping operation without a sourceObject object"); + NSAssert(objectOrDynamicMapping != nil, @"Cannot perform a mapping operation without a mapping"); + + self = [super init]; + if (self) { + self.sourceObject = sourceObject; + self.rootSourceObject = sourceObject; + self.destinationObject = destinationObject; + self.mapping = objectOrDynamicMapping; + self.metadataList = metadataList; + } + + return self; +} + +- (id)parentObjectForRelationshipMapping:(RKRelationshipMapping *)mapping +{ + id parentSourceObject = self.sourceObject; + NSString *sourceKeyPath = mapping.sourceKeyPath; + + NSRange lastDotRange = [sourceKeyPath rangeOfString:@"." options:NSBackwardsSearch|NSLiteralSearch]; + if (lastDotRange.length > 0) + { + NSString *parentKey = [sourceKeyPath substringToIndex:lastDotRange.location]; + id rootObject = self.rootSourceObject; + NSArray *metadata = self.metadataList; + for (NSString *key in [parentKey componentsSeparatedByString:@"."]) + { + parentSourceObject = [[RKMappingSourceObject alloc] initWithObject:[parentSourceObject valueForKey:key] + parentObject:parentSourceObject + rootObject:rootObject + metadata:metadata]; + } + } + + return parentSourceObject; +} + +- (id)destinationObjectForMappingRepresentation:(id)representation parentRepresentation:(id)parentRepresentation withMapping:(RKMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + RKObjectMapping *concreteMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + concreteMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + if (! concreteMapping) { + RKLogDebug(@"Unable to determine concrete object mapping from dynamic mapping %@ with which to map object representation: %@", mapping, representation); + return nil; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + concreteMapping = (RKObjectMapping *)mapping; + } + + id destinationObject = nil; + id dataSource = self.dataSource; + if ([dataSource respondsToSelector:@selector(mappingOperation:targetObjectForMapping:inRelationship:)]) + { + destinationObject = [dataSource mappingOperation:self targetObjectForMapping:concreteMapping inRelationship:relationshipMapping]; + } + + if (destinationObject == nil) + { + NSDictionary *dictionaryRepresentation = [representation isKindOfClass:[NSDictionary class]] ? representation : @{ [NSNull null] : representation }; + RKMappingMetadata *parentMetadata = [RKMappingMetadata new]; + parentMetadata.parentObject = self.destinationObject ?: [NSNull null]; + NSArray *metadata = RKInsertInMetadataList(self.metadataList, parentMetadata, nil); + RKMappingSourceObject *sourceObject = [[RKMappingSourceObject alloc] initWithObject:dictionaryRepresentation parentObject:parentRepresentation rootObject:self.rootSourceObject metadata:metadata]; + destinationObject = [dataSource mappingOperation:self targetObjectForRepresentation:(NSDictionary *)sourceObject withMapping:concreteMapping inRelationship:relationshipMapping]; + } + + return destinationObject; +} + +- (BOOL)validateValue:(id *)value atKeyPath:(NSString *)keyPath +{ + BOOL success = YES; + + if (self.objectMapping.performsKeyValueValidation) { + id destinationObject = self.destinationObject; + + if ([destinationObject respondsToSelector:@selector(validateValue:forKeyPath:error:)]) { + NSError *validationError; + success = [destinationObject validateValue:value forKeyPath:keyPath error:&validationError]; + if (!success) { + self.error = validationError; + if (validationError) { + RKLogError(@"Validation failed while mapping attribute at key path '%@' to value. Error: %@", keyPath, [validationError localizedDescription]); + RKLogValidationError(validationError); + } else { + RKLogWarning(@"Destination object %@ rejected attribute value for keyPath %@. Skipping...", self.destinationObject, keyPath); + } + RKLogDebug(@"(Value for key path '%@': %@)", keyPath, *value); + } + } + } + + return success; +} + +- (BOOL)shouldSetValue:(id *)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping +{ + if ([self.delegate respondsToSelector:@selector(mappingOperation:shouldSetValue:forKeyPath:usingMapping:)]) { + return [self.delegate mappingOperation:self shouldSetValue:*value forKeyPath:keyPath usingMapping:propertyMapping]; + } + + // Always set the properties + if (self.shouldSetUnchangedValues) { + return [self validateValue:value atKeyPath:keyPath]; + } + + id currentValue = [self.destinationObject valueForKeyPath:keyPath]; + if (currentValue == [NSNull null]) { + currentValue = nil; + } + + /* + WTF - This workaround should not be necessary, but I have been unable to replicate + the circumstances that trigger it in a unit test to fix elsewhere. The proper place + to handle it is in transformValue:atKeyPath:toType: + + See issue & pull request: https://github.com/RestKit/RestKit/pull/436 + */ + if (*value == [NSNull null]) *value = nil; + + if (nil == currentValue && nil == *value) { + // Both are nil + return NO; + } else if (nil == *value || nil == currentValue) { + // One is nil and the other is not + return [self validateValue:value atKeyPath:keyPath]; + } + + if (! RKObjectIsEqualToObject(*value, currentValue)) { + // Validate value for key + return [self validateValue:value atKeyPath:keyPath]; + } + return NO; +} + +- (NSArray *)applyNestingToMappings:(NSArray *)propertyMappings +{ + if (self.nestedAttributeSubstitutionKey == nil) return propertyMappings; + + return RKApplyNestingAttributeValueToMappings(self.nestedAttributeSubstitutionKey, self.nestedAttributeSubstitutionValue, propertyMappings); +} + +- (void)cacheMappingsIfNeeded +{ + if (!_nestedAttributeMappings) + { + RKObjectMapping *mapping = self.objectMapping; + + if (self.nestedAttributeSubstitutionKey == nil) { + _relationshipMappings = mapping.relationshipMappings; + _nestedAttributeMappings = mapping.attributeMappings; + _simpleAttributeMappings = mapping.keyAttributeMappings; + _keyPathAttributeMappings = mapping.keyPathAttributeMappings; + } + else { + _nestedAttributeMappings = [self applyNestingToMappings:mapping.attributeMappings]; + _relationshipMappings = [self applyNestingToMappings:mapping.relationshipMappings]; + NSMutableArray *simpleList = [[NSMutableArray alloc] initWithCapacity:[_nestedAttributeMappings count]]; + NSMutableArray *keyPathList = [[NSMutableArray alloc] initWithCapacity:[_nestedAttributeMappings count]]; + + // The nested substitution may have changed which properties are simple vs keyPath, so we have to + // re-check based on the nesting result. + for (RKPropertyMapping *mapping in _nestedAttributeMappings) { + BOOL isSimple = [mapping.sourceKeyPath rangeOfString:@"." options:NSLiteralSearch].length == 0; + NSMutableArray *arrayToAdd = isSimple? simpleList : keyPathList; + [arrayToAdd addObject:mapping]; + } + + _simpleAttributeMappings = simpleList; + _keyPathAttributeMappings = keyPathList; + } + } +} + +- (NSArray *)nestedAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _nestedAttributeMappings; +} + +- (NSArray *)simpleAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _simpleAttributeMappings; +} + +- (NSArray *)keyPathAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _keyPathAttributeMappings; +} + +- (NSArray *)relationshipMappings +{ + [self cacheMappingsIfNeeded]; + return _relationshipMappings; +} + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue withPropertyMapping:(RKPropertyMapping *)propertyMapping error:(NSError *__autoreleasing *)error +{ + if (! inputValue) { + *outputValue = nil; + // We only want to consider the transformation successful and assign nil if the mapping calls for it + return propertyMapping.objectMapping.assignsDefaultValueForMissingAttributes; + } + Class transformedValueClass = propertyMapping.propertyValueClass ?: [self.objectMapping classForKeyPath:propertyMapping.destinationKeyPath]; + if (! transformedValueClass) { + *outputValue = inputValue; + return YES; + } + RKLogTrace(@"Found transformable value at keyPath '%@'. Transforming from class '%@' to '%@'", propertyMapping.sourceKeyPath, NSStringFromClass([inputValue class]), NSStringFromClass(transformedValueClass)); + BOOL success = [propertyMapping.valueTransformer transformValue:inputValue toValue:outputValue ofClass:transformedValueClass error:error]; + if (! success) RKLogError(@"Failed transformation of value at keyPath '%@' to representation of type '%@': %@", propertyMapping.sourceKeyPath, transformedValueClass, *error); + return success; +} + +- (BOOL)applyAttributeMapping:(RKAttributeMapping *)attributeMapping withValue:(id)value +{ + id transformedValue = nil; + NSError *error = nil; + if (! [self transformValue:value toValue:&transformedValue withPropertyMapping:attributeMapping error:&error]) return NO; + + NSString *destinationKeyPath = attributeMapping.destinationKeyPath; + id destinationObject = self.destinationObject; + id delegate = self.delegate; + + if ([delegate respondsToSelector:@selector(mappingOperation:didFindValue:forKeyPath:mapping:)]) { + [delegate mappingOperation:self didFindValue:value forKeyPath:attributeMapping.sourceKeyPath mapping:attributeMapping]; + } + RKLogTrace(@"Mapping attribute value keyPath '%@' to '%@'", attributeMapping.sourceKeyPath, destinationKeyPath); + + // If we have a nil value for a primitive property, we need to coerce it into a KVC usable value or bail out + if (transformedValue == nil && RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(destinationKeyPath, destinationObject)) { + RKLogDebug(@"Detected `nil` value transformation for primitive property at keyPath '%@'", destinationKeyPath); + transformedValue = RKPrimitiveValueForNilValueOfClass([self.objectMapping classForKeyPath:destinationKeyPath]); + if (! transformedValue) { + RKLogTrace(@"Skipped mapping of attribute value from keyPath '%@ to keyPath '%@' -- Unable to transform `nil` into primitive value representation", attributeMapping.sourceKeyPath, destinationKeyPath); + return NO; + } + } + + RKSetIntermediateDictionaryValuesOnObjectForKeyPath(destinationObject, destinationKeyPath); + + // Ensure that the value is different + if ([self shouldSetValue:&transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]) { + RKLogTrace(@"Mapped attribute value from keyPath '%@' to '%@'. Value: %@", attributeMapping.sourceKeyPath, destinationKeyPath, transformedValue); + + if (destinationKeyPath) { + [destinationObject setValue:transformedValue forKeyPath:destinationKeyPath]; + } else { + if ([destinationObject isKindOfClass:[NSMutableDictionary class]] && [transformedValue isKindOfClass:[NSDictionary class]]) { + [destinationObject setDictionary:transformedValue]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Unable to set value for destination object of type '%@': Can only directly set destination object for `NSMutableDictionary` targets. (transformedValue=%@)", [destinationObject class], transformedValue]; + } + } + if ([delegate respondsToSelector:@selector(mappingOperation:didSetValue:forKeyPath:usingMapping:)]) { + [delegate mappingOperation:self didSetValue:transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]; + } + } else { + RKLogTrace(@"Skipped mapping of attribute value from keyPath '%@ to keyPath '%@' -- value is unchanged (%@)", attributeMapping.sourceKeyPath, destinationKeyPath, transformedValue); + if ([delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [delegate mappingOperation:self didNotSetUnchangedValue:transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]; + } + } + if (_collectsMappingInfo) { + [self.mappingInfo addPropertyMapping:attributeMapping]; + } + return YES; +} + +// Return YES if we mapped any attributes +- (BOOL)applyAttributeMappings:(NSArray *)attributeMappings +{ + // If we have a nesting substitution value, we have already succeeded + BOOL appliedMappings = (self.nestedAttributeSubstitutionKey != nil); + + if (!self.objectMapping.performsKeyValueValidation) { + RKLogDebug(@"Key-value validation is disabled for mapping, skipping..."); + } + + id sourceObject = self.sourceObject; + + for (RKAttributeMapping *attributeMapping in attributeMappings) { + if ([self isCancelled]) return NO; + + NSString *sourceKeyPath = attributeMapping.sourceKeyPath; + NSString *destinationKeyPath = attributeMapping.destinationKeyPath; + if ([sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName] || [destinationKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) { + RKLogTrace(@"Skipping attribute mapping for special keyPath '%@'", sourceKeyPath); + continue; + } + + id value = (sourceKeyPath == nil) ? [sourceObject valueForKey:@"self"] : [sourceObject valueForKeyPath:sourceKeyPath]; + if ([self applyAttributeMapping:attributeMapping withValue:value]) { + appliedMappings = YES; + } else { + id delegate = self.delegate; + RKObjectMapping *objectMapping = self.objectMapping; + + if ([delegate respondsToSelector:@selector(mappingOperation:didNotFindValueForKeyPath:mapping:)]) { + [delegate mappingOperation:self didNotFindValueForKeyPath:sourceKeyPath mapping:attributeMapping]; + } + RKLogTrace(@"Did not find mappable attribute value keyPath '%@'", sourceKeyPath); + + // Optionally set the default value for missing values + if (objectMapping.assignsDefaultValueForMissingAttributes) { + [self.destinationObject setValue:[objectMapping defaultValueForAttribute:destinationKeyPath] + forKeyPath:destinationKeyPath]; + RKLogTrace(@"Setting nil for missing attribute value at keyPath '%@'", sourceKeyPath); + } + } + + // Fail out if an error has occurred + if (self.error) break; + } + + return appliedMappings; +} + +- (BOOL)mapNestedObject:(id)anObject toObject:(id)anotherObject parent:(id)parentSourceObject withRelationshipMapping:(RKRelationshipMapping *)relationshipMapping metadataList:(NSArray *)metadataList +{ + NSAssert(anObject, @"Cannot map nested object without a nested source object"); + NSAssert(anotherObject, @"Cannot map nested object without a destination object"); + NSAssert(relationshipMapping, @"Cannot map a nested object relationship without a relationship mapping"); + + RKLogTrace(@"Performing nested object mapping using mapping %@ for data: %@", relationshipMapping, anObject); + RKMappingOperation *subOperation = [[RKMappingOperation alloc] initWithSourceObject:anObject destinationObject:anotherObject mapping:relationshipMapping.mapping metadataList:metadataList]; + subOperation.dataSource = self.dataSource; + subOperation.delegate = self.delegate; + subOperation.parentSourceObject = parentSourceObject; + subOperation.rootSourceObject = self.rootSourceObject; + subOperation.newDestinationObject = YES; + [subOperation start]; + + if (subOperation.error) { + RKLogWarning(@"WARNING: Failed mapping nested object: %@", [subOperation.error localizedDescription]); + } else if (self.collectsMappingInfo) { + RKMappingInfo *mappingInfo = self.mappingInfo; + RKMappingInfo *subMappingInfo = subOperation.mappingInfo; + [mappingInfo addPropertyMapping:relationshipMapping]; + if (subMappingInfo) { + [mappingInfo addMappingInfo:subMappingInfo forRelationshipMapping:relationshipMapping]; + } + } + + return YES; +} + +- (BOOL)applyReplaceAssignmentPolicyForRelationshipMapping:(RKRelationshipMapping *)relationshipMapping +{ + if (relationshipMapping.assignmentPolicy == RKReplaceAssignmentPolicy) { + id dataSource = self.dataSource; + if ([dataSource respondsToSelector:@selector(mappingOperation:deleteExistingValueOfRelationshipWithMapping:error:)]) { + NSError *error = nil; + BOOL success = [dataSource mappingOperation:self deleteExistingValueOfRelationshipWithMapping:relationshipMapping error:&error]; + if (! success) { + RKLogError(@"Failed to delete existing value of relationship mapped with RKReplaceAssignmentPolicy: %@", error); + self.error = error; + return NO; + } + } else { + RKLogWarning(@"Requested mapping with `RKReplaceAssignmentPolicy` assignment policy, but the data source does not support it. Mapping has proceeded identically to the `RKSetAssignmentPolicy`."); + } + } + + return YES; +} + +- (BOOL)mapOneToOneRelationshipWithValue:(id)value mapping:(RKRelationshipMapping *)relationshipMapping +{ + static dispatch_once_t onceToken; + static NSDictionary *noIndexMetadata; + dispatch_once(&onceToken, ^{ + noIndexMetadata = @{ @"mapping" : @{ @"collectionIndex" : [NSNull null] } }; + }); + + // One to one relationship + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + RKLogDebug(@"Mapping one to one relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, destinationKeyPath); + + if (relationshipMapping.assignmentPolicy == RKUnionAssignmentPolicy) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Invalid assignment policy: cannot union a one-to-one relationship." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo]; + return NO; + } + + id parentSourceObject = [self parentObjectForRelationshipMapping:relationshipMapping]; + id destinationObject = [self destinationObjectForMappingRepresentation:value parentRepresentation:parentSourceObject withMapping:relationshipMapping.mapping inRelationship:relationshipMapping]; + if (! destinationObject) { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipMapping.mapping, destinationObject); + return NO; + } + + NSArray *subOperationMetadata = RKInsertInMetadataList(self.metadataList, noIndexMetadata, nil); + [self mapNestedObject:value toObject:destinationObject parent:parentSourceObject withRelationshipMapping:relationshipMapping metadataList:subOperationMetadata]; + + // If the relationship has changed, set it + if ([self shouldSetValue:&destinationObject forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + if (! [self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + return NO; + } + + RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, destinationKeyPath, destinationObject); + [self.destinationObject setValue:destinationObject forKeyPath:destinationKeyPath]; + } else { + if ([self.delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [self.delegate mappingOperation:self didNotSetUnchangedValue:destinationObject forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + } + + return YES; +} + +- (BOOL)mapCoreDataToManyRelationshipValue:(id)valueForRelationship withMapping:(RKRelationshipMapping *)relationshipMapping +{ + id destinationObject = self.destinationObject; + if (! RKIsManagedObject(destinationObject)) return NO; + + RKLogTrace(@"Mapping a to-many relationship for an `NSManagedObject`. About to apply value via mutable[Set|Array]ValueForKey"); + if ([valueForRelationship isKindOfClass:[NSSet class]]) { + RKLogTrace(@"Mapped `NSSet` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + NSMutableSet *destinationSet = [destinationObject mutableSetValueForKeyPath:relationshipMapping.destinationKeyPath]; + [destinationSet setSet:valueForRelationship]; + } else if ([valueForRelationship isKindOfClass:[NSArray class]]) { + RKLogTrace(@"Mapped `NSArray` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + NSMutableArray *destinationArray = [destinationObject mutableArrayValueForKeyPath:relationshipMapping.destinationKeyPath]; + [destinationArray setArray:valueForRelationship]; + } else if ([valueForRelationship isKindOfClass:[NSOrderedSet class]]) { + RKLogTrace(@"Mapped `NSOrderedSet` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + [destinationObject setValue:valueForRelationship forKeyPath:relationshipMapping.destinationKeyPath]; + } + + return YES; +} + +- (BOOL)mapOneToManyRelationshipWithValue:(id)value mapping:(RKRelationshipMapping *)relationshipMapping +{ + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + + // One to many relationship + RKLogDebug(@"Mapping one to many relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, destinationKeyPath); + + NSMutableArray *relationshipCollection = [NSMutableArray arrayWithCapacity:[value count]]; + if (RKObjectIsCollectionOfCollections(value)) { + RKLogWarning(@"WARNING: Detected a relationship mapping for a collection containing another collection. This is probably not what you want. Consider using a KVC collection operator (such as @unionOfArrays) to flatten your mappable collection."); + RKLogWarning(@"Key path '%@' yielded collection containing another collection rather than a collection of objects", relationshipMapping.sourceKeyPath); + RKLogDebug(@"(Value at key path '%@': %@)", relationshipMapping.sourceKeyPath, value); + } + + if (relationshipMapping.assignmentPolicy == RKUnionAssignmentPolicy) { + RKLogDebug(@"Mapping relationship with union assignment policy: constructing combined relationship value."); + id existingObjects = [self.destinationObject valueForKeyPath:destinationKeyPath]; + if (existingObjects) { + NSArray *existingObjectsArray = nil; + NSError *error = nil; + [[RKValueTransformer defaultValueTransformer] transformValue:existingObjects toValue:&existingObjectsArray ofClass:[NSArray class] error:&error]; + [relationshipCollection addObjectsFromArray:existingObjectsArray]; + } + } + else if (relationshipMapping.assignmentPolicy == RKReplaceAssignmentPolicy) { + if (! [self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + return NO; + } + } + + RKMapping *relationshipDestinationMapping = relationshipMapping.mapping; + id parentSourceObject = [self parentObjectForRelationshipMapping:relationshipMapping]; + RKMappingIndexMetadata *indexMetadata = [RKMappingIndexMetadata new]; + NSArray *subOperationMetadata = RKInsertInMetadataList(self.metadataList, indexMetadata, nil); + [value enumerateObjectsUsingBlock:^(id nestedObject, NSUInteger collectionIndex, BOOL *stop) { + id mappableObject = [self destinationObjectForMappingRepresentation:nestedObject parentRepresentation:parentSourceObject withMapping:relationshipDestinationMapping inRelationship:relationshipMapping]; + if (mappableObject) { + indexMetadata.collectionIndex = collectionIndex; + if ([self mapNestedObject:nestedObject toObject:mappableObject parent:parentSourceObject withRelationshipMapping:relationshipMapping metadataList:subOperationMetadata]) { + [relationshipCollection addObject:mappableObject]; + } + } else { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipDestinationMapping, nestedObject); + } + }]; + + id valueForRelationship = nil; + NSError *error = nil; + if (! [self transformValue:relationshipCollection toValue:&valueForRelationship withPropertyMapping:relationshipMapping error:&error]) return NO; + + // If the relationship has changed, set it + if ([self shouldSetValue:&valueForRelationship forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + if (! [self mapCoreDataToManyRelationshipValue:valueForRelationship withMapping:relationshipMapping]) { + RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, destinationKeyPath, valueForRelationship); + [self.destinationObject setValue:valueForRelationship forKeyPath:destinationKeyPath]; + } + } else { + if ([self.delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [self.delegate mappingOperation:self didNotSetUnchangedValue:valueForRelationship forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + + return NO; + } + + return YES; +} + +- (BOOL)applyRelationshipMappings +{ + NSAssert(self.dataSource, @"Cannot perform relationship mapping without a data source"); + NSUInteger mappingsApplied = 0; + RKObjectMapping *parentObjectMapping = self.objectMapping; + id sourceObject = self.sourceObject; + id destinationObject = self.destinationObject; + id delegate = self.delegate; + + for (RKRelationshipMapping *relationshipMapping in [self relationshipMappings]) { + if ([self isCancelled]) return NO; + + NSString *sourceKeyPath = relationshipMapping.sourceKeyPath; + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + id value = nil; + + if (sourceKeyPath) { + value = [sourceObject valueForKeyPath:sourceKeyPath]; + } else { + // The nil source keyPath indicates that we want to map directly from the parent representation + value = sourceObject; + RKMapping *destinationMapping = relationshipMapping.mapping; + RKObjectMapping *objectMapping = nil; + + if ([destinationMapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)destinationMapping; + } else if ([destinationMapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)destinationMapping objectMappingForRepresentation:value]; + } + + if (! objectMapping) continue; // Mapping declined + if (! RKObjectContainsValueForMappings(value, objectMapping.propertyMappings)) { + continue; + } + } + + // Track that we applied this mapping + mappingsApplied++; + + if (value == nil) { + RKLogDebug(@"Did not find mappable relationship value keyPath '%@'", sourceKeyPath); + if (! parentObjectMapping.assignsNilForMissingRelationships) continue; + } + + if (value == [NSNull null]) { + RKLogDebug(@"Found null value at keyPath '%@'", sourceKeyPath); + value = nil; + } + + // nil out the property if necessary + if (value == nil) { + Class relationshipClass = [parentObjectMapping classForKeyPath:destinationKeyPath]; + BOOL mappingToCollection = RKClassIsCollection(relationshipClass); + RKAssignmentPolicy assignmentPolicy = relationshipMapping.assignmentPolicy; + if (assignmentPolicy == RKUnionAssignmentPolicy && mappingToCollection) { + // Unioning `nil` with the existing value is functionally equivalent to doing nothing, so just continue + continue; + } else if (assignmentPolicy == RKUnionAssignmentPolicy) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Invalid assignment policy: cannot union a one-to-one relationship." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo]; + continue; + } else if (assignmentPolicy == RKReplaceAssignmentPolicy) { + if (! [self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + continue; + } + } + + if ([self shouldSetValue:&value forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + RKLogTrace(@"Setting nil for relationship value at keyPath '%@'", sourceKeyPath); + [destinationObject setValue:value forKeyPath:destinationKeyPath]; + } + + continue; + } + + // Handle case where incoming content is collection represented by a dictionary + if (relationshipMapping.mapping.forceCollectionMapping) { + // If we have forced mapping of a dictionary, map each subdictionary + if ([value isKindOfClass:[NSDictionary class]]) { + RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); + NSArray *objectsToMap = [NSMutableArray arrayWithCapacity:[value count]]; + for (id key in value) { + NSDictionary *dictionaryToMap = @{key: [value valueForKey:key]}; + [(NSMutableArray *)objectsToMap addObject:dictionaryToMap]; + } + value = objectsToMap; + } else { + RKLogWarning(@"Collection mapping forced but mappable objects is of type '%@' rather than NSDictionary", NSStringFromClass([value class])); + } + } + + // Handle case where incoming content is a single object, but we want a collection + Class relationshipClass = [parentObjectMapping classForKeyPath:destinationKeyPath]; + BOOL mappingToCollection = RKClassIsCollection(relationshipClass); + BOOL objectIsCollection = RKObjectIsCollection(value); + if (mappingToCollection && !objectIsCollection) { + RKLogDebug(@"Asked to map a single object into a collection relationship. Transforming to an instance of: %@", NSStringFromClass(relationshipClass)); + if ([relationshipClass isSubclassOfClass:[NSArray class]]) { + value = [relationshipClass arrayWithObject:value]; + objectIsCollection = YES; + } else if ([relationshipClass isSubclassOfClass:[NSSet class]]) { + value = [relationshipClass setWithObject:value]; + objectIsCollection = YES; + } else if ([relationshipClass isSubclassOfClass:[NSOrderedSet class]]) { + value = [relationshipClass orderedSetWithObject:value]; + objectIsCollection = YES; + } else { + RKLogWarning(@"Failed to transform single object"); + } + } + + BOOL setValueForRelationship; + if (objectIsCollection) { + setValueForRelationship = [self mapOneToManyRelationshipWithValue:value mapping:relationshipMapping]; + } else { + setValueForRelationship = [self mapOneToOneRelationshipWithValue:value mapping:relationshipMapping]; + } + + if (! setValueForRelationship) continue; + + // Notify the delegate + if ([delegate respondsToSelector:@selector(mappingOperation:didSetValue:forKeyPath:usingMapping:)]) { + id setValue = [destinationObject valueForKeyPath:destinationKeyPath]; + [delegate mappingOperation:self didSetValue:setValue forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + + // Fail out if a validation error has occurred + if (self.error) break; + } + + return mappingsApplied > 0; +} + +- (void)applyNestedMappings +{ + RKObjectMapping *objectMapping = self.objectMapping; + RKAttributeMapping *attributeMapping = [objectMapping mappingForSourceKeyPath:RKObjectMappingNestingAttributeKeyName]; + if (attributeMapping) { + RKLogDebug(@"Found nested mapping definition to attribute '%@'", attributeMapping.destinationKeyPath); + id attributeValue = [[self.sourceObject allKeys] lastObject]; + if (attributeValue) { + RKLogDebug(@"Found nesting value of '%@' for attribute '%@'", attributeValue, attributeMapping.destinationKeyPath); + self.nestedAttributeSubstitutionKey = attributeMapping.destinationKeyPath; + self.nestedAttributeSubstitutionValue = attributeValue; + [self applyAttributeMapping:attributeMapping withValue:attributeValue]; + } else { + RKLogWarning(@"Unable to find nesting value for attribute '%@'", attributeMapping.destinationKeyPath); + } + } + + // Serialization + attributeMapping = [objectMapping mappingForDestinationKeyPath:RKObjectMappingNestingAttributeKeyName]; + if (attributeMapping) { + RKLogDebug(@"Found nested mapping definition to attribute '%@'", attributeMapping.destinationKeyPath); + id attributeValue = [self.sourceObject valueForKeyPath:attributeMapping.sourceKeyPath]; + if (attributeValue) { + RKLogDebug(@"Found nesting value of '%@' for attribute '%@'", attributeValue, attributeMapping.sourceKeyPath); + self.nestedAttributeSubstitutionKey = attributeMapping.sourceKeyPath; + self.nestedAttributeSubstitutionValue = attributeValue; + } else { + RKLogWarning(@"Unable to find nesting value for attribute '%@'", attributeMapping.destinationKeyPath); + } + } +} + +- (void)cancel +{ + self.cancelled = YES; + RKLogDebug(@"Mapping operation cancelled: %@", self); +} + +- (void)start +{ + [self main]; +} + +- (void)main +{ + if ([self isCancelled]) return; + + // Handle metadata + id parentSourceObject = self.parentSourceObject; + id sourceObject = [[RKMappingSourceObject alloc] initWithObject:self.sourceObject parentObject:parentSourceObject rootObject:self.rootSourceObject metadata:self.metadataList]; + self.sourceObject = sourceObject; + + RKLogDebug(@"Starting mapping operation..."); + RKLogTrace(@"Performing mapping operation: %@", self); + + id dataSource = self.dataSource; + id delegate = self.delegate; + RKMapping *mapping = self.mapping; + RKObjectMapping *objectMapping; + + if (! self.destinationObject) { + self.destinationObject = [self destinationObjectForMappingRepresentation:sourceObject parentRepresentation:parentSourceObject withMapping:mapping inRelationship:nil]; + if (! self.destinationObject) { + RKLogDebug(@"Mapping operation failed: Given nil destination object and unable to instantiate a destination object for mapping."); + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Cannot perform a mapping operation with a nil destination object." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorNilDestinationObject userInfo:userInfo]; + return; + } + self.newDestinationObject = YES; + } + + self.collectsMappingInfo = (![dataSource respondsToSelector:@selector(mappingOperationShouldCollectMappingInfo:)] || + [dataSource mappingOperationShouldCollectMappingInfo:self]); + + self.shouldSetUnchangedValues = ([self.dataSource respondsToSelector:@selector(mappingOperationShouldSetUnchangedValues:)] && + [self.dataSource mappingOperationShouldSetUnchangedValues:self]); + + // Determine the concrete mapping if we were initialized with a dynamic mapping + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + self.objectMapping = objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:sourceObject]; + if (! objectMapping) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"A dynamic mapping failed to return a concrete object mapping matching the representation being mapped." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnableToDetermineMapping userInfo:userInfo]; + return; + } + RKLogDebug(@"RKObjectMappingOperation was initialized with a dynamic mapping. Determined concrete mapping = %@", objectMapping); + + if ([delegate respondsToSelector:@selector(mappingOperation:didSelectObjectMapping:forDynamicMapping:)]) { + [delegate mappingOperation:self didSelectObjectMapping:objectMapping forDynamicMapping:(RKDynamicMapping *)mapping]; + } + if (self.collectsMappingInfo) { + self.mappingInfo = [[RKMappingInfo alloc] initWithObjectMapping:objectMapping dynamicMapping:(RKDynamicMapping *)mapping]; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + self.objectMapping = objectMapping = (RKObjectMapping *)mapping; + if (self.collectsMappingInfo) { + self.mappingInfo = [[RKMappingInfo alloc] initWithObjectMapping:objectMapping dynamicMapping:nil]; + } + } + + BOOL canSkipMapping = [dataSource respondsToSelector:@selector(mappingOperationShouldSkipPropertyMapping:)] && [dataSource mappingOperationShouldSkipPropertyMapping:self]; + if (! canSkipMapping) { + [self applyNestedMappings]; + if ([self isCancelled]) return; + BOOL mappedSimpleAttributes = [self applyAttributeMappings:[self simpleAttributeMappings]]; + if ([self isCancelled]) return; + BOOL mappedRelationships = [[self relationshipMappings] count] ? [self applyRelationshipMappings] : NO; + if ([self isCancelled]) return; + // NOTE: We map key path attributes last to allow you to map across the object graphs for objects created/updated by the relationship mappings + BOOL mappedKeyPathAttributes = [self applyAttributeMappings:[self keyPathAttributeMappings]]; + + if (!mappedSimpleAttributes && !mappedRelationships && !mappedKeyPathAttributes) { + // We did not find anything to do + RKLogDebug(@"Mapping operation did not find any mappable values for the attribute and relationship mappings in the given object representation"); + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"No mappable values found for any of the attributes or relationship mappings" }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableRepresentation userInfo:userInfo]; + } + + // We did some mapping work, if there's no error let's commit our changes to the data source + if (self.error == nil) { + if ([dataSource respondsToSelector:@selector(commitChangesForMappingOperation:error:)]) { + NSError *error = nil; + BOOL success = [dataSource commitChangesForMappingOperation:self error:&error]; + if (! success) { + self.error = error; + } + } + } + } + + if (self.error) { + if ([delegate respondsToSelector:@selector(mappingOperation:didFailWithError:)]) { + [delegate mappingOperation:self didFailWithError:self.error]; + } + + RKLogDebug(@"Failed mapping operation: %@", [self.error localizedDescription]); + } else { + RKLogDebug(@"Finished mapping operation successfully..."); + } +} + +- (BOOL)performMapping:(NSError **)error +{ + [self start]; + if (error) *error = self.error; + return self.error == nil; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p> for '%@' object. Mapping values from object %@ to object %@ with object mapping %@", + [self class], self, NSStringFromClass([self.destinationObject class]), self.sourceObject, self.destinationObject, self.objectMapping]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h new file mode 100644 index 0000000..2d06b34 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1,110 @@ +// +// RKMappingOperationDataSource.h +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class RKObjectMapping, RKMappingOperation, RKRelationshipMapping; + +/** + An object that adopts the `RKMappingOperationDataSource` protocol is responsible for the retrieval or creation of target objects within an `RKMapperOperation` or `RKMappingOperation`. A data source is responsible for meeting the requirements of the underlying data store implementation and must return a key-value coding compliant object instance that can be used as the target object of a mapping operation. It is also responsible for commiting any changes necessary to the underlying data store once a mapping operation has completed its work. + + At a minimum, a data source must implement the `mappingOperation:targetObjectForRepresentation:withMapping:` method. This method is responsible for finding an existing object instance to be updated or creating a new object if no existing object could be found or the underlying data store does not support persistence. Object mapping operations which target `NSObject` derived classes will always result in mapping to new transient objects, while persistent data stores such as Core Data can be queried to retrieve existing objects for update. + + @see `RKManagedObjectMappingOperationDataSource` + */ +@protocol RKMappingOperationDataSource <NSObject> + +@required + +/** + Asks the data source for the target object for an object mapping operation given an `NSDictionary` representation of the object's properties and the mapping object that will be used to perform the mapping. + + The `representation` value is a fragment of content from a deserialized response that has been identified as containing content that is mappable using the given mapping. + + @param mappingOperation The mapping operation requesting the target object. + @param representation A dictionary representation of the properties to be mapped onto the retrieved target object. + @param mapping The object mapping to be used to perform a mapping from the representation to the target object. + @return A key-value coding compliant object to perform the mapping on to. + */ +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping; + +@optional + +/** + Asks the data source for the target object for an object mapping operation the mapping object that will be used to perform the mapping. + + If not implemented or it returns nil, then the + `mappingOperation:targetObjectForRepresentation:withMapping:inRelationship:` method will be called to determine the target. + + It is preferable to implement this method if the `representation` is not needed to determine the target object, + as obtaining that value is somewhat expensive. + + @param mappingOperation The mapping operation requesting the target object. + @param representation A dictionary representation of the properties to be mapped onto the retrieved target object. + @param mapping The object mapping to be used to perform a mapping from the representation to the target object. + @return A key-value coding compliant object to perform the mapping on to. + */ +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping; + + +/** + Tells the data source to commit any changes to the underlying data store. + + @param mappingOperation The mapping operation that has completed its work. + @param error A pointer to an error to be set in the event that the mapping operation could not be committed. + @return A Boolean value indicating if the changes for the mapping operation were committed successfully. + */ +- (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation error:(NSError **)error; + +/** + Tells the data source to delete the existing value for a relationship that has been mapped with an assignment policy of `RKReplaceAssignmentPolicy`. + + @param mappingOperation The mapping operation that is executing. + @param relationshipMapping The relationship mapping for which the existing value is being replaced. + @param error A pointer to an error to be set in the event that the deletion operation could not be completed. + @return A Boolean value indicating if the existing objects for the relationship were successfully deleted. + */ +- (BOOL)mappingOperation:(RKMappingOperation *)mappingOperation deleteExistingValueOfRelationshipWithMapping:(RKRelationshipMapping *)relationshipMapping error:(NSError **)error; + +/** + Asks the data source if it should set values for properties without checking that the value has been changed. This method can result in a performance improvement during mapping as the mapping operation will not attempt to assess the change state of the property being mapped. + + If this method is not implemented by the data source, then the mapping operation defaults to `NO`. + + @param mappingOperation The mapping operation that is querying the data source. + @return `YES` if the mapping operation should disregard property change status, else `NO`. + */ +- (BOOL)mappingOperationShouldSetUnchangedValues:(RKMappingOperation *)mappingOperation; + +- (BOOL)mappingOperationShouldSkipPropertyMapping:(RKMappingOperation *)mappingOperation; + +/** + Asks the data source if the mapping operation should collect `RKMappingInfo` information during the mapping + (stored in the `mappingInfo` property). If not needed, it can be a substantially faster to skip it. The + `mappingInfo` property will be nil if not collected. + + If this method is not implemented by the data source, then the mapping operation defaults to `YES`. + + @param mappingOperation The mapping operation that is querying the data source. + @return `YES` if the mapping operation should collect mapping information, else `NO`. +*/ +- (BOOL)mappingOperationShouldCollectMappingInfo:(RKMappingOperation *)mappingOperation; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h new file mode 100644 index 0000000..2cdeff0 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h @@ -0,0 +1,91 @@ +// +// RKMappingResult.h +// RestKit +// +// Created by Blake Watters on 5/7/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKMappingResult` class represents the aggregate object mapping results returned by an `RKMapperOperation` object. The mapping result provides a thin interface on top of an `NSDictionary` and provides convenient interfaces for accessing the mapping results in various representations. + */ +@interface RKMappingResult : NSObject + +///---------------------------------------- +/// @name Creating a Mapping Result +///---------------------------------------- + +/** + Initializes the receiver with a dictionary of mapped key paths and object values. + + @param dictionary A dictionary wherein the keys represent mapped key paths and the values represent the objects mapped at those key paths. Cannot be nil. + @return The receiver, initialized with the given dictionary. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +///---------------------------------------- +/// @name Retrieving Result Representations +///---------------------------------------- + +/** + Returns a representation of the mapping result as a dictionary. + + The keys of the returned dictionary will correspond to the mapped key paths in the source object representation and the values will be the mapped objects. The returned value is a copy of the dictionary that was used to initialize the mapping result. + + @return A dictionary containing the mapping results. + */ +- (NSDictionary *)dictionary; + +/** + Returns a representation of the mapping result as a single object by returning the first mapped value from the aggregate array of mapped objects. + + The mapping result is coerced into a single object by retrieving all mapped objects and returning the first object. If the mapping result is empty, `nil` is returned. + + @return The first object contained in the mapping result. + */ +@property (nonatomic, readonly, strong) id firstObject; + +/** + Returns a representation of the mapping result as an array of objects. + + The array returned is a flattened collection of all mapped object values contained in the underlying dictionary result representation. No guarantee is made as to the ordering of objects within the returned collection when more than one key path was mapped, as `NSDictionary` objects are unordered, + + @return An array containing the objects contained in the mapping result. + */ +- (NSArray *)array; + +/** + Returns a representation of the mapping result as a set of objects. + + The set returned is a flattened collection of all mapped object values contained in the underlying dictionary result representation. + + @return A set containing the objects contained in the mapping result. + */ +@property (nonatomic, readonly, copy) NSSet *set; + +///---------------------------------------- +/// @name Counting Entries +///---------------------------------------- + +/** + Returns a count of the number of objects contained in the mapping result. This is an aggregate count of all objects across all mapped key paths in the result. + + @return A count of the number of mapped objects in the mapping result. + */ +@property (nonatomic, readonly) NSUInteger count; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m new file mode 100644 index 0000000..d3b7f58 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m @@ -0,0 +1,81 @@ +// +// RKMappingResult.m +// RestKit +// +// Created by Blake Watters on 5/7/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingResult.h" + +@interface RKMappingResult () +@property (nonatomic, strong) NSDictionary *keyPathToMappedObjects; +@end + +@implementation RKMappingResult + +- (instancetype)initWithDictionary:(id)dictionary +{ + NSParameterAssert(dictionary); + self = [self init]; + if (self) { + self.keyPathToMappedObjects = dictionary; + } + + return self; +} + +- (NSDictionary *)dictionary +{ + return [self.keyPathToMappedObjects copy]; +} + +- (NSArray *)array +{ + // Flatten results down into a single array + NSMutableArray *collection = [NSMutableArray array]; + for (id object in [self.keyPathToMappedObjects allValues]) { + // We don't want to strip the keys off of a mapped dictionary result + if (NO == [object isKindOfClass:[NSDictionary class]] && [object respondsToSelector:@selector(allObjects)]) { + [collection addObjectsFromArray:[object allObjects]]; + } else { + [collection addObject:object]; + } + } + + return collection; +} + +- (NSSet *)set +{ + return [NSSet setWithArray:[self array]]; +} + +- (id)firstObject +{ + return [[self array] firstObject]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, results=%@>", NSStringFromClass([self class]), self, self.keyPathToMappedObjects]; +} + +- (NSUInteger)count +{ + return [[self array] count]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h new file mode 100644 index 0000000..8884778 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h @@ -0,0 +1,528 @@ +// +// RKObjectMapping.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMacros.h" +#import "RKMapping.h" +#import "RKValueTransformers.h" + +@class RKPropertyMapping, RKAttributeMapping, RKRelationshipMapping; +@protocol RKValueTransforming; + +/** + An `RKObjectMapping` object describes a transformation between object represenations using key-value coding and run-time type introspection. The mapping is defined in terms of a source object class and a collection of `RKPropertyMapping` objects describing how key paths in the source representation should be transformed into attributes and relationships on the target object. Object mappings are provided to instances of `RKMapperOperation` and `RKMappingOperation` to perform the transformations they describe. + + Object mappings are containers of property mappings that describe the actual key path transformations. There are two types of property mappings: + + 1. `RKAttributeMapping`: An attribute mapping describes a transformation between a single value from a source key path to a destination key path. The value to be mapped is read from the source object representation using `valueForKeyPath:` and then set to the destination key path using `setValueForKeyPath:`. Before the value is set, the `RKObjecMappingOperation` performing the mapping performs runtime introspection on the destination property to determine what, if any, type transformation is to be performed. Typical type transformations include reading an `NSString` value representation and mapping it to an `NSDecimalNumber` destination key path or reading an `NSString` and transforming it into an `NSDate` value before assigning to the destination. + 1. `RKRelationshipMapping`: A relationship mapping describes a transformation between a nested child object or objects from a source key path to a destination key path using another `RKObjectMapping`. The child objects to be mapped are read from the source object representation using `valueForKeyPath:`, then mapped recursively using the object mapping associated with the relationship mapping, and then finally assigned to the destination key path. Before assignment to the destination key path runtime type introspection is performed to determine if any type transformation is necessary. For relationship mappings, common type transformations include transforming a single object value in an `NSArray` or transforming an `NSArray` of object values into an `NSSet`. + + All type transformations available are discussed in detail in the documentation for `RKValueTransformer`. + + ## Transforming Representation to Property Keys + + Configuring object mappings can become quite repetitive if the keys in your serialized object representations follow a different convention than their local domain counterparts. For example, consider a typical JSON document in the "snake case" format: + + {"user": {"first_name": "Blake", "last_name": "Watters", "email_address": "blake@restkit.org"}} + + Typically when configuring a mapping for the object represented in this document we would transform the destination properties into the Objective-C idiomatic "llama case" variation. This can produce lengthy, error-prone mapping configurations in which the transformations are specified manually: + + RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKUser class]]; + [userMapping addAttributeMappingsFromDictionary:@{ @"first_name": @"firstName", @"last_name": @"lastName", @"email_address", @"emailAddress" }]; + + To combat this repetition, a block can be designated to perform a transformation on source keys to produce corresponding destination keys: + + [userMapping setSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { + // Value transformer compliments of TransformerKit (See https://github.com/mattt/TransformerKit) + return [[NSValueTransformer valueTransformerForName:TKLlamaCaseStringTransformerName] transformedValue:sourceKey]; + }]; + + With the block configured, the original configuration can be changed into a simpler array based invocation: + + [userMapping addAttributeMappingsFromArray:@[ @"first_name", @"last_name", @"email_address" ]]; + + Transformation blocks can be configured on a per-mapping basis via `setSourceToDestinationKeyTransformationBlock:` or globally via `[RKObjectMapping setDefaultSourceToDestinationKeyTransformationBlock:]`. + + @see `RKAttributeMapping` + @see `RKRelationshipMapping` + @see `RKConnectionMapping` + @see `RKMappingOperation` + @see `RKPropertyInspector` + */ +@interface RKObjectMapping : RKMapping <NSCopying> + +///--------------------------------- +/// @name Creating an Object Mapping +///--------------------------------- + +/** + Returns an object mapping for the specified class that is ready for configuration + + @param objectClass The class that the mapping targets. + @return A new mapping object. + */ ++ (instancetype)mappingForClass:(Class)objectClass; + +/** + Initializes the receiver with a given object class. This is the designated initializer. + + @param objectClass The class that the mapping targets. Cannot be `nil`. + @return The receiver, initialized with the given class. + */ +- (instancetype)initWithClass:(Class)objectClass; + +/** + Returns an object mapping with an `objectClass` of `NSMutableDictionary`. + + Request mappings are used when configuring mappings that are to be used for transforming local objects into HTTP parameters using the `RKObjectParameterization` class. + + @return An object mapping with an object class of `NSMutableDictionary`. + @see `RKObjectParameterization` + @see `RKObjectManager` + */ ++ (RKObjectMapping *)requestMapping; + +///---------------------------------- +/// @name Accessing Property Mappings +///---------------------------------- + +/** + The aggregate collection of attribute and relationship mappings within this object mapping. + */ +@property (nonatomic, copy, readonly) NSArray *propertyMappings; + +/** + Returns the property mappings of the receiver in a dictionary, where the keys are the source key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + + @return The property mappings of the receiver in a dictionary, where the keys are the source key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + @warning Note this method does not return any property mappings with a `nil` value for the source key path in the dictionary returned. + */ +@property (nonatomic, readonly) NSDictionary *propertyMappingsBySourceKeyPath; + +/** + Returns the property mappings of the receiver in a dictionary, where the keys are the destination key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + + @return The property mappings of the receiver in a dictionary, where the keys are the destination key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + @warning Note this method does not return any property mappings with a `nil` value for the source key path in the dictionary returned. + */ +@property (nonatomic, readonly) NSDictionary *propertyMappingsByDestinationKeyPath; + +/** + The collection of attribute mappings within this object mapping. + */ +@property (nonatomic, readonly) NSArray *attributeMappings; + +/** + The collection of single key attribute mappings within this object mapping. + + These are mappings where the source key path is a single key, and not a key path with multiple components. + */ +@property (nonatomic, readonly) NSArray *keyAttributeMappings; + +/** + The collection of key path attribute mappings within this object mapping. + + A key path mapping is one where the source key path is actually a path with multiple components. + */ +@property (nonatomic, readonly) NSArray *keyPathAttributeMappings; + +/** + The collection of relationship mappings within this object mapping. + */ +@property (nonatomic, readonly) NSArray *relationshipMappings; + +/** + Returns the property mapping registered with the receiver with the given source key path. + + @param sourceKeyPath The key path to retrieve. + */ +- (id)mappingForSourceKeyPath:(NSString *)sourceKeyPath; + +/** + Returns the property mapping registered with the receiver with the given destinationKeyPath key path. + + @param destinationKeyPath The key path to retrieve. + */ +- (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath; + +///--------------------------- +/// Managing Property Mappings +///--------------------------- + +/** + Adds a property mapping to the receiver. + + @param propertyMapping The property mapping to be added to the object mapping. + */ +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping; + +/** + Adds an array of `RKAttributeMapping` or `RKRelationshipMapping` objects to the receiver. + + @param arrayOfPropertyMappings The array of property mappings to be added to the object mapping. + */ +- (void)addPropertyMappingsFromArray:(NSArray *)arrayOfPropertyMappings; + +/** + Removes an `RKAttributeMapping` or `RKRelationshipMapping` from the receiver. + + @param propertyMapping The attribute or relationship mapping to remove. + */ +- (void)removePropertyMapping:(RKPropertyMapping *)propertyMapping; + +/** + Adds attribute mappings from a given dictionary wherein the keys represent the source key path and the values represent the names of the target attributes on the destination object. + + @param keyPathToAttributeNames A dictionary keyed by source key to destination attribute name. + */ +- (void)addAttributeMappingsFromDictionary:(NSDictionary *)keyPathToAttributeNames; + +/** + Adds attribute mappings to the receiver from a given array. + + The array can contain `RKAttributeMapping` objects or `NSString` values. If an `NSString` is given, then a new `RKAttributeMapping` object is instantiated with a `sourceKeyPath` and `destinationKeyPath` equal to the string value. + + @param arrayOfAttributeNamesOrMappings An array of `RKAttributeMapping` or `NSString` values to be added to the receiver's set of attribute mappings, + */ +- (void)addAttributeMappingsFromArray:(NSArray *)arrayOfAttributeNamesOrMappings; + +/** + Adds a relationship mapping to the receiver with the given source key path and mapping. + + The destination key path will be the same as the source key path or processed by the source to destination key transformation block, if any is configured. + + @param sourceKeyPath The source key path at which to read the nested representation of the related objects. + @param mapping The object mapping with which to process the related object representation. + */ +- (void)addRelationshipMappingWithSourceKeyPath:(NSString *)sourceKeyPath mapping:(RKMapping *)mapping; + +///------------------------------------- +/// @name Configuring Key Transformation +///------------------------------------- + +/** + Sets an application-wide default transformation block to be used when attribute or relationship mappings are added to an object mapping by source key path. + + @param block The block to be set as the default source to destination key transformer for all object mappings in the application. + @see [RKObjectMapping setPropertyNameTransformationBlock:] + */ ++ (void)setDefaultSourceToDestinationKeyTransformationBlock:(NSString * (^)(RKObjectMapping *mapping, NSString *sourceKey))block; + +/** + Sets a block to executed to transform a source key into a destination key. + + The transformation block set with this method is used whenever an attribute or relationship mapping is added to the receiver via a method that accepts a string value for the source key. The block will be executed with the source key as the only argument and the value returned will be taken as the corresponding destination key. Methods on the `RKObjectMapping` class that will trigger the execution of the block configured via this method include: + * `addAttributeMappingsFromArray:` - Each string element contained in the given array is interpretted as a source key path and will be evaluated with the block to obtain a corresponding destination key path. + * `addRelationshipMappingWithSourceKeyPath:mapping:` - The source key path will be evaluated with the block to obtain a corresponding destination key path. + + @param block The block to execute when the receiver needs to transform a source key into a destination key. The block has a string return value specifying the destination key and accepts a single string argument: the source key that is to be transformed. + @warning Please note that the block given accepts a **key** as opposed to a **key path**. When a key path is given to a method supporting key transformation it will be decomposed into its key components by splitting the key path at the '.' (period) character, then each key will be evaluated using the transformation block and the results will be joined together into a new key path with the period character delimiter. + */ +- (void)setSourceToDestinationKeyTransformationBlock:(NSString * (^)(RKObjectMapping *mapping, NSString *sourceKey))block; + +///---------------------------------- +/// @name Mapping Nested Dictionaries +///---------------------------------- + +/** + Adds an attribute mapping from a dynamic nesting key value to an attribute. The mapped attribute name can then be referenced within other attribute mappings to access the nested content. + + For example, consider the following JSON: + + { "users": + { + "blake": { "id": 1234, "email": "blake@restkit.org" }, + "rachit": { "id": 5678, "email": "rachit@restkit.org" } + } + } + + We can configure our mappings to handle this in the following form: + + RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[User class]]; + mapping.forceCollectionMapping = YES; // RestKit cannot infer this is a collection, so we force it + [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"firstName"]; + [mapping addAttributeMappingsFromDictionary:@{ @"{firstName}.id": @"userID", @"{firstName}.email": @"email" }]; + */ +- (void)addAttributeMappingFromKeyOfRepresentationToAttribute:(NSString *)attributeName; + +/** + Adds an attribute mapping to a dynamic nesting key from an attribute. The mapped attribute name can then be referenced wthin other attribute mappings to map content under the nesting key path. + + For example, consider that we wish to map a local user object with the properties 'id', 'firstName' and 'email': + + RKUser *user = [RKUser new]; + user.firstName = @"blake"; + user.userID = @(1234); + user.email = @"blake@restkit.org"; + + And we wish to map it into JSON that looks like: + + { "blake": { "id": 1234, "email": "blake@restkit.org" } } + + We can configure our request mapping to handle this like so: + + RKObjectMapping *mapping = [RKObjectMapping requestMapping]; + [mapping addAttributeMappingToKeyOfRepresentationFromAttribute:@"firstName"]; + [mapping addAttributeMappingsFromDictionary:@{ @"userID": @"{firstName}.id", @"email": @"{firstName}.email" }]; + */ +- (void)addAttributeMappingToKeyOfRepresentationFromAttribute:(NSString *)attributeName; + +///---------------------------------- +/// @name Configuring Mapping Options +///---------------------------------- + +/** + The target class that the receiver describes a mapping for. + */ +@property (nonatomic, weak, readonly) Class objectClass; + +/** + When `YES`, any attributes that have mappings defined but are not present within the source object will be set to nil, clearing any existing value. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL assignsDefaultValueForMissingAttributes; + +/** + When `YES`, any relationships that have mappings defined but are not present within the source object will be set to `nil`, clearing any existing value. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL assignsNilForMissingRelationships; + +/** + When `YES`, key-value validation will be invoked at object mapping time. + + **Default**: `YES` + @see `validateValue:forKey:error:` + */ +@property (nonatomic, assign) BOOL performsKeyValueValidation; + +/** + A value transformer with which to process input values being mapped with the receiver. Defaults to a copy of `[RKValueTransformer defaultTransformer]`. + */ +@property (nonatomic, strong) id<RKValueTransforming> valueTransformer; + +/** + Returns the default value to be assigned to the specified attribute when it is missing from a mappable payload. + + The default implementation returns nil for transient object mappings. On an entity mapping, the default value returned from the Entity definition will be used. + + @see `[RKEntityMapping defaultValueForAttribute:]` + */ +- (id)defaultValueForAttribute:(NSString *)attributeName; + +///---------------------------------- +/// @name Generating Inverse Mappings +///---------------------------------- + +/** + Generates an inverse mapping for the rules specified within this object mapping. + + This can be used to quickly generate a corresponding serialization mapping from a configured object mapping. The inverse mapping will have the source and destination keyPaths swapped for all attribute and relationship mappings. All mapping configuration and date formatters are copied from the parent to the inverse mapping. + + @return A new mapping that will map the inverse of the receiver. + */ +- (instancetype)inverseMapping; + +/** + Generates an inverse mapping with all property mappings of the receiver that pass the given test. Each `RKAttributeMapping` and `RKRelationshipMapping` added to the receiver is yielded to the block for evaluation. The block is also invoked for any nested relationships that are traversed during the inversion process. + + @param predicate A block object to be invoked for each `RKPropertyMapping` that is considered for inversion. The block has a Boolean return value and accepts a single argument: the property mapping that is being evaluated for inversion. + @return A new mapping that will map the inverse of the receiver. + @see inverseMapping + */ +- (instancetype)inverseMappingWithPropertyMappingsPassingTest:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate; + +///--------------------------------------------------- +/// @name Obtaining Information About the Target Class +///--------------------------------------------------- + +/** + Returns the class of the attribute or relationship property of the target `objectClass` with the given name. + + Given the name of a string property, this will return an `NSString`, etc. + + @param propertyName The name of the property we would like to retrieve the type of. + @return The class of the property. + */ +- (Class)classForProperty:(NSString *)propertyName; + +/** + Returns the class of the attribute or relationship property of the target `objectClass` at the given key path. + + Given a key path to a string property, this will return an `NSString`, etc. + + @param keyPath The name of the property we would like to retrieve the type of. + @return The class of the property at the given key path. + */ +- (Class)classForKeyPath:(NSString *)keyPath; + +@end + +///////////////////////////////////////////////////////////////////////////// + +/** + **Deprecated in v0.21.0** + + This category contains deprecated API interfaces for configuring date formatters. Starting in RestKit 0.20.4 date formatting is configured via the `RKValueTransformer` API's. + + Defines the interface for configuring time and date formatting handling within RestKit object mappings. For performance reasons, RestKit reuses a pool of date formatters rather than constructing them at mapping time. This collection of date formatters can be configured on a per-object mapping or application-wide basis using the static methods exposed in this category. + */ +@interface RKObjectMapping (LegacyDateAndTimeFormatting) + +/** + **Deprecated in v0.21.0** + + This method accesses `[RKValueTransformer defaultTransformer]` and returns all `NSDate` <-> `NSString` value transformers. + + Returns the collection of default date formatters that will be used for all object mappings that have not been configured specifically. + + Out of the box, RestKit initializes default date formatters for you in the UTC time zone with the following format strings: + + * `yyyy-MM-dd'T'HH:mm:ss'Z'` + * `MM/dd/yyyy` + + @return An array of `NSFormatter` objects used when mapping strings into NSDate attributes + */ ++ (NSArray *)defaultDateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method accesses `[RKValueTransformer defaultTransformer]` and removes all `NSDate` <-> `NSString` value transformers that are instances of `NSFormatter` and then adds the given array of formatters to the default transformer. + + Sets the collection of default date formatters to the specified array. The array should contain configured instances of NSDateFormatter in the order in which you want them applied during object mapping operations. + + @param dateFormatters An array of date formatters to replace the existing defaults. + @see `defaultDateFormatters` + */ ++ (void)setDefaultDateFormatters:(NSArray *)dateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This methods prepends the given date formatter to `[RKValueTransformer defaultValueTransformer]`. + + Adds a date formatter instance to the default collection + + @param dateFormatter An `NSFormatter` object to prepend to the default formatters collection + @see `defaultDateFormatters` + */ ++ (void)addDefaultDateFormatter:(NSFormatter *)dateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method instantiates a new `NSDateFormatter` object with the given format string and time zone and prepends it to `[RKValueTransformer defaultValueTransformer]`. + + Convenience method for quickly constructing a date formatter and adding it to the collection of default date formatters. The locale is auto-configured to `en_US_POSIX`. + + @param dateFormatString The dateFormat string to assign to the newly constructed `NSDateFormatter` instance + @param nilOrTimeZone The NSTimeZone object to configure on the `NSDateFormatter` instance. Defaults to UTC time. + @see `NSDateFormatter` + */ ++ (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method returns the first `NSString` -> `NSDate` value transformer that is an instance of `NSFormatter` in `[RKValueTransformer defaultValueTransformer]`. + + Returns the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. + + Defaults to an instance of the `RKISO8601DateFormatter` configured with the UTC time-zone. The format string is equal to "yyyy-MM-DDThh:mm:ssTZD" + + For details about the ISO-8601 format, see http://www.w3.org/TR/NOTE-datetime + + @return The preferred NSFormatter object to use when serializing dates into strings + */ ++ (NSFormatter *)preferredDateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Access `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method inserts the given date formatter at position zero in `[RKValueTransformer defaultValueTransformer]`, ensuring that it will be used for all transformations from `NSDate` -> `NSString`. + + Sets the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. + + @param dateFormatter The NSFormatter object to designate as the new preferred instance + */ ++ (void)setPreferredDateFormatter:(NSFormatter *)dateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +///---------------------------------- +/// @name Configuring Date Formatters +///---------------------------------- + +/** + **Deprecated in v0.21.0** + + An array of `NSFormatter` objects to use when mapping string values into `NSDate` attributes on the target `objectClass`. Each date formatter will be invoked with the string value being mapped until one of the date formatters does not return nil. + + Defaults to the application-wide collection of date formatters configured via `[RKObjectMapping setDefaultDateFormatters:]` + + @see `[RKObjectMapping defaultDateFormatters]` + */ +@property (nonatomic, strong) NSArray *dateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Use `valueTransformer` instead"); + +/** + **Deprecated in v0.21.0** + + The `NSFormatter` object for your application's preferred date and time configuration. This date formatter will be used when generating string representations of NSDate attributes (i.e. during serialization to URL form encoded or JSON format). + + Defaults to the application-wide preferred date formatter configured via: `[RKObjectMapping setPreferredDateFormatter:]` + + @see `[RKObjectMapping preferredDateFormatter]` + */ +@property (nonatomic, strong) NSFormatter *preferredDateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Use `valueTransformer` instead"); + +@end + +@interface RKObjectMapping (Deprecations) +// These methods were named to be more idiomation. Properties beginning with `set` generate method names like `setSetDefaultValueForMissingAttributes` and `performKeyValueValidation` reads more as a command to perform something than a configuration switch. +@property (nonatomic, assign, getter = shouldSetDefaultValueForMissingAttributes) BOOL setDefaultValueForMissingAttributes DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `assignsDefaultValueForMissingAttributes`"); +@property (nonatomic, assign) BOOL setNilForMissingRelationships DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `assignsNilForMissingRelationships`"); +@property (nonatomic, assign) BOOL performKeyValueValidation DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `performsKeyValueValidation`"); +@end + +///---------------- +/// @name Functions +///---------------- + +/** + Returns an date representation of a given string value by attempting to parse the string with all default date formatters in turn. + + @param dateString A string object encoding a date value. + @return An `NSDate` object parsed from the given string, or `nil` if the string was found to be unparsable by all default date formatters. + @see [RKObjectMapping defaultDateFormatters] + */ +NSDate *RKDateFromString(NSString *dateString); + +/** + Returns a string representation of a given date formatted with the preferred date formatter. + + This is a convenience function that is equivalent to the following example code: + + NSString *string = [[RKObjectMapping preferredDateFormatter] stringForObjectValue:date] + + @param date The date object to be formatted. + @return An `NSString` object representation of the given date formatted by the preferred date formatter. + @see [RKObjectMapping preferredDateFormatter] + */ +NSString *RKStringFromDate(NSDate *date); diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m new file mode 100644 index 0000000..ed69c6f --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m @@ -0,0 +1,616 @@ +// +// RKObjectMapping.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <CoreFoundation/CoreFoundation.h> +#import "RKObjectMapping.h" +#import "RKRelationshipMapping.h" +#import "RKPropertyInspector.h" +#import "RKLog.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKValueTransformers.h" +#import "ISO8601DateFormatterValueTransformer.h" + +typedef NSString * (^RKSourceToDesinationKeyTransformationBlock)(RKObjectMapping *, NSString *); + +// Constants +NSString * const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE>"; + +static RKSourceToDesinationKeyTransformationBlock defaultSourceToDestinationKeyTransformationBlock = nil; + +@interface RKObjectMapping (Copying) +- (void)copyPropertiesFromMapping:(RKObjectMapping *)mapping; +@end + +@interface RKMappingInverter : NSObject +@property (nonatomic, strong) RKObjectMapping *mapping; +@property (nonatomic, strong) NSMutableDictionary *invertedMappings; + +- (instancetype)initWithMapping:(RKObjectMapping *)mapping; +- (RKObjectMapping *)inverseMappingWithPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate; +@end + +@implementation RKMappingInverter + +- (instancetype)initWithMapping:(RKObjectMapping *)mapping +{ + self = [self init]; + if (self) { + self.mapping = mapping; + self.invertedMappings = [NSMutableDictionary dictionary]; + } + return self; +} + +- (RKObjectMapping *)invertMapping:(RKObjectMapping *)mapping withPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + // Use an NSValue to obtain a non-copied key into our inversed mappings dictionary + NSValue *dictionaryKey = [NSValue valueWithNonretainedObject:mapping]; + RKObjectMapping *inverseMapping = (self.invertedMappings)[dictionaryKey]; + if (inverseMapping) return inverseMapping; + + inverseMapping = [RKObjectMapping requestMapping]; + (self.invertedMappings)[dictionaryKey] = inverseMapping; + [inverseMapping copyPropertiesFromMapping:mapping]; + // We want to serialize `nil` values + inverseMapping.assignsDefaultValueForMissingAttributes = YES; + + for (RKAttributeMapping *attributeMapping in mapping.attributeMappings) { + if (predicate && !predicate(attributeMapping)) continue; + [inverseMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeMapping.destinationKeyPath toKeyPath:attributeMapping.sourceKeyPath]]; + } + + for (RKRelationshipMapping *relationshipMapping in mapping.relationshipMappings) { + RKObjectMapping *mapping = (RKObjectMapping *) relationshipMapping.mapping; + if (! [mapping isKindOfClass:[RKObjectMapping class]]) { + RKLogWarning(@"Unable to generate inverse mapping for relationship '%@': %@ relationships cannot be inversed.", relationshipMapping.sourceKeyPath, NSStringFromClass([mapping class])); + continue; + } + if (predicate && !predicate(relationshipMapping)) continue; + RKMapping *inverseRelationshipMapping = [self invertMapping:mapping withPredicate:predicate]; + if (inverseRelationshipMapping) [inverseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:relationshipMapping.destinationKeyPath toKeyPath:relationshipMapping.sourceKeyPath withMapping:inverseRelationshipMapping]]; + } + + return inverseMapping; +} + +- (RKObjectMapping *)inverseMappingWithPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + return [self invertMapping:self.mapping withPredicate:predicate]; +} + +@end + +@interface RKPropertyMapping () +@property (nonatomic, weak, readwrite) RKObjectMapping *objectMapping; +@end + +@interface RKObjectMapping () +@property (nonatomic, weak, readwrite) Class objectClass; +@property (nonatomic, copy, readwrite) NSArray *propertyMappings; + +@property (nonatomic, strong) NSArray *relationshipMappings; +@property (nonatomic, strong) NSArray *attributeMappings; +@property (nonatomic, strong) NSArray *keyAttributeMappings; +@property (nonatomic, strong) NSArray *keyPathAttributeMappings; +@property (nonatomic, strong) NSMutableDictionary *propertiesBySourceKeyPath; +@property (nonatomic, strong) NSMutableDictionary *propertiesByDestinationKeyPath; + +@property (nonatomic, weak, readonly) NSArray *mappedKeyPaths; +@property (nonatomic, copy) RKSourceToDesinationKeyTransformationBlock sourceToDestinationKeyTransformationBlock; +@end + +@implementation RKObjectMapping + ++ (instancetype)mappingForClass:(Class)objectClass +{ + return [[self alloc] initWithClass:objectClass]; +} + ++ (RKObjectMapping *)requestMapping +{ + if (! [self isEqual:[RKObjectMapping class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`%@` is not meant to be invoked on `%@`. You probably want to invoke `[RKObjectMapping requestMapping]`.", + NSStringFromSelector(_cmd), + NSStringFromClass(self)] + userInfo:nil]; + } + + // TODO: Hook up value transformers from `RKObjectParameterization` + RKObjectMapping *objectMapping = [self mappingForClass:[NSMutableDictionary class]]; + objectMapping.assignsDefaultValueForMissingAttributes = YES; + return objectMapping; +} + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Add an ISO8601DateFormatter to the transformation stack for backwards compatibility + RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; + }); +} + +- (instancetype)initWithClass:(Class)objectClass +{ + self = [super init]; + if (self) { + self.objectClass = objectClass; + self.propertyMappings = [NSArray new]; + self.relationshipMappings = [NSArray new]; + self.attributeMappings = [NSArray new]; + self.keyAttributeMappings = [NSArray new]; + self.keyPathAttributeMappings = [NSArray new]; + self.propertiesBySourceKeyPath = [NSMutableDictionary new]; + self.propertiesByDestinationKeyPath = [NSMutableDictionary new]; + self.assignsDefaultValueForMissingAttributes = NO; + self.assignsNilForMissingRelationships = NO; + self.forceCollectionMapping = NO; + self.performsKeyValueValidation = YES; + self.sourceToDestinationKeyTransformationBlock = defaultSourceToDestinationKeyTransformationBlock; + self.valueTransformer = [[RKValueTransformer defaultValueTransformer] copy]; + } + + return self; +} + +- (void)copyPropertiesFromMapping:(RKObjectMapping *)mapping +{ + self.assignsDefaultValueForMissingAttributes = mapping.assignsDefaultValueForMissingAttributes; + self.assignsNilForMissingRelationships = mapping.assignsNilForMissingRelationships; + self.forceCollectionMapping = mapping.forceCollectionMapping; + self.performsKeyValueValidation = mapping.performsKeyValueValidation; + self.valueTransformer = mapping.valueTransformer; + self.sourceToDestinationKeyTransformationBlock = mapping.sourceToDestinationKeyTransformationBlock; +} + +- (id)copyWithZone:(NSZone *)zone +{ + RKObjectMapping *copy = [[[self class] allocWithZone:zone] initWithClass:self.objectClass]; + [copy copyPropertiesFromMapping:self]; + + for (RKPropertyMapping *propertyMapping in self.propertyMappings) { + [copy addPropertyMapping:[propertyMapping copy]]; + } + + return copy; +} + ++ (void)setDefaultSourceToDestinationKeyTransformationBlock:(RKSourceToDesinationKeyTransformationBlock)block +{ + defaultSourceToDestinationKeyTransformationBlock = block; +} + +- (NSDictionary *)propertyMappingsBySourceKeyPath +{ + return [self.propertiesBySourceKeyPath copy]; +} + +- (NSDictionary *)propertyMappingsByDestinationKeyPath +{ + return [self.propertiesByDestinationKeyPath copy]; +} + +- (NSArray *)mappedKeyPaths +{ + return [self.propertyMappings valueForKey:@"destinationKeyPath"]; +} + +- (NSArray *)attributeMappings +{ + return _attributeMappings; +} + +- (NSArray *)relationshipMappings +{ + return _relationshipMappings; +} + +- (NSArray *)keyAttributeMappings +{ + return _keyAttributeMappings; +} + +- (NSArray *)keyPathAttributeMappings +{ + return _keyPathAttributeMappings; +} + +static NSArray *RKAddProperty(NSArray *array, RKPropertyMapping *mapping) +{ + return (array)? [array arrayByAddingObject:mapping] : @[mapping]; +} + +static NSArray *RKRemoveProperty(NSArray *array, RKPropertyMapping *mapping) +{ + if (![array containsObject:mapping]) return array; + NSMutableArray *mappings = [[NSMutableArray alloc] initWithArray:array]; //alloc/init avoids autorelease + [mappings removeObject:mapping]; + return [mappings copy]; +} + +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping +{ + NSAssert1([[self mappedKeyPaths] containsObject:propertyMapping.destinationKeyPath] == NO, + @"Unable to add mapping for keyPath %@, one already exists...", propertyMapping.destinationKeyPath); + NSAssert(self.propertyMappings, @"self.propertyMappings is nil"); + NSAssert(propertyMapping.objectMapping == nil, @"Cannot add a property mapping object that has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the mapping: `[propertyMapping copy]`"); + propertyMapping.objectMapping = self; + self.propertyMappings = [self.propertyMappings arrayByAddingObject:propertyMapping]; + [self.propertiesBySourceKeyPath setObject:propertyMapping forKey:propertyMapping.sourceKeyPath ?: [NSNull null]]; + if (propertyMapping.destinationKeyPath) (self.propertiesByDestinationKeyPath)[propertyMapping.destinationKeyPath] = propertyMapping; + if ([propertyMapping isMemberOfClass:[RKRelationshipMapping class]]) { + self.relationshipMappings = RKAddProperty(self.relationshipMappings, propertyMapping); + } + else if ([propertyMapping isMemberOfClass:[RKAttributeMapping class]]) + { + self.attributeMappings = RKAddProperty(self.attributeMappings, propertyMapping); + if ([propertyMapping.sourceKeyPath rangeOfString:@"." options:NSLiteralSearch].length == 0) { + self.keyAttributeMappings = RKAddProperty(self.keyAttributeMappings, propertyMapping); + } + else { + self.keyPathAttributeMappings = RKAddProperty(self.keyPathAttributeMappings, propertyMapping); + } + } + + if (propertyMapping.propertyValueClass == Nil && ![self.objectClass isSubclassOfClass:[NSDictionary class]]) { + propertyMapping.propertyValueClass = [self classForKeyPath:propertyMapping.destinationKeyPath]; + } +} + +- (void)addPropertyMappingsFromArray:(NSArray *)arrayOfPropertyMappings +{ + NSAssert([[arrayOfPropertyMappings valueForKeyPath:@"@distinctUnionOfObjects.objectMapping"] count] == 0, @"One or more of the property mappings in the given array has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the array of mappings: `[[NSArray alloc] initWithArray:arrayOfPropertyMappings copyItems:YES]`"); + for (RKPropertyMapping *propertyMapping in arrayOfPropertyMappings) { + [self addPropertyMapping:propertyMapping]; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p objectClass=%@ propertyMappings=%@>", + NSStringFromClass([self class]), self, NSStringFromClass(self.objectClass), self.propertyMappings]; +} + +- (id)mappingForSourceKeyPath:(NSString *)sourceKeyPath +{ + return _propertiesBySourceKeyPath[sourceKeyPath ?: [NSNull null]]; +} + +- (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath +{ + return _propertiesByDestinationKeyPath[destinationKeyPath]; +} + +// Evaluate each component individually so that camelization, etc. considers each component individually +- (NSString *)transformSourceKeyPath:(NSString *)keyPath +{ + if (!self.sourceToDestinationKeyTransformationBlock) return keyPath; + + NSRange dotRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + if (dotRange.length == 0) { + return self.sourceToDestinationKeyTransformationBlock(self, keyPath); + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + NSMutableArray *mutableComponents = [NSMutableArray arrayWithCapacity:[components count]]; + [components enumerateObjectsUsingBlock:^(id component, NSUInteger idx, BOOL *stop) { + [mutableComponents addObject:self.sourceToDestinationKeyTransformationBlock(self, component)]; + }]; + + return [mutableComponents componentsJoinedByString:@"."]; +} + +- (void)addAttributeMappingsFromDictionary:(NSDictionary *)keyPathToAttributeNames +{ + for (NSString *attributeKeyPath in keyPathToAttributeNames) { + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeKeyPath toKeyPath:keyPathToAttributeNames[attributeKeyPath]]]; + } +} + +- (void)addAttributeMappingsFromArray:(NSArray *)arrayOfAttributeNamesOrMappings +{ + NSMutableArray *arrayOfAttributeMappings = [NSMutableArray arrayWithCapacity:[arrayOfAttributeNamesOrMappings count]]; + for (id entry in arrayOfAttributeNamesOrMappings) { + if ([entry isKindOfClass:[NSString class]]) { + NSString *destinationKeyPath = [self transformSourceKeyPath:entry]; + [arrayOfAttributeMappings addObject:[RKAttributeMapping attributeMappingFromKeyPath:entry toKeyPath:destinationKeyPath]]; + } else if ([entry isKindOfClass:[RKAttributeMapping class]]) { + [arrayOfAttributeMappings addObject:entry]; + } else { + [NSException raise:NSInvalidArgumentException + format:@"*** - [%@ %@]: Unable to attribute mapping from unsupported entry of type '%@' (%@).", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([entry class]), entry]; + } + } + + [self addPropertyMappingsFromArray:arrayOfAttributeMappings]; +} + +- (void)addRelationshipMappingWithSourceKeyPath:(NSString *)sourceKeyPath mapping:(RKMapping *)mapping +{ + NSParameterAssert(sourceKeyPath); + NSParameterAssert(mapping); + + NSString *destinationKeyPath = [self transformSourceKeyPath:sourceKeyPath]; + RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath withMapping:mapping]; + [self addPropertyMapping:relationshipMapping]; +} + +- (void)removePropertyMapping:(RKPropertyMapping *)attributeOrRelationshipMapping +{ + if ([self.propertyMappings containsObject:attributeOrRelationshipMapping]) { + attributeOrRelationshipMapping.objectMapping = nil; + self.propertyMappings = RKRemoveProperty(self.propertyMappings, attributeOrRelationshipMapping); + self.relationshipMappings = RKRemoveProperty(self.relationshipMappings, attributeOrRelationshipMapping); + self.attributeMappings = RKRemoveProperty(self.attributeMappings, attributeOrRelationshipMapping); + self.keyAttributeMappings = RKRemoveProperty(self.keyAttributeMappings, attributeOrRelationshipMapping); + self.keyPathAttributeMappings = RKRemoveProperty(self.keyPathAttributeMappings, attributeOrRelationshipMapping); + [self.propertiesBySourceKeyPath removeObjectForKey:attributeOrRelationshipMapping.sourceKeyPath ?: [NSNull null]]; + [self.propertiesByDestinationKeyPath removeObjectForKey:attributeOrRelationshipMapping.destinationKeyPath]; + } +} + +- (instancetype)inverseMappingWithPropertyMappingsPassingTest:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + RKMappingInverter *mappingInverter = [[RKMappingInverter alloc] initWithMapping:self]; + return [mappingInverter inverseMappingWithPredicate:predicate]; +} + +- (instancetype)inverseMapping +{ + return [self inverseMappingWithPropertyMappingsPassingTest:nil]; +} + +- (void)addAttributeMappingFromKeyOfRepresentationToAttribute:(NSString *)attributeName +{ + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:RKObjectMappingNestingAttributeKeyName toKeyPath:attributeName]]; +} + +- (void)addAttributeMappingToKeyOfRepresentationFromAttribute:(NSString *)attributeName +{ + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeName toKeyPath:RKObjectMappingNestingAttributeKeyName]]; +} + +- (RKAttributeMapping *)mappingForAttribute:(NSString *)attributeKey +{ + for (RKAttributeMapping *mapping in [self attributeMappings]) { + if ([mapping.destinationKeyPath isEqualToString:attributeKey]) { + return mapping; + } + } + + return nil; +} + +- (RKRelationshipMapping *)mappingForRelationship:(NSString *)relationshipKey +{ + for (RKRelationshipMapping *mapping in [self relationshipMappings]) { + if ([mapping.destinationKeyPath isEqualToString:relationshipKey]) { + return mapping; + } + } + + return nil; +} + +- (id)defaultValueForAttribute:(NSString *)attributeName +{ + return nil; +} + +- (Class)classForProperty:(NSString *)propertyName +{ + return [[RKPropertyInspector sharedInspector] classForPropertyNamed:propertyName ofClass:self.objectClass isPrimitive:nil]; +} + +- (Class)classForKeyPath:(NSString *)keyPath +{ + if (keyPath == nil) return self.objectClass; + + RKPropertyInspector *inspector = [RKPropertyInspector sharedInspector]; + + if ([keyPath rangeOfString:@"." options:NSLiteralSearch].length == 0) { + return [inspector classForPropertyNamed:keyPath ofClass:self.objectClass isPrimitive:nil]; + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + Class propertyClass = self.objectClass; + for (NSString *property in components) { + propertyClass = [inspector classForPropertyNamed:property ofClass:propertyClass isPrimitive:nil]; + if (! propertyClass) break; + } + + return propertyClass; +} + +- (BOOL)isEqualToMapping:(RKObjectMapping *)otherMapping +{ + if (! [otherMapping isKindOfClass:[RKObjectMapping class]]) return NO; + if ((self.objectClass && otherMapping.objectClass) && + ! [otherMapping.objectClass isEqual:self.objectClass]) { + return NO; + } else if (self.objectClass != nil && otherMapping.objectClass == nil) { + return NO; + } else if (self.objectClass == nil && otherMapping.objectClass != nil) { + return NO; + } + + // Check that the number of attribute/relationship mappings is equal and compare all + if ([self.propertyMappings count] != [otherMapping.propertyMappings count]) return NO; + + for (RKPropertyMapping *propertyMapping in self.propertyMappings) { + RKPropertyMapping *otherPropertyMapping = [otherMapping mappingForSourceKeyPath:propertyMapping.sourceKeyPath]; + if (! [propertyMapping isEqualToMapping:otherPropertyMapping]) return NO; + } + + return YES; +} + +@end + +///////////////////////////////////////////////////////////////////////////// + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +@implementation RKObjectMapping (LegacyDateAndTimeFormatting) + ++ (NSArray *)defaultDateFormatters +{ + NSArray *valueTransformers = [[RKValueTransformer defaultValueTransformer] valueTransformersForTransformingFromClass:[NSString class] toClass:[NSDate class]]; + NSMutableArray *dateFormatters = [NSMutableArray arrayWithCapacity:[valueTransformers count]]; + for (id<RKValueTransforming> valueTransformer in valueTransformers) { + if ([valueTransformer respondsToSelector:@selector(dateFromString:)]) [dateFormatters addObject:valueTransformer]; + } + return dateFormatters; +} + ++ (void)setDefaultDateFormatters:(NSArray *)dateFormatters +{ + NSArray *defaultDateFormatters = [self defaultDateFormatters]; + for (NSDateFormatter *dateFormatter in defaultDateFormatters) { + [[RKValueTransformer defaultValueTransformer] removeValueTransformer:dateFormatter]; + } + + for (NSDateFormatter *dateFormatter in dateFormatters) { + [[RKValueTransformer defaultValueTransformer] addValueTransformer:dateFormatter]; + } +} + ++ (void)addDefaultDateFormatter:(id)dateFormatter +{ + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +} + ++ (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone +{ + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormatString; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = nilOrTimeZone ?: [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + [self addDefaultDateFormatter:dateFormatter]; +} + ++ (NSFormatter *)preferredDateFormatter +{ + NSArray *defaultDateFormatters = [self defaultDateFormatters]; + return [defaultDateFormatters count] ? defaultDateFormatters[0] : nil; +} + ++ (void)setPreferredDateFormatter:(NSDateFormatter *)dateFormatter +{ + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +} + +#pragma mark - Date and Time + +- (NSFormatter *)preferredDateFormatter +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + NSArray *dateToStringTransformers = [(RKCompoundValueTransformer *)self.valueTransformer valueTransformersForTransformingFromClass:[NSDate class] toClass:[NSString class]]; + for (id<RKValueTransforming> valueTransformer in dateToStringTransformers) { + if ([valueTransformer isKindOfClass:[NSFormatter class]]) return (NSFormatter *)valueTransformer; + } + } + return nil; +} + +- (void)setPreferredDateFormatter:(NSFormatter *)preferredDateFormatter +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + [(RKCompoundValueTransformer *)self.valueTransformer insertValueTransformer:(NSFormatter<RKValueTransforming> *)preferredDateFormatter atIndex:0]; + } +} + +- (NSArray *)dateFormatters +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + return [(RKCompoundValueTransformer *)self.valueTransformer valueTransformersForTransformingFromClass:[NSDate class] toClass:[NSString class]]; + } else return nil; +} + +- (void)setDateFormatters:(NSArray *)dateFormatters +{ + if (! [self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) [NSException raise:NSInternalInconsistencyException format:@"Cannot set date formatters: the receiver's `valueTransformer` is not an instance of `RKCompoundValueTransformer`."]; + for (id<RKValueTransforming> dateFormatter in [self dateFormatters]) { + [(RKCompoundValueTransformer *)self.valueTransformer removeValueTransformer:dateFormatter]; + } + for (id<RKValueTransforming> dateFormatter in dateFormatters) { + [(RKCompoundValueTransformer *)self.valueTransformer addValueTransformer:dateFormatter]; + } +} + +@end + +@implementation RKObjectMapping (Deprecations) + +- (BOOL)shouldSetDefaultValueForMissingAttributes +{ + return self.assignsDefaultValueForMissingAttributes; +} + +- (void)setSetDefaultValueForMissingAttributes:(BOOL)setDefaultValueForMissingAttributes +{ + self.assignsDefaultValueForMissingAttributes = setDefaultValueForMissingAttributes; +} + +- (BOOL)setNilForMissingRelationships +{ + return self.assignsNilForMissingRelationships; +} + +- (void)setSetNilForMissingRelationships:(BOOL)setNilForMissingRelationships +{ + self.assignsNilForMissingRelationships = setNilForMissingRelationships; +} + +- (BOOL)performKeyValueValidation +{ + return self.performsKeyValueValidation; +} + +- (void)setPerformKeyValueValidation:(BOOL)performKeyValueValidation +{ + self.performsKeyValueValidation = performKeyValueValidation; +} + +@end + +#pragma clang diagnostic pop + +#pragma mark - Functions + +NSDate *RKDateFromString(NSString *dateString) +{ + NSDate *outputDate = nil; + NSError *error = nil; + BOOL success = [[RKValueTransformer defaultValueTransformer] transformValue:dateString toValue:&outputDate ofClass:[NSDate class] error:&error]; + return success ? outputDate : nil; +} + +NSString *RKStringFromDate(NSDate *date) +{ + NSString *outputString = nil; + NSError *error = nil; + BOOL success = [[RKValueTransformer defaultValueTransformer] transformValue:date toValue:&outputString ofClass:[NSString class] error:&error]; + return success ? outputString : nil; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h new file mode 100644 index 0000000..577550c --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1,112 @@ +// +// RKDynamicMappingMatcher.h +// RestKit +// +// Created by Jeff Arena on 8/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "RKObjectMapping.h" + +/** + The `RKObjectMappingMatcher` class provides an interface for encapsulating the selection of an object mapping based on runtime values. Matcher objects may be configured by key path and expected value or with a predicate object. + + ## Key Path Matching + + A key path matcher object is initialized with a key path, an expected value to be read from the key path, and an object mapping that is to be applied if the match evaluates to `YES`. When evaluating the match, the matcher invokes `valueForKeyPath:` on the object being matched and compares the value returned with the `expectedValue` via the `RKObjectIsEqualToObject` function. This provides a flexible, semantic match of the property value. + + Alternatively, a key path matcher object can be initialized with an expected class instead. When evaluating the match, the matcher invokes `valueForKeyPath:` on the object being matched and compares the value returned with the `expectedClass` via the `isSubclassOfClass:` method. This provides a flexible, semantic match of the property value class. + + ## Predicate Matching + + A predicate matcher object is initialized with a predicate object and an object mapping that is to be applied if the predicate evaluates to `YES` for the object being matched. + */ +@interface RKObjectMappingMatcher : NSObject + +///------------------------------------- +/// @name Constructing Key Path Matchers +///------------------------------------- + +/** + Creates and returns a key path matcher object with a given key path, expected value, and an object mapping that applies in the event of a positive match. + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedValue The value that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping; + +/** + Creates and returns a key path matcher object with a given key path, expected class, and an object mapping that applies in the event of a positive match. + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedClass The Class that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping; + +/** + Creates and returns a key path matcher object with a given key path, and a map of expected values to associated RKObjectMapping objects that applies in the event of a positive match with its associated value. This method can evaluate the keyPath once + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedValue The value that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path and expected value map. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping; + +///-------------------------------------- +/// @name Constructing Predicate Matchers +///-------------------------------------- + +/** + Creates and returns a predicate matcher object with a given predicate and an object mapping that applies in the predicate evaluates positively. + + @param predicate The predicate with which to evaluate the matched object. + @param objectMapping The object mapping object that applies if the predicate evaluates positively for the matched object. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping; + + +/** + Creates and returns a matcher object with a given block which returns the RKObjectMapping instance to use, and an optional array of possible object mappings which could be returned. + + @param possibleMappings The list of known possible RKObjectMapping instances which could be returned. This is used to aid RKDynamicMapping's -objectMappings method which is used in some instances, but is not required for mapping. The block could return a new instance if needed. + @param block The block with which to evaluate the matched object, and return the object mapping to use. Return nil if no match (i.e. a `NO` return from the `-matches:` method). + @return The receiver, initialized with the given block ans possible mappings. + */ ++ (instancetype)matcherWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block; + +///----------------------------------- +/// @name Accessing the Object Mapping +///----------------------------------- + +/** + Returns the list of all known RKObjectMapping instances which could be returned from this matcher. This is called when added to or removed from an RKDynamicMapping, and is used to populate the `objectMappings` property there. The default implementation returns the single value set in the `objectMapping` property, so if that is the only possibility then this method does not need to be overridden. + */ +@property (nonatomic, readonly) NSArray *possibleObjectMappings; + +/** + The object mapping object that applies when the receiver matches a given object. + + @see `matches:` + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +///------------------------- +/// @name Evaluating a Match +///------------------------- + +/** + Returns a Boolean value that indicates if the given object matches the expectations of the receiver. + + @param object The object to be evaluated. + @return `YES` if the object matches the expectations of the receiver, else `NO`. + */ +- (BOOL)matches:(id)object; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m new file mode 100644 index 0000000..4efebc3 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m @@ -0,0 +1,273 @@ +// +// RKDynamicMappingMatcher.m +// RestKit +// +// Created by Jeff Arena on 8/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "RKObjectMappingMatcher.h" +#import "RKObjectUtilities.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface RKObjectMappingMatcher () +@property (nonatomic, strong, readwrite) RKObjectMapping *objectMapping; +@end + +@interface RKKeyPathObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, strong, readwrite) id expectedValue; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKKeyPathClassObjectMappingMatcher : RKObjectMappingMatcher + +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, readwrite) Class expectedClass; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; + +@end + +@interface RKKeyPathValueMapObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, copy) NSDictionary *valueMap; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKPredicateObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, strong) NSPredicate *predicate; + +- (instancetype)initWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKBlockObjectMatchingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSArray *possibleMappings; +@property (nonatomic, copy) RKObjectMapping *(^block)(id representation); +- (instancetype)initWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block NS_DESIGNATED_INITIALIZER; +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation RKObjectMappingMatcher + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKKeyPathObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedValue:expectedValue objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKKeyPathClassObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedClass:expectedClass objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping +{ + return [[RKKeyPathValueMapObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedValueMap:valueToObjectMapping]; +} + ++ (instancetype)matcherWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKPredicateObjectMappingMatcher alloc] initWithPredicate:predicate objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block +{ + return [[RKBlockObjectMatchingMatcher alloc] initWithPossibleMappings:mappings block:block]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + if ([self isMemberOfClass:[RKObjectMappingMatcher class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is not meant to be directly instantiated. Use one of the initializer methods instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + RKObjectMapping *mapping = self.objectMapping; + return mapping ? @[mapping] : nil; +} + +- (BOOL)matches:(id)object +{ + return NO; +} + +@end + +@implementation RKKeyPathObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(expectedValue); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.expectedValue = expectedValue; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + if (value == nil) return NO; + return RKObjectIsEqualToObject(value, self.expectedValue); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` == '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.keyPath, self.expectedValue, self.objectMapping]; +} + +@end + +@implementation RKKeyPathClassObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(expectedClass); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.expectedClass = expectedClass; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + return [[value class] isSubclassOfClass:self.expectedClass]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` == '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.keyPath, self.expectedClass, self.objectMapping]; +} + +@end + +@implementation RKKeyPathValueMapObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(valueToObjectMapping.count > 0); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.valueMap = valueToObjectMapping; + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + return [self.valueMap allValues]; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + RKObjectMapping *mapping = (self.valueMap)[value]; + if (mapping) { + self.objectMapping = mapping; + return YES; + } + + return NO; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` in '%@'>", NSStringFromClass([self class]), self, self.keyPath, [self.valueMap allKeys]]; +} + +@end + +@implementation RKPredicateObjectMappingMatcher + +- (instancetype)initWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(predicate); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.predicate = predicate; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + return [self.predicate evaluateWithObject:object]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.predicate, self.objectMapping]; +} + +@end + +@implementation RKBlockObjectMatchingMatcher + +- (instancetype)initWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block +{ + NSParameterAssert(block); + self = [super init]; + if (self) { + self.block = block; + self.possibleMappings = mappings; + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + return self.possibleMappings; +} + +- (BOOL)matches:(id)object +{ + RKObjectMapping *mapping = self.block(object); + if (mapping) { + self.objectMapping = mapping; + return YES; + } + + return NO; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when '%@'>", NSStringFromClass([self class]), self, self.block]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 100644 index 0000000..3daf216 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1,27 @@ +// +// RKObjectMappingOperationDataSource.h +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingOperationDataSource.h" + +/** + The `RKObjectMappingOperationDataSource` class is an implementation of the `RKMappingOperationDataSource` protocol for use in performing object mappings that target plain old `NSObject` derived classes (as opposed to `NSManagedObject` derived persistent entities). + */ +@interface RKObjectMappingOperationDataSource : NSObject <RKMappingOperationDataSource> +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m new file mode 100644 index 0000000..e8aba71 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m @@ -0,0 +1,48 @@ +// +// RKObjectMappingOperationDataSource.m +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMappingOperationDataSource.h" +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" + +@implementation RKObjectMappingOperationDataSource + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation + withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + return [mapping.objectClass new]; +} + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + return [mapping.objectClass new]; +} + +- (BOOL)mappingOperationShouldCollectMappingInfo:(RKMappingOperation *)mappingOperation +{ + return NO; +} + +- (BOOL)mappingOperationShouldSetUnchangedValues:(RKMappingOperation *)mappingOperation +{ + return [mappingOperation isNewDestinationObject]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h new file mode 100644 index 0000000..d8a4043 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1,113 @@ +// +// RKObjectUtilities.h +// RestKit +// +// Created by Blake Watters on 9/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a Boolean value that indicates whether the given objects are equal. + + The actual method of comparison is dependendent upon the class of the objects given. For example, given two `NSString` objects equality would be tested using `isEqualToString:`. + + @param object The first object to compare. + @param anotherObject The second object to compare. + @return `YES` if the objects are equal, otherwise `NO`. + */ +BOOL RKObjectIsEqualToObject(id object, id anotherObject); + +/** + Returns a Boolean value that indicates if the given class is a collection. + + The following classes are considered collections: + + 1. `NSSet` + 1. `NSArray` + 1. `NSOrderedSet` + + `NSDictionary` objects are **not** considered collections as they are typically object representations. + + @param aClass The class to check. + @return `YES` if the given class is a collection. + */ +BOOL RKClassIsCollection(Class aClass); + +/** + Returns a Boolean value that indicates if the given object is a collection. + + Implemented by invoking `RKClassIsCollection` with the class of the given object. + @param object The object to be tested. + @return `YES` if the given object is a collection, else `NO`. + @see `RKClassIsCollection` + */ +BOOL RKObjectIsCollection(id object); + +/** + Returns a Boolean value that indicates if the given object is collection containing only instances of `NSManagedObject` or a class that inherits from `NSManagedObject`. + + @param object The object to be tested. + @return `YES` if the object is a collection containing only `NSManagedObject` derived objects. + */ +BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object); + +/** + Returns a Boolean value that indicates if the given object is a collection containing subcollections. + + @param object The object to be tested. + @return `YES` if the object is a collection of collections, else `NO`. + */ +BOOL RKObjectIsCollectionOfCollections(id object); + +/** + Returns an appropriate class to use for KVC access based on the Objective C runtime type encoding. + + Objective C Runtime type encodings: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html + KVC Scalar/Structure support: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/DataTypes.html#//apple_ref/doc/uid/20002171-BAJEAIEE + + @param type An Objective C Runtime type encoding + @return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible. + */ +Class RKKeyValueCodingClassForObjCType(const char *type); + +/** + Returns an appropriate class to use for KVC access based on the output obtained via the `property_getAttributes` reflection API. + + @param attr A c string containing encoding attribute information. + @return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible. + */ +Class RKKeyValueCodingClassFromPropertyAttributes(const char *attr); + +/** + Returns the name of a property when provided the name of a property obtained via the `property_getAttributes` reflection API. + + @param attributeString A string object encoding attribute information. + @return The class name for the property type encoded in the given attribute string or `@"NULL"` if the property does not have an object type (the declared property is for a primitive type). + */ +NSString *RKPropertyTypeFromAttributeString(NSString *attributeString); + +#ifdef __cplusplus +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m new file mode 100644 index 0000000..052335e --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m @@ -0,0 +1,148 @@ +// +// RKObjectUtilities.m +// RestKit +// +// Created by Blake Watters on 9/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/message.h> +#import <objc/runtime.h> +#import "RKObjectUtilities.h" + +BOOL RKObjectIsEqualToObject(id object, id anotherObject) { + NSCAssert(object, @"Expected object not to be nil"); + NSCAssert(anotherObject, @"Expected anotherObject not to be nil"); + + return (object == anotherObject) || [object isEqual:anotherObject]; +} + +BOOL RKClassIsCollection(Class aClass) +{ + return (aClass && ([aClass isSubclassOfClass:[NSSet class]] || + [aClass isSubclassOfClass:[NSArray class]] || + [aClass isSubclassOfClass:[NSOrderedSet class]])); +} + +BOOL RKObjectIsCollection(id object) +{ + return RKClassIsCollection([object class]); +} + +BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object) +{ + if (! RKObjectIsCollection(object)) return NO; + Class managedObjectClass = NSClassFromString(@"NSManagedObject"); + if (! managedObjectClass) return NO; + for (id instance in object) { + if (! [instance isKindOfClass:managedObjectClass]) return NO; + } + return YES; +} + +BOOL RKObjectIsCollectionOfCollections(id object) +{ + if (! RKObjectIsCollection(object)) return NO; + id collectionSanityCheckObject = nil; + if ([object respondsToSelector:@selector(anyObject)]) collectionSanityCheckObject = [object anyObject]; + if ([object respondsToSelector:@selector(lastObject)]) collectionSanityCheckObject = [object lastObject]; + return RKObjectIsCollection(collectionSanityCheckObject); +} + +Class RKKeyValueCodingClassForObjCType(const char *type) +{ + if (type) { + switch (type[0]) { + case _C_ID: { + char *openingQuoteLoc = strchr(type, '"'); + if (openingQuoteLoc) { + char *closingQuoteLoc = strchr(openingQuoteLoc+1, '"'); + if (closingQuoteLoc) { + size_t classNameStrLen = closingQuoteLoc-openingQuoteLoc; + char className[classNameStrLen]; + memcpy(className, openingQuoteLoc+1, classNameStrLen-1); + // Null-terminate the array to stringify + className[classNameStrLen-1] = '\0'; + return objc_getClass(className); + } + } + // If there is no quoted class type (id), it can be used as-is. + return Nil; + } + + case _C_CHR: // char + case _C_UCHR: // unsigned char + case _C_SHT: // short + case _C_USHT: // unsigned short + case _C_INT: // int + case _C_UINT: // unsigned int + case _C_LNG: // long + case _C_ULNG: // unsigned long + case _C_LNG_LNG: // long long + case _C_ULNG_LNG: // unsigned long long + case _C_FLT: // float + case _C_DBL: // double + return [NSNumber class]; + + case _C_BOOL: // C++ bool or C99 _Bool + return objc_getClass("NSCFBoolean") + ?: objc_getClass("__NSCFBoolean") + ?: [NSNumber class]; + + case _C_STRUCT_B: // struct + case _C_BFLD: // bitfield + case _C_UNION_B: // union + return [NSValue class]; + + case _C_ARY_B: // c array + case _C_PTR: // pointer + case _C_VOID: // void + case _C_CHARPTR: // char * + case _C_CLASS: // Class + case _C_SEL: // selector + case _C_UNDEF: // unknown type (function pointer, etc) + default: + break; + } + } + return Nil; +} + +Class RKKeyValueCodingClassFromPropertyAttributes(const char *attr) +{ + if (attr) { + const char *typeIdentifierLoc = strchr(attr, 'T'); + if (typeIdentifierLoc) { + return RKKeyValueCodingClassForObjCType(typeIdentifierLoc+1); + } + } + return Nil; +} + +NSString *RKPropertyTypeFromAttributeString(NSString *attributeString) +{ + NSString *type = [NSString string]; + NSScanner *typeScanner = [NSScanner scannerWithString:attributeString]; + [typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"@"] intoString:NULL]; + + // we are not dealing with an object + if ([typeScanner isAtEnd]) { + return @"NULL"; + } + [typeScanner scanCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"@"] intoString:NULL]; + // this gets the actual object type + [typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&type]; + return type; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h new file mode 100644 index 0000000..98b5d07 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1,117 @@ +// +// RKPropertyInspector.h +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class NSEntityDescription; + +/** + * The object used to store attributes for each property; used as the value in the class dictionary. + */ +@interface RKPropertyInspectorPropertyInfo : NSObject + +/** + Creates a new RKPropertyInspectorPropertyInfo instance with the given information + */ ++ (instancetype)propertyInfoWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive; + +/** + The name of the property + */ +@property (nonatomic, copy, readonly) NSString *name; + +/** + The class used for key-value coding access to the property. + + If the property is an object type, then the class set for this key will be the type of the property. If the property is a primitive, then the class set for the key will be the boxed type used for KVC access to the property. For example, an `NSInteger` property is boxed to an `NSNumber` for KVC purposes. + */ +@property (nonatomic, strong, readonly) Class keyValueCodingClass; + +/** + A BOOL value that indicates if the property is a primitive (non-object) value. + */ +@property (nonatomic, readonly) BOOL isPrimitive; + +@end + + +/** + The `RKPropertyInspector` class provides an interface for introspecting the properties and attributes of classes using the reflection capabilities of the Objective-C runtime. Once inspected, the properties inspection details are cached. + */ +@interface RKPropertyInspector : NSObject + +///----------------------------------------------- +/// @name Retrieving the Shared Inspector Instance +///----------------------------------------------- + +/** + Returns the shared property inspector singleton instance. + + @return The shared `RKPropertyInspector` instance. + */ ++ (RKPropertyInspector *)sharedInspector; + +///------------------------------------------------------ +/// @name Retrieving the Properties and Types for a Class +///------------------------------------------------------ + +/** + Returns a dictionary keyed by property name that includes the key-value coding class of the property and a Boolean indicating if the property is backed by a primitive (non-object) value. The RKPropertyInspectorPropertyInfo object for each property includes details about the key-value coding class representing the property and if the property is backed by a primitive type. + + @param objectClass The class to inspect the properties of. + @return A dictionary keyed by property name that includes details about all declared properties of the class. + */ +- (NSDictionary *)propertyInspectionForClass:(Class)objectClass; + +/** + Returns the `Class` object specifying the type of the property with given name on a class. + + @param propertyName The name of the property to retrieve the type of. + @param objectClass The class to retrieve the property from. + @param isPrimitive A pointer to a Boolean value to set indicating if the specified property is of a primitive (non-object) type. + @return A `Class` object specifying the type of the requested property. + */ +- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass isPrimitive:(BOOL *)isPrimitive; + +@end + +///---------------------------- +/// @name Convenience Functions +///---------------------------- + +/** + Returns the class of the attribute or relationship property at the key path of the given object. + + Given a key path to a string property, this will return an `NSString`, etc. + + @param keyPath The key path to the property to retrieve the class of. + @param object The object to evaluate. + @return The class of the property at the given key path. + */ +Class RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(NSString *keyPath, id object); + +/** + Returns a Boolean value indicating if the property at the specified key path for a given object is modeled by a primitive type. + + @param keyPath The key path to inspect the property of. + @param object The object to evaluate. + @return `YES` if the property is a primitive, else `NO`. + */ +BOOL RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(NSString *keyPath, id object); diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m new file mode 100644 index 0000000..7106713 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m @@ -0,0 +1,207 @@ +// +// RKPropertyInspector.m +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKPropertyInspector.h" +#import "RKLog.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +NSString * const RKPropertyInspectionNameKey = @"name"; +NSString * const RKPropertyInspectionKeyValueCodingClassKey = @"keyValueCodingClass"; +NSString * const RKPropertyInspectionIsPrimitiveKey = @"isPrimitive"; + + +@implementation RKPropertyInspectorPropertyInfo + ++ (instancetype)propertyInfoWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive +{ + return [[self alloc] initWithName:name keyValueClass:kvClass isPrimitive:isPrimitive]; +} + +- (instancetype)initWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive +{ + if (self = [super init]) { + _name = [name copy]; + _keyValueCodingClass = kvClass; + _isPrimitive = isPrimitive; + } + return self; +} + +@end + + +@interface RKPropertyInspector () +#if OS_OBJECT_USE_OBJC +@property (nonatomic, strong) dispatch_queue_t queue; +#else +@property (nonatomic, assign) dispatch_queue_t queue; +#endif +@property (nonatomic, strong) NSMutableDictionary *inspectionCache; +@end + +@implementation RKPropertyInspector + ++ (RKPropertyInspector *)sharedInspector +{ + static RKPropertyInspector *sharedInspector = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInspector = [RKPropertyInspector new]; + }); + + return sharedInspector; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + // NOTE: We use an `NSMutableDictionary` because it is *much* faster than `NSCache` on lookup + self.inspectionCache = [NSMutableDictionary dictionary]; + self.queue = dispatch_queue_create("org.restkit.core-data.property-inspection-queue", DISPATCH_QUEUE_CONCURRENT); + } + + return self; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_queue) dispatch_release(_queue); +#endif + _queue = NULL; +} + +- (NSDictionary *)propertyInspectionForClass:(Class)objectClass +{ + __block NSMutableDictionary *inspection; + dispatch_sync(self.queue, ^{ + inspection = (self.inspectionCache)[objectClass]; + }); + if (inspection) return inspection; + + inspection = [NSMutableDictionary dictionary]; + + //include superclass properties + Class currentClass = objectClass; + while (currentClass != nil) { + // Get the raw list of properties + unsigned int outCount = 0; + objc_property_t *propList = class_copyPropertyList(currentClass, &outCount); + + // Collect the property names + for (typeof(outCount) i = 0; i < outCount; i++) { + objc_property_t *prop = propList + i; + const char *propName = property_getName(*prop); + + if (strcmp(propName, "_mapkit_hasPanoramaID") != 0) { + const char *attr = property_getAttributes(*prop); + if (attr) { + Class aClass = RKKeyValueCodingClassFromPropertyAttributes(attr); + if (aClass) { + NSString *propNameString = [[NSString alloc] initWithCString:propName encoding:NSUTF8StringEncoding]; + if (propNameString) { + BOOL isPrimitive = NO; + if (attr) { + const char *typeIdentifierLoc = strchr(attr, 'T'); + if (typeIdentifierLoc) { + isPrimitive = (typeIdentifierLoc[1] != '@'); + } + } + + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:propNameString + keyValueClass:aClass + isPrimitive:isPrimitive]; + inspection[propNameString] = info; + } + } + } + } + } + + free(propList); + Class superclass = [currentClass superclass]; + Class nsManagedObject = NSClassFromString(@"NSManagedObject"); + currentClass = (superclass == [NSObject class] || (nsManagedObject && superclass == nsManagedObject)) ? nil : superclass; + } + + /* dispatch_barrier_async is dangerous if we are called from +initialize */ + dispatch_barrier_sync(self.queue, ^{ + (self.inspectionCache)[(id<NSCopying>)objectClass] = inspection; + RKLogDebug(@"Cached property inspection for Class '%@': %@", NSStringFromClass(objectClass), inspection); + }); + return inspection; +} + +- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass isPrimitive:(BOOL *)isPrimitive +{ + NSDictionary *classInspection = [self propertyInspectionForClass:objectClass]; + RKPropertyInspectorPropertyInfo *propertyInspection = classInspection[propertyName]; + if (isPrimitive) *isPrimitive = propertyInspection.isPrimitive; + return propertyInspection.keyValueCodingClass; +} + +@end + + +@interface NSObject (RKPropertyInspection) +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive; +@end + +@implementation NSObject (RKPropertyInspection) + +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive +{ + NSRange dotRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + RKPropertyInspector *inspector = [RKPropertyInspector sharedInspector]; + Class propertyClass = [self class]; + + if (dotRange.length == 0) { + return [inspector classForPropertyNamed:keyPath ofClass:propertyClass isPrimitive:isPrimitive]; + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + for (NSString *property in components) { + propertyClass = [inspector classForPropertyNamed:property ofClass:propertyClass isPrimitive:isPrimitive]; + if (! propertyClass) break; + } + + return propertyClass; +} + +@end + +Class RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(NSString *keyPath, id object) +{ + return [object rk_classForPropertyAtKeyPath:keyPath isPrimitive:nil]; +} + +BOOL RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(NSString *keyPath, id object) +{ + BOOL isPrimitive = NO; + [object rk_classForPropertyAtKeyPath:keyPath isPrimitive:&isPrimitive]; + return isPrimitive; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h new file mode 100644 index 0000000..5f39859 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1,84 @@ +// +// RKPropertyMapping.h +// RestKit +// +// Created by Blake Watters on 8/27/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class RKObjectMapping; +@protocol RKValueTransforming; + +/** + `RKPropertyMapping` is an abstract class for describing the properties being mapped within an `RKObjectMapping` or `RKEntityMapping` object. It defines the common interface for its concrete subclasses `RKAttributeMapping` and `RKRelationshipMapping`. Each property mapping defines a single transformation from a source key path (often in the deserialized representation of a JSON or XML document) to a destination key path (typically on a target object). + */ +@interface RKPropertyMapping : NSObject <NSCopying> + +///------------------------------------------ +/// @name Accessing the Parent Object Mapping +///------------------------------------------ + +/** + Returns the object mapping the receiver is added to. + */ +@property (nonatomic, weak, readonly) RKObjectMapping *objectMapping; + +///----------------------------------------------------- +/// @name Accessing the Source and Destination Key Paths +///----------------------------------------------------- + +/** + A key path on the source object from which to get information that is to be mapped onto the destination object. + */ +@property (nonatomic, copy, readonly) NSString *sourceKeyPath; + +/** + A key path on the destination object on which to set information that has been mapped from the source object. + */ +@property (nonatomic, copy, readonly) NSString *destinationKeyPath; + +///------------------------------------- +/// @name Specifying a Value Transformer +///------------------------------------- + +/** + Specifies the class used to represent the value of the mapped property. A value of `Nil` (which is the default value) indicates the property class is to be determined by runtime introspection. + + In cases where run-time type introspection cannot be performed (such as during object parameterization) you can specify the class used to represent the value of the property being mapped. + */ +@property (nonatomic, strong) Class propertyValueClass; + +/** + A value transformer with which to process input values being mapped with the receiver. If `nil`, then the `valueTransformer` of the parent `objectMapping` will be used instead. + */ +@property (nonatomic, strong) id<RKValueTransforming> valueTransformer; + +///---------------------------------- +/// @name Comparing Property Mappings +///---------------------------------- + +/** + Compares the receiving property mapping to another property mapping. + + Two property mappings are equal if they are of the same type (i.e. an `RKAttributeMapping` or an `RKRelatiobshipMapping` object) and specify a mapping from the same source key path to the same destination key path. + + @param otherMapping The property mapping object with which to compare the receiver. + @return `YES` if `otherMapping` specifies the same mapping as the receiver, otherwise `NO`. + */ +- (BOOL)isEqualToMapping:(RKPropertyMapping *)otherMapping; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m new file mode 100644 index 0000000..6d4debd --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m @@ -0,0 +1,77 @@ +// +// RKPropertyMapping.m +// RestKit +// +// Created by Blake Watters on 8/27/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" +#import "RKObjectMapping.h" + +/** + For consistency with URI Templates (and most web templating languages in general) we are transitioning + to using braces "{}" instead of parentheses "()" for denoting the variables in the key paths. + */ +static NSString *RKStringByReplacingUnderscoresWithBraces(NSString *string) +{ + return [[string stringByReplacingOccurrencesOfString:@"(" withString:@"{"] stringByReplacingOccurrencesOfString:@")" withString:@"}"]; +} + +@interface RKPropertyMapping () +// Synthesize as read/write to allow assignment in `RKObjectMapping` +@property (nonatomic, weak, readwrite) RKObjectMapping *objectMapping; +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@implementation RKPropertyMapping + +- (id)copyWithZone:(NSZone *)zone +{ + RKPropertyMapping *copy = [[[self class] allocWithZone:zone] init]; + copy.sourceKeyPath = self.sourceKeyPath; + copy.destinationKeyPath = self.destinationKeyPath; + return copy; +} + +- (BOOL)isEqualToMapping:(RKPropertyMapping *)otherMapping +{ + return [otherMapping isMemberOfClass:[self class]] && + (self.sourceKeyPath == otherMapping.sourceKeyPath || [self.sourceKeyPath isEqual:otherMapping.sourceKeyPath]) && + [self.destinationKeyPath isEqual:otherMapping.destinationKeyPath]; +} + +- (void)setSourceKeyPath:(NSString *)sourceKeyPath +{ + _sourceKeyPath = RKStringByReplacingUnderscoresWithBraces(sourceKeyPath); +} + +- (void)setDestinationKeyPath:(NSString *)destinationKeyPath +{ + _destinationKeyPath = RKStringByReplacingUnderscoresWithBraces(destinationKeyPath); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p %@ => %@>", self.class, self, self.sourceKeyPath, self.destinationKeyPath]; +} + +- (id<RKValueTransforming>)valueTransformer +{ + return _valueTransformer ?: [self.objectMapping valueTransformer]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h new file mode 100644 index 0000000..5c81276 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1,95 @@ +// +// RKRelationshipMapping.h +// RestKit +// +// Created by Blake Watters on 5/4/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" + +@class RKMapping; + +typedef NS_ENUM(NSInteger, RKAssignmentPolicy) { + RKAssignmentPolicySet, // Set the relationship to the new value and leave the existing objects alone, breaking the relationship to existing objects at the destination. This is the default policy for `RKRelationshipMapping`. + RKAssignmentPolicyReplace, // Set the relationship to the new value and destroy the previous value, replacing the existing objects at the destination of the relationship. + RKAssignmentPolicyUnion, // Set the relationship to the union of the existing value and the new value being assigned. Only applicable for to-many relationships. + + // Deprecated + RKSetAssignmentPolicy = RKAssignmentPolicySet, // Will be deprecated, use `RKAssignmentPolicySet` instead + RKReplaceAssignmentPolicy = RKAssignmentPolicyReplace, // Will be deprecated, use `RKAssignmentPolicyReplace` instead + RKUnionAssignmentPolicy = RKAssignmentPolicyUnion, // Will be deprecated, use `RKAssignmentPolicyUnion` instead +} ; + +/** + The `RKRelationshipMapping` class is used to describe relationships of a class in an `RKObjectMapping` or an entity in an `RKEntityMapping` object. + + `RKRelationshipMapping` extends `RKPropertyMapping` to describe features specific to relationships, including the `RKMapping` object describing how to map the destination object. + + Relationship mappings are described in terms of a source key path, which identifies a key in the parent object representation under which the data for the relationship is nested, and a destination key path, which specifies the key path at which the mapped object is to be assigned on the parent entity. The key paths of the property mappings of the `RKMapping` object in the relationship mapping are evaluated against the nested object representationship at the source key path. + + ## Mapping a Non-nested Relationship from the Parent Representation + + It can often be desirable to map data for a relationship directly from the parent object representation, rather than under a nested key path. When a relationship mapping is constructed with a `nil` value for the source key path, then the `RKMapping` object is evaluated against the parent representation. + + ## Assignment Policy + + When mapping a relationship, the typical desired behavior is to set the destination of the relationship to the newly mapped values from the object representation being processed. There are times in which it is desirable to use different assignment behaviors. The way in which the relationship is assigned can be controlled by the assignmentPolicy property. There are currently three distinct assignment policies available: + + 1. `RKSetAssignmentPolicy` - Instructs the mapper to assign the new destination value to the relationship directly. No further action is taken and the relationship to the old objects is broken. This is the default assignment policy. + 1. `RKReplaceAssignmentPolicy` - Instructs the mapper to assign the new destination value to the relationship and delete any existing object or objects at the destination. The deletion behavior is contextual based on the type of objects being mapped (i.e. Core Data vs NSObject) and is delegated to the mapping operation data source. + 1. `RKUnionAssignmentPolicy` - Instructs the mapper to build a new value for the relationship by unioning the existing value with the new value and set the combined value to the relationship. The union assignment policy is only appropriate for use with a to-many relationship. + + */ +@interface RKRelationshipMapping : RKPropertyMapping + +///-------------------------------------- +/// @name Creating a Relationship Mapping +///-------------------------------------- + +/** + Creates and returns a new relationship mapping object describing how to transform a related object representation at `sourceKeyPath` to a new representation at `destinationKeyPath` using the given mapping. + + The mapping may describe a to-one or a to-many relationship. The appropriate handling of the source representation is deferred until run-time and is determined by performing reflection on the data retrieved from the source object representation by sending a `valueForKeyPath:` message where the key path is the value given in `sourceKeyPath`. If an `NSArray`, `NSSet` or `NSOrderedSet` object is returned, the related object representation is processed as a to-many collection. Otherwise the representation is considered to be a to-one. + + @param sourceKeyPath A key path from which to retrieve data in the source object representation that is to be mapped as a relationship. If `nil`, then the mapping is performed directly against the parent object representation. + @param destinationKeyPath The key path on the destination object to set the object mapped results. + @param mapping A mapping object describing how to map the data retrieved from `sourceKeyPath` that is to be set on `destinationKeyPath`. + */ ++ (instancetype)relationshipMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)mapping; + +///---------------------------------------- +/// @name Accessing the Destination Mapping +///---------------------------------------- + +/** + An `RKMapping` object describing how to map the object representation at `sourceKeyPath` to a new represenation at `destinationKeyPath`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +///---------------------------------------- +/// @name Configuring the Assignment Policy +///---------------------------------------- + +/** + The assignment policy to use when applying the relationship mapping. + + The assignment policy determines how a relationship is set when there are existing objects at the destination of the relationship. The existing values can be disconnected from the parent and left in the graph (`RKSetAssignmentPolicy`), deleted and replaced by the new value (`RKReplaceAssignmentPolicy`), or the new value can be unioned with the existing objects to create a new combined value (`RKUnionAssignmentPolicy`). + + **Default**: `RKSetAssignmentPolicy` + */ +@property (nonatomic, assign) RKAssignmentPolicy assignmentPolicy; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m new file mode 100644 index 0000000..ae867c0 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m @@ -0,0 +1,70 @@ +// +// RKRelationshipMapping.m +// RestKit +// +// Created by Blake Watters on 5/4/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRelationshipMapping.h" +#import "RKMapping.h" + +@interface RKPropertyMapping () +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@interface RKRelationshipMapping () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@end + +@implementation RKRelationshipMapping + ++ (instancetype)relationshipMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)mapping +{ + RKRelationshipMapping *relationshipMapping = [self new]; + relationshipMapping.sourceKeyPath = sourceKeyPath; + relationshipMapping.destinationKeyPath = destinationKeyPath; + relationshipMapping.mapping = mapping; + return relationshipMapping; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.assignmentPolicy = RKSetAssignmentPolicy; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone +{ + RKRelationshipMapping *copy = [super copyWithZone:zone]; + copy.mapping = self.mapping; + copy.assignmentPolicy = self.assignmentPolicy; + return copy; +} + +- (BOOL)isEqualToMapping:(RKRelationshipMapping *)otherMapping +{ + if (! [otherMapping isMemberOfClass:[RKRelationshipMapping class]]) return NO; + if (! [super isEqualToMapping:otherMapping]) return NO; + if (self.mapping == nil && otherMapping.mapping == nil) return YES; + + return [self.mapping isEqualToMapping:otherMapping.mapping]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/RestKit.h b/Unit-2-Journal/Pods/RestKit/Code/RestKit.h new file mode 100644 index 0000000..30e1951 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/RestKit.h @@ -0,0 +1,50 @@ +// +// RestKit.h +// RestKit +// +// Created by Blake Watters on 2/19/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef _RESTKIT_ +#define _RESTKIT_ + +#if __has_include("ObjectMapping.h") +#import "ObjectMapping.h" +#endif + +#if __has_include("Network.h") +#import "Network.h" +#endif + +#if __has_include("Support.h") +#import "Support.h" +#endif + +#if __has_include("RKCoreData.h") +#import "RKCoreData.h" +#endif + +/** + Set the App logging component. This header + file is generally only imported by apps that + are pulling in all of RestKit. By setting the + log component to App here, we allow the app developer + to use RKLog() in their own app. + */ +#undef RKLogComponent +#define RKLogComponent RKlcl_cApp + +#endif /* _RESTKIT_ */ diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support.h b/Unit-2-Journal/Pods/RestKit/Code/Support.h new file mode 100644 index 0000000..ba3e127 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support.h @@ -0,0 +1,31 @@ +// +// Support.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Load shared support code +#import "RKErrors.h" +#import "RKMIMETypes.h" +#import "RKLog.h" +#import "RKDotNetDateFormatter.h" +#import "RKPathUtilities.h" +#import "RKDictionaryUtilities.h" +#import "RKURLEncodedSerialization.h" +#import "RKNSJSONSerialization.h" +#import "RKMIMETypeSerialization.h" +#import "RKStringTokenizer.h" diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.h new file mode 100644 index 0000000..1752c3b --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.h @@ -0,0 +1,46 @@ +// +// RKDictionaryUtilities.h +// RestKit +// +// Created by Blake Watters on 9/11/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef __cplusplus +extern "C" { +#endif + +#import <Foundation/Foundation.h> + +/** + Reverse merges two dictionary to produce a new dictionary wherein the keys in the second dictionary have taken precedence in instances where keys overlap. The merge is performed recursively such that subdictionaries are reverse merged as well. + + @param dict1 The dictionary to be reverse merged. + @param dict2 A secondary dictionary to perform the reverse merging with. + @return A new `NSDicionary` object that is the product of the reverse merge. + */ +NSDictionary *RKDictionaryByMergingDictionaryWithDictionary(NSDictionary *dict1, NSDictionary *dict2); + +/** + Return a new dictionary by stripping out any percent escapes (such as %20) from the given dictionary's key and values. + + @param dictionary The dictionary from which to remove the percent escape sequences. + @return A new `NSDictionary` wherein any percent escape sequences in the key and values have been replaced with their literal values. + */ +NSDictionary *RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(NSDictionary *dictionary); + +#ifdef __cplusplus +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.m new file mode 100644 index 0000000..66b09ce --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDictionaryUtilities.m @@ -0,0 +1,44 @@ +// +// RKDictionaryUtilities.m +// RestKit +// +// Created by Blake Watters on 9/11/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// + +#import "RKDictionaryUtilities.h" + +NSDictionary *RKDictionaryByMergingDictionaryWithDictionary(NSDictionary *dict1, NSDictionary *dict2) +{ + if (! dict1) return dict2; + if (! dict2) return dict1; + + NSMutableDictionary *mergedDictionary = [dict1 mutableCopy]; + + for (id key2 in dict2) { + id obj2 = dict2[key2]; + id obj1 = dict1[key2]; + if ([obj1 isKindOfClass:[NSDictionary class]] && [obj2 isKindOfClass:[NSDictionary class]]) { + NSDictionary *mergedSubdict = RKDictionaryByMergingDictionaryWithDictionary(obj1, obj2); + mergedDictionary[key2] = mergedSubdict; + } else { + mergedDictionary[key2] = obj2; + } + } + + return mergedDictionary; +} + +NSDictionary *RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(NSDictionary *dictionary) +{ + NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) + { + NSString *escapedKey = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + id escapedValue = value; + if ([value respondsToSelector:@selector(stringByReplacingPercentEscapesUsingEncoding:)]) + escapedValue = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + results[escapedKey] = escapedValue; + }]; + return results; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h new file mode 100644 index 0000000..03bc2b4 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h @@ -0,0 +1,73 @@ +// +// RKDotNetDateFormatter.h +// RestKit +// +// Created by Greg Combs on 9/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + A subclass of `NSDateFormatter` that serves as translator between ASP.NET date serializations in JSON strings and NSDate objects. This is useful for properly mapping these dates from an ASP.NET driven backend. + + @warning DO NOT attempt to use `setDateFormat:` on this class. It will return invalid results. + */ +@interface RKDotNetDateFormatter : NSDateFormatter + +/** + Instantiates an autoreleased `RKDotNetDateFormatter` object with the timezone set to the given value. The default time zone is UTC. + + The supplied timeZone, such as one produced with `[NSTimeZone timeZoneWithName:@"UTC"]`, + is only used during calls to `stringFromDate:, for a detailed explanation see `dateFromString:` + + @param timeZone An NSTimeZone object. A `nil` value sets the timezone to the default value of UTC. + @return An autoreleased `RKDotNetDateFormatter` object + @see dotNetDateFormatter + */ ++ (instancetype)dotNetDateFormatterWithTimeZone:(NSTimeZone *)timeZone; + +/** + Returns an `NSDate` object from an ASP.NET style date string respresentation, as seen in JSON. + + Acceptable examples are: + /Date(1112715000000-0500)/ + /Date(1112715000000)/ + /Date(-1112715000000)/ + Where 1112715000000 is the number of milliseconds since January 1, 1970 00:00 GMT/UTC, and -0500 represents the timezone offset from GMT in 24-hour time. Negatives milliseconds are treated as dates before January 1, 1970. + + *NOTE* `NSDate` objects do not have timezones, and you should never change an actual date value based on a timezone offset. However, timezones are important when presenting dates to the user. Therefore, If an offset is present in the ASP.NET string (it should be), we actually ignore the offset portion because we want to store the actual date value in its raw form, without any pollution of timezone information. If, on the other hand, there is no offset in the ASP.NET string, we assume GMT (+0000) anyway. In summation, for this class `setTimeZone:` is ignored except when using `stringFromDate:` + + @param string The ASP.NET style string, /Date(1112715000000-0500)/ + @return An `NSDate` object. + @see `stringFromDate` + @see `NSDateFormatter` + @see `NSTimeZone` + */ +- (NSDate *)dateFromString:(NSString *)string; + +/** + Returns an ASP.NET style date string from an NSDate, such as /Date(1112715000000+0000)/ Where 1112715000000 is the number of milliseconds since January 1, 1970 00:00 GMT/UTC, and +0000 is the timezone offset from GMT in 24-hour time. + + *NOTE *GMT (+0000) is assumed otherwise specified via `setTimeZone:` + + @param date An `NSDate` object from which to return a string value. + @return The ASP.NET style string, /Date(1112715000000-0500)/ + @see `dateFromString` + @see `NSDateFormatter` + @see `NSTimeZone` + */ +- (NSString *)stringFromDate:(NSDate *)date; +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m new file mode 100644 index 0000000..11e2a53 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m @@ -0,0 +1,115 @@ +// +// RKDotNetDateFormatter.h +// RestKit +// +// Created by Greg Combs on 9/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKDotNetDateFormatter.h" +#import "RKLog.h" + +static BOOL RKDotNetDateFormatterIsValidRange(NSRange rangeOfMatch) +{ + return (!NSEqualRanges(rangeOfMatch, NSMakeRange(NSNotFound, 0))); +} + +static NSTimeInterval RKDotNetDateFormatterSecondsFromMilliseconds(NSTimeInterval millisecs) +{ + return millisecs / 1000.f; +} + +static NSTimeInterval RKDotNetDateFormatterMillisecondsFromSeconds(NSTimeInterval seconds) +{ + return seconds *1000.f; +} + +@interface RKDotNetDateFormatter () +@property (nonatomic, strong) NSRegularExpression *dotNetExpression; + +- (NSString *)millisecondsFromString:(NSString *)string; +@end + +@implementation RKDotNetDateFormatter + ++ (instancetype)dotNetDateFormatterWithTimeZone:(NSTimeZone *)newTimeZone +{ + RKDotNetDateFormatter *formatter = [self new]; + if (newTimeZone) formatter.timeZone = newTimeZone; + return formatter; +} + +- (NSDate *)dateFromString:(NSString *)string +{ + NSString *milliseconds = [self millisecondsFromString:string]; + if (!milliseconds) { + RKLogError(@"Attempted to interpret an invalid .NET date string: %@", string); + return nil; + } + NSTimeInterval seconds = RKDotNetDateFormatterSecondsFromMilliseconds([milliseconds doubleValue]); + return [NSDate dateWithTimeIntervalSince1970:seconds]; +} + + +- (NSString *)stringFromDate:(NSDate *)date +{ + if (!date) { + RKLogError(@"Attempted to represent an invalid date: %@", date); + return nil; + } + return [self stringForObjectValue:date]; +} + +- (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error +{ + NSDate *date = [self dateFromString:string]; + if (outValue) + *outValue = date; + return (date != nil); +} + +- (NSString *)stringForObjectValue:(id)value +{ + NSParameterAssert([value isKindOfClass:[NSDate class]]); + NSString *timeZoneOffset = [super stringForObjectValue:value]; + NSTimeInterval milliseconds = RKDotNetDateFormatterMillisecondsFromSeconds([(NSDate *)value timeIntervalSince1970]); + return [NSString stringWithFormat:@"/Date(%1.0lf%@)/", milliseconds, timeZoneOffset]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + self.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; + [self setDateFormat:@"ZZ"]; // GMT offset, like "-0500" + NSString *pattern = @"\\/Date\\((-?\\d+)((?:[\\+\\-]\\d+)?)\\)\\/"; // /Date(mSecs)/ or /Date(-mSecs)/ or /Date(mSecs-0400)/ + self.dotNetExpression = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:NULL]; + } + return self; +} + +- (NSString *)millisecondsFromString:(NSString *)string +{ + if (!string) return nil; + NSTextCheckingResult *match = [self.dotNetExpression firstMatchInString:string options:NSMatchingReportCompletion range:NSMakeRange(0, [string length])]; + if (!match) return nil; + NSRange millisecRange = [match rangeAtIndex:1]; + if (!RKDotNetDateFormatterIsValidRange(millisecRange)) return nil; + NSString *milliseconds = [string substringWithRange:millisecRange]; + return milliseconds; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.h new file mode 100644 index 0000000..bf79280 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.h @@ -0,0 +1,59 @@ +// +// RKErrors.h +// RestKit +// +// Created by Blake Watters on 3/25/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +///--------------------------- +/// @name Error Domain & Codes +///--------------------------- + +// The error domain for RestKit generated errors +extern NSString * const RKErrorDomain; + +typedef NS_ENUM(NSInteger, RKRestKitError) { + RKUnsupportedMIMETypeError = 1, + RKOperationCancelledError = 2 +} ; + + +///-------------------------------------- +/// @name Error User Info Dictionary Keys +///-------------------------------------- + +/** + The key RestKit generated errors will appear at within an NSNotification + indicating an error + */ +extern NSString *const RKErrorNotificationErrorKey; + +/** + When RestKit constructs an NSError object from one or more RKErrorMessage + (or other object mapped error representations), the userInfo of the NSError + object will be populated with an array of the underlying error objects. + + These underlying errors can be accessed via RKObjectMapperErrorObjectsKey key. + + @see RKObjectMappingResult + */ +extern NSString *const RKObjectMapperErrorObjectsKey; + +extern NSString *const RKDetailedErrorsKey; // When multiple errors occur, they are stored in a composite error + +extern NSString *const RKMIMETypeErrorKey; diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.m new file mode 100644 index 0000000..ae9a154 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKErrors.m @@ -0,0 +1,28 @@ +// +// RKErrors.m +// RestKit +// +// Created by Blake Watters on 3/25/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrors.h" + +NSString * const RKErrorDomain = @"org.restkit.RestKit.ErrorDomain"; + +NSString * const RKObjectMapperErrorObjectsKey = @"RKObjectMapperErrorObjectsKey"; +NSString * const RKErrorNotificationErrorKey = @"error"; +NSString * const RKDetailedErrorsKey = @"DetailedErrors"; +NSString * const RKMIMETypeErrorKey = @"MIME Type"; diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.h new file mode 100644 index 0000000..da5de94 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.h @@ -0,0 +1,248 @@ +// +// RKLog.h +// RestKit +// +// Created by Blake Watters on 5/3/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/** + RestKit Logging is based on the LibComponentLogging framework + + @see lcl_config_components_RK.h + @see lcl_config_logger_RK.h + */ +#import "lcl_RK.h" + +/** + * Protocol which classes can implement to determine how RestKit log messages actually get handled. + * There is a single "current" logging class installed, which all log messages will flow + * through. + */ +@protocol RKLogging + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)file + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... NS_FORMAT_FUNCTION(6, 7); + +@end + +/** + * Functions to get and set the current RKLogging class. + */ +Class <RKLogging> RKGetLoggingClass(void); +void RKSetLoggingClass(Class <RKLogging> loggingClass); + + + +/** + RKLogComponent defines the active component within any given portion of RestKit + + By default, messages will log to the base 'RestKit' log component. All other components + used by RestKit are nested under this parent, so this effectively sets the default log + level for the entire library. + + The component can be undef'd and redefined to change the active logging component. + */ +#define RKLogComponent RKlcl_cRestKit + +/** + The logging macros. These macros will log to the currently active logging component + at the log level identified in the name of the macro. + + For example, in the `RKMappingOperation` class we would redefine the RKLogComponent: + + #undef RKLogComponent + #define RKLogComponent RKlcl_cRestKitObjectMapping + + The RKlcl_c prefix is the LibComponentLogging data structure identifying the logging component + we want to target within this portion of the codebase. See lcl_config_component_RK.h for reference. + + Having defined the logging component, invoking the logger via: + + RKLogInfo(@"This is my log message!"); + + Would result in a log message similar to: + + I RestKit.ObjectMapping:RKLog.h:42 This is my log message! + + The message will only be logged if the log level for the active component is equal to or higher + than the level the message was logged at (in this case, Info). + */ +#define RKLogCritical(...) \ +RKlcl_log(RKLogComponent, RKlcl_vCritical, @"" __VA_ARGS__) + +#define RKLogError(...) \ +RKlcl_log(RKLogComponent, RKlcl_vError, @"" __VA_ARGS__) + +#define RKLogWarning(...) \ +RKlcl_log(RKLogComponent, RKlcl_vWarning, @"" __VA_ARGS__) + +#define RKLogInfo(...) \ +RKlcl_log(RKLogComponent, RKlcl_vInfo, @"" __VA_ARGS__) + +#define RKLogDebug(...) \ +RKlcl_log(RKLogComponent, RKlcl_vDebug, @"" __VA_ARGS__) + +#define RKLogTrace(...) \ +RKlcl_log(RKLogComponent, RKlcl_vTrace, @"" __VA_ARGS__) + +/** + Log Level Aliases + + These aliases simply map the log levels defined within LibComponentLogger to something more friendly + */ +#define RKLogLevelOff RKlcl_vOff +#define RKLogLevelCritical RKlcl_vCritical +#define RKLogLevelError RKlcl_vError +#define RKLogLevelWarning RKlcl_vWarning +#define RKLogLevelInfo RKlcl_vInfo +#define RKLogLevelDebug RKlcl_vDebug +#define RKLogLevelTrace RKlcl_vTrace + +/** + Alias the LibComponentLogger logging configuration method. Also ensures logging + is initialized for the framework. + + Expects the name of the component and a log level. + + Examples: + + // Log debugging messages from the Network component + RKLogConfigureByName("RestKit/Network", RKLogLevelDebug); + + // Log only critical messages from the Object Mapping component + RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelCritical); + */ +#define RKLogConfigureByName(name, level) \ +RKlcl_configure_by_name(name, level); + +/** + Alias for configuring the LibComponentLogger logging component for the App. This + enables the end-user of RestKit to leverage RKLog() to log messages inside of + their apps. + */ +#define RKLogSetAppLoggingLevel(level) \ +RKlcl_configure_by_name("App", level); + +/** + Temporarily changes the logging level for the specified component and executes the block. Any logging + statements executed within the body of the block against the specified component will log at the new + logging level. After the block has executed, the logging level is restored to its previous state. + */ +#define RKLogToComponentWithLevelWhileExecutingBlock(_component, _level, _block) \ + do { \ + int _currentLevel = _RKlcl_component_level[_component]; \ + RKlcl_configure_by_component(_component, _level); \ + @try { \ + _block(); \ + } \ + @catch (NSException *exception) { \ + @throw; \ + } \ + @finally { \ + RKlcl_configure_by_component(_component, _currentLevel); \ + } \ + } while (false); + +/** + Temporarily turns off logging for the given logging component during execution of the block. + After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogSilenceComponentWhileExecutingBlock(component, _block) \ + RKLogToComponentWithLevelWhileExecutingBlock(component, RKLogLevelOff, _block) + +/** + Temporarily changes the logging level for the configured RKLogComponent and executes the block. Any logging + statements executed within the body of the block for the current logging component will log at the new + logging level. After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogWithLevelWhileExecutingBlock(_level, _block) \ + RKLogToComponentWithLevelWhileExecutingBlock(RKLogComponent, _level, _block) + + +/** + Temporarily turns off logging for current logging component during execution of the block. + After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogSilenceWhileExecutingBlock(_block) \ + RKLogToComponentWithLevelWhileExecutingBlock(RKLogComponent, RKLogLevelOff, _block) + + +/** + Set the Default Log Level + + Based on the presence of the DEBUG flag, we default the logging for the RestKit parent component + to Info or Warning. + + You can override this setting by defining RKLogLevelDefault as a pre-processor macro. + */ +#ifndef RKLogLevelDefault + #ifdef DEBUG + #define RKLogLevelDefault RKLogLevelInfo + #else + #define RKLogLevelDefault RKLogLevelWarning + #endif +#endif + +/** + Configure RestKit logging from environment variables. + (Use Option + Command + R to set Environment Variables prior to run.) + + For example to configure the equivalent of setting the following in code: + RKLogConfigureByName("RestKit/Network", RKLogLevelTrace); + + Define an environment variable named 'RKLogLevel.RestKit.Network' and set its value to "Trace" + + See lcl_config_components_RK.h for configurable RestKit logging components. + + Valid values are the following: + Default or 0 + Critical or 1 + Error or 2 + Warning or 3 + Info or 4 + Debug or 5 + Trace or 6 + */ +void RKLogConfigureFromEnvironment(void); + +/** + Logs extensive information about an NSError generated as the results + of a failed key-value validation error. + */ +void RKLogValidationError(NSError *error); + +#ifdef _COREDATADEFINES_H +/** + Logs extensive information an NSError generated as the result of a + failed Core Data interaction, such as the execution of a fetch request + or the saving of a managed object context. + + The error will be logged to the RestKit/CoreData component with an + error level of RKLogLevelError regardless of the current logging context + at invocation time. + */ +void RKLogCoreDataError(NSError *error); +#endif + +/** + Logs the value of an NSUInteger as a binary string. Useful when + examining integers containing bitmasked values. + */ +void RKLogIntegerAsBinary(NSUInteger); diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.m new file mode 100644 index 0000000..100798e --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLog.m @@ -0,0 +1,213 @@ +// +// RKLog.m +// RestKit +// +// Created by Blake Watters on 6/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKLog.h" + +@interface RKNSLogLogger : NSObject <RKLogging> +@end + +#if RKLOG_USE_NSLOGGER && __has_include("LCLNSLogger_RK.h") + #import "LCLNSLogger_RK.h" + #define RKLOG_CLASS LCLNSLogger_RK + +#elif __has_include("DDLog.h") + #import "RKLumberjackLogger.h" + #define RKLOG_CLASS RKLumberjackLogger + +#else + #define RKLOG_CLASS RKNSLogLogger +#endif + +// Hook into Objective-C runtime to configure logging when we are loaded +@interface RKLogInitializer : NSObject +@end + +@implementation RKLogInitializer + ++ (void)load +{ + RKlcl_configure_by_name("RestKit*", RKLogLevelDefault); + RKlcl_configure_by_name("App", RKLogLevelDefault); + if (RKGetLoggingClass() == Nil) RKSetLoggingClass([RKLOG_CLASS class]); + RKLogInfo(@"RestKit logging initialized..."); +} + +@end + +static Class <RKLogging> RKLoggingClass; + +Class <RKLogging> RKGetLoggingClass(void) +{ + return RKLoggingClass; +} + +void RKSetLoggingClass(Class <RKLogging> loggingClass) +{ + RKLoggingClass = loggingClass; +} + +@implementation RKNSLogLogger + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)file + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... +{ + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + const char *fileName = (fileName = strrchr(file, '/')) ? fileName + 1 : file; + NSLog(@"%s %s:%s:%d %@", _RKlcl_level_header_1[level], _RKlcl_component_header[component], fileName, line, message); +} + +@end + +int RKLogLevelForString(NSString *, NSString *); + +void RKLogConfigureFromEnvironment(void) +{ + static NSString *logComponentPrefix = @"RKLogLevel."; + + NSDictionary *envVars = [[NSProcessInfo processInfo] environment]; + + for (NSString *envVarName in [envVars allKeys]) { + if ([envVarName hasPrefix:logComponentPrefix]) { + NSString *logLevel = [envVars valueForKey:envVarName]; + NSString *logComponent = [envVarName stringByReplacingOccurrencesOfString:logComponentPrefix withString:@""]; + logComponent = [logComponent stringByReplacingOccurrencesOfString:@"." withString:@"/"]; + + const char *log_component_c_str = [logComponent cStringUsingEncoding:NSUTF8StringEncoding]; + int log_level_int = RKLogLevelForString(logLevel, envVarName); + RKLogConfigureByName(log_component_c_str, log_level_int); + } + } +} + + +int RKLogLevelForString(NSString *logLevel, NSString *envVarName) +{ + // Forgive the user if they specify the full name for the value i.e. "RKLogLevelDebug" instead of "Debug" + logLevel = [logLevel stringByReplacingOccurrencesOfString:@"RKLogLevel" withString:@""]; + + if ([logLevel isEqualToString:@"Off"] || + [logLevel isEqualToString:@"0"]) { + return RKLogLevelOff; + } + else if ([logLevel isEqualToString:@"Critical"] || + [logLevel isEqualToString:@"1"]) { + return RKLogLevelCritical; + } + else if ([logLevel isEqualToString:@"Error"] || + [logLevel isEqualToString:@"2"]) { + return RKLogLevelError; + } + else if ([logLevel isEqualToString:@"Warning"] || + [logLevel isEqualToString:@"3"]) { + return RKLogLevelWarning; + } + else if ([logLevel isEqualToString:@"Info"] || + [logLevel isEqualToString:@"4"]) { + return RKLogLevelInfo; + } + else if ([logLevel isEqualToString:@"Debug"] || + [logLevel isEqualToString:@"5"]) { + return RKLogLevelDebug; + } + else if ([logLevel isEqualToString:@"Trace"] || + [logLevel isEqualToString:@"6"]) { + return RKLogLevelTrace; + } + else if ([logLevel isEqualToString:@"Default"]) { + return RKLogLevelDefault; + } + else { + NSString *errorMessage = [NSString stringWithFormat:@"The value: \"%@\" for the environment variable: \"%@\" is invalid. \ + \nThe log level must be set to one of the following values \ + \n Default or 0 \ + \n Critical or 1 \ + \n Error or 2 \ + \n Warning or 3 \ + \n Info or 4 \ + \n Debug or 5 \ + \n Trace or 6\n", logLevel, envVarName]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:errorMessage userInfo:nil]; + + return -1; + } +} + +void RKLogIntegerAsBinary(NSUInteger bitMask) +{ + NSUInteger bit = ~(NSUIntegerMax >> 1); + NSMutableString *string = [NSMutableString string]; + do { + [string appendString:(((NSUInteger)bitMask & bit) ? @"1" : @"0")]; + } while (bit >>= 1); + + NSLog(@"Value of %ld in binary: %@", (long)bitMask, string); +} + +void RKLogValidationError(NSError *error) +{ +#ifdef _COREDATADEFINES_H + if ([[error domain] isEqualToString:NSCocoaErrorDomain]) { + NSDictionary *userInfo = [error userInfo]; + NSArray *errors = [userInfo valueForKey:@"NSDetailedErrors"]; + if (errors) { + for (NSError *detailedError in errors) { + NSDictionary *subUserInfo = [detailedError userInfo]; + RKLogError(@"Detailed Error\n \ + NSLocalizedDescriptionKey:\t\t%@\n \ + NSValidationKeyErrorKey:\t\t\t%@\n \ + NSValidationPredicateErrorKey:\t%@\n \ + NSValidationObjectErrorKey:\n%@\n", + [subUserInfo valueForKey:NSLocalizedDescriptionKey], + [subUserInfo valueForKey:NSValidationKeyErrorKey], + [subUserInfo valueForKey:NSValidationPredicateErrorKey], + [subUserInfo valueForKey:NSValidationObjectErrorKey]); + } + } else { + RKLogError(@"Validation Error\n \ + NSLocalizedDescriptionKey:\t\t%@\n \ + NSValidationKeyErrorKey:\t\t\t%@\n \ + NSValidationPredicateErrorKey:\t%@\n \ + NSValidationObjectErrorKey:\n%@\n", + [userInfo valueForKey:NSLocalizedDescriptionKey], + [userInfo valueForKey:NSValidationKeyErrorKey], + [userInfo valueForKey:NSValidationPredicateErrorKey], + [userInfo valueForKey:NSValidationObjectErrorKey]); + } + return; + } +#endif + RKLogError(@"Validation Error: %@ (userInfo: %@)", error, [error userInfo]); +} + +#ifdef _COREDATADEFINES_H +void RKLogCoreDataError(NSError *error) +{ + RKLogToComponentWithLevelWhileExecutingBlock(RKlcl_cRestKitCoreData, RKLogLevelError, ^{ + RKLogValidationError(error); + }); +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.h new file mode 100644 index 0000000..c77def6 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.h @@ -0,0 +1,17 @@ +// +// RKLumberjackLogger.h +// Pods +// +// Created by C_Lindberg,Carl on 10/31/14. +// +// + +#import <Foundation/Foundation.h> + +#if __has_include("DDLog.h") +#import "RKLog.h" + +@interface RKLumberjackLogger : NSObject <RKLogging> +@end + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.m new file mode 100644 index 0000000..34b2cc8 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKLumberjackLogger.m @@ -0,0 +1,107 @@ +// +// RKLumberjackLogger.m +// Pods +// +// Created by C_Lindberg,Carl on 10/31/14. +// +// + +#if __has_include("DDLog.h") +#import "RKLumberjackLogger.h" +#import "DDLog.h" + +@implementation RKLumberjackLogger + ++ (int)ddLogLevelFromRKLogLevel:(_RKlcl_level_t)rkLevel +{ + switch (rkLevel) + { + case RKLogLevelOff: return LOG_LEVEL_OFF; + case RKLogLevelCritical: return LOG_LEVEL_ERROR; + case RKLogLevelError: return LOG_LEVEL_ERROR; + case RKLogLevelWarning: return LOG_LEVEL_WARN; + case RKLogLevelInfo: return LOG_LEVEL_INFO; + case RKLogLevelDebug: return LOG_LEVEL_DEBUG; + case RKLogLevelTrace: return LOG_LEVEL_VERBOSE; + } + + return LOG_LEVEL_DEBUG; +} + ++ (int)ddLogFlagFromRKLogLevel:(_RKlcl_level_t)rkLevel +{ + switch (rkLevel) + { + case RKLogLevelOff: return 0; + case RKLogLevelCritical: return LOG_FLAG_ERROR; + case RKLogLevelError: return LOG_FLAG_ERROR; + case RKLogLevelWarning: return LOG_FLAG_WARN; + case RKLogLevelInfo: return LOG_FLAG_INFO; + case RKLogLevelDebug: return LOG_FLAG_DEBUG; + case RKLogLevelTrace: return LOG_FLAG_VERBOSE; + } + + return LOG_FLAG_DEBUG; +} + ++ (_RKlcl_level_t)rkLogLevelFromDDLogLevel:(int)ddLogLevel +{ + if (ddLogLevel & LOG_FLAG_VERBOSE) return RKLogLevelTrace; + if (ddLogLevel & LOG_FLAG_DEBUG) return RKLogLevelDebug; + if (ddLogLevel & LOG_FLAG_INFO) return RKLogLevelInfo; + if (ddLogLevel & LOG_FLAG_WARN) return RKLogLevelWarning; + if (ddLogLevel & LOG_FLAG_ERROR) return RKLogLevelError; + + return RKLogLevelOff; +} + + +#pragma mark RKLogging + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)path + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... +{ + va_list args; + va_start(args, format); + + int flag = [self ddLogFlagFromRKLogLevel:level]; + int componentLevel = [self ddLogLevelFromRKLogLevel:_RKlcl_component_level[component]]; + BOOL async = LOG_ASYNC_ENABLED && ((flag & LOG_FLAG_ERROR) == 0); + + [DDLog log:async + level:componentLevel + flag:flag + context:0 /* Could define a special value here to identify RestKit logs to any backend loggers */ + file:path function:function line:line + tag:nil + format:format args:args]; + va_end(args); +} + +@end + +/* Create a DDRegisteredDynamicLogging class for each RestKit component */ + +#undef _RKlcl_component +#define _RKlcl_component(_identifier, _header, _name) \ + @interface RKLumberjackLog##_identifier : NSObject <DDRegisteredDynamicLogging> \ + @end \ + @implementation RKLumberjackLog##_identifier \ + + (int)ddLogLevel { \ + _RKlcl_level_t level = _RKlcl_component_level[RKlcl_c##_identifier]; \ + return [RKLumberjackLogger ddLogLevelFromRKLogLevel:level]; \ + } \ + + (void)ddSetLogLevel:(int)logLevel { \ + RKLogConfigureByName(_name, [RKLumberjackLogger rkLogLevelFromDDLogLevel:logLevel]); \ + } \ + @end + +#include "lcl_config_components_RK.h" +#undef _RKlcl_component + + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h new file mode 100644 index 0000000..071869a --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h @@ -0,0 +1,97 @@ +// +// RKMIMETypeSerialization.h +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" +#import "RKSerialization.h" + +/** + The `RKMIMETypeSerialization` class provides support for the registration of classes conforming to the `RKSerialization` protocol by MIME Type and the serialization and deserialization of content by MIME Type. Serialization implementations may be registered by an exact string match (i.e. 'application/json' for a JSON serialization implementation) or by regular expression to match MIME Type by pattern. + */ +@interface RKMIMETypeSerialization : NSObject + +///--------------------------------------- +/// @name Managing MIME Type Registrations +///--------------------------------------- + +/** + Registers the given serialization class to handle content for the given MIME Type identifier. + + MIME Types may be given as either a string or as a regular expression that matches the MIME Types for which the given serialization should handle. Serializations are searched in the reverse order of their registration. If a registration is made for an already registered MIME Type, the new registration will take precedence. + + @param serializationClass The class conforming to the RKSerialization protocol to be registered as handling the given MIME Type. + @param MIMETypeStringOrRegularExpression A string or regular expression specifying the MIME Type(s) that given serialization implementation is to be registered as handling. + */ ++ (void)registerClass:(Class<RKSerialization>)serializationClass forMIMEType:(id)MIMETypeStringOrRegularExpression; + +/** + Unregisters the given serialization class from handling any MIME Types. + + After this method is invoked, invocations of `serializationForMIMEType:` will no longer return the unregistered serialization class. + + @param serializationClass The class conforming to the `RKSerialization` protocol to be unregistered. + */ ++ (void)unregisterClass:(Class<RKSerialization>)serializationClass; + +/** + Returns the serialization class registered to handle the given MIME Type. + + Searches the registrations in reverse order for the first serialization implementation registered to handle the given MIME Type. Matches are determined by doing a lowercase string comparison if the MIME Type was registered with a string identifier or by evaluating a regular expression match against the given MIME Type if registered with a regular expression. + + @param MIMEType The MIME Type for which to return the registered `RKSerialization` conformant class. + @return A class conforming to the RKSerialization protocol registered for the given MIME Type or nil if none was found. + */ ++ (Class<RKSerialization>)serializationClassForMIMEType:(NSString *)MIMEType; + +/** + Returns a set containing the string values for all MIME Types for which a serialization implementation has been registered. + + @return An `NSSet` object whose elements are `NSString` values enumerating the registered MIME Types. + */ ++ (NSSet *)registeredMIMETypes; + +///--------------------------------------------------------- +/// @name Serializing and Deserializing Content by MIME Type +///--------------------------------------------------------- + +/** + Deserializes and returns a Foundation object representation of the given UTF-8 encoded data in the serialization format for the given MIME Type. + + On invocation, searches the registrations by invoking `serializationClassForMIMEType:` with the given MIME Type and then invokes `objectFromData:error:` on the `RKSerialization` conformant class returned. If no serialization implementation is found to handle the given MIME Type, nil is returned and the given error pointer will be set to an NSError object with the `RKMissingSerializationForMIMETypeError` code. + + @param data The UTF-8 encoded data representation of the object to be deserialized. + @param MIMEType The MIME Type of the serialization format the data is in. + @param error A pointer to an NSError object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (id)objectFromData:(NSData *)data MIMEType:(NSString *)MIMEType error:(NSError **)error; + +/** + Serializes and returns a UTF-8 encoded data representation of the given Foundation object in the serialization format for the given MIME Type. + + On invocation, searches the registrations by invoking `serializationClassForMIMEType:` with the given MIME Type and then invokes `objectFromData:error:` on the `RKSerialization` conformant class returned. If no serialization implementation is found to handle the given MIME Type, nil is returned and the given error pointer will be set to an NSError object with the `RKMissingSerializationForMIMETypeError` code. + + @param object The Foundation object to serialized. + @param MIMEType The MIME Type of the serialization format the data is in. + @param error A pointer to an NSError object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (NSData *)dataFromObject:(id)object MIMEType:(NSString *)MIMEType error:(NSError **)error; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m new file mode 100644 index 0000000..caf4145 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m @@ -0,0 +1,182 @@ +// +// RKMIMETypeSerialization.m +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypeSerialization.h" +#import "RKErrors.h" +#import "RKSerialization.h" +#import "RKLog.h" +#import "RKURLEncodedSerialization.h" +#import "RKNSJSONSerialization.h" + +// Define logging component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitSupport + +@interface RKMIMETypeSerializationRegistration : NSObject + +@property (nonatomic, strong) id MIMETypeStringOrRegularExpression; +@property (nonatomic, assign) Class<RKSerialization> serializationClass; + +- (instancetype)initWithMIMEType:(id)MIMETypeStringOrRegularExpression serializationClass:(Class<RKSerialization>)serializationClass NS_DESIGNATED_INITIALIZER; +- (BOOL)matchesMIMEType:(NSString *)MIMEType; +@end + +@implementation RKMIMETypeSerializationRegistration + +- (instancetype)initWithMIMEType:(id)MIMETypeStringOrRegularExpression serializationClass:(Class<RKSerialization>)serializationClass +{ + NSParameterAssert(MIMETypeStringOrRegularExpression); + NSParameterAssert(serializationClass); + NSAssert([MIMETypeStringOrRegularExpression isKindOfClass:[NSString class]] + || [MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]], + @"Can only register a serialization class for a MIME Type by string or regular expression."); + + self = [super init]; + if (self) { + self.MIMETypeStringOrRegularExpression = MIMETypeStringOrRegularExpression; + self.serializationClass = serializationClass; + } + + return self; +} + +- (BOOL)matchesMIMEType:(NSString *)MIMEType +{ + return RKMIMETypeInSet(MIMEType, [NSSet setWithObject:self.MIMETypeStringOrRegularExpression]); +} + +- (NSString *)description +{ + NSString *mimeTypeDescription = [self.MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]] ? + [NSString stringWithFormat:@"MIME Type =~ \"%@\"", self.MIMETypeStringOrRegularExpression] : + [NSString stringWithFormat:@"MIME Type == \"%@\"", self.MIMETypeStringOrRegularExpression]; + return [NSString stringWithFormat:@"<%@: %p, %@, serializationClass=%@>", + NSStringFromClass([self class]), self, mimeTypeDescription, NSStringFromClass(self.serializationClass)]; +} + +@end + +@interface RKMIMETypeSerialization () +@property (nonatomic, strong) NSMutableArray *registrations; +@end + +@implementation RKMIMETypeSerialization + ++ (RKMIMETypeSerialization *)sharedSerialization +{ + static RKMIMETypeSerialization *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[RKMIMETypeSerialization alloc] init]; + [sharedInstance addRegistrationsForKnownSerializations]; + }); + return sharedInstance; + +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.registrations = [NSMutableArray new]; + } + + return self; +} + +- (void)addRegistrationsForKnownSerializations +{ + // URL Encoded + [self.registrations addObject:[[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:RKMIMETypeFormURLEncoded + serializationClass:[RKURLEncodedSerialization class]]]; + // JSON + [self.registrations addObject:[[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:RKMIMETypeJSON + serializationClass:[RKNSJSONSerialization class]]]; +} + +#pragma mark - Public + ++ (Class<RKSerialization>)serializationClassForMIMEType:(NSString *)MIMEType +{ + for (RKMIMETypeSerializationRegistration *registration in [[self sharedSerialization].registrations reverseObjectEnumerator]) { + if ([registration matchesMIMEType:MIMEType]) { + return registration.serializationClass; + } + } + return nil; +} + ++ (void)registerClass:(Class<RKSerialization>)serializationClass forMIMEType:(id)MIMETypeStringOrRegularExpression +{ + RKMIMETypeSerializationRegistration *registration = [[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:MIMETypeStringOrRegularExpression serializationClass:serializationClass]; + [[self sharedSerialization].registrations addObject:registration]; +} + ++ (void)unregisterClass:(Class<RKSerialization>)serializationClass +{ + NSArray *registrationsCopy = [[self sharedSerialization].registrations copy]; + for (RKMIMETypeSerializationRegistration *registration in registrationsCopy) { + if (registration.serializationClass == serializationClass) { + [[self sharedSerialization].registrations removeObject:registration]; + } + } +} + ++ (NSSet *)registeredMIMETypes +{ + return [NSSet setWithArray:[[self sharedSerialization].registrations valueForKey:@"MIMETypeStringOrRegularExpression"]]; +} + ++ (id)objectFromData:(NSData *)data MIMEType:(NSString *)MIMEType error:(NSError **)error +{ + NSParameterAssert(data); + NSParameterAssert(MIMEType); + + Class<RKSerialization> serializationClass = [self serializationClassForMIMEType:MIMEType]; + if (!serializationClass) { + if (error) { + NSString* errorMessage = [NSString stringWithFormat:@"Cannot deserialize data: No serialization registered for MIME Type '%@'", MIMEType]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage, RKMIMETypeErrorKey : MIMEType }; + *error = [NSError errorWithDomain:RKErrorDomain code:RKUnsupportedMIMETypeError userInfo:userInfo]; + } + return nil; + } + + return [serializationClass objectFromData:data error:error]; +} + ++ (id)dataFromObject:(id)object MIMEType:(NSString *)MIMEType error:(NSError **)error +{ + NSParameterAssert(object); + NSParameterAssert(MIMEType); + Class<RKSerialization> serializationClass = [self serializationClassForMIMEType:MIMEType]; + if (!serializationClass) { + if (error) { + NSString* errorMessage = [NSString stringWithFormat:@"Cannot deserialize data: No serialization registered for MIME Type '%@'", MIMEType]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage, RKMIMETypeErrorKey : MIMEType }; + *error = [NSError errorWithDomain:RKErrorDomain code:RKUnsupportedMIMETypeError userInfo:userInfo]; + } + return nil; + } + + return [serializationClass dataFromObject:object error:error]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.h new file mode 100644 index 0000000..8415d28 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.h @@ -0,0 +1,52 @@ +// +// RKMIMETypes.h +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + MIME Type Constants + */ + +/// MIME Type application/json +extern NSString * const RKMIMETypeJSON; + +/// MIME Type application/x-www-form-urlencoded +extern NSString * const RKMIMETypeFormURLEncoded; + +/// MIME Type application/xml +extern NSString * const RKMIMETypeXML; + +/// MIME Type text/xml +extern NSString * const RKMIMETypeTextXML; + +/** + Returns `YES` if the given MIME Type matches any MIME Type identifiers in the given set. + + @param MIMEType The MIME Type to evaluate the match for. + @param MIMETypes An `NSSet` object who entries are `NSString` or `NSRegularExpression` objects specifying MIME Types. + @return `YES` if the given MIME Type matches any identifier in the set, else `NO`. + */ +BOOL RKMIMETypeInSet(NSString *MIMEType, NSSet *MIMETypes); + +#ifdef __cplusplus +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.m new file mode 100644 index 0000000..c22ff5f --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMIMETypes.m @@ -0,0 +1,44 @@ +// +// RKMIMETypes.m +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" + +NSString * const RKMIMETypeJSON = @"application/json"; +NSString * const RKMIMETypeFormURLEncoded = @"application/x-www-form-urlencoded"; +NSString * const RKMIMETypeXML = @"application/xml"; +NSString * const RKMIMETypeTextXML = @"text/xml"; + +BOOL RKMIMETypeInSet(NSString *MIMEType, NSSet *MIMETypes) +{ + for (id MIMETypeStringOrRegularExpression in MIMETypes) { + if ([MIMETypeStringOrRegularExpression isKindOfClass:[NSString class]]) { + if ([[MIMETypeStringOrRegularExpression lowercaseString] isEqualToString:[MIMEType lowercaseString]]) return YES; + } else if ([MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]]) { + NSRegularExpression *regex = (NSRegularExpression *) MIMETypeStringOrRegularExpression; + NSUInteger numberOfMatches = [regex numberOfMatchesInString:[MIMEType lowercaseString] options:0 range:NSMakeRange(0, [MIMEType length])]; + if (numberOfMatches > 0) return YES; + } else { + NSString *reason = [NSString stringWithFormat:@"Unable to evaluate match for MIME Type '%@': expected an `NSString` or `NSRegularExpression`, got a `%@`", MIMEType, NSStringFromClass([MIMEType class])]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + } + + return NO; +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKMacros.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMacros.h new file mode 100644 index 0000000..2852d08 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKMacros.h @@ -0,0 +1,51 @@ +// +// RKMacros.h +// RestKit +// +// Created by Jawwad Ahmad on 7/18/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef RestKit_RKMacros_h +#define RestKit_RKMacros_h + +/* + Instead of using the normal DEPRECATED_ATTRIBUTE use DEPRECATED_ATTRIBUTE_MESSAGE(message) + to display a helpful recommendation message along with the deprecation message. + */ +#ifndef DEPRECATED_ATTRIBUTE_MESSAGE +#define DEPRECATED_ATTRIBUTE_MESSAGE(message) __attribute__((deprecated (message))) +#endif + +/* + Add this macro before each category implementation, so we don't have to use + -all_load or -force_load to load object files from static libraries that only contain + categories and no classes. + See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info. + + Shamelessly borrowed from Three20 + */ +#define RK_FIX_CATEGORY_BUG(name) @interface RK_FIX_CATEGORY_BUG##name @end \ +@implementation RK_FIX_CATEGORY_BUG##name @end + +/* + Raises an `NSInvalidArgumentException` in the event that the given value is not an instance of the given class or an instance of any class that inherits from that class. + */ +#define RKAssertValueIsKindOfClass(value, expectedClass) \ +if (! [value isKindOfClass:expectedClass]) { \ +[NSException raise:NSInvalidArgumentException format:@"%@ invoked with invalid input value: expected a `%@`, but instead got a `%@`", [self class], expectedClass, [value class]]; \ +} + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.h new file mode 100644 index 0000000..598e250 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.h @@ -0,0 +1,29 @@ +// +// RKNSJSONSerialization.h +// RestKit +// +// Created by Blake Watters on 8/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKSerialization.h" + +/** + The `RKNSJSONSerialization` class conforms to the `RKSerialization` protocol and provides support for the serialization and deserialization of data in the JSON format using the Apple provided `NSJSONSerialization` class. This is the default JSON implementation for RestKit. + + @see http://www.json.org/ + */ +@interface RKNSJSONSerialization : NSObject <RKSerialization> +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.m new file mode 100644 index 0000000..3b277ea --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKNSJSONSerialization.m @@ -0,0 +1,35 @@ +// +// RKNSJSONSerialization.m +// RestKit +// +// Created by Blake Watters on 8/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKNSJSONSerialization.h" + +@implementation RKNSJSONSerialization + ++ (id)objectFromData:(NSData *)data error:(NSError **)error +{ + return [NSJSONSerialization JSONObjectWithData:data options:0 error:error]; +} + ++ (NSData *)dataFromObject:(id)object error:(NSError **)error +{ + return [NSJSONSerialization dataWithJSONObject:object options:0 error:error]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.h new file mode 100644 index 0000000..bd7ea49 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.h @@ -0,0 +1,158 @@ +// +// RKOperationStateMachine.h +// RestKit +// +// Created by Blake Watters on 4/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKOperationStateMachine` class provides an implementation of a state machine that is suitable for implementing a concurrent `NSOperation` subclass via composition. The concurrency mechanism is a dispatch queue. The state machine takes care of correctly implementing all aspects of a concurrent `NSOperation` including: + 1. Asynchronous execution + 1. Locking + 1. Appropriate state transitions + 1. Cancellation + 1. State Instrospection + + The state machine begins its life in the ready state. Upon start, the state transitions to executing and a user-supplied execution block is invoked on the operation's dispatch queue. The operation remains in the executing state until it is finished. Just before the operation is finished, a finalization block is invoked. In the event that the operation is cancelled, then an optional cancellation block is invoked. Note that because cancellation semantics can vary widely, a cancelled operation is merely flagged as being cancelled. It is the responsibility of the operation to ensure that a cancelled operation is finished as soon as possible. + + The underlying implementation of the state machine is backed by [TransitionKit](http://github.com/blakewatters/TransitionKit) + */ +@interface RKOperationStateMachine : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithOperation: instead."))); + +///----------------------------------- +/// @name Initializing a State Machine +///----------------------------------- + +/** + Initializes a new state machine object with a given operation and dispatch queue. + + @param operation The operation that the receiver is modeling the concurrent lifecycle of. + @param dispatchQueue The dispatch queue on which the operation executes concurrently. + @return The receiver, initialized with the given operation and queue. + */ +- (instancetype)initWithOperation:(NSOperation *)operation dispatchQueue:(dispatch_queue_t)dispatchQueue NS_DESIGNATED_INITIALIZER; + +///----------------------- +/// @name Inspecting State +///----------------------- + +/** + Returns a Boolean value that indicates if the receiver is ready to be started. + + @return `YES` if the receiver is ready to be started, else `NO`. + */ +@property (nonatomic, getter=isReady, readonly) BOOL ready; + +/** + Returns a Boolean value that indicates if the receiver is executing. + + @return `YES` if the receiver is executing, else `NO`. + */ +@property (nonatomic, getter=isExecuting, readonly) BOOL executing; + +/** + Returns a Boolean value that indicates if the receiver has been cancelled. + + @return `YES` if the receiver has been cancelled, else `NO`. + */ +@property (nonatomic, getter=isCancelled, readonly) BOOL cancelled; + +/** + Returns a Boolean value that indicates if the receiver has finished executing. + + @return `YES` if the receiver is finished, else `NO`. + */ +@property (nonatomic, getter=isFinished, readonly) BOOL finished; + +///-------------------- +/// @name Firing Events +///-------------------- + +/** + Starts the operation by transitioning into the executing state and asychronously invoking the execution block on the operation dispatch queue. + */ +- (void)start; + +/** + Finishes the operation by transitioning from the executing state to the finished state. The state transition is executed asynchronously on the operation dispatch queue. Invokes the finalization block just before the state changes from executing to finished. + */ +- (void)finish; + +/** + Marks the operation is being cancelled. Cancellation results in state transition because cancellation semantics can vary widely. Once the cancellation flag has been set (`isCancelled` return `YES`), the cancellation block is invoked asynchronously on the operation dispatch queue. The operation must be finished as soon as possible. + */ +- (void)cancel; + +///--------------------------------- +/// @name Configuring Event Handlers +///--------------------------------- + +/** + Sets a block to be executed on the operation dispatch queue once the operation transitions to the executing state. + + @param block The block to be executed. + */ +- (void)setExecutionBlock:(void (^)(void))block; + +/** + Sets a block to be executed when the operation is cancelled. The block will be invoked on the operation dispatch queue. Cancellation does not trigger any state transition -- the operation must still be explicitly finished as soon as possible. If appropriate, the operation may be finished within the body of the cancellation block. + + @param block The block to be executed. + */ +- (void)setCancellationBlock:(void (^)(void))block; + +/** + Sets a block to be executed when the operation is about to transition from executing to finished. This block is invoked regardless of the cancellation state. This block should be used to perform any last minute cleanup or preparation before the operation finishes. + + @param block The block to be executed. + */ +- (void)setFinalizationBlock:(void (^)(void))block; + +///------------------------------ +/// @name Accessing Configuration +///------------------------------ + +/** + The operation that the receiver is modeling the lifecycle of. + */ +@property (nonatomic, weak, readonly) NSOperation *operation; + +/** + The dispatch queue within which the state machine executes. + */ +@property (nonatomic, assign, readonly) dispatch_queue_t dispatchQueue; + +///------------------------------------------ +/// @name Performing Blocks that Mutate State +///------------------------------------------ + +/** + Executes a block after acquiring an exclusive lock on the receiver. This enables the block to safely mutate the state of the operation. The execution context of the block is not changed -- it is always executed within the caller's thread context. If you wish to guarantee execution on the dispatch queue backing the state machine then you must dispatch onto the queue before submitting your block for execution. + + @param block The block to execute after acquiring an exclusive lock on the receiver. + */ +- (void)performBlockWithLock:(void (^)())block; + +@end + +/** + Raised when an unexpected error has occurred. + */ +extern NSString *const RKOperationFailureException; diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.m new file mode 100644 index 0000000..33bb1ab --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKOperationStateMachine.m @@ -0,0 +1,209 @@ +// +// RKOperationStateMachine.m +// RestKit +// +// Created by Blake Watters on 4/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TransitionKit.h" +#import "RKOperationStateMachine.h" + +NSString *const RKOperationFailureException = @"RKOperationFailureException"; + +static NSString *const RKOperationStateReady = @"Ready"; +static NSString *const RKOperationStateExecuting = @"Executing"; +static NSString *const RKOperationStateFinished = @"Finished"; + +static NSString *const RKOperationEventStart = @"start"; +static NSString *const RKOperationEventFinish = @"finish"; + +static NSString *const RKOperationLockName = @"org.restkit.operation.lock"; + +@interface RKOperationStateMachine () +@property (nonatomic, strong) TKStateMachine *stateMachine; +@property (nonatomic, weak, readwrite) NSOperation *operation; +@property (nonatomic, assign, readwrite) dispatch_queue_t dispatchQueue; +@property (nonatomic, assign, getter = isCancelled) BOOL cancelled; +@property (nonatomic, copy) void (^cancellationBlock)(void); +@property (nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation RKOperationStateMachine + +- (instancetype)initWithOperation:(NSOperation *)operation dispatchQueue:(dispatch_queue_t)dispatchQueue +{ + if (! operation) [NSException raise:NSInvalidArgumentException format:@"Invalid argument: `operation` cannot be nil."]; + if (! dispatchQueue) [NSException raise:NSInvalidArgumentException format:@"Invalid argument: `dispatchQueue` cannot be nil."]; + self = [super init]; + if (self) { + self.operation = operation; + self.dispatchQueue = dispatchQueue; + self.stateMachine = [TKStateMachine new]; + self.lock = [NSRecursiveLock new]; + [self.lock setName:RKOperationLockName]; + + // NOTE: State transitions are guarded by a lock via start/finish/cancel action methods + TKState *readyState = [TKState stateWithName:RKOperationStateReady]; + __weak __typeof(self)weakSelf = self; + [readyState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isReady"]; + }]; + [readyState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isReady"]; + }]; + + TKState *executingState = [TKState stateWithName:RKOperationStateExecuting]; + [executingState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isExecuting"]; + }]; + // NOTE: isExecuting KVO for `setDidEnterStateBlock:` configured below in `setExecutionBlock` + [executingState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isExecuting"]; + }]; + [executingState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isExecuting"]; + }]; + [executingState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [NSException raise:NSInternalInconsistencyException format:@"You must configure an execution block via `setExecutionBlock:`."]; + }]; + + TKState *finishedState = [TKState stateWithName:RKOperationStateFinished]; + [finishedState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + }]; + [finishedState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isFinished"]; + }]; + [finishedState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + }]; + [finishedState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isFinished"]; + }]; + + [self.stateMachine addStates:@[ readyState, executingState, finishedState ]]; + + TKEvent *startEvent = [TKEvent eventWithName:RKOperationEventStart transitioningFromStates:@[ readyState ] toState:executingState]; + TKEvent *finishEvent = [TKEvent eventWithName:RKOperationEventFinish transitioningFromStates:@[ executingState ] toState:finishedState]; + [self.stateMachine addEvents:@[ startEvent, finishEvent ]]; + + self.stateMachine.initialState = readyState; + [self.stateMachine activate]; + } + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithOperation: instead.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (BOOL)isReady +{ + return [self.stateMachine isInState:RKOperationStateReady]; +} + +- (BOOL)isExecuting +{ + return [self.stateMachine isInState:RKOperationStateExecuting]; +} + +- (BOOL)isFinished +{ + return [self.stateMachine isInState:RKOperationStateFinished]; +} + +- (void)start +{ + if (! self.dispatchQueue) [NSException raise:NSInternalInconsistencyException format:@"You must configure an `operationQueue`."]; + [self performBlockWithLock:^{ + NSError *error = nil; + BOOL success = [self.stateMachine fireEvent:RKOperationEventStart userInfo:nil error:&error]; + if (! success) [NSException raise:RKOperationFailureException format:@"The operation unexpectedly failed to start due to an error: %@", error]; + }]; +} + +- (void)finish +{ + // Ensure that we are finished from the operation queue + dispatch_async(self.dispatchQueue, ^{ + [self performBlockWithLock:^{ + NSError *error = nil; + BOOL success = [self.stateMachine fireEvent:RKOperationEventFinish userInfo:nil error:&error]; + if (! success) [NSException raise:RKOperationFailureException format:@"The operation unexpectedly failed to finish due to an error: %@", error]; + }]; + }); +} + +- (void)cancel +{ + if ([self isCancelled] || [self isFinished]) return; + [self performBlockWithLock:^{ + self.cancelled = YES; + }]; + + if (self.cancellationBlock) { + dispatch_async(self.dispatchQueue, ^{ + [self performBlockWithLock:self.cancellationBlock]; + }); + } +} + +- (void)setExecutionBlock:(void (^)(void))block +{ + __weak __typeof(self)weakSelf = self; + TKState *executingState = [self.stateMachine stateNamed:RKOperationStateExecuting]; + [executingState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isExecuting"]; + dispatch_async(weakSelf.dispatchQueue, ^{ + block(); + }); + }]; +} + +- (void)setFinalizationBlock:(void (^)(void))block +{ + __weak __typeof(self)weakSelf = self; + TKState *finishedState = [self.stateMachine stateNamed:RKOperationStateFinished]; + [finishedState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf performBlockWithLock:^{ + // Must emit KVO as we are replacing the block configured in `initWithOperation:queue:` + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + block(); + }]; + }]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p (for %@:%p), state: %@, cancelled: %@>", + [self class], self, + [self.operation class], self.operation, + self.stateMachine.currentState.name, + ([self isCancelled] ? @"YES" : @"NO")]; +} + +- (void)performBlockWithLock:(void (^)())block +{ + [self.lock lock]; + block(); + [self.lock unlock]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.h new file mode 100644 index 0000000..c7155d7 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.h @@ -0,0 +1,62 @@ +// +// RKPathUtilities.h +// RestKit +// +// Created by Blake Watters on 12/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Returns the path to the Application Data directory for the executing application. On iOS, this is a sandboxed path specific for the executing application. On OS X, this is an application specific path under `NSApplicationSupportDirectory` (i.e. ~/Application Support). + + @return The full path to the application data directory. + */ +NSString *RKApplicationDataDirectory(void); + +/** + Returns a path to the root caches directory used by RestKit for storage. On iOS, this is a sanboxed path specific for the executing application. On OS X, this is an application specific path under NSCachesDirectory (i.e. ~/Library/Caches). + + @return The full path to the Caches directory. + */ +NSString *RKCachesDirectory(void); + +/** + Ensures that a directory exists at a given path by checking for the existence of the directory and creating it if it does not exist. + + @param path The path to ensure a directory exists at. + @param error On input, a pointer to an error object. + @returns A Boolean value indicating if the directory exists. + */ +BOOL RKEnsureDirectoryExistsAtPath(NSString *path, NSError **error); + +/** + Returns a MIME Type for a given path by using the Core Services framework. + + For example, given a string with the path `@"/Users/blake/Documents/monkey.json"` `@"application/json"` would be returned as the MIME Type. + + @param path The path to return the MIME Type for. + @return The expected MIME Type of the resource identified by the path or nil if unknown. + */ +NSString *RKMIMETypeFromPathExtension(NSString *path); + +/** + Excludes the item at a given path from backup via iTunes and/or iCloud using the approaches detailed in "Apple Technical Q&A QA1719". + + Excluding a path from backup can be necessary in order to conform to the iCloud Data Storage Guidelines. Please refer to the following links for more details: + + 1. [iCloud Data Storage Guidelines](https://developer.apple.com/icloud/documentation/data-storage/) + 1. [Technical Q&A QA1719](http://developer.apple.com/library/ios/#qa/qa1719/_index.html) + + @param path The path to the item that is to be excluded from backup. + */ +void RKSetExcludeFromBackupAttributeForItemAtPath(NSString *path); + +#ifdef __cplusplus +} +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.m new file mode 100644 index 0000000..373657a --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKPathUtilities.m @@ -0,0 +1,153 @@ +// +// RKPathUtilities.m +// RestKit +// +// Created by Blake Watters on 12/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#if TARGET_OS_IPHONE +#import <MobileCoreServices/UTType.h> +#import <UIKit/UIDevice.h> +#else +#import <CoreServices/CoreServices.h> +#endif +#import <Availability.h> +#import <sys/xattr.h> +#import "RKPathUtilities.h" +#import "RKLog.h" + +NSString *RKExecutableName(void); + +NSString *RKApplicationDataDirectory(void) +{ +#if TARGET_OS_IPHONE + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + return ([paths count] > 0) ? paths[0] : nil; +#else + NSFileManager *sharedFM = [NSFileManager defaultManager]; + + NSArray *possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory + inDomains:NSUserDomainMask]; + NSURL *appSupportDir = nil; + NSURL *appDirectory = nil; + + if ([possibleURLs count] >= 1) { + appSupportDir = possibleURLs[0]; + } + + if (appSupportDir) { + appDirectory = [appSupportDir URLByAppendingPathComponent:RKExecutableName()]; + return [appDirectory path]; + } + + return nil; +#endif +} + +NSString *RKExecutableName(void) +{ + NSString *executableName = [[[NSBundle mainBundle] executablePath] lastPathComponent]; + if (nil == executableName) { + RKLogWarning(@"Unable to determine CFBundleExecutable: storing data under RestKit directory name."); + executableName = @"RestKit"; + } + + return executableName; +} + +NSString *RKCachesDirectory(void) +{ +#if TARGET_OS_IPHONE + return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +#else + NSString *path = nil; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if ([paths count]) { + path = [paths[0] stringByAppendingPathComponent:RKExecutableName()]; + } + + return path; +#endif +} + +BOOL RKEnsureDirectoryExistsAtPath(NSString *path, NSError **error) +{ + BOOL isDirectory; + if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) { + if (isDirectory) { + // Exists at a path and is a directory, we're good + if (error) *error = nil; + return YES; + } + } + + // Create the directory and any intermediates + NSError *errorReference = (error == nil) ? nil : *error; + if (! [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&errorReference]) { + RKLogError(@"Failed to create requested directory at path '%@': %@", path, errorReference); + return NO; + } + + return YES; +} + +static NSDictionary *RKDictionaryOfFileExtensionsToMIMETypes() +{ + return @{ @"json": @"application/json" }; +} + +NSString *RKMIMETypeFromPathExtension(NSString *path) +{ + NSString *pathExtension = [path pathExtension]; + CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)pathExtension, NULL); + if (uti != NULL) { + CFStringRef mime = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType); + CFRelease(uti); + if (mime != NULL) { + NSString *type = [NSString stringWithString:(__bridge NSString *)mime]; + CFRelease(mime); + return type; + } + } + + // Consult our internal dictionary of mappings if not found + return [RKDictionaryOfFileExtensionsToMIMETypes() valueForKey:pathExtension]; +} + +void RKSetExcludeFromBackupAttributeForItemAtPath(NSString *path) +{ + NSCParameterAssert(path); + NSCAssert([[NSFileManager defaultManager] fileExistsAtPath:path], @"Cannot set Exclude from Backup attribute for non-existant item at path: '%@'", path); + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + NSError *error = nil; + NSURL *URL = [NSURL fileURLWithPath:path]; + + NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:@"5.1" options:NSNumericSearch]; + if (order == NSOrderedSame || order == NSOrderedDescending) { + // On iOS >= 5.1, we can use the resource value API's. Note that we probe the iOS version number directly because the `setResourceValue:forKey:` symbol is defined in iOS 4.0 and greater, but performs no operation when invoked until iOS 5.1 + BOOL success = [URL setResourceValue:@(YES) forKey:NSURLIsExcludedFromBackupKey error:&error]; + if (!success) { + RKLogError(@"Failed to exclude item at path '%@' from Backup: %@", path, error); + } + } else { + order = [[UIDevice currentDevice].systemVersion compare:@"5.0.1" options: NSNumericSearch]; + if (order == NSOrderedSame || order == NSOrderedDescending) { + // On iOS 5.0.1 we must use the extended attribute API's directly + const char* filePath = [[URL path] fileSystemRepresentation]; + const char* attrName = "com.apple.MobileBackup"; + u_int8_t attrValue = 1; + + int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); + if (result != 0) { + RKLogError(@"Failed to exclude item at path '%@' from Backup. setxattr returned result code %d", path, result); + } + } else { + RKLogWarning(@"Unable to exclude item from backup: resource value and extended attribute APIs are only available on iOS 5.0.1 and up"); + } + } +#else + RKLogDebug(@"Not built for iOS -- excluding path from Backup is not possible."); +#endif +} diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKSerialization.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKSerialization.h new file mode 100644 index 0000000..073c73d --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKSerialization.h @@ -0,0 +1,54 @@ +// +// RKSerialization.h +// RestKit +// +// Created by Blake Watters on 10/1/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/** + The `RKSerialization` protocol declares two methods that a class must implement so that it can provide support for serializing objects to and deserializing objects from UTF-8 encoded data representations of a serialization format such as JSON or XML. Serialization implementations typically handle data in a given MIME Type (i.e. `application/json`) and may be registered with the `RKMIMETypeSerialization` class. + + @see `RKMIMETypeSerialization` + */ +@protocol RKSerialization <NSObject> + +///------------------------------ +/// @name Deserializing an Object +///------------------------------ + +/** + Deserializes and returns the given data in the format supported by the receiver (i.e. JSON, XML, etc) as a Foundation object representation. + + @param data The UTF-8 encoded data representation of the object to be deserialized. + @param error A pointer to an `NSError` object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (id)objectFromData:(NSData *)data error:(NSError **)error; + +///---------------------------- +/// @name Serializing an Object +///---------------------------- + +/** + Serializes and returns a UTF-8 encoded data representation of the given Foundation object in the format supported by the receiver (i.e. JSON, XML, etc). + + @param object The object to be serialized. + @param error A pointer to an NSError object. + @return A data representation of the given object in UTF-8 encoding, or nil if an error occurred. + */ ++ (NSData *)dataFromObject:(id)object error:(NSError **)error; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.h new file mode 100644 index 0000000..721671d --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.h @@ -0,0 +1,51 @@ +// +// RKStringTokenizer.h +// RestKit +// +// Created by Blake Watters on 7/30/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKStringTokenizer` class provides an interface for tokenizing input text into a set of searchable words. Diacritics are removed and the input text is tokenized case insensitively. A set of stop words can be optionally trimmed from the result token set. + */ +@interface RKStringTokenizer : NSObject + +///------------------------------- +/// @name Configuring Tokenization +///------------------------------- + +/** + The set of stop words that are to be removed from the token set. + + Defaults to nil. + */ +@property (nonatomic, strong) NSSet *stopWords; + +///---------------------------------- +/// @name Tokenizing a String of Text +///---------------------------------- + +/** + Tokenizes the given string by folding it case and diacritic insensitively and then splitting it apart using the the word unit delimiters for the current locale. If a set of stop words has been provided, the resulting token set will have the stop words subtracted. + + @param string A string of text you wish to tokenize. + @returns A set of searchable text tokens extracted from the given string. + */ +- (NSSet *)tokenize:(NSString *)string; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.m new file mode 100644 index 0000000..48e3644 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKStringTokenizer.m @@ -0,0 +1,42 @@ +// +// RKStringTokenizer.m +// RestKit +// +// Created by Blake Watters on 7/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// + +#import "RKStringTokenizer.h" + +@implementation RKStringTokenizer + +- (NSSet *)tokenize:(NSString *)string +{ + NSMutableSet *tokens = [NSMutableSet set]; + + CFLocaleRef locale = CFLocaleCopyCurrent(); + + // Remove diacratics and lowercase our input text + NSString *tokenizeText = string = [string stringByFoldingWithOptions:kCFCompareCaseInsensitive|kCFCompareDiacriticInsensitive locale:[NSLocale systemLocale]]; + CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (__bridge CFStringRef)tokenizeText, CFRangeMake(0, CFStringGetLength((__bridge CFStringRef)tokenizeText)), kCFStringTokenizerUnitWord, locale); + CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone; + + while (kCFStringTokenizerTokenNone != (tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer))) { + CFRange tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer); + + NSRange range = NSMakeRange(tokenRange.location, tokenRange.length); + NSString *token = [string substringWithRange:range]; + + [tokens addObject:token]; + } + + CFRelease(tokenizer); + CFRelease(locale); + + // Remove any stop words + if (self.stopWords) [tokens minusSet:self.stopWords]; + + return tokens; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h b/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h new file mode 100644 index 0000000..3c109d2 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h @@ -0,0 +1,74 @@ +// +// RKURLEncodedSerialization.h +// RestKit +// +// Created by Blake Watters on 9/4/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKSerialization.h" + +/** + The `RKURLEncodedSerialization` class conforms to the `RKSerialization` protocol and provides support for the serialization and deserialization of URL encoded data. URL encoding is used to replace certain characters in a string with equivalent percent escape sequences. The list of characters replaced by the implementation are designed as illegal URL characters by RFC 3986. URL encoded data is used for the submission of HTML forms with the MIME Type `application/x-www-form-urlencoded`. + + @see http://www.w3.org/TR/html401/interact/forms.html + @see http://www.ietf.org/rfc/rfc3986.txt + */ +@interface RKURLEncodedSerialization : NSObject <RKSerialization> + +@end + +/** + Creates and returns a new `NSDictionary` object from the given URL-encoded string, using the specified encoding. + + The dictionary is constructed by splitting the string into components using the `&` character as the delimiter. The results array of strings is then split again using the `=` character as the delimiter. Each resulting key and value delimited by the `=` character is then URL decoded and added a resulting dictionary. The process is across the entire string. Any extraneous `=` characters not delimiting a key and value are ignored. The corresponding values for any keys that appear multiple times within the string be coalesced into an `NSArray` of values. + + @param URLEncodedString A URL-encoded string that is to be parsed into an `NSDictionary`. + @param encoding The encoding to use when URL-decoding the components of the given string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return An `NSDictionary` object containing the keys and values deserialized from the URL-encoded string. + */ +NSDictionary *RKDictionaryFromURLEncodedStringWithEncoding(NSString *URLEncodedString, NSStringEncoding encoding); + +/** + Returns a URL-encoded `NSString` object containing the entries in the given `NSDictionary` object. + + The dictionary is created by collecting each key-value pair, URL-encoding a string representation of the key-value pair, and then joining the components with "&". + + @param dictionary The dictionary from to construct the URL-encoded string. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return A new `NSString` object in the given encoding containing a URL-encoded serialization of the entries in the given dictionary. + @see `AFQueryStringFromParametersWithEncoding` + */ +NSString *RKURLEncodedStringFromDictionaryWithEncoding(NSDictionary *dictionary, NSStringEncoding encoding); + +/** + Returns a copy of the given string with the characters that are unsafe for use in a URL query string replaced with the equivalent percent escape sequences. + + @param string The string to be escaped. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return A new `NSString` object in the given encoding with the query string unsafe characters replaced with percent escape sequences. + */ +NSString *RKPercentEscapedQueryStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding); + +/** + Creates and returns a new `NSDictionary` object containing the keys and values in the query string of the given string. + + The given string is searched for a `?` character denoting the beginning of the query parameters. If none is found, the entire string is treated as a URL encoded query string. The parameters are extracted from the query string by invoking `RKDictionaryFromURLEncodedStringWithEncoding()` with the query string. + + @param string A string containing a query string that is to be tokenized into a dictionary of parameters. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return An `NSDictionary` object containing the keys and values contained in the query string of the given string. + */ +NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding encoding); diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m b/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m new file mode 100644 index 0000000..09f7ae7 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m @@ -0,0 +1,190 @@ +// +// RKURLEncodedSerialization.m +// RestKit +// +// Created by Blake Watters on 9/4/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKURLEncodedSerialization.h" + +#pragma mark - AFNetworking + +// Taken from https://github.com/AFNetworking/AFNetworking/blob/49f2f8c9a907977ec1b3afb182404ae0a6bce883/AFNetworking/AFURLRequestSerialization.m + +static NSString * const RKAFCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*"; + +static NSString * RKAFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const RKAFCharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)RKAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)RKAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)RKAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +#pragma mark - + +@interface RKAFQueryStringPair : NSObject +@property (readwrite, nonatomic, strong) id field; +@property (readwrite, nonatomic, strong) id value; + +- (instancetype)initWithField:(id)field value:(id)value NS_DESIGNATED_INITIALIZER; + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; +@end + +@implementation RKAFQueryStringPair + +- (instancetype)initWithField:(id)field value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.field = field; + self.value = value; + + return self; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + if (!self.value || [self.value isEqual:[NSNull null]]) { + return RKAFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); + } else { + return [NSString stringWithFormat:@"%@=%@", RKAFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; + } +} + +@end + +#pragma mark - + +extern NSArray * RKAFQueryStringPairsFromDictionary(NSDictionary *dictionary); +extern NSArray * RKAFQueryStringPairsFromKeyAndValue(NSString *key, id value); + +static NSString * RKAFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutablePairs = [NSMutableArray array]; + for (RKAFQueryStringPair *pair in RKAFQueryStringPairsFromDictionary(parameters)) { + [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutablePairs componentsJoinedByString:@"&"]; +} + +NSArray * RKAFQueryStringPairsFromDictionary(NSDictionary *dictionary) { + return RKAFQueryStringPairsFromKeyAndValue(nil, dictionary); +} + +NSArray * RKAFQueryStringPairsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries + for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + id nestedValue = dictionary[nestedKey]; + if (nestedValue) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + for (id nestedValue in array) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + } + } else if ([value isKindOfClass:[NSSet class]]) { + NSSet *set = value; + for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue(key, obj)]; + } + } else { + [mutableQueryStringComponents addObject:[[RKAFQueryStringPair alloc] initWithField:key value:value]]; + } + + return mutableQueryStringComponents; +} + +#pragma mark - RestKit + +@implementation RKURLEncodedSerialization + ++ (id)objectFromData:(NSData *)data error:(NSError **)error +{ + NSString *string = [NSString stringWithUTF8String:[data bytes]]; + return RKDictionaryFromURLEncodedStringWithEncoding(string, NSUTF8StringEncoding); +} + ++ (NSData *)dataFromObject:(id)object error:(NSError **)error +{ + NSString *string = RKURLEncodedStringFromDictionaryWithEncoding(object, NSUTF8StringEncoding); + return [string dataUsingEncoding:NSUTF8StringEncoding]; +} + +@end + +NSDictionary *RKDictionaryFromURLEncodedStringWithEncoding(NSString *URLEncodedString, NSStringEncoding encoding) +{ + NSMutableDictionary *queryComponents = [NSMutableDictionary dictionary]; + for (NSString *keyValuePairString in [URLEncodedString componentsSeparatedByString:@"&"]) { + NSArray *keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="]; + if ([keyValuePairArray count] < 2) continue; // Verify that there is at least one key, and at least one value. Ignore extra = signs + NSString *key = [keyValuePairArray[0] stringByReplacingPercentEscapesUsingEncoding:encoding]; + NSString *value = [keyValuePairArray[1] stringByReplacingPercentEscapesUsingEncoding:encoding]; + + // URL spec says that multiple values are allowed per key + id results = queryComponents[key]; + if (results) { + if ([results isKindOfClass:[NSMutableArray class]]) { + [(NSMutableArray *)results addObject:value]; + } else { + // On second occurrence of the key, convert into an array + NSMutableArray *values = [NSMutableArray arrayWithObjects:results, value, nil]; + queryComponents[key] = values; + } + } else { + queryComponents[key] = value; + } + } + return queryComponents; +} + +NSString *RKURLEncodedStringFromDictionaryWithEncoding(NSDictionary *dictionary, NSStringEncoding encoding) +{ + return RKAFQueryStringFromParametersWithEncoding(dictionary, encoding); +} + +// This replicates `AFPercentEscapedQueryStringPairMemberFromStringWithEncoding`. Should send PR exposing non-static version +NSString *RKPercentEscapedQueryStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding) +{ + // Escape characters that are legal in URIs, but have unintentional semantic significance when used in a query string parameter + static NSString * const kAFLegalCharactersToBeEscaped = @":/.?&=;+!@$()~"; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFLegalCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding encoding) +{ + NSRange chopRange = [string rangeOfString:@"?"]; + if (chopRange.length > 0) { + chopRange.location += 1; // we want inclusive chopping up *through *"?" + if (chopRange.location < [string length]) string = [string substringFromIndex:chopRange.location]; + } + return RKDictionaryFromURLEncodedStringWithEncoding(string, encoding); +} + diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_components_RK.h b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_components_RK.h new file mode 100644 index 0000000..3638292 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_components_RK.h @@ -0,0 +1,62 @@ +// +// lcl_config_components_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// The lcl_config_components_RK.h file is used to define the application's log +// components. +// +// Use the code +// +// _RKlcl_component(<identifier>, <header>, <name>) +// +// for defining a log component, where +// +// - <identifier> is the unique name of a log component which is used in calls +// to RKlcl_log etc. A symbol 'RKlcl_c<identifier>' is automatically created for +// each log component. +// +// - <header> is a C string in UTF-8 which should be used by a logging back-end +// when writing a log message for the log component. The header is a technical +// key for identifying a log component's messages. It is recommended to use +// a 'Reverse ICANN' naming scheme when the header contains grouping +// information, e.g. 'example.main.component1'. +// +// - <name> is a C string in UTF-8 which contains the name of the log component +// and its grouping information in a non-technical, human-readable way +// which could be used by a user interface. Groups should be separated by the +// path separator '/', e.g. 'Example/Main/Component 1'. +// + + +// +// RestKit Logging Components +// + +_RKlcl_component(App, "app", "App") +_RKlcl_component(RestKit, "restkit", "RestKit") +_RKlcl_component(RestKitCoreData, "restkit.core_data", "RestKit/CoreData") +_RKlcl_component(RestKitCoreDataCache, "restkit.core_data.cache", "RestKit/CoreData/Cache") +_RKlcl_component(RestKitNetwork, "restkit.network", "RestKit/Network") +_RKlcl_component(RestKitNetworkCoreData, "restkit.network.core_data", "RestKit/Network/CoreData") +_RKlcl_component(RestKitObjectMapping, "restkit.object_mapping", "RestKit/ObjectMapping") +_RKlcl_component(RestKitSearch, "restkit.search", "RestKit/Search") +_RKlcl_component(RestKitSupport, "restkit.support", "RestKit/Support") +_RKlcl_component(RestKitTesting, "restkit.testing", "RestKit/Testing") +_RKlcl_component(RestKitUI, "restkit.ui", "RestKit/UI") diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h new file mode 100644 index 0000000..6229343 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h @@ -0,0 +1,20 @@ +// +// lcl_config_extensions_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + diff --git a/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_logger_RK.h b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_logger_RK.h new file mode 100644 index 0000000..64e2ffa --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Support/lcl_config_logger_RK.h @@ -0,0 +1,53 @@ +// +// lcl_config_logger_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// Integration with LibComponentLogging Core. +// + +// ARC/non-ARC autorelease pool +#define _RKlcl_logger_autoreleasepool_arc 0 +#if defined(__has_feature) +# if __has_feature(objc_arc) +# undef _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_arc 1 +# endif +#endif + +#if _RKlcl_logger_autoreleasepool_arc + #define _RKlcl_logger_autoreleasepool_begin @autoreleasepool { + #define _RKlcl_logger_autoreleasepool_end } +#else + #define _RKlcl_logger_autoreleasepool_begin NSAutoreleasePool *_RKlcl_logpool = [[NSAutoreleasePool alloc] init]; + #define _RKlcl_logger_autoreleasepool_end [_RKlcl_logpool release]; +#endif + + +#define _RKlcl_logger(_component, _level, _format, ...) { \ + _RKlcl_logger_autoreleasepool_begin \ + [RKGetLoggingClass() logWithComponent:_component \ + level:_level \ + path:__FILE__ \ + line:__LINE__ \ + function:__PRETTY_FUNCTION__ \ + format:_format, ## __VA_ARGS__]; \ + _RKlcl_logger_autoreleasepool_end \ +} + diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing.h b/Unit-2-Journal/Pods/RestKit/Code/Testing.h new file mode 100644 index 0000000..a76696a --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing.h @@ -0,0 +1,31 @@ +// +// Testing.h +// RestKit +// +// Created by Blake Watters on 2/1/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +#import "RKTestFixture.h" +#import "RKTestNotificationObserver.h" +#import "RKTestFactory.h" +#import "RKTestHelpers.h" +#import "RKMappingTest.h" + +#ifdef _COREDATADEFINES_H +#import "RKConnectionTestExpectation.h" +#endif + diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.h new file mode 100644 index 0000000..ba40ded --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.h @@ -0,0 +1,111 @@ +// +// RKBenchmark.h +// RestKit +// +// Derived from Benchmark class: https://gist.github.com/1479490 +// Created by Sijawusz Pur Rahnama on 03/02/09. +// Copyleft 2009. Some rights reserved. +// + +#import <Foundation/Foundation.h> + +/** + The `RKBenchmark` classes provide a simple, lightweight interface for quickly benchmarking the performance of units of code. Benchmark objects can be used procedurally, by manually starting & stopping the benchmark, or using a block interface to measure the execution time of the block. + */ +@interface RKBenchmark : NSObject + +///--------------------------------- +/// @name Accessing Benchmark Values +///--------------------------------- + +/** + A name for the benchmark. Can be nil. + */ +@property (nonatomic, strong) NSString *name; + +/** + The start time of the benchmark as an absolute time value. + */ +@property (nonatomic, assign, readonly) CFAbsoluteTime startTime; + +/** + The end time of the benchmark as an absolute time value. + */ +@property (nonatomic, assign, readonly) CFAbsoluteTime endTime; + +/** + The elapsed time of the benchmark as determined by subtracting the end time from the start time. Returns zero until the benchmark has been stopped. + */ +@property (nonatomic, assign, readonly) CFTimeInterval elapsedTime; + +///------------------------------------ +/// @name Quickly Performing Benchmarks +///------------------------------------ + +/** + */ ++ (id)report:(NSString *)info executionBlock:(void (^)(void))block; + +/** + Performs a benchmark and returns a time interval measurement of the total time elapsed during the execution of the blocl. + + @param block A block to execute and measure the elapsed time during execution. + @return A time interval equal to the total time elapsed during execution. + */ ++ (CFTimeInterval)measureWithExecutionBlock:(void (^)(void))block; + +///--------------------------------- +/// @name Creating Benchmark Objects +///--------------------------------- + +/** + Retrieves or creates a benchmark object instance with a given name. + + @param name A name for the benchmark. + @return A new or existing benchmark object with the given name. + */ ++ (RKBenchmark *)instanceWithName:(NSString *)name; + +/** + Creates and returns a benchmark object with a name. + + @param name A name for the benchmark. + @return A new benchmark object with the given name. + */ ++ (instancetype)benchmarkWithName:(NSString *)name; + +/** + Initializes a new benchmark object with a name. + + @param name The name to initialize the receiver with. + @return The receiver, initialized with the given name. + */ +- (instancetype)initWithName:(NSString *)name; + +///---------------------------- +/// @name Performing Benchmarks +///---------------------------- + +/** + Runs a benchmark by starting the receiver, executing the block, and then stopping the benchmark object. + + @param executionBlock A block to execute as the body of the benchmark. + */ +- (void)run:(void (^)(void))executionBlock; + +/** + Starts the benchmark by recording the start time. + */ +- (void)start; + +/** + Stops the benchmark by recording the stop time. + */ +- (void)stop; + +/** + Logs the current benchmark status. If the receiver has been stopped, the elapsed time of the benchmark is logged. If the benchmark is still running, the total time since the benchmark was started is logged. + */ +- (void)log; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.m new file mode 100644 index 0000000..844e06c --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKBenchmark.m @@ -0,0 +1,129 @@ +// +// RKBenchmark.h +// RestKit +// +// Derived from Benchmark class: https://gist.github.com/1479490 +// Created by Sijawusz Pur Rahnama on 03/02/09. +// Copyleft 2009. Some rights reserved. +// + +#import "RKBenchmark.h" + +@interface RKBenchmark () +@property (nonatomic, assign, readwrite) CFAbsoluteTime startTime; +@property (nonatomic, assign, readwrite) CFAbsoluteTime endTime; +@property (nonatomic, assign, readwrite) CFTimeInterval elapsedTime; +@property (nonatomic, assign, getter = isStopped) BOOL stopped; +@end + +@implementation RKBenchmark + +static NSMutableDictionary *__sharedBenchmarks = nil; + ++ (NSMutableDictionary *)sharedBenchmarks +{ + if (!__sharedBenchmarks) { + __sharedBenchmarks = [[NSMutableDictionary alloc] init]; + } + return __sharedBenchmarks; +} + ++ (id)instanceWithName:(NSString *)name +{ + @synchronized (self) { + // get the benchmark or create it on-the-fly + id benchmark = [self sharedBenchmarks][name]; + if (!benchmark) { + benchmark = [self benchmarkWithName:name]; + [self sharedBenchmarks][name] = benchmark; + } + return benchmark; + } + return nil; +} + +@synthesize name = _name; +@synthesize startTime = _startTime; +@synthesize endTime = _endTime; +@synthesize elapsedTime = _elapsedTime; +@synthesize stopped = _stopped; + +# pragma mark - +# pragma mark Quick access class methods + ++ (id)report:(NSString *)info executionBlock:(void (^)(void))block +{ + RKBenchmark *benchmark = [self instanceWithName:info]; + [benchmark run:block]; + [benchmark log]; + return benchmark; +} + ++ (CFTimeInterval)measureWithExecutionBlock:(void (^)(void))block +{ + RKBenchmark *benchmark = [self new]; + [benchmark run:block]; + return benchmark.elapsedTime; +} + +# pragma mark - +# pragma mark Initializers + ++ (instancetype)benchmarkWithName:(NSString *)name +{ + return [[self alloc] initWithName:name]; +} + +- (instancetype)initWithName:(NSString *)name +{ + if (self = [self init]) { + self.name = name; + } + return self; +} + +# pragma mark - +# pragma mark Benchmark methods + +- (void)run:(void (^)(void))executionBlock +{ + [self start]; + executionBlock(); + [self stop]; +} + +- (void)start +{ + self.startTime = CFAbsoluteTimeGetCurrent(); +} + +- (void)stop +{ + self.endTime = CFAbsoluteTimeGetCurrent(); + self.stopped = YES; + + // Calculate elapsed time + CFDateRef startDate = CFDateCreate(NULL, self.startTime); + CFDateRef endDate = CFDateCreate(NULL, self.endTime); + self.elapsedTime = CFDateGetTimeIntervalSinceDate(endDate, startDate); + CFRelease(startDate); + CFRelease(endDate); +} + +- (void)log +{ + CFTimeInterval timeElapsed; + if (self.isStopped) { + timeElapsed = self.elapsedTime; + } else { + CFDateRef startDate = CFDateCreate(NULL, self.startTime); + timeElapsed = CFDateGetTimeIntervalSinceDate(startDate, (CFDateRef)[NSDate date]); + CFRelease(startDate); + } + + // log elapsed time + if (_name) NSLog(@"Benchmark '%@' took %f seconds.", _name, timeElapsed); + else NSLog(@"Benchmark took %f seconds.", timeElapsed); +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.h new file mode 100644 index 0000000..6dceaea --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.h @@ -0,0 +1,87 @@ +// +// RKConnectionTestExpectation.h +// RestKit +// +// Created by Blake Watters on 12/8/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H + +#import <Foundation/Foundation.h> + +/** + An `RKConnectionTestExpectation` object defines an expectation that a Core Data relationship is connected during the execution of a `RKMappingTest`. These expectation are used to unit test a connection specified via an `RKConnectionDescription` object. + + @see `RKMappingTest` + @see `RKConnectionDescription` + */ +@interface RKConnectionTestExpectation : NSObject + +///---------------------------- +/// @name Creating Expectations +///---------------------------- + +/** + Creates and returns a connection expectation for the specified relationship name, attributes dictionary, and value. + + @param relationshipName The name of the relationship expected to be connected. + @param attributes A dictionary specifying the attributes that are expected to be used to establish the connection. + @param value The value that is expected to be set for the relationship when the connection is established. + @return A newly constructed connection expectation, initialized with the given relationship name, attributes dictionary, and expected value. + */ ++ (instancetype)expectationWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value; + +/** + Initializes the receiver with the given relationship name, attributes dictionary, and value. + + @param relationshipName The name of the relationship expected to be connected. + @param attributes A dictionary specifying the attributes that are expected to be used to establish the connection. + @param value The value that is expected to be set for the relationship when the connection is established. + @return The receiver, initialized with the given relationship name, attributes dictionary, and expected value. + */ +- (instancetype)initWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value; + +///------------------------------------ +/// @name Accessing Expectation Details +///------------------------------------ + +/** + The name of the relationship that is expected to be connected. Cannot be `nil`. + */ +@property (nonatomic, copy, readonly) NSString *relationshipName; + +/** + The dictionary of attributes that are expected to be used when the connection is established. May be `nil`. + */ +@property (nonatomic, copy, readonly) NSDictionary *attributes; + +/** + The value that is expected to be set for the relationship when connected. May be `nil`. + + A value of `nil` indicates that expectation does not specify an exact value for the connection, only that it was set during the execution of the test. A value of `[NSNull null]` indicates that the connection is expected to be connected to a nil value. + */ +@property (nonatomic, strong, readonly) id value; + +/** + Returns a string summary of the connection that is expected to be established. + + @return A string describing the expected connection. + */ +@property (nonatomic, readonly, copy) NSString *summary; + +@end + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.m new file mode 100644 index 0000000..7f86eb7 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKConnectionTestExpectation.m @@ -0,0 +1,69 @@ +// +// RKConnectionTestExpectation.m +// RestKit +// +// Created by Blake Watters on 12/8/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H + +#import "RKConnectionTestExpectation.h" +#import "RKObjectUtilities.h" + +@interface RKConnectionTestExpectation () +@property (nonatomic, copy, readwrite) NSString *relationshipName; +@property (nonatomic, copy, readwrite) NSDictionary *attributes; +@property (nonatomic, strong, readwrite) id value; +@end + +@implementation RKConnectionTestExpectation + ++ (instancetype)expectationWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value +{ + return [[self alloc] initWithRelationshipName:relationshipName attributes:attributes value:value]; +} + +- (instancetype)initWithRelationshipName:(NSString *)relationshipName attributes:(NSDictionary *)attributes value:(id)value +{ + NSParameterAssert(relationshipName); + NSAssert(value == nil || + [value isKindOfClass:[NSManagedObject class]] || + RKObjectIsCollectionContainingOnlyManagedObjects(value), @"Can only expect a connection to `nil`, a `NSManagedObject`, or a collection of `NSManagedObject` objects"); + self = [self init]; + if (self) { + self.relationshipName = relationshipName; + self.attributes = attributes; + self.value = value; + } + return self; +} + +- (NSString *)summary +{ + return [NSString stringWithFormat:@"connect relationship '%@'", self.relationshipName]; +} + +- (NSString *)description +{ + NSMutableString *description = [[self summary] mutableCopy]; + if (self.attributes) [description appendFormat:@" using attributes %@", self.attributes]; + if (self.value) [description appendFormat:@" to value %@", self.value]; + return description; +} + +@end + +#endif diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.h new file mode 100644 index 0000000..7375884 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.h @@ -0,0 +1,219 @@ +// +// RKMappingTest.h +// RestKit +// +// Created by Blake Watters on 2/17/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKMappingOperation.h" +#import "RKPropertyMappingTestExpectation.h" + +@protocol RKMappingOperationDataSource, RKManagedObjectCaching; + +///---------------- +/// @name Constants +///---------------- + +/** + The domain for all errors constructed by the `RKMappingTest` class. + */ +extern NSString * const RKMappingTestErrorDomain; + +/** + Name of an exception that occurs when an `RKMappingTest` object fails verification. Raised by `verifyExpectation`. + */ +extern NSString * const RKMappingTestVerificationFailureException; + +/** + Mapping Test Errors + */ +enum { + RKMappingTestUnsatisfiedExpectationError, // An expected mapping event did not occur + RKMappingTestEvaluationBlockError, // An evaluation block returned `NO` when evaluating a mapping event + RKMappingTestValueInequalityError, // A value was not equal to the expected value + RKMappingTestMappingMismatchError, // A mapping occurred using an unexpected `RKObjectMapping` object +}; + +/** + @define RKMappingTestExpectationTestCondition + @abstract Tests a condition and returns `NO` and error if it is not true. + @discussion This is a useful macro when constructing mapping test evaluation blocks. It will test a condition and return `NO` as well as construct an error. This is meant to be used **only** within the body of a `RKMappingTestExpectationEvaluationBlock` object. + @param condition The condition to test. + @param errorCode An error code in the RKMappingTestErrorDomain indicating the nature of the failure. + @param error The NSError object to put the error string into. May be nil, but should usually be the error parameter from the expectation evaluation block. + @param ... A string describing the error. + */ +#define RKMappingTestCondition(condition, errorCode, error, ...) ({ \ +if (!(condition)) { \ +if (error) { \ +*error = [NSError errorWithDomain:RKMappingTestErrorDomain code:errorCode userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:__VA_ARGS__], NSLocalizedDescriptionKey, nil]]; \ +} \ +return NO; \ +} \ +}) + +/** + The `RKMappingTestEvent` object for the mapping event which failed to satify the expectation. + */ +extern NSString * const RKMappingTestEventErrorKey; + +/** + The `RKMappingTestExpectation` object which was not satisfied by a mapping event. + */ +extern NSString * const RKMappingTestExpectationErrorKey; + +/** + An `RKMappingTest` object provides support for unit testing a RestKit object mapping operation by evaluation expectations against events recorded during an object mapping operation. + */ +@interface RKMappingTest : NSObject + +///--------------------- +/// @name Creating Tests +///--------------------- + +/** + Creates and returns a new test for a given object mapping, source object and destination + object. + + @param mapping The mapping being tested. + @param sourceObject The source object being mapped from. + @param destinationObject The destionation object being to. + @return A new mapping test object for a mapping, a source object and a destination object. + */ ++ (instancetype)testForMapping:(RKMapping *)mapping sourceObject:(id)sourceObject destinationObject:(id)destinationObject; + +/** + Initializes the receiver with a given object mapping, source object, and destination object. + + @param mapping The mapping being tested. + @param sourceObject The source object being mapped from. + @param destinationObject The destionation object being to. + @return The receiver, initialized with mapping, sourceObject and destinationObject. + */ +- (instancetype)initWithMapping:(RKMapping *)mapping sourceObject:(id)sourceObject destinationObject:(id)destinationObject NS_DESIGNATED_INITIALIZER; + +///---------------------------- +/// @name Managing Expectations +///---------------------------- + +/** + Adds an expectation to the receiver to be evaluated during verification. + + @param expectation An expectation object to evaluate during test verification. Must be an instance of `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`. + @see `RKMappingTestExpectation` + @see `verifiesOnExpect` + */ +- (void)addExpectation:(id)expectation; + +/** + Evaluates the given expectation against the mapping test and returns a Boolean value indicating if the expectation is met by the receiver. + + Invocation of this method will implicitly invoke `performMapping` if the mapping has not yet been performed. + + @param expectation The expectation to evaluate against the receiver. Must be an intance of either `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`. + @param error A pointer to an `NSError` object to be set describing the failure in the event that the expectation is not met. + @return `YES` if the expectation is met, else `NO`. + */ +- (BOOL)evaluateExpectation:(id)expectation error:(NSError **)error; + +///------------------------ +/// @name Verifying Results +///------------------------ + +/** + Performs the object mapping operation and records any mapping events that occur. The mapping events can be verified against expectation through a subsequent call to verify. + + @exception NSInternalInconsistencyException Raises an `NSInternalInconsistencyException` if mapping fails. + */ +- (void)performMapping; + +/** + Verifies that the mapping is configured correctly by performing an object mapping operation and ensuring that all expectations are met. + + @exception RKMappingTestVerificationFailureException Raises an `RKMappingTestVerificationFailureException` exception if mapping fails or any expectation is not satisfied. + */ +- (void)verify; + +/** + Evaluates the expectations and returns a Boolean value indicating if all expectations are satisfied. + + Invocation of this method will implicitly invoke `performMapping` if the mapping has not yet been performed. + + @return `YES` if all expectations were met, else `NO`. + */ +@property (nonatomic, readonly) BOOL evaluate; + +///------------------------- +/// @name Test Configuration +///------------------------- + +/** + The mapping under test. Can be either an `RKObjectMapping` or `RKDynamicMapping` object. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + A data source for the mapping operation. + + If `nil`, an appropriate data source will be constructed for you using the available configuration of the receiver. + */ +@property (nonatomic, strong) id<RKMappingOperationDataSource> mappingOperationDataSource; + +/** + A key path to apply to the source object to specify the location of the root of the data under test. Useful when testing subsets of a larger payload or object graph. + + **Default**: `nil` + */ +@property (nonatomic, copy) NSString *rootKeyPath; + +/** + The source object being mapped from. + */ +@property (nonatomic, strong, readonly) id sourceObject; + +/** + The destionation object being mapped to. + + If `nil`, the mapping test will instantiate a destination object to perform the mapping by invoking `[self.mappingOperationDataSource objectForMappableContent:self.sourceObject mapping:self.mapping]` to obtain a new object from the data source and then assign the object as the value for the destinationObject property. + + @see `mappingOperationDataSource` + */ +@property (nonatomic, strong, readonly) id destinationObject; + +#ifdef _COREDATADEFINES_H + +///---------------------------- +/// @name Core Data Integration +///---------------------------- + +/** + The managed object context within which to perform the mapping test. Required if testing an `RKEntityMapping` object and an appropriate `mappingOperationDataSource` has not been configured. + + When the `mappingOperationDataSource` property is `nil` and the test targets an entity mapping, this context is used to configure an `RKManagedObjectMappingOperationDataSource` object for the purpose of executing the test. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache to use when performing a mapping test. + + If the value of this property is `nil` and the test targets an entity mapping, an instance of `RKFetchRequestManagedObjectCache` will be constructed and used as the cache for the purposes of testing. + */ +@property (nonatomic, strong) id<RKManagedObjectCaching> managedObjectCache; + +#endif // _COREDATADEFINES_H + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.m new file mode 100644 index 0000000..9ef84e5 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKMappingTest.m @@ -0,0 +1,523 @@ +// +// RKMappingTest.m +// RestKit +// +// Created by Blake Watters on 2/17/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingTest.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKRelationshipMapping.h" +#import "RKErrors.h" +#import "RKObjectUtilities.h" +#import "RKLog.h" + +// Core Data +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKEntityMapping.h" +#import "RKConnectionDescription.h" +#import "RKConnectionTestExpectation.h" +#import "RKFetchRequestManagedObjectCache.h" +#import "RKManagedObjectMappingOperationDataSource.h" +#endif +#endif + +// Error Constants +NSString * const RKMappingTestErrorDomain = @"org.restkit.RKMappingTest.ErrorDomain"; +NSString * const RKMappingTestEventErrorKey = @"RKMappingTestEventErrorKey"; +NSString * const RKMappingTestExpectationErrorKey = @"RKMappingTestExpectationErrorKey"; +NSString * const RKMappingTestValueErrorKey = @"RKMappingTestValueErrorKey"; +NSString * const RKMappingTestVerificationFailureException = @"RKMappingTestVerificationFailureException"; + +///----------------------------------------------------------------------------- +///----------------------------------------------------------------------------- + +@interface RKMappingTestEvent : NSObject + +@property (nonatomic, strong, readonly) RKPropertyMapping *propertyMapping; +#ifdef RKCoreDataIncluded +@property (nonatomic, strong, readonly) RKConnectionDescription *connection; +#endif +@property (nonatomic, strong, readonly) id value; + +@property (weak, nonatomic, readonly) NSString *sourceKeyPath; +@property (weak, nonatomic, readonly) NSString *destinationKeyPath; + ++ (RKMappingTestEvent *)eventWithMapping:(RKPropertyMapping *)propertyMapping value:(id)value; + +#ifdef RKCoreDataIncluded ++ (RKMappingTestEvent *)eventWithConnection:(RKConnectionDescription *)connection value:(id)value; +#endif + +@end + +@interface RKMappingTestEvent () +@property (nonatomic, strong, readwrite) id value; +@property (nonatomic, strong, readwrite) RKPropertyMapping *propertyMapping; +#ifdef RKCoreDataIncluded +@property (nonatomic, strong, readwrite) RKConnectionDescription *connection; +#endif +@end + +@implementation RKMappingTestEvent + ++ (RKMappingTestEvent *)eventWithMapping:(RKPropertyMapping *)propertyMapping value:(id)value +{ + RKMappingTestEvent *event = [RKMappingTestEvent new]; + event.value = value; + event.propertyMapping = propertyMapping; + + return event; +} + +#ifdef RKCoreDataIncluded ++ (RKMappingTestEvent *)eventWithConnection:(RKConnectionDescription *)connection value:(id)value +{ + RKMappingTestEvent *event = [RKMappingTestEvent new]; + event.connection = connection; + event.value = value; + return event; +} +#endif + +- (NSString *)sourceKeyPath +{ + return [self.propertyMapping sourceKeyPath]; +} + +- (NSString *)destinationKeyPath +{ + return [self.propertyMapping destinationKeyPath]; +} + +- (NSString *)description +{ + if (self.propertyMapping) { + return [NSString stringWithFormat:@"%@ mapped sourceKeyPath '%@' => destinationKeyPath '%@' with value: %@>", [self class], + self.sourceKeyPath, self.destinationKeyPath, self.value]; + } +#ifdef RKCoreDataIncluded + else if (self.connection) { + if ([self.connection isForeignKeyConnection]) { + return [NSString stringWithFormat:@"%@ connected Relationship '%@' using attributes '%@' to value: %@>", [self class], + [self.connection.relationship name], [self.connection.attributes valueForKey:@"name"], self.value]; + } else if ([self.connection isKeyPathConnection]) { + return [NSString stringWithFormat:@"%@ connected Relationship '%@' using keyPath '%@' to value: %@>", [self class], + [self.connection.relationship name], self.connection.keyPath, self.value]; + } + } +#endif + + return [super description]; +} + +@end + +///----------------------------------------------------------------------------- +///----------------------------------------------------------------------------- + +@interface RKMappingTest () <RKMappingOperationDelegate> +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, strong, readwrite) id sourceObject; +@property (nonatomic, strong, readwrite) id destinationObject; +@property (nonatomic, strong) NSMutableArray *expectations; +@property (nonatomic, strong) NSMutableArray *events; +@property (nonatomic, assign, getter = hasPerformedMapping) BOOL performedMapping; + +// Method Definitions for old compilers +- (void)performMapping; +- (void)verifyExpectation:(RKPropertyMappingTestExpectation *)expectation; + +@end + +@implementation RKMappingTest + ++ (instancetype)testForMapping:(RKMapping *)mapping sourceObject:(id)sourceObject destinationObject:(id)destinationObject +{ + return [[self alloc] initWithMapping:mapping sourceObject:sourceObject destinationObject:destinationObject]; +} + +- (instancetype)initWithMapping:(RKMapping *)mapping sourceObject:(id)sourceObject destinationObject:(id)destinationObject +{ + NSAssert(sourceObject != nil, @"Cannot perform a mapping operation without a sourceObject object"); + NSAssert(mapping != nil, @"Cannot perform a mapping operation without a mapping"); + + self = [super init]; + if (self) { + self.sourceObject = sourceObject; + self.destinationObject = destinationObject; + self.mapping = mapping; + self.expectations = [NSMutableArray new]; + self.events = [NSMutableArray new]; + self.performedMapping = NO; + } + + return self; +} + +- (void)addExpectation:(id)expectation +{ + NSParameterAssert(expectation); + Class connectionTestExpectation = NSClassFromString(@"RKConnectionTestExpectation"); + if (![expectation isKindOfClass:[RKPropertyMappingTestExpectation class]] && ![expectation isKindOfClass:connectionTestExpectation]) { + [NSException raise:NSInvalidArgumentException + format:@"Invalid expectation: expected an object of type `%@` or `%@`, but instead got a `%@`", + [RKPropertyMappingTestExpectation class], @"RKConnectionTestExpectation", expectation]; + } + [self.expectations addObject:expectation]; +} + +- (RKMappingTestEvent *)eventMatchingExpectation:(id)expectation +{ +#ifdef RKCoreDataIncluded + Class connectionTestExpectation = NSClassFromString(@"RKConnectionTestExpectation"); +#endif + for (RKMappingTestEvent *event in [self.events copy]) { + if ([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]]) { + RKPropertyMappingTestExpectation *propertyExpectation = (RKPropertyMappingTestExpectation *) expectation; + if ([event.sourceKeyPath isEqualToString:propertyExpectation.sourceKeyPath] && [event.destinationKeyPath isEqualToString:propertyExpectation.destinationKeyPath]) { + return event; + } else if ((event.sourceKeyPath == nil && propertyExpectation.sourceKeyPath == nil) && ([event.destinationKeyPath isEqualToString:propertyExpectation.destinationKeyPath])) { + return event; + } + } +#ifdef RKCoreDataIncluded + else if ([expectation isKindOfClass:connectionTestExpectation]) { + RKConnectionTestExpectation *connectionExpectation = (RKConnectionTestExpectation *) expectation; + if ([[event.connection.relationship name] isEqualToString:connectionExpectation.relationshipName]) { + return event; + } + } +#endif + } + + return nil; +} + +- (NSError *)errorForExpectation:(RKPropertyMappingTestExpectation *)expectation + withCode:(NSInteger)errorCode + userInfo:(NSDictionary *)userInfo + description:(NSString *)description + reason:(NSString *)reason +{ + NSMutableDictionary *fullUserInfo = [userInfo mutableCopy]; + fullUserInfo[NSLocalizedDescriptionKey] = description; + fullUserInfo[NSLocalizedFailureReasonErrorKey] = reason; + return [NSError errorWithDomain:RKMappingTestErrorDomain code:errorCode userInfo:fullUserInfo]; +} + +- (BOOL)event:(RKMappingTestEvent *)event satisfiesExpectation:(id)expectation error:(NSError **)error +{ + BOOL success = NO; + + NSDictionary *userInfo = @{ RKMappingTestEventErrorKey : event, + RKMappingTestExpectationErrorKey : expectation }; + if ([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]]) { + RKPropertyMappingTestExpectation *propertyExpectation = (RKPropertyMappingTestExpectation *)expectation; + if (propertyExpectation.evaluationBlock) { + // Let the expectation block evaluate the match + NSError *blockError = nil; + success = propertyExpectation.evaluationBlock(expectation, event.propertyMapping, event.value, &blockError); + + if (! success) { + if (blockError) { + // If the block has given us an error, use the reason + NSMutableDictionary *mutableUserInfo = [userInfo mutableCopy]; + [mutableUserInfo setValue:blockError forKey:NSUnderlyingErrorKey]; + NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not", + expectation, [event.value class], event.value]; + + if (error) { + *error = [self errorForExpectation:expectation + withCode:RKMappingTestEvaluationBlockError + userInfo:mutableUserInfo + description:[blockError localizedDescription] + reason:reason]; + + *error = blockError; + } + } else { + NSString *description = [NSString stringWithFormat:@"evaluation block returned `NO` for %@ value '%@'", [event.value class], event.value]; + NSString *reason = [NSString stringWithFormat:@"expected to %@ with value %@ '%@', but it did not", + expectation, [event.value class], event.value]; + if (error) { + *error = [self errorForExpectation:expectation + withCode:RKMappingTestEvaluationBlockError + userInfo:userInfo + description:description + reason:reason]; + } + } + } + } else if (propertyExpectation.value) { + // Use RestKit comparison magic to match values + success = RKObjectIsEqualToObject(event.value, propertyExpectation.value); + + if (! success) { + NSString *description = [NSString stringWithFormat:@"mapped to unexpected %@ value '%@'", [event.value class], event.value]; + NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead got %@ '%@'", + expectation, [event.value class], event.value]; + if (error) { + *error = [self errorForExpectation:expectation + withCode:RKMappingTestValueInequalityError + userInfo:userInfo + description:description + reason:reason]; + } + } + } else if (propertyExpectation.mapping) { + if ([event.propertyMapping isKindOfClass:[RKRelationshipMapping class]]) { + // Check the mapping that was used to map the relationship + RKMapping *relationshipMapping = [(RKRelationshipMapping *)event.propertyMapping mapping]; + success = [relationshipMapping isEqualToMapping:propertyExpectation.mapping]; + + if (! success) { + NSString *description = [NSString stringWithFormat:@"mapped using unexpected mapping: %@", relationshipMapping]; + NSString *reason = [NSString stringWithFormat:@"expected to %@, but was instead mapped using: %@", + expectation, relationshipMapping]; + if (error) { + *error = [self errorForExpectation:expectation + withCode:RKMappingTestMappingMismatchError + userInfo:userInfo + description:description + reason:reason]; + } + } + } else { + NSString *description = [NSString stringWithFormat:@"expected a property mapping of type `RKRelationshipMapping` but instead got a `%@`", [propertyExpectation.mapping class]]; + NSString *reason = [NSString stringWithFormat:@"expected to %@, but instead of a `RKRelationshipMapping` got a `%@`", + expectation, [propertyExpectation.mapping class]]; + if (error) { + *error = [self errorForExpectation:expectation + withCode:RKMappingTestMappingMismatchError + userInfo:userInfo + description:description + reason:reason]; + } + + // Error message here that a relationship was not mapped!!! + return NO; + } + } else { + // We only wanted to know that a mapping occured between the keyPaths + success = YES; + } + } +#ifdef RKCoreDataIncluded + else if ([expectation isKindOfClass:[RKConnectionTestExpectation class]]) { + RKConnectionTestExpectation *connectionExpectation = (RKConnectionTestExpectation *)expectation; + id expectedValue = connectionExpectation.value; + id connectedValue = event.value; + + // Check that the connection attributes match + if (connectionExpectation.attributes) { + RKMappingTestCondition([connectionExpectation.attributes isEqualToDictionary:event.connection.attributes], RKMappingTestValueInequalityError, error, @"established connection using unexpected attributes: %@", event.connection.attributes); + } + + // Wrong objects + if (expectedValue) { + RKMappingTestCondition(connectedValue, RKMappingTestValueInequalityError, error, @"unexpectedly connected to nil object set (%@)", connectedValue); + + if ([connectedValue isKindOfClass:[NSManagedObject class]] && [connectionExpectation.value isKindOfClass:[NSManagedObject class]]) { + // Do a managed object ID comparison + RKMappingTestCondition([[connectedValue objectID] isEqual:[expectedValue objectID]], RKMappingTestValueInequalityError, error, @"connected to unexpected managed object: %@", connectedValue); + } else { + // If we are connecting to a collection of managed objects, do a comparison of object IDs + if (RKObjectIsCollectionContainingOnlyManagedObjects(connectedValue) && RKObjectIsCollectionContainingOnlyManagedObjects(expectedValue)) { + RKMappingTestCondition(RKObjectIsEqualToObject([connectedValue valueForKeyPath:@"objectID"], [expectedValue valueForKeyPath:@"objectID"]), RKMappingTestValueInequalityError, error, @"connected to unexpected %@ value '%@'", [connectedValue class], connectedValue); + } else { + RKMappingTestCondition(RKObjectIsEqualToObject(connectedValue, expectedValue), RKMappingTestValueInequalityError, error, @"connected to unexpected %@ value '%@'", [connectedValue class], connectedValue); + } + } + } else { + RKMappingTestCondition(connectedValue == nil, RKMappingTestValueInequalityError, error, @"unexpectedly connected to non-nil object set (%@)", connectedValue); + } + + return YES; + } +#endif + return success; +} + +- (id<RKMappingOperationDataSource>)dataSourceForMappingOperation:(RKMappingOperation *)mappingOperation +{ + // If we have been given an explicit data source, use it + if (self.mappingOperationDataSource) return self.mappingOperationDataSource; + +#ifdef RKCoreDataIncluded + if ([self.mapping isKindOfClass:[RKEntityMapping class]]) { + NSAssert(self.managedObjectContext, @"Cannot test an `RKEntityMapping` with a nil managed object context."); + id<RKManagedObjectCaching> managedObjectCache = self.managedObjectCache ?: [RKFetchRequestManagedObjectCache new]; + RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:self.managedObjectContext cache:managedObjectCache]; + + // Configure an operation queue to enable easy testing of connection operations + NSOperationQueue *operationQueue = [NSOperationQueue new]; + dataSource.operationQueue = operationQueue; + return dataSource; + } else { + return [RKObjectMappingOperationDataSource new]; + } +#else + return [RKObjectMappingOperationDataSource new]; +#endif +} + +- (void)performMapping +{ + // Ensure repeated invocations of verify only result in a single mapping operation + if (! self.hasPerformedMapping) { + id sourceObject = self.rootKeyPath ? [self.sourceObject valueForKeyPath:self.rootKeyPath] : self.sourceObject; + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:sourceObject destinationObject:self.destinationObject mapping:self.mapping]; + id<RKMappingOperationDataSource> dataSource = [self dataSourceForMappingOperation:mappingOperation]; + mappingOperation.dataSource = dataSource; + mappingOperation.delegate = self; + [mappingOperation start]; + if (mappingOperation.error) { + [NSException raise:NSInternalInconsistencyException format:@"%p: failed with error: %@\n%@ during mapping from %@ to %@ with mapping %@", + self, mappingOperation.error, [self description], self.sourceObject, self.destinationObject, self.mapping]; + } + + // Let the connection operations execute to completion +#ifdef RKCoreDataIncluded + Class managedObjectMappingOperationDataSourceClass = NSClassFromString(@"RKManagedObjectMappingOperationDataSource"); + if ([mappingOperation.dataSource isKindOfClass:managedObjectMappingOperationDataSourceClass]) { + NSOperationQueue *operationQueue = [(RKManagedObjectMappingOperationDataSource *)mappingOperation.dataSource operationQueue]; + if (! [operationQueue isEqual:[NSOperationQueue mainQueue]]) { + [operationQueue waitUntilAllOperationsAreFinished]; + } + } +#endif + + self.performedMapping = YES; + + // Get the destination object from the mapping operation + if (! self.destinationObject) self.destinationObject = mappingOperation.destinationObject; + } +} + +- (void)verifyExpectation:(RKPropertyMappingTestExpectation *)expectation +{ + RKMappingTestEvent *event = [self eventMatchingExpectation:expectation]; + if (event) { + // Found a matching event, check if it satisfies the expectation + NSError *error = nil; + if (! [self event:event satisfiesExpectation:expectation error:&error]) { + NSDictionary *userInfo = @{ NSUnderlyingErrorKey: error, + RKMappingTestEventErrorKey: event, + RKMappingTestExpectationErrorKey: expectation }; + [[NSException exceptionWithName:RKMappingTestVerificationFailureException + reason:[error localizedDescription] + userInfo:userInfo] raise]; + } + } else { + // No match + [NSException raise:NSInternalInconsistencyException format:@"%@: expectation not satisfied: %@, but did not.", + [self description], [expectation summary]]; + } +} + +- (void)verify +{ + [self performMapping]; + + for (RKPropertyMappingTestExpectation *expectation in self.expectations) { + [self verifyExpectation:expectation]; + } +} + +#pragma mark - Evaluating Expectations + +- (BOOL)evaluate +{ + [self performMapping]; + + for (RKPropertyMappingTestExpectation *expectation in self.expectations) { + if (! [self evaluateExpectation:expectation error:nil]) return NO; + } + + return YES; +} + +- (BOOL)evaluateExpectation:(id)expectation error:(NSError **)error +{ + NSParameterAssert(expectation); + Class connectionTestExpectation = NSClassFromString(@"RKConnectionTestExpectation"); + if (! ([expectation isKindOfClass:[RKPropertyMappingTestExpectation class]] || (connectionTestExpectation && [expectation isKindOfClass:connectionTestExpectation]))) [NSException raise:NSInvalidArgumentException format:@"Must be an instance of `RKPropertyMappingTestExpectation` or `RKConnectionTestExpectation`"]; + [self performMapping]; + + RKMappingTestEvent *event = [self eventMatchingExpectation:expectation]; + if (event) { + if (! [self event:event satisfiesExpectation:expectation error:error]) { + return NO; + } + } else { + if (error) { + NSDictionary *userInfo = @{ + RKMappingTestExpectationErrorKey : expectation, + NSLocalizedDescriptionKey : [NSString stringWithFormat:@"expected to %@, but did not.", [expectation summary]], + NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:@"%@: %@, but did not.", [self description], [expectation summary]] + }; + *error = [NSError errorWithDomain:RKMappingTestErrorDomain code:RKMappingTestUnsatisfiedExpectationError userInfo:userInfo]; + }; + return NO; + } + + return YES; +} + +- (NSString *)expectationsDescription +{ + return [self.expectations valueForKey:@"description"]; +} + +- (NSString *)eventsDescription +{ + return [self.events valueForKey:@"description"]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ Expectations: %@\nEvents: %@", + [self class], [self expectationsDescription], [self eventsDescription]]; +} + +#pragma mark - RKMappingOperationDelegate + +- (void)addEvent:(RKMappingTestEvent *)event +{ + @synchronized(self.events) { [self.events addObject:event]; }; +} + +- (void)mappingOperation:(RKMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKAttributeMapping *)mapping +{ + [self addEvent:[RKMappingTestEvent eventWithMapping:mapping value:value]]; +} + +- (void)mappingOperation:(RKMappingOperation *)operation didNotSetUnchangedValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKAttributeMapping *)mapping +{ + [self addEvent:[RKMappingTestEvent eventWithMapping:mapping value:value]]; +} + +#ifdef RKCoreDataIncluded +- (void)mappingOperation:(RKMappingOperation *)operation didConnectRelationship:(NSRelationshipDescription *)relationship toValue:(id)value usingConnection:(RKConnectionDescription *)connection +{ + [self addEvent:[RKMappingTestEvent eventWithConnection:connection value:value]]; +} +#endif + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.h new file mode 100644 index 0000000..0af8ded --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.h @@ -0,0 +1,121 @@ +// +// RKPropertyMappingTestExpectation.h +// RestKit +// +// Created by Blake Watters on 2/17/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +@class RKMapping, RKPropertyMapping, RKPropertyMappingTestExpectation; + +/** + @typedef RKMappingTestExpectationEvaluationBlock + + @param expectation The expectation object itself. This is passed so that there is a reference available at the time of evaluation. + @param mapping The property mapping object that occurred for the source and destination key paths of the expectation. Will be an instance of `RKAttributeMapping, `RKRelationshipMapping`, or `RKConnectionMapping`. + @param mappedValue The value that was mapped. + @param error A pointer to an error object that is to be set in the event that the expectation evaluates negatively. If left to `nil`, a generic error will be generated. + */ +typedef BOOL (^RKMappingTestExpectationEvaluationBlock)(RKPropertyMappingTestExpectation *expectation, RKPropertyMapping *mapping, id mappedValue, NSError **error); + +/** + An `RKMappingTestExpectation` object defines an expected mapping event that should occur during the execution of a `RKMappingTest`. + + @see `RKMappingTest` + */ +@interface RKPropertyMappingTestExpectation : NSObject + +///---------------------------- +/// @name Creating Expectations +///---------------------------- + +/** + Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destination object. The value mapped is not evaluated. + + @param sourceKeyPath A key path on the source object that should be mapped. + @param destinationKeyPath A key path on the destination object that should be mapped onto. + @return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath. + */ ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath; + +/** + Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destination object with a given value. + + @param sourceKeyPath A key path on the source object that should be mapped. + @param destinationKeyPath A key path on the destination object that should be mapped onto. + @param value The value that is expected to be assigned to the destination object at destinationKeyPath. + @return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath with value. + */ ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value; + +/** + Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destinaton object and that the attribute mapping and value should evaluate to true with a given block. + + @param sourceKeyPath A key path on the source object that should be mapped. + @param destinationKeyPath A key path on the destination object that should be mapped onto. + @param evaluationBlock A block with which to evaluate the success of the mapping. + @return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath with value. + */ ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock; + +/** + Creates and returns a new expectation specifying that a key path in a source object should be mapped to another key path on a destinaton object using a specific object mapping for the relationship. + + @param sourceKeyPath A key path on the source object that should be mapped. + @param destinationKeyPath A key path on the destination object that should be mapped onto. + @param mapping An object mapping that is expected to be used for mapping the nested relationship. + @return An expectation specifying that sourceKeyPath should be mapped to destinationKeyPath using a specific object mapping. + */ ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping; + +///------------------------- +/// @name Expectation Values +///------------------------- + +/** + Returns a keyPath on the source object that a value should be mapped from. + */ +@property (nonatomic, copy, readonly) NSString *sourceKeyPath; + +/** + Returns a keyPath on the destination object that a value should be mapped to. + */ +@property (nonatomic, copy, readonly) NSString *destinationKeyPath; + +/** + Returns the expected value that should be set to the destinationKeyPath of the destination object. + */ +@property (nonatomic, strong, readonly) id value; + +/** + A block used to evaluate if the expectation has been satisfied. + + The block accepts three arguments, an `RKPropertyMapping` object denoting the attribute or relationship that was mapped, the mapped value, and a pointer to an error object that is to be set if the block evaluates negatively, and returns a Boolean value indicating if the mapping satisfies the expectations of the block. + */ +@property (nonatomic, copy, readonly) RKMappingTestExpectationEvaluationBlock evaluationBlock; + +/** + Returns the expected object mapping to be used for mapping a nested relationship. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + Returns a string summary of the expected keyPath mapping within the expectation + + @return A string describing the expected sourceKeyPath to destinationKeyPath mapping. + */ +@property (nonatomic, readonly, copy) NSString *summary; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.m new file mode 100644 index 0000000..8023f57 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKPropertyMappingTestExpectation.m @@ -0,0 +1,94 @@ +// +// RKMappingTestExpectation.m +// RestKit +// +// Created by Blake Watters on 2/17/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMappingTestExpectation.h" +#import "RKPropertyMapping.h" + +@interface RKPropertyMappingTestExpectation () +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@property (nonatomic, strong, readwrite) id value; +@property (nonatomic, copy, readwrite) RKMappingTestExpectationEvaluationBlock evaluationBlock; +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@end + +@implementation RKPropertyMappingTestExpectation + ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath +{ + RKPropertyMappingTestExpectation *expectation = [self new]; + expectation.sourceKeyPath = sourceKeyPath; + expectation.destinationKeyPath = destinationKeyPath; + + return expectation; +} + ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath value:(id)value +{ + RKPropertyMappingTestExpectation *expectation = [self new]; + expectation.sourceKeyPath = sourceKeyPath; + expectation.destinationKeyPath = destinationKeyPath; + expectation.value = value; + + return expectation; +} + ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath evaluationBlock:(RKMappingTestExpectationEvaluationBlock)evaluationBlock +{ + RKPropertyMappingTestExpectation *expectation = [self new]; + expectation.sourceKeyPath = sourceKeyPath; + expectation.destinationKeyPath = destinationKeyPath; + expectation.evaluationBlock = evaluationBlock; + + return expectation; +} + ++ (instancetype)expectationWithSourceKeyPath:(NSString *)sourceKeyPath destinationKeyPath:(NSString *)destinationKeyPath mapping:(RKMapping *)mapping +{ + RKPropertyMappingTestExpectation *expectation = [self new]; + expectation.sourceKeyPath = sourceKeyPath; + expectation.destinationKeyPath = destinationKeyPath; + expectation.mapping = mapping; + + return expectation; +} + +- (NSString *)summary +{ + return [NSString stringWithFormat:@"map '%@' to '%@'", self.sourceKeyPath, self.destinationKeyPath]; +} + +- (NSString *)description +{ + if (self.value) { + return [NSString stringWithFormat:@"map '%@' to '%@' with %@ value '%@'", + self.sourceKeyPath, self.destinationKeyPath, [self.value class], self.value]; + } else if (self.evaluationBlock) { + return [NSString stringWithFormat:@"map '%@' to '%@' satisfying evaluation block", + self.sourceKeyPath, self.destinationKeyPath]; + } else if (self.mapping) { + return [NSString stringWithFormat:@"map '%@' to '%@' using mapping: %@", + self.sourceKeyPath, self.destinationKeyPath, self.mapping]; + } + + return [self summary]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestConstants.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestConstants.m new file mode 100644 index 0000000..9e23183 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestConstants.m @@ -0,0 +1,30 @@ +// +// RKTestConstants.m +// RestKit +// +// Created by Blake Watters on 5/4/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/* + This file defines constants used by the Testing module. It is necessary due to strange + linking errors when building for the Device. When these constants were defined within + RKTestFactory.m, they would resolve on the Simulator but produce linker when building + for Device. [sbw - 05/04/2012] + */ +NSString * const RKTestFactoryDefaultNamesClient = @"client"; +NSString * const RKTestFactoryDefaultNamesObjectManager = @"objectManager"; +NSString * const RKTestFactoryDefaultNamesManagedObjectStore = @"managedObjectStore"; +NSString * const RKTestFactoryDefaultStoreFilename = @"RKTests.sqlite"; diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.h new file mode 100644 index 0000000..a5f7753 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.h @@ -0,0 +1,231 @@ +// +// RKTestFactory.h +// RestKit +// +// Created by Blake Watters on 2/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#endif +#endif + +/** + The default filename used for managed object stores created via the factory. + */ +extern NSString * const RKTestFactoryDefaultStoreFilename; + +/* + Default Factory Names + */ +extern NSString * const RKTestFactoryDefaultNamesClient; +extern NSString * const RKTestFactoryDefaultNamesObjectManager; +extern NSString * const RKTestFactoryDefaultNamesManagedObjectStore; + +@class RKManagedObjectStore; + +/** + The `RKTestFactory` class provides an interface for initializing RestKit objects within a unit testing environment. The factory is used to ensure isolation between test cases by ensuring that RestKit's important singleton objects are torn down between tests and that each test is working within a clean Core Data environment. Callback hooks are provided so that application specific set up and tear down logic can be integrated as well. + + The factory also provides for the definition of named factories for instantiating objects quickly. At initialization, there are factories defined for creating instances of `AFHTTPClient`, `RKObjectManager`, and `RKManagedObjectStore`. These factories may be redefined within your application should you choose to utilize a subclass or wish to centralize configuration of objects across the test suite. You may also define additional factories for building instances of objects specific to your application using the same infrastructure. + + ## Customizing the Factory + + The test factory is designed to be customized via an Objective-C category. All factory methods are implemented using blocks that have sensible defaults, but can be overridden by providing an alternate implementation. To do so, implement a category on the `RKTestFactory` class and provide an implementation of the `+ (void)load` method. Within the method body, configure your blocks as you see fit. An example implementation is provided below: + + @interface RKTestFactory (MyApp) + + // Create a convenience method for retrieving an object from the factory + + (GGAirport *)ohareAirport; + @end + + @implementation RKTestFactory (MyApp) + + + (void)load + { + [self setSetUpBlock:{ + // I am called on every invocation of `setUp`! + }]; + + // Replace the default object manager factory + [RKTestFactory defineFactory:RKTestFactoryDefaultNamesObjectManager withBlock:^id { + GGObjectManager *objectManager = [[GGObjectManager alloc] initWithBaseURL:[self baseURL]]; + return objectManager; + }]; + + // Define a new factory called 'ORD' that returns a representation of Chicago's O'Hare Airport + [RKTestFactory defineFactory:@"ORD" withBlock:^id{ + GGAirport *ord = [RKTestFactory insertManagedObjectForEntityForName:@"Airport" inManagedObjectContext:nil withProperties:nil]; + ord.airportID = @16; + ord.name = @"Chicago O'Hare International Airport"; + ord.code = @"ORD"; + ord.city = @"Chicago"; + ord.favorite = @(YES); + ord.timeZoneName = @"America/Chicago"; + ord.latitude = @(41.9781); + ord.longitude = @(-87.9061); + + return ord; + }]; + } + + + (GGAirport *)ohareAirport + { + return [self objectFromFactory:@"ORD"]; + } + + @end + */ +@interface RKTestFactory : NSObject + +///------------------------------ +/// @name Configuring the Factory +///------------------------------ + +/** + Returns the base URL with which to initialize `AFHTTPClient` and `RKObjectManager` instances created via the factory. + + @return The base URL for the factory. + */ ++ (NSURL *)baseURL; + +/** + Sets the base URL for the factory. + + @param URL The new base URL. + */ ++ (void)setBaseURL:(NSURL *)URL; + +///----------------------------------------------------------------------------- +/// @name Defining & Instantiating Objects from Factories +///----------------------------------------------------------------------------- + +/** + Defines a factory with a given name for building object instances using the + given block. When the factory singleton receives an objectFromFactory: message, + the block designated for the given factory name is invoked and the resulting object + reference is returned. + + Existing factories can be invoking defineFactory:withBlock: with an existing factory name. + + @param factoryName The name to assign the factory. + @param block A block to execute when building an object instance for the factory name. + */ ++ (void)defineFactory:(NSString *)factoryName withBlock:(id (^)())block; + +/** + Creates and returns a new instance of an object using the factory with the given name. + + @param factoryName The name of the factory to use when building the requested object. + @raises NSInvalidArgumentException Raised if a factory with the given name is not defined. + @param properties An `NSDictionary` of properties to be set on the created object. + @return An object built using the factory registered for the given name. + */ ++ (id)objectFromFactory:(NSString *)factoryName properties:(NSDictionary *)properties; ++ (id)objectFromFactory:(NSString *)factoryName; + +/** + Fetches a shared object from the factory with the given name. If an existing object has already been created, then that instance is returned. If a shared instance does not yet exist, one will be constructed and returned for this and all subsequent invocations of `sharedObjectFromFactory:`. Shared object instances are discarded when the factory is torn down. + + Shared objects are used to return object instances for cases where it does not make sense to instantiate a new instance on every invocation of the factory. A common example where this is appropriate is the `managedObjectStore` factory, where construction of a new store on each invocation would yield managed objects that cross Core Data stacks. + + @param factoryName The name of the factory to retrieve the shared instance of. + @return The shared object instance for the factory registered with the given name. + */ ++ (id)sharedObjectFromFactory:(NSString *)factoryName; + +#ifdef RKCoreDataIncluded +/** + Inserts a new managed object for the `NSEntityDescription` with the given name into the specified managed object context and sets properties on the instance from the given dictionary. A permanent managed object ID is obtained for the object so that it can be referenced across threads without any further work. + + @param entityName The name of the entity to insert a new managed object for. + @param managedObjectContext The managed object context to insert the new object into. If nil, then the managed object context returned by invoking `[RKTestFactory managedObjectStore].mainQueueManagedObjectContext]` is used. + @param properties A dictionary of properties to be set on the new managed object instance. + @return A new object inheriting from `NSManagedObject`. + */ ++ (id)insertManagedObjectForEntityForName:(NSString *)entityName + inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext + withProperties:(NSDictionary *)properties; +#endif + +/** + Returns a set of names for all defined factories. + + @return A set of the string names for all defined factories. + */ ++ (NSSet *)factoryNames; + +///-------------------------------- +/// @name Retrieving Shared Objects +///-------------------------------- + +/** + Fetches the shared `AFHTTPClient` object using the factory defined for the name `RKTestFactoryDefaultNamesClient`. + + @return The shared client instance. + */ ++ (id)client; + +/** + Fetches the shared `RKObjectManager` object using the factory defined for the name `RKTestFactoryDefaultNamesObjectManager`. + + @return The shared object manager instance. + */ ++ (id)objectManager; + +#ifdef RKCoreDataIncluded +/** + Fetches the shared an `RKManagedObjectStore` object using the factory defined for the name `RKTestFactoryDefaultNamesManagedObjectStore`. + + On first invocation per factory setup/teardown, a new managed object store will be configured and returned. If there is an existing persistent store (i.e. from a previous test invocation), then the persistent store is deleted. + + @return The shared managed object store instance. + */ ++ (RKManagedObjectStore *)managedObjectStore; +#endif + +///---------------------------------------------- +/// @name Configuring Set Up and Tear Down Blocks +///---------------------------------------------- + +/** + Sets a block to be executed when the `setUp` method is called as part of a test run. + */ ++ (void)setSetupBlock:(void (^)())block; + +/** + Sets a block to be executed when the `tearDown` method is called as part of a test run. + */ ++ (void)setTearDownBlock:(void (^)())block; + +///-------------------------- +/// @name Managing Test State +///-------------------------- + +/** + Sets up the RestKit testing environment. Executes the block set via `setSetupBlock:` to perform application specific setup. + + Note that the firt time that the `setUp` method is invoked, it will execute a `tearDown` to clear any configuration that may have taken place in during application launch. + */ ++ (void)setUp; + +/** + Tears down the RestKit testing environment by clearing singleton instances, helping to ensure test case isolation. Executes the block set via `setTearDownBlock:` to perform application specific cleanup. + */ ++ (void)tearDown; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.m new file mode 100644 index 0000000..c3eb6c5 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFactory.m @@ -0,0 +1,303 @@ +// +// RKTestFactory.m +// RestKit +// +// Created by Blake Watters on 2/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "AFHTTPClient.h" +#import "RKTestFactory.h" +#import "RKLog.h" +#import "RKObjectManager.h" +#import "RKPathUtilities.h" +#import "RKMIMETypeSerialization.h" +#import "RKObjectRequestOperation.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectStore.h" +#endif +#endif + +// Expose MIME Type singleton and initialization routine +@interface RKMIMETypeSerialization () ++ (RKMIMETypeSerialization *)sharedSerialization; +- (void)addRegistrationsForKnownSerializations; +@end + +@interface RKTestFactory () + +@property (nonatomic, strong) NSURL *baseURL; +@property (nonatomic, strong) NSMutableDictionary *factoryBlocks; +@property (nonatomic, strong) NSMutableDictionary *sharedObjectsByFactoryName; +@property (nonatomic, copy) void (^setUpBlock)(); +@property (nonatomic, copy) void (^tearDownBlock)(); + ++ (RKTestFactory *)sharedFactory; +- (void)defineFactory:(NSString *)factoryName withBlock:(id (^)())block; +- (id)objectFromFactory:(NSString *)factoryName properties:(NSDictionary *)properties; +- (void)defineDefaultFactories; + +@end + +@implementation RKTestFactory + ++ (void)initialize +{ + // Ensure the shared factory is initialized + [self sharedFactory]; +} + ++ (RKTestFactory *)sharedFactory +{ + static RKTestFactory *sharedFactory = nil; + if (!sharedFactory) { + sharedFactory = [RKTestFactory new]; + } + + return sharedFactory; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.baseURL = [NSURL URLWithString:@"http://127.0.0.1:4567"]; + self.factoryBlocks = [NSMutableDictionary new]; + self.sharedObjectsByFactoryName = [NSMutableDictionary new]; + [self defineDefaultFactories]; + } + + return self; +} + +- (void)defineFactory:(NSString *)factoryName withBlock:(id (^)())block +{ + (self.factoryBlocks)[factoryName] = [block copy]; +} + +- (id)objectFromFactory:(NSString *)factoryName properties:(NSDictionary *)properties +{ + id (^block)() = (self.factoryBlocks)[factoryName]; + NSAssert(block, @"No factory is defined with the name '%@'", factoryName); + + id object = block(); + [object setValuesForKeysWithDictionary:properties]; + return object; +} + +- (id)sharedObjectFromFactory:(NSString *)factoryName +{ + id sharedObject = (self.sharedObjectsByFactoryName)[factoryName]; + if (!sharedObject) { + sharedObject = [self objectFromFactory:factoryName properties:nil]; + (self.sharedObjectsByFactoryName)[factoryName] = sharedObject; + } + return sharedObject; +} + +- (void)defineDefaultFactories +{ + [self defineFactory:RKTestFactoryDefaultNamesClient withBlock:^id { + __block AFHTTPClient *client; + RKLogSilenceComponentWhileExecutingBlock(RKlcl_cRestKitSupport, ^{ + client = [AFHTTPClient clientWithBaseURL:self.baseURL]; + }); + + return client; + }]; + + [self defineFactory:RKTestFactoryDefaultNamesObjectManager withBlock:^id { + __block RKObjectManager *objectManager; + RKLogSilenceComponentWhileExecutingBlock(RKlcl_cRestKitSupport, ^{ + objectManager = [RKObjectManager managerWithBaseURL:self.baseURL]; + }); + + return objectManager; + }]; + +#ifdef RKCoreDataIncluded + [self defineFactory:RKTestFactoryDefaultNamesManagedObjectStore withBlock:^id { + NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:RKTestFactoryDefaultStoreFilename]; + RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] init]; + NSError *error; + NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; + if (persistentStore) { + BOOL success = [managedObjectStore resetPersistentStores:&error]; + if (! success) { + RKLogError(@"Failed to reset persistent store: %@", error); + } + } + + return managedObjectStore; + }]; +#endif +} + +#pragma mark - Public Static Interface + ++ (NSURL *)baseURL +{ + return [RKTestFactory sharedFactory].baseURL; +} + ++ (void)setBaseURL:(NSURL *)URL +{ + [RKTestFactory sharedFactory].baseURL = URL; +} + ++ (void)defineFactory:(NSString *)factoryName withBlock:(id (^)())block +{ + [[RKTestFactory sharedFactory] defineFactory:factoryName withBlock:block]; +} + ++ (id)objectFromFactory:(NSString *)factoryName properties:(NSDictionary *)properties +{ + return [[RKTestFactory sharedFactory] objectFromFactory:factoryName properties:properties]; +} + ++ (id)objectFromFactory:(NSString *)factoryName +{ + return [[RKTestFactory sharedFactory] objectFromFactory:factoryName properties:nil]; +} + ++ (id)sharedObjectFromFactory:(NSString *)factoryName +{ + return [[RKTestFactory sharedFactory] sharedObjectFromFactory:factoryName]; +} + +#ifdef RKCoreDataIncluded ++ (id)insertManagedObjectForEntityForName:(NSString *)entityName + inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext + withProperties:(NSDictionary *)properties +{ + __block id managedObject; + __block NSError *error; + __block BOOL success; + if (!managedObjectContext) managedObjectContext = [[RKTestFactory managedObjectStore] mainQueueManagedObjectContext]; + [managedObjectContext performBlockAndWait:^{ + managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:managedObjectContext]; + success = [managedObjectContext obtainPermanentIDsForObjects:@[managedObject] error:&error]; + if (! success) { + RKLogWarning(@"Failed to obtain permanent objectID for managed object: %@", managedObject); + RKLogCoreDataError(error); + } + [managedObject setValuesForKeysWithDictionary:properties]; + }]; + return managedObject; +} +#endif + ++ (NSSet *)factoryNames +{ + return [NSSet setWithArray:[[RKTestFactory sharedFactory].factoryBlocks allKeys]]; +} + ++ (id)client +{ + return [self sharedObjectFromFactory:RKTestFactoryDefaultNamesClient]; +} + ++ (id)objectManager +{ + return [self sharedObjectFromFactory:RKTestFactoryDefaultNamesObjectManager]; +} + +#ifdef RKCoreDataIncluded ++ (id)managedObjectStore +{ + return [self sharedObjectFromFactory:RKTestFactoryDefaultNamesManagedObjectStore]; +} +#endif + ++ (void)setSetupBlock:(void (^)())block +{ + [RKTestFactory sharedFactory].setUpBlock = block; +} + ++ (void)setTearDownBlock:(void (^)())block +{ + [RKTestFactory sharedFactory].tearDownBlock = block; +} + ++ (void)setUp +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // On initial set up, perform a tear down to clear any state from the application launch + [self tearDown]; + }); + + [[RKTestFactory sharedFactory].sharedObjectsByFactoryName removeAllObjects]; + [RKObjectManager setSharedManager:nil]; +#ifdef RKCoreDataIncluded + [RKManagedObjectStore setDefaultStore:nil]; +#endif + + // Restore the default MIME Type Serializations in case a test has manipulated the registry + [[RKMIMETypeSerialization sharedSerialization] addRegistrationsForKnownSerializations]; + + // Delete the store if it exists + NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:RKTestFactoryDefaultStoreFilename]; + if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + } + + // Clear the NSURLCache + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + + if ([RKTestFactory sharedFactory].setUpBlock) [RKTestFactory sharedFactory].setUpBlock(); +} + ++ (void)tearDown +{ + if ([RKTestFactory sharedFactory].tearDownBlock) [RKTestFactory sharedFactory].tearDownBlock(); + + // Cancel any network operations and clear the cache + [[RKObjectManager sharedManager].operationQueue cancelAllOperations]; + [[NSURLCache sharedURLCache] removeAllCachedResponses]; + + // Cancel any object mapping in the response mapping queue + [[RKObjectRequestOperation responseMappingQueue] cancelAllOperations]; + +#ifdef RKCoreDataIncluded + // Ensure the existing defaultStore is shut down + [[NSNotificationCenter defaultCenter] removeObserver:[RKManagedObjectStore defaultStore]]; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + if ([[RKManagedObjectStore defaultStore] respondsToSelector:@selector(stopIndexingPersistentStoreManagedObjectContext)]) { + // Search component is optional + [[RKManagedObjectStore defaultStore] performSelector:@selector(stopIndexingPersistentStoreManagedObjectContext)]; + + if ([[RKManagedObjectStore defaultStore] respondsToSelector:@selector(searchIndexer)]) { + id searchIndexer = [[RKManagedObjectStore defaultStore] valueForKey:@"searchIndexer"]; + [searchIndexer performSelector:@selector(cancelAllIndexingOperations)]; + } + } +#pragma clang diagnostic pop + +#endif + + [[RKTestFactory sharedFactory].sharedObjectsByFactoryName removeAllObjects]; + [RKObjectManager setSharedManager:nil]; +#ifdef RKCoreDataIncluded + [RKManagedObjectStore setDefaultStore:nil]; +#endif +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.h new file mode 100644 index 0000000..d3525a3 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.h @@ -0,0 +1,87 @@ +// +// RKTestFixture.h +// RestKit +// +// Created by Blake Watters on 2/1/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#endif + +/** + Provides a static method API for conveniently accessing fixture data contained within a designated `NSBundle`. Useful when writing unit tests that leverage fixture data for testing parsing and object mapping operations. + */ +@interface RKTestFixture : NSObject + +/** + Returns the NSBundle object designated as the source location for unit testing fixture data. + + @return The NSBundle object designated as the source location for unit testing fixture data + or nil if none has been configured. + */ ++ (NSBundle *)fixtureBundle; + +/** + Designates the specified NSBundle object as the source location for unit testing fixture data. + + @param bundle The new fixture NSBundle object. + */ ++ (void)setFixtureBundle:(NSBundle *)bundle; + +/** + Returns the full path to the specified fixture file on within the fixture bundle. + + @param fixtureName The name of the fixture file. + @return The full path to the specified fixture file or nil if it cannot be located. + */ ++ (NSString *)pathForFixture:(NSString *)fixtureName; + +/** + Creates and returns a string object by reading data from the fixture identified by the specified file name using UTF-8 encoding. + + @param fixtureName The name of the fixture file. + @return A string created by reading data from the specified fixture file using the NSUTF8StringEncoding. + */ ++ (NSString *)stringWithContentsOfFixture:(NSString *)fixtureName; + +/** + Creates and returns a data object by reading every byte from the fixture identified by the specified file name. + + @param fixtureName The name of the resource file. + @return A data object by reading every byte from the fixture file. + */ ++ (NSData *)dataWithContentsOfFixture:(NSString *)fixtureName; + +/** + Returns the MIME Type for the fixture identified by the specified name. + + @param fixtureName The name of the fixture file. + @return The MIME Type for the resource file or nil if the file could not be located. + */ ++ (NSString *)MIMETypeForFixture:(NSString *)fixtureName; + +/** + Creates and returns an object representation of the data from the fixture identified by the specified file name by reading the data as a string and parsing it using a parser appropriate for the MIME Type of the file. + + @param fixtureName The name of the resource file. + @return A new image object for the specified file, or nil if the method could not initialize the image from the specified file. + @see `RKMIMETypeSerialization` + */ ++ (id)parsedObjectWithContentsOfFixture:(NSString *)fixtureName; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.m new file mode 100644 index 0000000..920fd6c --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestFixture.m @@ -0,0 +1,98 @@ +// +// RKTestFixture.m +// RestKit +// +// Created by Blake Watters on 2/1/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKTestFixture.h" +#import "RKLog.h" +#import "RKPathUtilities.h" +#import "RKMIMETypeSerialization.h" + +static NSBundle *fixtureBundle = nil; + +@implementation RKTestFixture + ++ (NSBundle *)fixtureBundle +{ + NSAssert(fixtureBundle != nil, @"Bundle for fixture has not been set. Use setFixtureBundle: to set it."); + return fixtureBundle; +} + ++ (void)setFixtureBundle:(NSBundle *)bundle +{ + NSAssert(bundle != nil, @"Bundle for fixture cannot be nil."); + fixtureBundle = bundle; +} + ++ (NSString *)pathForFixture:(NSString *)fixtureName +{ + return [[self fixtureBundle] pathForResource:fixtureName ofType:nil]; +} + ++ (NSString *)stringWithContentsOfFixture:(NSString *)fixtureName +{ + NSError *error = nil; + NSString *resourcePath = [[self fixtureBundle] pathForResource:fixtureName ofType:nil]; + if (! resourcePath) { + RKLogWarning(@"Failed to locate Fixture named '%@' in bundle %@: File Not Found.", fixtureName, [self fixtureBundle]); + return nil; + } + + NSString *fixtureData = [NSString stringWithContentsOfFile:resourcePath encoding:NSUTF8StringEncoding error:&error]; + if (fixtureData == nil && error) { + RKLogWarning(@"Failed to read "); + } + + return fixtureData; +} + ++ (NSData *)dataWithContentsOfFixture:(NSString *)fixtureName +{ + NSString *resourcePath = [[self fixtureBundle] pathForResource:fixtureName ofType:nil]; + if (! resourcePath) { + RKLogWarning(@"Failed to locate Fixture named '%@' in bundle %@: File Not Found.", fixtureName, [self fixtureBundle]); + return nil; + } + + return [NSData dataWithContentsOfFile:resourcePath]; +} + ++ (NSString *)MIMETypeForFixture:(NSString *)fixtureName +{ + NSString *resourcePath = [[self fixtureBundle] pathForResource:fixtureName ofType:nil]; + if (resourcePath) { + return RKMIMETypeFromPathExtension(resourcePath); + } + + return nil; +} + ++ (id)parsedObjectWithContentsOfFixture:(NSString *)fixtureName +{ + NSError *error = nil; + NSData *resourceContents = [self dataWithContentsOfFixture:fixtureName]; + NSAssert(resourceContents, @"Failed to read fixture named '%@'", fixtureName); + NSString *MIMEType = [self MIMETypeForFixture:fixtureName]; + NSAssert(MIMEType, @"Failed to determine MIME type of fixture named '%@'", fixtureName); + + id object = [RKMIMETypeSerialization objectFromData:resourceContents MIMEType:MIMEType error:&error]; + NSAssert(object, @"Failed to parse fixture name '%@' in bundle %@. Error: %@", fixtureName, [self fixtureBundle], [error localizedDescription]); + return object; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.h new file mode 100644 index 0000000..0c924ce --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.h @@ -0,0 +1,123 @@ +// +// RKTestHelpers.h +// RestKit +// +// Created by Blake Watters on 10/2/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKHTTPUtilities.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#endif +#endif + +@class RKRoute, RKObjectManager; + +/** + The `RKTestHelpers` class provides a number of helpful utility methods for use in unit or integration tests for RestKit applications. + */ +@interface RKTestHelpers : NSObject + +///---------------------- +/// @name Stubbing Routes +///---------------------- + +/** + Stubs the route with the given class and method with a given path pattern. + + @param objectClass The class of the route to stub. + @param method The method of the route to stub. + @param pathPattern The path pattern to return instead in place of the current route's value. + @param nilOrObjectManager The object manager to stub the route on. If `nil`, the shared object manager be be used. + @return The new stubbed route object that was added to the route set of the target object manager. + */ ++ (RKRoute *)stubRouteForClass:(Class)objectClass + method:(RKRequestMethod)method + withPathPattern:(NSString *)pathPattern + onObjectManager:(RKObjectManager *)nilOrObjectManager; + +/** + Stubs the route with the given name with a given path pattern. + + @param routeName The name of the route to stub. + @param pathPattern The path pattern to return instead in place of the current route's value. + @param nilOrObjectManager The object manager to stub the route on. If `nil`, the shared object manager be be used. + @return The new stubbed route object that was added to the route set of the target object manager. + */ ++ (RKRoute *)stubRouteNamed:(NSString *)routeName + withPathPattern:(NSString *)pathPattern + onObjectManager:(RKObjectManager *)nilOrObjectManager; + +/** + Stubs the relationship route for a given class with a given path pattern. + + @param relationshipName The name of the relationship to stub the route of. + @param objectClass The class of the route to stub. + @param pathPattern The path pattern to return instead in place of the current route's value. + @param nilOrObjectManager The object manager to stub the route on. If `nil`, the shared object manager be be used. + @return The new stubbed route object that was added to the route set of the target object manager. + */ ++ (RKRoute *)stubRouteForRelationship:(NSString *)relationshipName + ofClass:(Class)objectClass + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + onObjectManager:(RKObjectManager *)nilOrObjectManager; + +#ifdef RKCoreDataIncluded +/** + Finds all registered fetch request blocks matching the given path pattern and adds a new fetch request block that returns the same value as the origin block that matches the given relative string portion of a URL object. + + @param pathPattern The path pattern that matches the fetch request blocks to be copied. + @param relativeString The relative string portion of the NSURL objects that the new blocks will match exactly. + @param nilOrObjectManager The object manager to stub the route on. If `nil`, the shared object manager be be used. + */ ++ (void)copyFetchRequestBlocksMatchingPathPattern:(NSString *)pathPattern + toBlocksMatchingRelativeString:(NSString *)relativeString + onObjectManager:(RKObjectManager *)nilOrObjectManager; +#endif + +///----------------------------- +/// @name Working with the Cache +///----------------------------- + +/** + Disables caching by setting a new `[NSURLCache sharedURLCache]` instance in which the memory and disk limits have been set to zero. + */ ++ (void)disableCaching; + +/** + Creates, stores, and returns a `NSCachedURLResponse` object containing an `NSHTTPURLResponse` for the given request with a 200 (OK) status code. + + @param request The request to cache the response for. + @param responseData The response data to be stored in the cache. + @return The cached URL response that was stored to the cache. + */ ++ (NSCachedURLResponse *)cacheResponseForRequest:(NSURLRequest *)request withResponseData:(NSData *)responseData; + +/** + Creates, stores, and returns a `NSCachedURLResponse` object containing an `NSHTTPURLResponse` for the given URL and HTTP method with the given response data and a 200 (OK) status code. + + @param URL The URL to cache the response for. + @param HTTPMethod The HTTP method of the request (i.e. 'GET', 'POST', 'PUT', 'PATCH', or 'DELETE'). + @param responseData The response data to be stored in the cache. + @return The cached URL response that was stored to the cache. + */ ++ (NSCachedURLResponse *)cacheResponseForURL:(NSURL *)URL HTTPMethod:(NSString *)HTTPMethod headers:(NSDictionary *)requestHeaders withData:(NSData *)responseData; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.m new file mode 100644 index 0000000..3884fba --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestHelpers.m @@ -0,0 +1,150 @@ +// +// RKTestHelpers.m +// RestKit +// +// Created by Blake Watters on 10/2/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKTestHelpers.h" +#import "RKObjectManager.h" +#import "RKRoute.h" +#import "RKPathUtilities.h" +#import "RKLog.h" +#import "SOCKit.h" +#import "RKRouteSet.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectRequestOperation.h" +#endif +#endif + +@implementation RKTestHelpers + ++ (RKRoute *)stubRouteForClass:(Class)objectClass method:(RKRequestMethod)method withPathPattern:(NSString *)pathPattern onObjectManager:(RKObjectManager *)nilOrObjectManager +{ + RKObjectManager *objectManager = nilOrObjectManager ?: [RKObjectManager sharedManager]; + RKRoute *route = [objectManager.router.routeSet routeForClass:objectClass method:method]; + NSAssert(route, @"Expected to retrieve a route, but got nil"); + [objectManager.router.routeSet removeRoute:route]; + RKRoute *stubbedRoute = [RKRoute routeWithClass:objectClass pathPattern:pathPattern method:method]; + [objectManager.router.routeSet addRoute:stubbedRoute]; + return stubbedRoute; +} + ++ (RKRoute *)stubRouteNamed:(NSString *)routeName withPathPattern:(NSString *)pathPattern onObjectManager:(RKObjectManager *)nilOrObjectManager +{ + RKObjectManager *objectManager = nilOrObjectManager ?: [RKObjectManager sharedManager]; + RKRoute *route = [objectManager.router.routeSet routeForName:routeName]; + NSAssert(route, @"Expected to retrieve a route, but got nil"); + [objectManager.router.routeSet removeRoute:route]; + RKRoute *stubbedRoute = [RKRoute routeWithName:routeName pathPattern:pathPattern method:route.method]; + [objectManager.router.routeSet addRoute:stubbedRoute]; +#ifdef RKCoreDataIncluded + [self copyFetchRequestBlocksMatchingPathPattern:route.pathPattern toBlocksMatchingRelativeString:pathPattern onObjectManager:objectManager]; +#endif + return stubbedRoute; +} + ++ (RKRoute *)stubRouteForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass method:(RKRequestMethod)method pathPattern:(NSString *)pathPattern onObjectManager:(RKObjectManager *)nilOrObjectManager +{ + RKObjectManager *objectManager = nilOrObjectManager ?: [RKObjectManager sharedManager]; + RKRoute *route = [objectManager.router.routeSet routeForRelationship:relationshipName ofClass:objectClass method:method]; + NSAssert(route, @"Expected to retrieve a route, but got nil"); + [objectManager.router.routeSet removeRoute:route]; + RKRoute *stubbedRoute = [RKRoute routeWithRelationshipName:relationshipName objectClass:objectClass pathPattern:pathPattern method:method]; + [objectManager.router.routeSet addRoute:stubbedRoute]; +#ifdef RKCoreDataIncluded + [self copyFetchRequestBlocksMatchingPathPattern:route.pathPattern toBlocksMatchingRelativeString:pathPattern onObjectManager:objectManager]; +#endif + return stubbedRoute; +} + +#ifdef RKCoreDataIncluded ++ (void)copyFetchRequestBlocksMatchingPathPattern:(NSString *)pathPattern + toBlocksMatchingRelativeString:(NSString *)relativeString + onObjectManager:(RKObjectManager *)nilOrObjectManager +{ + RKObjectManager *objectManager = nilOrObjectManager ?: [RKObjectManager sharedManager]; + + // Extract the dynamic portions of the path pattern to construct a set of parameters + SOCPattern *pattern = [SOCPattern patternWithString:pathPattern]; + NSArray *parameterNames = [pattern valueForKeyPath:@"parameters.string"]; + NSMutableDictionary *stubbedParameters = [NSMutableDictionary dictionaryWithCapacity:[parameterNames count]]; + for (NSString *parameter in parameterNames) { + [stubbedParameters setValue:@"value" forKey:parameter]; + } + NSString *stubbedPathPattern = [pattern stringFromObject:stubbedParameters]; + + NSURL *URL = [NSURL URLWithString:stubbedPathPattern relativeToURL:objectManager.HTTPClient.baseURL]; + NSAssert(URL, @"Failed to build URL from path pattern '%@' relative to base URL '%@'", pathPattern, objectManager.HTTPClient.baseURL); + for (RKFetchRequestBlock block in objectManager.fetchRequestBlocks) { + NSFetchRequest *fetchRequest = block(URL); + if (fetchRequest) { + // Add a new block that matches our stubbed path + [objectManager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) { + // TODO: Note that relativeString does not work because NSURLRequest drops the relative parent of the URL + // if ([[URL relativeString] isEqualToString:relativeString]) { + if ([[URL path] isEqualToString:relativeString]) { + return fetchRequest; + } + + return nil; + }]; + + break; + } + } +} +#endif + ++ (void)disableCaching +{ + NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]; + [NSURLCache setSharedURLCache:sharedCache]; +} + ++ (NSCachedURLResponse *)cacheResponseForRequest:(NSURLRequest *)request withResponseData:(NSData *)responseData +{ + NSParameterAssert(request); + NSParameterAssert(responseData); + + NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[request URL] statusCode:200 HTTPVersion:@"1.1" headerFields:nil]; + NSAssert(response, @"Failed to build cached response"); + NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:responseData]; + [[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:request]; + + // Verify that we can get the cached response back + NSCachedURLResponse *__unused storedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + NSAssert(storedResponse, @"Expected to retrieve cached response for request '%@', instead got nil.", request); + + return cachedResponse; +} + ++ (NSCachedURLResponse *)cacheResponseForURL:(NSURL *)URL HTTPMethod:(NSString *)HTTPMethod headers:(NSDictionary *)requestHeaders withData:(NSData *)responseData +{ + NSParameterAssert(URL); + NSParameterAssert(HTTPMethod); + NSParameterAssert(responseData); + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + request.HTTPMethod = HTTPMethod; + [request setAllHTTPHeaderFields:requestHeaders]; + return [self cacheResponseForRequest:request withResponseData:responseData]; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.h b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.h new file mode 100644 index 0000000..d7a6712 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.h @@ -0,0 +1,98 @@ +// +// RKTestNotificationObserver.h +// RestKit +// +// Created by Jeff Arena on 8/23/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import <Foundation/Foundation.h> + +/** + An RKTestNotificationObserver object provides support for awaiting a notification + to be posted as the result of an asynchronous operation by spinning the run loop. This + enables a straight-forward unit testing workflow by blocking execution of the test until + a notification is posted. + */ +@interface RKTestNotificationObserver : NSObject + +/** + The name of the notification the receiver is awaiting. + */ +@property (nonatomic, copy) NSString *name; + +/** + The object expected to post the notification the receiver is awaiting. + + Can be nil. + */ +@property (nonatomic, weak) id object; + +/** + The timeout interval, in seconds, to wait for the notification to be posted. + + **Default**: 3 seconds + */ +@property (nonatomic, assign) NSTimeInterval timeout; + +/** + Creates and initializes a notification obsercer object. + + @return The newly created notification observer. + */ ++ (RKTestNotificationObserver *)notificationObserver; + +/** + Instantiate a notification observer for the given notification name and object + + @param notificationName The name of the NSNotification we want to watch for + @param notificationSender The source object of the NSNotification we want to watch for + @return The newly created notification observer initialized with notificationName and notificationSender. + */ ++ (RKTestNotificationObserver *)notificationObserverForName:(NSString *)notificationName object:(id)notificationSender; + +/** + Instantiate a notification observer for the given notification name + + @param notificationName The name of the NSNotification we want to watch for + */ ++ (RKTestNotificationObserver *)notificationObserverForName:(NSString *)notificationName; + +/** + Adds the receiver as an observer for the notification name and object under test. + + If the observer has not already been added when waitForNotification + is invoked, it will be added before the runloop cycling begins. + */ +- (void)addObserver; + +/** + Wait for a notification matching the name and source object we are observing to be posted. + + This method will block by spinning the runloop waiting for an appropriate notification matching + our observed name and object to be posted or the timeout configured is exceeded. + */ +- (void)waitForNotification; + +/*** @name Block Helpers */ + +/** + Configures a notification observer to wait for the a notification with the given name to be posted + by the source object during execution of the block. + + @param name The name of the notification we are waiting for + @param notificationSender The object we are waiting to post the notification + @param block A block to invoke to trigger the notification activity + */ ++ (void)waitForNotificationWithName:(NSString *)name object:(id)notificationSender usingBlock:(void(^)())block; + +/** + Configures a notification observer to wait for the a notification with the given name to be posted + during execution of the block. + + @param name The name of the notification we are waiting for + @param block A block to invoke to trigger the notification activity + */ ++ (void)waitForNotificationWithName:(NSString *)name usingBlock:(void(^)())block; + +@end diff --git a/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.m b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.m new file mode 100644 index 0000000..d5a531b --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Code/Testing/RKTestNotificationObserver.m @@ -0,0 +1,110 @@ +// +// RKTestNotificationObserver.m +// RestKit +// +// Created by Jeff Arena on 8/23/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "RKTestNotificationObserver.h" + +@interface RKTestNotificationObserver () +@property (nonatomic, assign, getter = isObserverAdded) BOOL observerAdded; +@property (nonatomic, assign, getter = isAwaitingNotification) BOOL awaitingNotification; +@property (nonatomic, strong) NSDate *startDate; +@end + +@implementation RKTestNotificationObserver + + ++ (void)waitForNotificationWithName:(NSString *)name object:(id)object usingBlock:(void(^)())block +{ + RKTestNotificationObserver *observer = [RKTestNotificationObserver notificationObserverForName:name object:object]; + [observer addObserver]; + block(); + [observer waitForNotification]; +} + ++ (void)waitForNotificationWithName:(NSString *)name usingBlock:(void(^)())block +{ + [self waitForNotificationWithName:name object:nil usingBlock:block]; +} + ++ (RKTestNotificationObserver *)notificationObserver +{ + return [[self alloc] init]; +} + ++ (RKTestNotificationObserver *)notificationObserverForName:(NSString *)notificationName object:(id)object +{ + RKTestNotificationObserver *notificationObserver = [self notificationObserver]; + notificationObserver.object = object; + notificationObserver.name = notificationName; + return notificationObserver; +} + ++ (RKTestNotificationObserver *)notificationObserverForName:(NSString *)notificationName +{ + return [self notificationObserverForName:notificationName object:nil]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _timeout = 5; + _awaitingNotification = NO; + } + return self; +} + +- (void)dealloc +{ + [self removeObserver]; +} + +- (void)addObserver +{ + if (self.isObserverAdded) return; + + NSAssert(_name, @"Notification name cannot be nil"); + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processNotification:) + name:self.name + object:self.object]; + self.observerAdded = YES; + self.awaitingNotification = YES; + self.startDate = [NSDate date]; +} + +- (void)removeObserver +{ + if (! self.isObserverAdded) return; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)waitForNotification +{ + [self addObserver]; + + while (self.isAwaitingNotification) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + if ([[NSDate date] timeIntervalSinceDate:self.startDate] > self.timeout) { + [NSException raise:nil format:@"*** Operation timed out after %f seconds...", self.timeout]; + self.awaitingNotification = NO; + } + } + + [self removeObserver]; +} + +- (void)processNotification:(NSNotification *)notification +{ + NSAssert([self.name isEqualToString:notification.name], + @"Received notification (%@) differs from expected notification (%@)", + notification.name, self.name); + self.awaitingNotification = NO; +} + +@end diff --git a/Unit-2-Journal/Pods/RestKit/LICENSE b/Unit-2-Journal/Pods/RestKit/LICENSE new file mode 100644 index 0000000..eb8d4bc --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Unit-2-Journal/Pods/RestKit/README.md b/Unit-2-Journal/Pods/RestKit/README.md new file mode 100644 index 0000000..8037e42 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/README.md @@ -0,0 +1,629 @@ +# RestKit + +[![Build Status](http://img.shields.io/travis/RestKit/RestKit/development.svg?style=flat)](https://travis-ci.org/RestKit/RestKit) +[![Pod Version](http://img.shields.io/cocoapods/v/RestKit.svg?style=flat)](http://cocoadocs.org/docsets/RestKit/) +[![Pod Platform](http://img.shields.io/cocoapods/p/RestKit.svg?style=flat)](http://cocoadocs.org/docsets/RestKit/) +[![Pod License](http://img.shields.io/cocoapods/l/RestKit.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![Visit our IRC channel](http://img.shields.io/badge/IRC-%23RestKit-green.svg?style=flat)](https://kiwiirc.com/client/irc.freenode.net/?nick=rkuser|?&theme=basic#RestKit) + +RestKit is a modern Objective-C framework for implementing RESTful web services clients on iOS and Mac OS X. It provides a powerful [object mapping](https://github.com/RestKit/RestKit/wiki/Object-mapping) engine that seamlessly integrates with [Core Data](http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/cdProgrammingGuide.html) and a simple set of networking primitives for mapping HTTP requests and responses built on top of [AFNetworking](https://github.com/AFNetworking/AFNetworking). It has an elegant, carefully designed set of APIs that make accessing and modeling RESTful resources feel almost magical. For example, here's how to access the Twitter public timeline and turn the JSON contents into an array of Tweet objects: + +``` objective-c +@interface RKTweet : NSObject +@property (nonatomic, copy) NSNumber *userID; +@property (nonatomic, copy) NSString *username; +@property (nonatomic, copy) NSString *text; +@end + +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTweet class]]; +[mapping addAttributeMappingsFromDictionary:@{ + @"user.name": @"username", + @"user.id": @"userID", + @"text": @"text" +}]; + +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:nil]; +NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/public_timeline.json"]; +NSURLRequest *request = [NSURLRequest requestWithURL:url]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"The public timeline Tweets: %@", [result array]); +} failure:nil]; +[operation start]; +``` + +## Getting Started + +- [Download RestKit](https://github.com/RestKit/RestKit/releases) and play with the [examples](https://github.com/RestKit/RestKit/tree/development/Examples) for iPhone and Mac OS X +- First time with RestKit? Read the ["Overview"](#overview) section below and then check out the ["Getting Acquainted with RestKit"](https://github.com/RestKit/RKGist/blob/master/TUTORIAL.md) tutorial and [Object Mapping Reference](https://github.com/RestKit/RestKit/wiki/Object-mapping) documents in the wiki to jump right in. +- Upgrading from RestKit 0.9.x or 0.10.x? Read the ["Upgrading to RestKit 0.20.x"](https://github.com/RestKit/RestKit/wiki/Upgrading-from-v0.10.x-to-v0.20.0) guide in the wiki +- Adding RestKit to an existing [AFNetworking](https://github.com/AFNetworking/AFNetworking) application? Read the [AFNetworking Integration](https://github.com/RestKit/RestKit/wiki/AFNetworking-Integration) document to learn details about how the frameworks fit together. +- Review the [source code API documentation](http://restkit.org/api/latest) for a detailed look at the classes and API's in RestKit. A great place to start is [RKObjectManager](http://restkit.org/api/latest/Classes/RKObjectManager.html). +- Still need some help? Ask questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/restkit) or the [mailing list](http://groups.google.com/group/restkit), ping us on [Twitter](http://twitter.com/RestKit) or chat with us on [IRC](https://kiwiirc.com/client/irc.freenode.net/?nick=rkuser|?&theme=basic#RestKit). + +## Overview + +RestKit is designed to be modular and each module strives to maintain a minimal set of dependencies across the framework and with the host platform. At the core of library sits the object mapping engine, which is responsible for transforming objects between representations (such as JSON/XML <-> local domain objects). + +### Object Mapping Fundamentals + +The object mapping engine is built on top of the [Key-Value Coding](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html) (KVC) informal protocol that is foundational to numerous Cocoa technologies such as key-value observing, bindings, and Core Data. Object mappings are expressed as pairs of KVC key paths that specify the source and destination attributes or relationships that are to be transformed. + +RestKit leverages the highly dynamic Objective-C runtime to infer the developers desired intent by examining the type of the source and destination properties and performing appropriate type transformations. For example, given a source key path of `created_at` that identifies a string within a parsed JSON document and a destination key path of `creationDate` that identifies an `NSDate` property on a target object, RestKit will transform the date from a string into an `NSDate` using an `NSDateFormatter`. Numerous other transformations are provided out of the box and the engine is pluggable to allow the developer to define new transformations or replace an existing transformation with a new implementation. + +The mapper fully supports both simple attribute as well as relationship mappings in which nested to-one or to-many child objects are mapped recursively. Through relationship mappings, one object mapping can be added to another to compose aggregate mappings that are capable of processing arbitrarily complex source documents. + +Object mapping is a deep topic and is explored in exhaustive detail in the [Object Mapping Guide](https://github.com/RestKit/RestKit/wiki/Object-mapping) on the wiki. + +### API Quickstart + +RestKit is broken into several modules that cleanly separate the mapping engine from the HTTP and Core Data integrations to provide maximum flexibility. Key classes in each module are highlighted below and each module is hyperlinked to the README.md contained within the source code. + +<table> + <tr><th colspan="2" style="text-align:center;"><a href="Code/ObjectMapping/README.md">Object Mapping</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectMapping.html">RKObjectMapping</a></td> + <td>Encapsulates configuration for transforming object representations as expressed by key-value coding keypaths.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKAttributeMapping.html">RKAttributeMapping</a></td> + <td>Specifies a desired transformation between attributes within an object or entity mapping in terms of a source and destination key path.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRelationshipMapping.html">RKRelationshipMapping</a></td> + <td>Specifies a desired mapping of a nested to-one or to-many child objects in in terms of a source and destination key path and an <tt>RKObjectMapping</tt> with which to map the attributes of the child object.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKDynamicMapping.html">RKDynamicMapping</a></td> + <td>Specifies a flexible mapping in which the decision about which <tt>RKObjectMapping</tt> is to be used to process a given document is deferred to run time.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMapperOperation.html">RKMapperOperation</a></td> + <td>Provides an interface for mapping a deserialized document into a set of local domain objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMappingOperation.html">RKMappingOperation</a></td> + <td>An <tt>NSOperation</tt> that performs a mapping between object representations using an <tt>RKObjectMapping</tt>.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Network/README.md">Networking</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRequestDescriptor.html">RKRequestDescriptor</a></td> + <td>Describes a request that can be sent from the application to a remote web application for a given object type.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKResponseDescriptor.html">RKResponseDescriptor</a></td> + <td>Describes an object mappable response that may be returned from a remote web application in terms of an object mapping, a key path, a <a href="http://cocoadocs.org/docsets/SOCKit/">SOCKit pattern</a> for matching the URL, and a set of status codes that define the circumstances in which the mapping is appropriate for a given response.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectParameterization.html">RKObjectParameterization</a></td> + <td>Performs mapping of a given object into an <tt>NSDictionary</tt> representation suitable for use as the parameters of an HTTP request.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectRequestOperation.html">RKObjectRequestOperation</a></td> + <td>An <tt>NSOperation</tt> that sends an HTTP request and performs object mapping on the parsed response body using the configurations expressed in a set of <tt>RKResponseDescriptor</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKResponseMapper.html">RKResponseMapperOperation</a></td> + <td>An <tt>NSOperation</tt> that provides support for object mapping an <tt>NSHTTPURLResponse</tt> using a set of <tt>RKResponseDescriptor</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectManager.html">RKObjectManager</a></td> + <td>Captures the common patterns for communicating with a RESTful web application over HTTP using object mapping including: + <ul> + <li>Centralizing <tt>RKRequestDescriptor</tt> and <tt>RKResponseDescriptor</tt> configurations</li> + <li>Describing URL configuration with an <tt>RKRouter</tt></li> + <li>Serializing objects and sending requests with the serialized representations</li> + <li>Sending requests to load remote resources and object mapping the response bodies</li> + <li>Building multi-part form requests for objects</li> + </ul> + </td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRouter.html">RKRouter</a></td> + <td>Generates <tt>NSURL</tt> objects from a base URL and a set of <tt>RKRoute</tt> objects describing relative paths used by the application.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRoute.html">RKRoute</a></td> + <td>Describes a single relative path for a given object type and HTTP method, the relationship of an object, or a symbolic name.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/CoreData/README.md">Core Data</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectStore.html">RKManagedObjectStore</a></td> + <td>Encapsulates Core Data configuration including an <tt>NSManagedObjectModel</tt>, a <tt>NSPersistentStoreCoordinator</tt>, and a pair of <tt>NSManagedObjectContext</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKEntityMapping.html">RKEntityMapping</a></td> + <td>Models a mapping for transforming an object representation into a <tt>NSManagedObject</tt> instance for a given <tt>NSEntityDescription</tt>.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKConnectionDescription.html">RKConnectionDescription</a></td> + <td>Describes a mapping for establishing a relationship between Core Data entities using foreign key attributes.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectRequestOperation.html">RKManagedObjectRequestOperation</a></td> + <td>An <tt>NSOperation</tt> subclass that sends an HTTP request and performs object mapping on the parsed response body to create <tt>NSManagedObject</tt> instances, establishes relationships between objects using <tt>RKConnectionDescription</tt> objects, and cleans up orphaned objects that no longer exist in the remote backend system.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectImporter.html">RKManagedObjectImporter</a></td> + <td>Provides support for bulk mapping of managed objects using <tt>RKEntityMapping</tt> objects for two use cases: + <ol> + <li>Bulk importing of parsed documents into an <tt>NSPersistentStore.</tt></li> + <li>Generating a <a href="Docs for database seeding">seed database</a> for initializing an application's Core Data store with an initial data set upon installation.</li> + </ol> + </td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Search/README.md">Search</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKSearchIndexer.html">RKSearchIndexer</a></td> + <td>Provides support for generating a full-text searchable index within Core Data for string attributes of entities within an application.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKSearchPredicate.html">RKSearchPredicate</a></td> + <td>Generates an <tt>NSCompoundPredicate</tt> given a string of text that will search an index built with an <tt>RKSearchIndexer</tt> across any indexed entity.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Testing/README.md">Testing</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMappingTest.html">RKMappingTest</a></td> + <td>Provides support for unit testing object mapping configurations given a parsed document and an object or entity mapping. Expectations are configured in terms of expected key path mappings and/or expected transformation results.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKTestFixture.html">RKTestFixture</a></td> + <td>Provides an interface for easily generating test fixture data for unit testing.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKTestFactory.html">RKTestFactory</a></td> + <td>Provides support for creating objects for use in testing.</td> + </tr> +</table> + +### + +## Examples + +### Object Request +``` objective-c +// GET a single Article from /articles/1234.json and map it into an object +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + Article *article = [result firstObject]; + NSLog(@"Mapped the article: %@", article); +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + NSLog(@"Failed with error: %@", [error localizedDescription]); +}]; +[operation start]; +``` + +### Managed Object Request +``` objective-c +// GET an Article and its Categories from /articles/888.json and map into Core Data entities +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!", "categories": [{"id": 1, "name": "Core Data"]} +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:managedObjectStore]; +[categoryMapping addAttributeMappingsFromDictionary:@{ "id": "categoryID", @"name": "name" }]; +RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore]; +[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]]; + +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/888.json"]]; +RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +operation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext; +operation.managedObjectCache = managedObjectStore.managedObjectCache; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + Article *article = [result firstObject]; + NSLog(@"Mapped the article: %@", article); + NSLog(@"Mapped the category: %@", [article.categories anyObject]); +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + NSLog(@"Failed with error: %@", [error localizedDescription]); +}]; +NSOperationQueue *operationQueue = [NSOperationQueue new]; +[operationQueue addOperation:operation]; +``` + +### Map a Client Error Response to an NSError +``` objective-c +// GET /articles/error.json returns a 422 (Unprocessable Entity) +// JSON looks like {"errors": "Some Error Has Occurred"} + +// You can map errors to any class, but `RKErrorMessage` is included for free +RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]]; +// The entire value at the source key path containing the errors maps to the message +[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]]; + +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError); +// Any response in the 4xx status code range with an "errors" key path uses this mapping +RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/error.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[errorDescriptor]]; +[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) { + // The `description` method of the class the error is mapped to is used to construct the value of the localizedDescription + NSLog(@"Loaded this error: %@", [error localizedDescription]); + + // You can access the model object used to construct the `NSError` via the `userInfo` + RKErrorMessage *errorMessage = [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject]; +}]; +``` + +### Centralize Configuration in an Object Manager +``` objective-c +// Set up Article and Error Response Descriptors +// Successful JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes]; + +// Error JSON looks like {"errors": "Some Error Has Occurred"} +RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]]; +// The entire value at the source key path containing the errors maps to the message +[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError); +// Any response in the 4xx status code range with an "errors" key path uses this mapping +RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes]; + +// Add our descriptors to the manager +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager addResponseDescriptorsFromArray:@[ articleDescriptor, errorDescriptor ]]; + +[manager getObjectsAtPath:@"/articles/555.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { + // Handled with articleDescriptor +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + // Transport error or server error handled by errorDescriptor +}]; +``` + +### Configure Core Data Integration with the Object Manager +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +manager.managedObjectStore = managedObjectStore; +``` + +### Load a Collection of Objects at a Path +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager getObjectsAtPath:@"/articles" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { +} failure:^(RKObjectRequestOperation *operation, NSError *error) { +}]; +``` + +### Manage a Queue of Object Request Operations +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; + +[manager enqueueObjectRequestOperation:operation]; +[manager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodANY matchingPathPattern:@"/articles/:articleID\\.json"]; +``` + +### POST, PATCH, and DELETE an Object +``` objective-c +RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Article class]]; +[responseMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes]; + +RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; // objectClass == NSMutableDictionary +[requestMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +// For any object of class Article, serialize into an NSMutableDictionary using the given mapping and nest +// under the 'article' key path +RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[Article class] rootKeyPath:@"article" method:RKRequestMethodAny]; + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager addRequestDescriptor:requestDescriptor]; +[manager addResponseDescriptor:articleDescriptor]; + +Article *article = [Article new]; +article.title = @"Introduction to RestKit"; +article.body = @"This is some text."; +article.author = @"Blake"; + +// POST to create +[manager postObject:article path:@"/articles" parameters:nil success:nil failure:nil]; + +// PATCH to update +article.body = @"New Body"; +[manager patchObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil]; + +// DELETE to destroy +[manager deleteObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil]; +``` + +### Configure Logging +``` objective-c +// Log all HTTP traffic with request and response bodies +RKLogConfigureByName("RestKit/Network", RKLogLevelTrace); + +// Log debugging info about Core Data +RKLogConfigureByName("RestKit/CoreData", RKLogLevelDebug); + +// Raise logging for a block +RKLogWithLevelWhileExecutingBlock(RKLogLevelTrace, ^{ + // Do something that generates logs +}); +``` + +### Configure Routing +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +// Class Routing +[manager.router.routeSet addRoute:[RKRoute routeWithClass:[GGSegment class] pathPattern:@"/segments/:segmentID\\.json" method:RKRequestMethodGET]]; + +// Relationship Routing +[manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"amenities" objectClass:[GGAirport class] pathPattern:@"/airports/:airportID/amenities.json" method:RKRequestMethodGET]]; + +// Named Routes +[manager.router.routeSet addRoute:[RKRoute routeWithName:@"thumbs_down_review" resourcePathPattern:@"/reviews/:reviewID/thumbs_down" method:RKRequestMethodPOST]]; +``` + +### POST an Object with a File Attachment +``` objective-c +Article *article = [Article new]; +UIImage *image = [UIImage imageNamed:@"some_image.png"]; + +// Serialize the Article attributes then attach a file +NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:article method:RKRequestMethodPOST path:nil parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { + [formData appendPartWithFileData:UIImagePNGRepresentation(image) + name:@"article[image]" + fileName:@"photo.png" + mimeType:@"image/png"]; +}]; + +RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:nil failure:nil]; +[[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; // NOTE: Must be enqueued rather than started +``` + +### Enqueue a Batch of Object Request Operations +``` objective-c + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +Airport *jfk = [Airport new]; +jfk.code = @"jfk"; +Airport *lga = [Airport new]; +lga.code = @"lga"; +Airport *rdu = [Airport new]; +rdu.code = @"rdu"; + +// Enqueue a GET for '/airports/jfk/weather', '/airports/lga/weather', '/airports/rdu/weather' +RKRoute *route = [RKRoute routeWithName:@"airport_weather" resourcePathPattern:@"/airports/:code/weather" method:RKRequestMethodGET]; + +[manager enqueueBatchOfObjectRequestOperationsWithRoute:route + objects:@[ jfk, lga, rdu] + progress:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) { + NSLog(@"Finished %d operations", numberOfFinishedOperations); + } completion:^ (NSArray *operations) { + NSLog(@"All Weather Reports Loaded!"); + }]; +``` + +### Generate a Seed Database +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore]; +[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MySeedDatabase.sqlite"]; +RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectStore.managedObjectModel storePath:seedPath]; + +// Import the files "articles.json" from the Main Bundle using our RKEntityMapping +// JSON looks like {"articles": [ {"title": "Article 1", "body": "Text", "author": "Blake" ]} +NSError *error; +NSBundle *mainBundle = [NSBundle mainBundle]; +[importer importObjectsFromItemAtPath:[mainBundle pathForResource:@"articles" ofType:@"json"] + withMapping:articleMapping + keyPath:@"articles" + error:&error]; + +BOOL success = [importer finishImporting:&error]; +if (success) { + [importer logSeedingInfo]; +} +``` + +### Index and Search an Entity +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; +[managedObjectStore addSearchIndexingToEntityForName:@"Article" onAttributes:@[ @"title", @"body" ]]; +[managedObjectStore addInMemoryPersistentStore:nil]; +[managedObjectStore createManagedObjectContexts]; +[managedObjectStore startIndexingPersistentStoreManagedObjectContext]; + +Article *article1 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; +article1.title = @"First Article"; +article1.body = "This should match search"; + +Article *article2 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; +article2.title = @"Second Article"; +article2.body = "Does not"; + +BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:nil]; + +RKSearchPredicate *predicate = [RKSearchPredicate searchPredicateWithText:@"Match" type:NSAndPredicateType]; +NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"]; +fetchRequest.predicate = predicate; + +// Contains article1 due to body text containing 'match' +NSArray *matches = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:nil]; +NSLog(@"Found the matching articles: %@", matches); +``` + +### Unit Test a Mapping +``` objective-c +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +NSDictionary *article = @{ @"article": @{ @"title": @"My Title", @"body": @"The article body", @"author": @"Blake" } }; +RKMappingTest *mappingTest = [[RKMappingTest alloc] initWithMapping:mapping sourceObject:article destinationObject:nil]; + +[mappingTest expectMappingFromKeyPath:@"title" toKeyPath:@"title" value:@"My Title"]; +[mappingTest performMapping]; +[mappingTest verify]; +``` + +## Requirements + +RestKit requires [iOS 5.1.1](http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iOS5.html#//apple_ref/doc/uid/TP30915195-SW1) and above or [Mac OS X 10.7](http://developer.apple.com/library/mac/#releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_7.html#//apple_ref/doc/uid/TP40010355-SW5) and above. + +Several third-party open source libraries are used within RestKit, including: + +1. [AFNetworking](https://github.com/AFNetworking/AFNetworking) - Networking Support +2. [LibComponentLogging](http://0xc0.de/LibComponentLogging) - Logging Support +3. [SOCKit](https://github.com/jverkoey/sockit) - String <-> Object Coding +4. [iso8601parser](http://boredzo.org/iso8601parser/) - Support for parsing and generating ISO-8601 dates + +The following Cocoa frameworks must be linked into the application target for proper compilation: + +1. **CFNetwork.framework** on iOS +1. **CoreData.framework** +1. **Security.framework** +1. **MobileCoreServices.framework** on iOS or **CoreServices.framework** on OS X + +And the following linker flags must be set: + +1. **-ObjC** +1. **-all_load** + +### ARC + +As of [version 0.20.0](https://github.com/RestKit/RestKit/wiki/Restkit-0.20.0), RestKit has migrated the entire codebase to ARC. + +If you are including the RestKit sources directly into a project that does not yet use [Automatic Reference Counting](http://clang.llvm.org/docs/AutomaticReferenceCounting.html), you will need to set the `-fobjc-arc` compiler flag on all of the RestKit source files. To do this in Xcode, go to your active target and select the "Build Phases" tab. Now select all RestKit source files, press Enter, insert `-fobjc-arc` and then "Done" to enable ARC for RestKit. + +### Serialization Formats + +RestKit provides a pluggable interface for handling arbitrary serialization formats via the [`RKSerialization`](http://restkit.org/api/latest/Classes/RKSerialization.html) protocol and the [`RKMIMETypeSerialization`](http://restkit.org/api/latest/Classes/RKMIMETypeSerialization.html) class. Out of the box, RestKit supports handling the [JSON](http://www.json.org/) format for serializing and deserializing object representations via the [`NSJSONSerialization`](http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html) class. + +#### Additional Serializations + +Support for additional formats and alternate serialization backends is provided via external modules that can be added to the project. Currently the following serialization implementations are available for use: + +* JSONKit +* SBJSON +* YAJL +* NextiveJson +* XMLReader + XMLWriter + +## Installation + +The recommended approach for installing RestKit is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.19.1** using Git **>= 1.8.0** installed via Homebrew. + +### via CocoaPods + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add RestKit: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'RestKit', '~> 0.20.0' + +# Testing and Search are optional components +pod 'RestKit/Testing', '~> 0.20.0' +pod 'RestKit/Search', '~> 0.20.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +Please note that if your installation fails, it may be because you are installing with a version of Git lower than CocoaPods is expecting. Please ensure that you are running Git **>= 1.8.0** by executing `git --version`. You can get a full picture of the installation details by executing `pod install --verbose`. + +### From a Release Package or as a Git submodule + +Detailed installation instructions are available in the [Visual Install Guide](https://github.com/RestKit/RestKit/wiki/Installing-RestKit-v0.20.x-as-a-Git-Submodule) on the Wiki. + +## License + +RestKit is licensed under the terms of the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). Please see the [LICENSE](LICENSE) file for full details. + +## Credits + +RestKit is brought to you by [Blake Watters](http://twitter.com/blakewatters) and the RestKit team. + +Support is provided by the following organizations: + +* [GateGuru](http://www.gateguruapp.com/) +* [Two Toasters](http://www.twotoasters.com/) diff --git a/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h b/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 100644 index 0000000..c4e3324 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1,388 @@ +// +// +// lcl_RK.h -- LibComponentLogging, embedded, RestKit/RK +// +// +// Copyright (c) 2008-2012 Arne Harren <ah@0xc0.de> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef __RKLCL_H__ +#define __RKLCL_H__ + +#define _RKLCL_VERSION_MAJOR 1 +#define _RKLCL_VERSION_MINOR 3 +#define _RKLCL_VERSION_BUILD 1 +#define _RKLCL_VERSION_SUFFIX "" + +// +// lcl -- LibComponentLogging, embedded, RestKit/RK +// +// LibComponentLogging is a logging library for Objective-C applications +// with the following characteristics: +// +// - Log levels +// The library provides log levels for distinguishing between error messages, +// informational messages, and fine-grained trace messages for debugging. +// +// - Log components +// The library provides log components for identifying different parts of an +// application. A log component contains a unique identifier, a short name +// which is used as a header in a log message, and a full name which can be +// used in a user interface. +// +// - Active log level per log component +// At runtime, the library provides an active log level for each log +// component in order to enable/disable logging for certain parts of an +// application. +// +// - Grouping of log components +// Log components which have the same name prefix form a group of log +// components and logging can be enabled/disabled for the whole group with +// a single command. +// +// - Low runtime-overhead when logging is disabled +// Logging is based on a log macro which checks the active log level before +// constructing the log message and before evaluating log message arguments. +// +// - Code completion support +// The library provides symbols for log components and log levels which work +// with Xcode's code completion. All symbols, e.g. values or functions, which +// are relevant when using the logging library in an application, are prefixed +// with 'RKlcl_'. Internal symbols, which are needed when working with meta +// data, when defining log components, or when writing a logging back-end, are +// prefixed with '_RKlcl_'. Internal symbols, which are only used by the logging +// library itself, are prefixed with '__RKlcl_'. +// +// - Meta data +// The library provides public data structures which contain information about +// log levels and log components, e.g. headers and names. +// +// - Pluggable loggers +// The library does not contain a concrete logger, but provides a simple +// delegation mechanism for plugging-in a concrete logger based on the +// application's requirements, e.g. a logger which writes to the system log, +// or a logger which writes to a log file. The concrete logger is configured +// at build-time. +// +// Note: If the preprocessor symbol _RKLCL_NO_LOGGING is defined, the log macro +// will be defined to an empty effect. +// + + +#import <Foundation/Foundation.h> + + +// Use C linkage. +#ifdef __cplusplus +extern "C" { +#endif + + +// +// Log levels. +// + + +// Log levels, prefixed with 'RKlcl_v'. +enum _RKlcl_enum_level_t { + RKlcl_vOff = 0, + + RKlcl_vCritical, // critical situation + RKlcl_vError, // error situation + RKlcl_vWarning, // warning + RKlcl_vInfo, // informational message + RKlcl_vDebug, // coarse-grained debugging information + RKlcl_vTrace, // fine-grained debugging information + + _RKlcl_level_t_count, + _RKlcl_level_t_first = 0, + _RKlcl_level_t_last = _RKlcl_level_t_count-1 +}; + +// Log level type. +typedef uint32_t _RKlcl_level_t; +typedef uint8_t _RKlcl_level_narrow_t; + + +// +// Log components. +// + + +// Log components, prefixed with 'RKlcl_c'. +enum _RKlcl_enum_component_t { +# define _RKlcl_component(_identifier, _header, _name) \ + RKlcl_c##_identifier, \ + __RKlcl_log_symbol_RKlcl_c##_identifier = RKlcl_c##_identifier, +# include "lcl_config_components_RK.h" +# undef _RKlcl_component + + _RKlcl_component_t_count, + _RKlcl_component_t_first = 0, + _RKlcl_component_t_last = _RKlcl_component_t_count-1 +}; + +// Log component type. +typedef uint32_t _RKlcl_component_t; + + +// +// Functions and macros. +// + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ + // Ignore some warnings about variadic macros when using '-Weverything'. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wpedantic" +# endif +#endif + +// RKlcl_log(<component>, <level>, <format>[, <arg1>[, <arg2>[, ...]]]) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// <format> : a format string of type NSString (may include %@) +// <arg..> : optional arguments required by the format string +// +// Logs a message for the given log component at the given log level if the +// log level is active for the log component. +// +// The actual logging is done by _RKlcl_logger which must be defined by a concrete +// logging back-end. _RKlcl_logger has the same signature as RKlcl_log. +// +#ifdef _RKLCL_NO_LOGGING +# define RKlcl_log(_component, _level, _format, ...) \ + do { \ + } while (0) +#else +# define RKlcl_log(_component, _level, _format, ...) \ + do { \ + if (((_RKlcl_component_level[(__RKlcl_log_symbol(_component))]) >= \ + (__RKlcl_log_symbol(_level))) \ + ) { \ + _RKlcl_logger(_component, \ + _level, \ + _format, \ + ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +// RKlcl_log_if(<component>, <level>, <predicate>, <format>[, <arg1>[, ...]]) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// <predicate>: a predicate for conditional logging +// <format> : a format string of type NSString (may include %@) +// <arg..> : optional arguments required by the format string +// +// Logs a message for the given log component at the given log level if the +// log level is active for the log component and if the predicate evaluates +// to true. +// +// The predicate is only evaluated if the given log level is active. +// +// The actual logging is done by _RKlcl_logger which must be defined by a concrete +// logging back-end. _RKlcl_logger has the same signature as RKlcl_log. +// +#ifdef _RKLCL_NO_LOGGING +# define RKlcl_log_if(_component, _level, _predicate, _format, ...) \ + do { \ + } while (0) +#else +# define RKlcl_log_if(_component, _level, _predicate, _format, ...) \ + do { \ + if (((_RKlcl_component_level[(__RKlcl_log_symbol(_component))]) >= \ + (__RKlcl_log_symbol(_level))) \ + && \ + (_predicate) \ + ) { \ + _RKlcl_logger(_component, \ + _level, \ + _format, \ + ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +#endif + +// RKlcl_configure_by_component(<component>, <level>) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component. +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_component(_RKlcl_component_t component, _RKlcl_level_t level); + +// RKlcl_configure_by_identifier(<identifier>, <level>) +// +// <identifier>: a log component's identifier with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_identifier(const char *identifier, _RKlcl_level_t level); + +// RKlcl_configure_by_header(<header>, <level>) +// +// <header> : a log component's header with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_header(const char *header, _RKlcl_level_t level); + +// RKlcl_configure_by_name(<name>, <level>) +// +// <name> : a log component's name with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_name(const char *name, _RKlcl_level_t level); + + +// +// Internals. +// + + +// Active log levels, indexed by log component. +extern _RKlcl_level_narrow_t _RKlcl_component_level[_RKlcl_component_t_count]; + +// Log component identifiers, indexed by log component. +extern const char * const _RKlcl_component_identifier[_RKlcl_component_t_count]; + +// Log component headers, indexed by log component. +extern const char * const _RKlcl_component_header[_RKlcl_component_t_count]; + +// Log component names, indexed by log component. +extern const char * const _RKlcl_component_name[_RKlcl_component_t_count]; + +// Log level headers, indexed by log level. +extern const char * const _RKlcl_level_header[_RKlcl_level_t_count]; // full header +extern const char * const _RKlcl_level_header_1[_RKlcl_level_t_count]; // header with 1 character +extern const char * const _RKlcl_level_header_3[_RKlcl_level_t_count]; // header with 3 characters + +// Log level names, indexed by log level. +extern const char * const _RKlcl_level_name[_RKlcl_level_t_count]; + +// Version. +extern const char * const _RKlcl_version; + +// Log level symbols used by RKlcl_log, prefixed with '__RKlcl_log_symbol_RKlcl_v'. +enum { + __RKlcl_log_symbol_RKlcl_vCritical = RKlcl_vCritical, + __RKlcl_log_symbol_RKlcl_vError = RKlcl_vError, + __RKlcl_log_symbol_RKlcl_vWarning = RKlcl_vWarning, + __RKlcl_log_symbol_RKlcl_vInfo = RKlcl_vInfo, + __RKlcl_log_symbol_RKlcl_vDebug = RKlcl_vDebug, + __RKlcl_log_symbol_RKlcl_vTrace = RKlcl_vTrace +}; + +// Macro for appending the '__RKlcl_log_symbol_' prefix to a given symbol. +#define __RKlcl_log_symbol(_symbol) \ + __RKlcl_log_symbol_##_symbol + + +// End C linkage. +#ifdef __cplusplus +} +#endif + + +// Include logging back-end and definition of _RKlcl_logger. +#import "lcl_config_logger_RK.h" + + +// For simple configurations where 'lcl_config_logger_RK.h' is empty, define a +// default NSLog()-based _RKlcl_logger here. +#ifndef _RKlcl_logger + +// ARC/non-ARC autorelease pool +#define _RKlcl_logger_autoreleasepool_arc 0 +#if defined(__has_feature) +# if __has_feature(objc_arc) +# undef _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_arc 1 +# endif +#endif +#if _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_begin \ + @autoreleasepool { +# define _RKlcl_logger_autoreleasepool_end \ + } +#else +# define _RKlcl_logger_autoreleasepool_begin \ + NSAutoreleasePool *_RKlcl_logger_autoreleasepool = [[NSAutoreleasePool alloc] init]; +# define _RKlcl_logger_autoreleasepool_end \ + [_RKlcl_logger_autoreleasepool release]; +#endif + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ + // Ignore some warnings about variadic macros when using '-Weverything'. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wpedantic" +# endif +#endif + +// A simple default logger, which redirects to NSLog(). +#define _RKlcl_logger(_component, _level, _format, ...) { \ + _RKlcl_logger_autoreleasepool_begin \ + NSLog(@"%s %s:%@:%d " _format, \ + _RKlcl_level_header_1[_level], \ + _RKlcl_component_header[_component], \ + [@__FILE__ lastPathComponent], \ + __LINE__, \ + ## __VA_ARGS__); \ + _RKlcl_logger_autoreleasepool_end \ +} + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +#endif + +#endif + + +// Include extensions. +#import "lcl_config_extensions_RK.h" + + +#endif // __RKLCL_H__ + diff --git a/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m b/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m new file mode 100644 index 0000000..9c2a6b8 --- /dev/null +++ b/Unit-2-Journal/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m @@ -0,0 +1,176 @@ +// +// +// lcl_RK.m -- LibComponentLogging, embedded, RestKit/RK +// +// +// Copyright (c) 2008-2012 Arne Harren <ah@0xc0.de> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "lcl_RK.h" +#include <string.h> + + +// Active log levels, indexed by log component. +_RKlcl_level_narrow_t _RKlcl_component_level[_RKlcl_component_t_count]; + +// Log component identifiers, indexed by log component. +const char * const _RKlcl_component_identifier[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + #_identifier, +# include "lcl_config_components_RK.h" +# undef _RKlcl_component +}; + +// Log component headers, indexed by log component. +const char * const _RKlcl_component_header[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + _header, +# include "lcl_config_components_RK.h" +# undef _RKlcl_component +}; + +// Log component names, indexed by log component. +const char * const _RKlcl_component_name[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + _name, +# include "lcl_config_components_RK.h" +# undef _RKlcl_component +}; + +// Log level headers, indexed by log level. +const char * const _RKlcl_level_header[] = { + "-", + "CRITICAL", + "ERROR", + "WARNING", + "INFO", + "DEBUG", + "TRACE" +}; +const char * const _RKlcl_level_header_1[] = { + "-", + "C", + "E", + "W", + "I", + "D", + "T" +}; +const char * const _RKlcl_level_header_3[] = { + "---", + "CRI", + "ERR", + "WRN", + "INF", + "DBG", + "TRC" +}; + +// Log level names, indexed by log level. +const char * const _RKlcl_level_name[] = { + "Off", + "Critical", + "Error", + "Warning", + "Info", + "Debug", + "Trace" +}; + +// Version. +#define __RKlcl_version_to_string( _text) __RKlcl_version_to_string0(_text) +#define __RKlcl_version_to_string0(_text) #_text +const char * const _RKlcl_version = __RKlcl_version_to_string(_RKLCL_VERSION_MAJOR) + "." __RKlcl_version_to_string(_RKLCL_VERSION_MINOR) + "." __RKlcl_version_to_string(_RKLCL_VERSION_BUILD) + "" _RKLCL_VERSION_SUFFIX; + +// Configures the given log level for the given log component. +uint32_t RKlcl_configure_by_component(_RKlcl_component_t component, _RKlcl_level_t level) { + // unsupported level, clip to last level + if (level > _RKlcl_level_t_last) { + level = _RKlcl_level_t_last; + } + + // configure the component + if (component <= _RKlcl_component_t_last) { + _RKlcl_component_level[component] = level; + return 1; + } + + return 0; +} + +// Configures the given log level for the given log component(s). +static uint32_t _RKlcl_configure_by_text(uint32_t count, const char * const *texts, + _RKlcl_level_narrow_t *levels, const char *text, + _RKlcl_level_t level) { + // no text given, quit + if (text == NULL || text[0] == '\0') { + return 0; + } + + // unsupported level, clip to last level + if (level > _RKlcl_level_t_last) { + level = _RKlcl_level_t_last; + } + + // configure the components + uint32_t num_configured = 0; + size_t text_len = strlen(text); + if (text[text_len-1] == '*') { + // text ends with '*', wildcard suffix was specified + text_len--; + for (uint32_t c = 0; c < count; c++) { + if (strncmp(text, texts[c], text_len) == 0) { + levels[c] = level; + num_configured++; + } + } + } else { + // no wildcard suffix was specified + for (uint32_t c = 0; c < count; c++) { + if (strcmp(text, texts[c]) == 0) { + levels[c] = level; + num_configured++; + } + } + } + return num_configured; +} + +// Configures the given log level for the given log component(s) by identifier. +uint32_t RKlcl_configure_by_identifier(const char *identifier, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_identifier, + _RKlcl_component_level, identifier, level); +} + +// Configures the given log level for the given log component(s) by header. +uint32_t RKlcl_configure_by_header(const char *header, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_header, + _RKlcl_component_level, header, level); +} + +// Configures the given log level for the given log component(s) by name. +uint32_t RKlcl_configure_by_name(const char *name, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_name, + _RKlcl_component_level, name, level); +} + diff --git a/Unit-2-Journal/Pods/SOCKit/LICENSE b/Unit-2-Journal/Pods/SOCKit/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Unit-2-Journal/Pods/SOCKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Unit-2-Journal/Pods/SOCKit/README.mdown b/Unit-2-Journal/Pods/SOCKit/README.mdown new file mode 100644 index 0000000..8f66367 --- /dev/null +++ b/Unit-2-Journal/Pods/SOCKit/README.mdown @@ -0,0 +1,94 @@ +SOCKit +====== + +String <-> Object Coding for Objective-C. Rhymes with "socket". + +With SOCKit and [SOCPattern][] you can easily transform objects into strings and vice versa. + +### Two examples, cuz devs love examples. + +```obj-c +SOCPattern* pattern = [SOCPattern patternWithString:@"api.github.com/users/:username/gists"]; +[pattern stringFromObject:githubUser]; +> @"api.github.com/users/jverkoey/gists" +``` + +```obj-c +SOCPattern* pattern = [SOCPattern patternWithString:@"github.com/:username"]; +[pattern performSelector:@selector(initWithUsername:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey"]; +> <GithubUser> username = jverkoey +``` + +### Hey, this is really similar to defining routes in Rails. + +Damn straight it is. + +### And isn't this kind of like Three20's navigator? + +Except hella better. It's also entirely incompatible with Three20 routes. This kinda blows if +you've already invested a ton of energy into Three20's routing tech, but here are a few reasons +why SOCKit is better: + +1. *Selectors are not defined in the pattern*. The fact that Three20 requires that you define + selectors in the pattern is scary as hell: rename a method in one of your controllers and + your URL routing will silently break. No warnings, just broke. With SOCKit you define the + selectors using @selector notation and SOCKit infers the parameters from the pattern definition. + This way you can depend on the compiler to fire a warning if the selector isn't defined anywhere. +2. *Parameters are encoded using true KVC*. You now have full access to [KVC collection operators]. +3. *SOCKit is fully unit tested and documented*. Not much more to be said here. + +Here's a quick breakdown of the differences between Three20 and SOCKit, if SOCKit were used as +the backend for Three20's URL routing. + +``` +Three20: [map from:@"twitter://tweet/(initWithTweetId:)" toViewController:[TweetController class]]; +SOCKit: [map from:@"twitter://tweet/:id" toViewController:[TweetController class] selector:@selector(initWithTweetId:)]; + +Three20: [map from:[Tweet class] name:@"thread" toURL:@"twitter://tweet/(id)/thread"]; +SOCKit: [map from:[Tweet class] name:@"thread" toURL:@"twitter://tweet/:id/thread"]; +``` + +## Where it's being used + +SOCKit is a sibling project to [Nimbus][], a light-weight and modular framework that makes it +easy to blaze a trail with your iOS apps. Nimbus will soon be using SOCKit in a re-envisioning +of Three20's navigator. + +Users of RESTKit will notice that SOCKit provides similar functionality to RESTKit's +[RKMakePathWithObject][]. In fact, both `RKMakePathWithObject` and the underlying `RKPathMatcher` +class rely on SOCKit behind the scenes. + +## Adding SOCKit to your project + +This lightweight library is built to be a dead-simple airdrop directly into your project. Contained +in SOCKit.h and SOCKit.m is all of the functionality you will need in order to start mapping +Strings <-> Objects. To start using SOCKit, simply download or `git checkout` the SOCKit repo +and drag SOCKit.h and SOCKit.m to your project's source tree. `#import "SOCKit.h"` where you want +to use SOCKit and start pumping out some mad String <-> Object coding. + +## Some cool things + +When coding objects into strings you define parameters by prefixing the property name with a colon. +So if you have a Tweet object with a `tweetId` property, the pattern parameter name would look like +`:tweetId`. Simple enough. + +But now let's say you have a Tweet object that contains a reference to a TwitterUser object via +the `user` property, and that TwitterUser object has a `username` property. Check this out: +`:user.username`. If this was one of my tweets and I encoded the Tweet object using a SOCKit +pattern the resulting string would be `@"featherless"`. KVC rocks. + +## Learning more + +In-depth documentation can be found in the [SOCKit.h][SOCPattern] header file. + +## Contributing + +If you find a bug in SOCKit please file an issue on the Github [SOCKit issue tracker][]. Even +better: if you have a solution for the bug then fork the project and make a pull request. + +[SOCKit issue tracker]: https://github.com/jverkoey/sockit/issues +[SOCPattern]: https://github.com/jverkoey/sockit/blob/master/SOCKit.h +[KVC collection operators]: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE +[Nimbus]: http://jverkoey.github.com/nimbus +[RESTKit]: https://github.com/RestKit/RestKit +[RKMakePathWithObject]: https://github.com/RestKit/RestKit/blob/master/Code/Network/RKClient.m#L37 \ No newline at end of file diff --git a/Unit-2-Journal/Pods/SOCKit/SOCKit.h b/Unit-2-Journal/Pods/SOCKit/SOCKit.h new file mode 100644 index 0000000..57fcf44 --- /dev/null +++ b/Unit-2-Journal/Pods/SOCKit/SOCKit.h @@ -0,0 +1,214 @@ +// +// Copyright 2011-2012 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + * String <-> Object Coding. + * + * Code information from strings into objects and vice versa. + * + * A pattern is a string with parameter names prefixed by colons (":"). + * An example of a pattern string with one parameter named :username is: + * api.github.com/users/:username/gists + * + * Patterns, once created, can be used to efficiently turn objects into strings and + * vice versa. Respectively, these techniques are referred to as inbound and outbound. + * + * Inbound examples (creating strings from objects): + * + * pattern: api.github.com/users/:username/gists + * > [pattern stringFromObject:[GithubUser userWithUsername:@"jverkoey"]]; + * returns: api.github.com/users/jverkoey/gists + * + * pattern: api.github.com/repos/:username/:repo/issues + * > [pattern stringFromObject:[GithubRepo repoWithUsername:@"jverkoey" repo:@"sockit"]]; + * returns: api.github.com/repos/jverkoey/sockit/issues + * + * Outbound examples (performing selectors on objects with values from given strings): + * + * pattern: github.com/:username + * > [pattern performSelector:@selector(initWithUsername:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey"]; + * returns: an allocated, initialized, and autoreleased GithubUser object with @"jverkoey" passed + * to the initWithUsername: method. + * + * pattern: github.com/:username/:repo + * > [pattern performSelector:@selector(initWithUsername:repoName:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey/sockit"]; + * returns: an allocated, initialized, and autoreleased GithubUser object with @"jverkoey" and + * @"sockit" passed to the initWithUsername:repoName: method. + * + * pattern: github.com/:username + * > [pattern performSelector:@selector(setUsername:) onObject:githubUser sourceString:@"github.com/jverkoey"]; + * returns: nil because setUsername: does not have a return value. githubUser's username property + * is now @"jverkoey". + * + * Note 1: Parameters must be separated by string literals + * + * Pattern parameters must be separated by some sort of non-parameter character. + * This means that you can't define a pattern like :user:repo. This is because when we + * get around to wanting to decode the string back into an object we need some sort of + * delimiter between the parameters. + * + * Note 2: When colons aren't seen as parameters + * + * If you have colons in your text that aren't followed by a valid parameter name then the + * colon will be treated as static text. This is handy if you're defining a URL pattern. + * For example: @"http://github.com/:user" only has one parameter, :user. The ":" in http:// + * is treated as a string literal and not a parameter. + * + * Note 3: Escaping KVC characters + * + * If you need to use KVC characters in SOCKit patterns as literal string tokens and not + * treated with KVC then you must escape the characters using double backslashes. For example, + * @"/:userid.json" would create a pattern that uses KVC to access the json property of the + * username value. In this case, however, we wish to interpret the ".json" portion as a + * static string. + * + * In order to do so we must escape the "." using a double backslash: "\\.". For example: + * @"/:userid\\.json". This makes it possible to create strings of the form @"/3.json". + * This also works with outbound parameters, so that the string @"/3.json" can + * be used with the pattern to invoke a selector with "3" as the first argument rather + * than "3.json". + * + * You can escape the following characters: + * ":" => @"\\:" + * "@" => @"\\@" + * "." => @"\\." + * "\\" => @"\\\\" + * + * Note 4: Allocating new objects with outbound patterns + * + * SOCKit will allocate a new object of a given class if + * performSelector:onObject:sourceString: is provided a selector with "init" as a prefix + * and object is a Class. E.g. [GithubUser class]. + */ +@interface SOCPattern : NSObject { +@private + NSString* _patternString; + NSArray* _tokens; + NSArray* _parameters; +} + +/** + * Initializes a newly allocated pattern object with the given pattern string. + * + * Designated initializer. + */ +- (id)initWithString:(NSString *)string; ++ (id)patternWithString:(NSString *)string; + +/** + * Returns YES if the given string can be used with performSelector:onObject:sourceString: or + * extractParameterKeyValuesFromSourceString:. + * + * A matching string must exactly match all of the static portions of the pattern and provide + * values for each of the parameters. + * + * @param string A string that may or may not conform to this pattern. + * @returns YES if the given string conforms to this pattern, NO otherwise. + */ +- (BOOL)stringMatches:(NSString *)string; + +/** + * Performs the given selector on the object with the matching parameter values from sourceString. + * + * @param selector The selector to perform on the object. If there aren't enough + * parameters in the pattern then the excess parameters in the selector + * will be nil. + * @param object The object to perform the selector on. + * @param sourceString A string that conforms to this pattern. The parameter values from + * this string are used as the arguments when performing the selector + * on the object. + * @returns The initialized, autoreleased object if the selector is an initializer + * (prefixed with "init") and object is a Class, otherwise the return value from + * invoking the selector. + */ +- (id)performSelector:(SEL)selector onObject:(id)object sourceString:(NSString *)sourceString; + +/** + * Extracts the matching parameter values from sourceString into an NSDictionary. + * + * @param sourceString A string that conforms to this pattern. The parameter values from + * this string are extracted into the NSDictionary. + * @returns A dictionary of key value pairs. All values will be NSStrings. The keys will + * correspond to the pattern's parameter names. Duplicate key values will be + * overwritten by later values. + */ +- (NSDictionary *)parameterDictionaryFromSourceString:(NSString *)sourceString; + +/** + * Returns a string with the parameters of this pattern replaced using Key-Value Coding (KVC) + * on the receiving object. + * + * Parameters of the pattern are evaluated using valueForKeyPath:. See Apple's KVC documentation + * for more details. + * + * Key-Value Coding Fundamentals: + * http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/BasicPrinciples.html#//apple_ref/doc/uid/20002170-BAJEAIEE + * + * Collection Operators: + * http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE + * + * @param object The object whose properties will be used to replace the parameters in + * the pattern. + * @returns A string with the pattern parameters replaced by the object property values. + * @see stringFromObject:withBlock: + */ +- (NSString *)stringFromObject:(id)object; + +#if NS_BLOCKS_AVAILABLE +/** + * Returns a string with the parameters of this pattern replaced using Key-Value Coding (KVC) + * on the receiving object, and the result is (optionally) modified or encoded by the block. + * + * For example, consider we have individual object values that need percent escapes added to them, + * while preserving the slashes, question marks, and ampersands of a typical resource path. + * Using blocks, this is very succinct: + * + * @code + * NSDictionary* person = [NSDictionary dictionaryWithObjectsAndKeys: + * @"SECRET|KEY",@"password", + * @"Joe Bob Briggs", @"name", nil]; + * SOCPattern* soc = [SOCPattern patternWithString:@"/people/:name/:password"]; + * NSString* actualPath = [soc stringFromObject:person withBlock:^(NSString *)propertyValue) { + * return [propertyValue stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + * } + * NSString* expectedPath = @"/people/Joe%20Bob%20Briggs/SECRET%7CKEY"; + * @endcode + * + * @param object The object whose properties will be used to replace the parameters in + * the pattern. + * @param block An optional block (may be nil) that modifies or encodes each + * property value string. The block accepts one parameter - the property + * value as a string - and should return the modified property string. + * @returns A string with the pattern parameters replaced by the block-processed object + * property values. + * @see stringFromObject: + */ +- (NSString *)stringFromObject:(id)object withBlock:(NSString*(^)(NSString*))block; +#endif + +@end + +/** + * A convenience method for: + * + * SOCPattern* pattern = [SOCPattern patternWithString:string]; + * NSString* result = [pattern stringFromObject:object]; + * + * @see documentation for stringFromObject: + */ +NSString* SOCStringFromStringWithObject(NSString* string, id object); diff --git a/Unit-2-Journal/Pods/SOCKit/SOCKit.m b/Unit-2-Journal/Pods/SOCKit/SOCKit.m new file mode 100644 index 0000000..59e4a65 --- /dev/null +++ b/Unit-2-Journal/Pods/SOCKit/SOCKit.m @@ -0,0 +1,543 @@ +// +// Copyright 2011-2012 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "SOCKit.h" + +#import <objc/runtime.h> +#import <assert.h> + +typedef enum { + SOCArgumentTypeNone, + SOCArgumentTypePointer, + SOCArgumentTypeBool, + SOCArgumentTypeInteger, + SOCArgumentTypeLongLong, + SOCArgumentTypeFloat, + SOCArgumentTypeDouble, +} SOCArgumentType; + +SOCArgumentType SOCArgumentTypeForTypeAsChar(char argType); +NSString* kTemporaryBackslashToken = @"/backslash/"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@interface SOCParameter : NSObject { +@private + NSString* _string; +} + +- (id)initWithString:(NSString *)string; ++ (id)parameterWithString:(NSString *)string; + +- (NSString *)string; + +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@interface SOCPattern() + +- (void)_compilePattern; + +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation SOCPattern + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)dealloc { + [_patternString release]; _patternString = nil; + [_tokens release]; _tokens = nil; + [_parameters release]; _parameters = nil; + [super dealloc]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (id)initWithString:(NSString *)string { + if ((self = [super init])) { + _patternString = [string copy]; + + [self _compilePattern]; + } + return self; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (id)patternWithString:(NSString *)string { + return [[[self alloc] initWithString:string] autorelease]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Pattern Compilation + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSCharacterSet *)nonParameterCharacterSet { + NSMutableCharacterSet* parameterCharacterSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [parameterCharacterSet addCharactersInString:@".@_"]; + NSCharacterSet* nonParameterCharacterSet = [parameterCharacterSet invertedSet]; + return nonParameterCharacterSet; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)_compilePattern { + if ([_patternString length] == 0) { + return; + } + + NSMutableArray* tokens = [[NSMutableArray alloc] init]; + NSMutableArray* parameters = [[NSMutableArray alloc] init]; + + NSCharacterSet* nonParameterCharacterSet = [self nonParameterCharacterSet]; + + // Turn escaped backslashes into a special backslash token to avoid \\. being interpreted as + // `\` and `\.` rather than `\\` and `.`. + NSString* escapedPatternString = _patternString; + if ([escapedPatternString rangeOfString:@"\\\\"].length > 0) { + escapedPatternString = [escapedPatternString stringByReplacingOccurrencesOfString: @"\\\\" + withString: kTemporaryBackslashToken]; + } + + // Scan through the string, creating tokens that are either strings or parameters. + // Parameters are prefixed with ":". + NSScanner* scanner = [NSScanner scannerWithString:escapedPatternString]; + + // NSScanner skips whitespace and newlines by default (not ideal!). + [scanner setCharactersToBeSkipped:nil]; + + while (![scanner isAtEnd]) { + NSString* token = nil; + [scanner scanUpToString:@":" intoString:&token]; + + if ([token length] > 0) { + if (![token hasSuffix:@"\\"]) { + // Add this static text to the token list. + [tokens addObject:token]; + + } else { + // This token is escaping the next colon, so we skip the parameter creation. + [tokens addObject:[token stringByAppendingString:@":"]]; + + // Skip the colon. + [scanner setScanLocation:[scanner scanLocation] + 1]; + continue; + } + } + + if (![scanner isAtEnd]) { + // Skip the colon. + [scanner setScanLocation:[scanner scanLocation] + 1]; + + // Scanning won't modify the token if there aren't any characters to be read, so we must + // clear it before scanning again. + token = nil; + [scanner scanUpToCharactersFromSet:nonParameterCharacterSet intoString:&token]; + + if ([token length] > 0) { + // Only add parameters that have valid names. + SOCParameter* parameter = [SOCParameter parameterWithString:token]; + [parameters addObject:parameter]; + [tokens addObject:parameter]; + + } else { + // Allows for http:// to get by without creating a parameter. + [tokens addObject:@":"]; + } + } + } + + // This is an outbound pattern. + if ([parameters count] > 0) { + BOOL lastWasParameter = NO; + for (id token in tokens) { + if ([token isKindOfClass:[SOCParameter class]]) { + NSAssert(!lastWasParameter, @"Parameters must be separated by non-parameter characters."); + lastWasParameter = YES; + + } else { + lastWasParameter = NO; + } + } + } + + [_tokens release]; + _tokens = [tokens copy]; + [_parameters release]; _parameters = nil; + if ([parameters count] > 0) { + _parameters = [parameters copy]; + } + [tokens release]; tokens = nil; + [parameters release]; parameters = nil; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)_stringFromEscapedToken:(NSString *)token { + if ([token rangeOfString:@"\\"].length == 0 + && [token rangeOfString:kTemporaryBackslashToken].length == 0) { + // The common case (faster and creates fewer autoreleased strings). + return token; + + } else { + // Escaped characters may exist. + // Create a mutable copy so that we don't excessively create new autoreleased strings. + NSMutableString* mutableToken = [token mutableCopy]; + [mutableToken replaceOccurrencesOfString:@"\\." withString:@"." options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:@"\\@" withString:@"@" options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:@"\\:" withString:@":" options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:kTemporaryBackslashToken withString:@"\\" options:0 range:NSMakeRange(0, [mutableToken length])]; + return [mutableToken autorelease]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public Methods + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)gatherParameterValues:(NSArray**)pValues fromString:(NSString *)string { + const NSInteger stringLength = [string length]; + NSInteger validUpUntil = 0; + NSInteger matchingTokens = 0; + + NSMutableArray* values = nil; + if (nil != pValues) { + values = [NSMutableArray array]; + } + + NSInteger tokenIndex = 0; + for (id token in _tokens) { + + if ([token isKindOfClass:[NSString class]]) { + // Replace the escaped characters in the token before we start comparing the string. + token = [self _stringFromEscapedToken:token]; + + NSInteger tokenLength = [token length]; + if (validUpUntil + tokenLength > stringLength) { + // There aren't enough characters in the string to satisfy this token. + break; + } + if (![[string substringWithRange:NSMakeRange(validUpUntil, tokenLength)] + isEqualToString:token]) { + // The tokens don't match up. + break; + } + + // The string token matches. + validUpUntil += tokenLength; + ++matchingTokens; + + } else { + NSInteger parameterLocation = validUpUntil; + + // Look ahead for the next string token match. + if (tokenIndex + 1 < [_tokens count]) { + NSString* nextToken = [self _stringFromEscapedToken:[_tokens objectAtIndex:tokenIndex + 1]]; + NSAssert([nextToken isKindOfClass:[NSString class]], @"The token following a parameter must be a string."); + + NSRange nextTokenRange = [string rangeOfString:nextToken options:0 range:NSMakeRange(validUpUntil, stringLength - validUpUntil)]; + if (nextTokenRange.length == 0) { + // Couldn't find the next token. + break; + } + if (nextTokenRange.location == validUpUntil) { + // This parameter is empty. + break; + } + + validUpUntil = nextTokenRange.location; + ++matchingTokens; + + } else { + // Anything goes until the end of the string then. + if (validUpUntil == stringLength) { + // The last parameter is empty. + break; + } + + validUpUntil = stringLength; + ++matchingTokens; + } + + NSRange parameterRange = NSMakeRange(parameterLocation, validUpUntil - parameterLocation); + [values addObject:[string substringWithRange:parameterRange]]; + } + + ++tokenIndex; + } + + if (nil != pValues) { + *pValues = [[values copy] autorelease]; + } + + return validUpUntil == stringLength && matchingTokens == [_tokens count]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)stringMatches:(NSString *)string { + return [self gatherParameterValues:nil fromString:string]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)setArgument:(NSString*)text withType:(SOCArgumentType)type atIndex:(NSInteger)index forInvocation:(NSInvocation*)invocation { + // There are two implicit arguments with an invocation. + index+=2; + + switch (type) { + case SOCArgumentTypeNone: { + break; + } + case SOCArgumentTypeInteger: { + int val = [text intValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeLongLong: { + long long val = [text longLongValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeFloat: { + float val = [text floatValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeDouble: { + double val = [text doubleValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeBool: { + BOOL val = [text boolValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + default: { + [invocation setArgument:&text atIndex:index]; + break; + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)setArgumentsFromValues:(NSArray *)values forInvocation:(NSInvocation *)invocation { + Method method = class_getInstanceMethod([invocation.target class], invocation.selector); + NSAssert(nil != method, @"The method must exist with the given invocation target."); + + for (NSInteger ix = 0; ix < [values count]; ++ix) { + NSString* value = [values objectAtIndex:ix]; + + char argType[4]; + method_getArgumentType(method, (unsigned int) ix + 2, argType, sizeof(argType) / sizeof(argType[0])); + SOCArgumentType type = SOCArgumentTypeForTypeAsChar(argType[0]); + + [self setArgument:value withType:type atIndex:ix forInvocation:invocation]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (id)performSelector:(SEL)selector onObject:(id)object sourceString:(NSString *)sourceString { + BOOL isInitializer = [NSStringFromSelector(selector) hasPrefix:@"init"] && [object class] == object; + + if (isInitializer) { + object = [[object alloc] autorelease]; + } + + NSArray* values = nil; + BOOL succeeded = [self gatherParameterValues:&values fromString:sourceString]; + NSAssert(succeeded, @"The pattern can't be used with this string."); + + id returnValue = nil; + + if (succeeded) { + NSMethodSignature* sig = [object methodSignatureForSelector:selector]; + NSAssert(nil != sig, @"%@ does not respond to selector: '%@'", object, NSStringFromSelector(selector)); + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setTarget:object]; + [invocation setSelector:selector]; + [self setArgumentsFromValues:values forInvocation:invocation]; + [invocation invoke]; + + if (sig.methodReturnLength) { + [invocation getReturnValue:&returnValue]; + } + } + + return returnValue; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSDictionary *)parameterDictionaryFromSourceString:(NSString *)sourceString { + NSMutableDictionary* kvs = [[NSMutableDictionary alloc] initWithCapacity:[_parameters count]]; + + NSArray* values = nil; + BOOL succeeded = [self gatherParameterValues:&values fromString:sourceString]; + NSAssert(succeeded, @"The pattern can't be used with this string."); + + NSDictionary* result = nil; + + if (succeeded) { + for (NSInteger ix = 0; ix < [values count]; ++ix) { + SOCParameter* parameter = [_parameters objectAtIndex:ix]; + id value = [values objectAtIndex:ix]; + [kvs setObject:value forKey:parameter.string]; + } + + result = [[kvs copy] autorelease]; + [kvs release]; kvs = nil; + } + + return result; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)_stringWithParameterValues:(NSDictionary *)parameterValues { + NSMutableString* accumulator = [[NSMutableString alloc] initWithCapacity:[_patternString length]]; + + for (id token in _tokens) { + if ([token isKindOfClass:[NSString class]]) { + [accumulator appendString:[self _stringFromEscapedToken:token]]; + + } else { + SOCParameter* parameter = token; + [accumulator appendString:[parameterValues objectForKey:parameter.string]]; + } + } + + NSString* result = nil; + result = [[accumulator copy] autorelease]; + [accumulator release]; accumulator = nil; + return result; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)stringFromObject:(id)object { + if ([_tokens count] == 0) { + return @""; + } + NSMutableDictionary* parameterValues = + [NSMutableDictionary dictionaryWithCapacity:[_parameters count]]; + for (SOCParameter* parameter in _parameters) { + NSString* stringValue = [NSString stringWithFormat:@"%@", [object valueForKeyPath:parameter.string]]; + [parameterValues setObject:stringValue forKey:parameter.string]; + } + return [self _stringWithParameterValues:parameterValues]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#if NS_BLOCKS_AVAILABLE +- (NSString *)stringFromObject:(id)object withBlock:(NSString *(^)(NSString*))block { + if ([_tokens count] == 0) { + return @""; + } + NSMutableDictionary* parameterValues = [NSMutableDictionary dictionaryWithCapacity:[_parameters count]]; + for (SOCParameter* parameter in _parameters) { + NSString* stringValue = [NSString stringWithFormat:@"%@", [object valueForKeyPath:parameter.string]]; + if (nil != block) { + stringValue = block(stringValue); + } + if (nil != stringValue) { + [parameterValues setObject:stringValue forKey:parameter.string]; + } + } + return [self _stringWithParameterValues:parameterValues]; +} +#endif + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation SOCParameter + +- (void)dealloc { + [_string release]; _string = nil; + [super dealloc]; +} + +- (id)initWithString:(NSString *)string { + if ((self = [super init])) { + _string = [string copy]; + } + return self; +} + ++ (id)parameterWithString:(NSString *)string { + return [[[self alloc] initWithString:string] autorelease]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"Parameter: %@", _string]; +} + +- (NSString *)string { + return [[_string retain] autorelease]; +} + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +SOCArgumentType SOCArgumentTypeForTypeAsChar(char argType) { + if (argType == 'c' || argType == 'i' || argType == 's' || argType == 'l' || argType == 'C' + || argType == 'I' || argType == 'S' || argType == 'L') { + return SOCArgumentTypeInteger; + + } else if (argType == 'q' || argType == 'Q') { + return SOCArgumentTypeLongLong; + + } else if (argType == 'f') { + return SOCArgumentTypeFloat; + + } else if (argType == 'd') { + return SOCArgumentTypeDouble; + + } else if (argType == 'B') { + return SOCArgumentTypeBool; + + } else { + return SOCArgumentTypePointer; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +NSString* SOCStringFromStringWithObject(NSString* string, id object) { + SOCPattern* pattern = [[SOCPattern alloc] initWithString:string]; + NSString* result = [pattern stringFromObject:object]; + [pattern release]; + return result; +} diff --git a/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m new file mode 100644 index 0000000..6a29cf8 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_AFNetworking : NSObject +@end +@implementation PodsDummy_AFNetworking +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch new file mode 100644 index 0000000..8fb0298 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch @@ -0,0 +1,15 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + +#import <Availability.h> + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + #import <SystemConfiguration/SystemConfiguration.h> + #import <MobileCoreServices/MobileCoreServices.h> + #import <Security/Security.h> +#else + #import <SystemConfiguration/SystemConfiguration.h> + #import <CoreServices/CoreServices.h> + #import <Security/Security.h> +#endif diff --git a/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig new file mode 100644 index 0000000..104b316 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/AFNetworking" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -framework "CoreGraphics" -framework "MobileCoreServices" -framework "Security" -framework "SystemConfiguration" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-dummy.m b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-dummy.m new file mode 100644 index 0000000..aeabf61 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_Bolts : NSObject +@end +@implementation PodsDummy_Bolts +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts.xcconfig b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts.xcconfig new file mode 100644 index 0000000..6f90d1f --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Bolts/Bolts.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Bolts" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-dummy.m new file mode 100644 index 0000000..eb4f9df --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_FBSDKCoreKit : NSObject +@end +@implementation PodsDummy_FBSDKCoreKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit.xcconfig new file mode 100644 index 0000000..d056884 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKCoreKit/FBSDKCoreKit.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -weak_framework "Accounts" -weak_framework "AudioToolbox" -weak_framework "CoreGraphics" -weak_framework "CoreLocation" -weak_framework "Foundation" -weak_framework "QuartzCore" -weak_framework "Security" -weak_framework "Social" -weak_framework "UIKit" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-dummy.m new file mode 100644 index 0000000..ff16b39 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_FBSDKLoginKit : NSObject +@end +@implementation PodsDummy_FBSDKLoginKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit.xcconfig new file mode 100644 index 0000000..490a4b8 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKLoginKit/FBSDKLoginKit.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -weak_framework "Accounts" -weak_framework "AudioToolbox" -weak_framework "CoreGraphics" -weak_framework "CoreLocation" -weak_framework "Foundation" -weak_framework "QuartzCore" -weak_framework "Security" -weak_framework "Social" -weak_framework "UIKit" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-dummy.m new file mode 100644 index 0000000..8f70249 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_FBSDKShareKit : NSObject +@end +@implementation PodsDummy_FBSDKShareKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit.xcconfig new file mode 100644 index 0000000..dc1d18e --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FBSDKShareKit/FBSDKShareKit.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FBSDKShareKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -weak_framework "Accounts" -weak_framework "AudioToolbox" -weak_framework "CoreGraphics" -weak_framework "CoreLocation" -weak_framework "Foundation" -weak_framework "QuartzCore" -weak_framework "Security" -weak_framework "Social" -weak_framework "UIKit" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-dummy.m b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-dummy.m new file mode 100644 index 0000000..0b0eeb2 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_FoldingTabBar : NSObject +@end +@implementation PodsDummy_FoldingTabBar +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar.xcconfig b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar.xcconfig new file mode 100644 index 0000000..faecaec --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/FoldingTabBar/FoldingTabBar.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/FoldingTabBar" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -framework "QuartzCore" -framework "UIKit" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m new file mode 100644 index 0000000..8a45508 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_ISO8601DateFormatterValueTransformer : NSObject +@end +@implementation PodsDummy_ISO8601DateFormatterValueTransformer +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.xcconfig b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.xcconfig new file mode 100644 index 0000000..4f6b42a --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-dummy.m b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-dummy.m new file mode 100644 index 0000000..3f17a64 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_Parse : NSObject +@end +@implementation PodsDummy_Parse +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/Parse/Parse.xcconfig b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse.xcconfig new file mode 100644 index 0000000..fe8aeab --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Parse/Parse.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Parse" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -l"sqlite3" -l"z" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreGraphics" -framework "CoreLocation" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -weak_framework "Accounts" -weak_framework "Social" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown new file mode 100644 index 0000000..0577482 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown @@ -0,0 +1,1194 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## AFNetworking + +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## Bolts + +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. + +## FBSDKCoreKit + +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +## FBSDKLoginKit + +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +## FBSDKShareKit + +Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +## FoldingTabBar + +The MIT License (MIT) + +Copyright (c) 2015 Yalantis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +## ISO8601DateFormatterValueTransformer + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## Parse + +See https://www.parse.com/about/terms + +## RKValueTransformers + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## RestKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## SOCKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## TransitionKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## pop + +BSD License + +For Pop software + +Copyright (c) 2014, 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. + +Generated by CocoaPods - http://cocoapods.org diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.plist new file mode 100644 index 0000000..6d840be --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-acknowledgements.plist @@ -0,0 +1,1272 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>PreferenceSpecifiers</key> + <array> + <dict> + <key>FooterText</key> + <string>This application makes use of the following third party libraries:</string> + <key>Title</key> + <string>Acknowledgements</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +</string> + <key>Title</key> + <string>AFNetworking</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>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.</string> + <key>Title</key> + <string>Bolts</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +</string> + <key>Title</key> + <string>FBSDKCoreKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +</string> + <key>Title</key> + <string>FBSDKLoginKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +copy, modify, and distribute this software in source code or binary form for use +in connection with the web services and APIs provided by Facebook. + +As with any software that integrates with the Facebook platform, your use of +this software is subject to the Facebook Developer Principles and Policies +[http://developers.facebook.com/policy/]. This copyright notice shall be +included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +</string> + <key>Title</key> + <string>FBSDKShareKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>The MIT License (MIT) + +Copyright (c) 2015 Yalantis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +</string> + <key>Title</key> + <string>FoldingTabBar</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>ISO8601DateFormatterValueTransformer</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>See https://www.parse.com/about/terms</string> + <key>Title</key> + <string>Parse</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>RKValueTransformers</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>RestKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>SOCKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>TransitionKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>BSD License + +For Pop software + +Copyright (c) 2014, 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. +</string> + <key>Title</key> + <string>pop</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Generated by CocoaPods - http://cocoapods.org</string> + <key>Title</key> + <string></string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + </array> + <key>StringsTable</key> + <string>Acknowledgements</string> + <key>Title</key> + <string>Acknowledgements</string> +</dict> +</plist> diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-dummy.m b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-dummy.m new file mode 100644 index 0000000..ade64bd --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_Pods : NSObject +@end +@implementation PodsDummy_Pods +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-frameworks.sh b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-frameworks.sh new file mode 100755 index 0000000..6f76344 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-frameworks.sh @@ -0,0 +1,84 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # use filter instead of exclude so missing patterns dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-resources.sh b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-resources.sh new file mode 100755 index 0000000..bac2d3a --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods-resources.sh @@ -0,0 +1,101 @@ +#!/bin/sh +set -e + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +realpath() { + DIRECTORY="$(cd "${1%/*}" && pwd)" + FILENAME="${1##*/}" + echo "$DIRECTORY/$FILENAME" +} + +install_resource() +{ + case $1 in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.framework) + echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" + xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + /*) + echo "$1" + echo "$1" >> "$RESOURCES_TO_COPY" + ;; + *) + echo "${PODS_ROOT}/$1" + echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" + ;; + esac +} +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_resource "Parse/Parse/Resources/en.lproj" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_resource "Parse/Parse/Resources/en.lproj" +fi + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; + esac + + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "`realpath $PODS_ROOT`*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.debug.xcconfig new file mode 100644 index 0000000..9e83c6d --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.debug.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/Bolts" -isystem "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" -isystem "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" -isystem "${PODS_ROOT}/Headers/Public/FBSDKShareKit" -isystem "${PODS_ROOT}/Headers/Public/FoldingTabBar" -isystem "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" -isystem "${PODS_ROOT}/Headers/Public/Parse" -isystem "${PODS_ROOT}/Headers/Public/RKValueTransformers" -isystem "${PODS_ROOT}/Headers/Public/RestKit" -isystem "${PODS_ROOT}/Headers/Public/SOCKit" -isystem "${PODS_ROOT}/Headers/Public/TransitionKit" -isystem "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"Bolts" -l"FBSDKCoreKit" -l"FBSDKLoginKit" -l"FBSDKShareKit" -l"FoldingTabBar" -l"ISO8601DateFormatterValueTransformer" -l"Parse" -l"RKValueTransformers" -l"RestKit" -l"SOCKit" -l"TransitionKit" -l"c++" -l"pop" -l"sqlite3" -l"z" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreGraphics" -framework "CoreLocation" -framework "MobileCoreServices" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -weak_framework "Accounts" -weak_framework "AudioToolbox" -weak_framework "CoreGraphics" -weak_framework "CoreLocation" -weak_framework "Foundation" -weak_framework "QuartzCore" -weak_framework "Security" -weak_framework "Social" -weak_framework "UIKit" +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.release.xcconfig b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.release.xcconfig new file mode 100644 index 0000000..9e83c6d --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/Pods/Pods.release.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/Bolts" -isystem "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" -isystem "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" -isystem "${PODS_ROOT}/Headers/Public/FBSDKShareKit" -isystem "${PODS_ROOT}/Headers/Public/FoldingTabBar" -isystem "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" -isystem "${PODS_ROOT}/Headers/Public/Parse" -isystem "${PODS_ROOT}/Headers/Public/RKValueTransformers" -isystem "${PODS_ROOT}/Headers/Public/RestKit" -isystem "${PODS_ROOT}/Headers/Public/SOCKit" -isystem "${PODS_ROOT}/Headers/Public/TransitionKit" -isystem "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"Bolts" -l"FBSDKCoreKit" -l"FBSDKLoginKit" -l"FBSDKShareKit" -l"FoldingTabBar" -l"ISO8601DateFormatterValueTransformer" -l"Parse" -l"RKValueTransformers" -l"RestKit" -l"SOCKit" -l"TransitionKit" -l"c++" -l"pop" -l"sqlite3" -l"z" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreGraphics" -framework "CoreLocation" -framework "MobileCoreServices" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" -weak_framework "Accounts" -weak_framework "AudioToolbox" -weak_framework "CoreGraphics" -weak_framework "CoreLocation" -weak_framework "Foundation" -weak_framework "QuartzCore" -weak_framework "Security" -weak_framework "Social" -weak_framework "UIKit" +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m new file mode 100644 index 0000000..792c92a --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_RKValueTransformers : NSObject +@end +@implementation PodsDummy_RKValueTransformers +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers.xcconfig b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers.xcconfig new file mode 100644 index 0000000..8dd44ec --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RKValueTransformers/RKValueTransformers.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RKValueTransformers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-dummy.m new file mode 100644 index 0000000..61870a2 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_RestKit : NSObject +@end +@implementation PodsDummy_RestKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-prefix.pch new file mode 100644 index 0000000..c2ad09f --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit-prefix.pch @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + +#import <Availability.h> + +#define _AFNETWORKING_PIN_SSL_CERTIFICATES_ + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + #import <SystemConfiguration/SystemConfiguration.h> + #import <MobileCoreServices/MobileCoreServices.h> + #import <Security/Security.h> +#else + #import <SystemConfiguration/SystemConfiguration.h> + #import <CoreServices/CoreServices.h> + #import <Security/Security.h> +#endif +#if __has_include("RKCoreData.h") + #import <CoreData/CoreData.h> +#endif diff --git a/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit.xcconfig new file mode 100644 index 0000000..e074d5c --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/RestKit/RestKit.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RestKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -framework "CFNetwork" -framework "MobileCoreServices" -framework "Security" -framework "SystemConfiguration" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-dummy.m new file mode 100644 index 0000000..54b43ff --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_SOCKit : NSObject +@end +@implementation PodsDummy_SOCKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit.xcconfig new file mode 100644 index 0000000..ee8d8c2 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/SOCKit/SOCKit.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SOCKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m new file mode 100644 index 0000000..345483c --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_TransitionKit : NSObject +@end +@implementation PodsDummy_TransitionKit +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit.xcconfig b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit.xcconfig new file mode 100644 index 0000000..7add391 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/TransitionKit/TransitionKit.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/TransitionKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/Target Support Files/pop/pop-dummy.m b/Unit-2-Journal/Pods/Target Support Files/pop/pop-dummy.m new file mode 100644 index 0000000..19ed261 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/pop/pop-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_pop : NSObject +@end +@implementation PodsDummy_pop +@end diff --git a/Unit-2-Journal/Pods/Target Support Files/pop/pop-prefix.pch b/Unit-2-Journal/Pods/Target Support Files/pop/pop-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/pop/pop-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Unit-2-Journal/Pods/Target Support Files/pop/pop.xcconfig b/Unit-2-Journal/Pods/Target Support Files/pop/pop.xcconfig new file mode 100644 index 0000000..3a75c64 --- /dev/null +++ b/Unit-2-Journal/Pods/Target Support Files/pop/pop.xcconfig @@ -0,0 +1,7 @@ +CLANG_CXX_LANGUAGE_STANDARD = c++11 +CLANG_CXX_LIBRARY = libc++ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/pop" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/Bolts" "${PODS_ROOT}/Headers/Public/FBSDKCoreKit" "${PODS_ROOT}/Headers/Public/FBSDKLoginKit" "${PODS_ROOT}/Headers/Public/FBSDKShareKit" "${PODS_ROOT}/Headers/Public/FoldingTabBar" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/Parse" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/pop" +OTHER_LDFLAGS = -l"c++" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.h b/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.h new file mode 100644 index 0000000..abd2156 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.h @@ -0,0 +1,89 @@ +// +// TKEvent.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKState, TKTransition; + +/** + The `TKEvent` class describes an event within a state machine that causes a transition between states. Each event has a descriptive name and specifies the state that the machine will transition into after the event has been fired. Events can optionally be constrained to a set of source states that the machine must be in for the event to fire. + */ +@interface TKEvent : NSObject <NSCoding, NSCopying> + +///------------------------ +/// @name Creating an Event +///------------------------ + +/** + Creates and returns a new event object with the given name, source states, and destination state. + + @param name The name for the event. + @param sourceStates An array of `TKState` objects specifying the source states that the machine must be in for the event to be permitted to fire. + @param destinationState The state that the state machine will transition into after the event has fired. + @return A newly created event object. + */ ++ (instancetype)eventWithName:(NSString *)name transitioningFromStates:(NSArray *)sourceStates toState:(TKState *)destinationState; + +///------------------------------ +/// @name Accessing Event Details +///------------------------------ + +@property (nonatomic, copy, readonly) NSString *name; + +/** + An optional array of states that the state machine must be in before the event is allowed to fire. + + If `nil`, then the event can be fired when the state machine is in any state. + */ +@property (nonatomic, copy, readonly) NSArray *sourceStates; + +/** + The state that the state machine will transition into after the event has fired. + + Cannot be `nil`. + */ +@property (nonatomic, strong, readonly) TKState *destinationState; + +///------------------------------ +/// @name Setting Callback Blocks +///------------------------------ + +/** + Sets a block to be executed in order to determines if an event should be fired. If the block returns `YES`, then the event will be permitted to fire. + + @param block The block to be executed to determine if the event can be fired. The block has a Boolean return value and accepts two arguments: the event that is being evaluated to determine if it can be fired and its associated transition. If the block returns `YES`, then the event can be fired. + */ +- (void)setShouldFireEventBlock:(BOOL (^)(TKEvent *event, TKTransition *transition))block; + +/** + Sets a block to be executed before an event is fired, while the state machine is still in the source state. + + @param block The block to be executed. The block has no return value and accepts two arguments: the event that is about to be fired and its associated transition. + */ +- (void)setWillFireEventBlock:(void (^)(TKEvent *event, TKTransition *transition))block; + +/** + Sets a block to be executed after an event is fired, when the state machine has transitioned into the destination state. + + @param block The block to be executed. The block has no return value and accepts two arguments: the event that has just been fired and its associated transition. + */ +- (void)setDidFireEventBlock:(void (^)(TKEvent *event, TKTransition *transition))block; + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.m b/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.m new file mode 100644 index 0000000..8bbd728 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKEvent.m @@ -0,0 +1,101 @@ +// +// TKEvent.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKEvent.h" +#import "TKState.h" + +static NSString *TKDescribeSourceStates(NSArray *states) +{ + if (! [states count]) return @"any state"; + + NSMutableString *description = [NSMutableString string]; + [states enumerateObjectsUsingBlock:^(TKState *state, NSUInteger idx, BOOL *stop) { + NSString *separator = @""; + if (idx < [states count] - 1) separator = (idx == [states count] - 2) ? @" and " : @", "; + [description appendFormat:@"'%@'%@", state.name, separator]; + }]; + return description; +} + + +@interface TKEvent () +@property (nonatomic, copy, readwrite) NSString *name; +@property (nonatomic, copy, readwrite) NSArray *sourceStates; +@property (nonatomic, strong, readwrite) TKState *destinationState; +@property (nonatomic, copy) BOOL (^shouldFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^willFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^didFireEventBlock)(TKEvent *, TKTransition *); +@end + +@implementation TKEvent + ++ (instancetype)eventWithName:(NSString *)name transitioningFromStates:(NSArray *)sourceStates toState:(TKState *)destinationState +{ + if (! [name length]) [NSException raise:NSInvalidArgumentException format:@"The event name cannot be blank."]; + if (!destinationState) [NSException raise:NSInvalidArgumentException format:@"The destination state cannot be nil."]; + TKEvent *event = [self new]; + event.name = name; + event.sourceStates = sourceStates; + event.destinationState = destinationState; + return event; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p '%@' transitions from %@ to '%@'>", NSStringFromClass([self class]), self, self.name, TKDescribeSourceStates(self.sourceStates), self.destinationState.name]; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.name = [aDecoder decodeObjectForKey:@"name"]; + self.sourceStates = [aDecoder decodeObjectForKey:@"sourceStates"]; + self.destinationState = [aDecoder decodeObjectForKey:@"destinationState"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.name forKey:@"name"]; + [aCoder encodeObject:self.sourceStates forKey:@"sourceStates"]; + [aCoder encodeObject:self.destinationState forKey:@"destinationState"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKEvent *copiedEvent = [[[self class] allocWithZone:zone] init]; + copiedEvent.name = self.name; + copiedEvent.sourceStates = self.sourceStates; + copiedEvent.destinationState = self.destinationState; + copiedEvent.shouldFireEventBlock = self.shouldFireEventBlock; + copiedEvent.willFireEventBlock = self.willFireEventBlock; + copiedEvent.didFireEventBlock = self.didFireEventBlock; + return copiedEvent; +} + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKState.h b/Unit-2-Journal/Pods/TransitionKit/Code/TKState.h new file mode 100644 index 0000000..15a3dc8 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKState.h @@ -0,0 +1,83 @@ +// +// TKState.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKTransition; + +/** + The `TKState` class defines a particular state with a state machine. Each state must have a unique name within the state machine in which it is used. + */ +@interface TKState : NSObject <NSCoding, NSCopying> + +///----------------------- +/// @name Creating a State +///----------------------- + +/** + Creates and returns a new state object with the specified name. + + @param name The name of the state. Cannot be blank. + @return A newly created state object with the specified name. + */ ++ (instancetype)stateWithName:(NSString *)name; + +///------------------------------------ +/// @name Accessing the Name of a State +///------------------------------------ + +/** + The name of the receiver. Cannot be `nil` and must be unique within the state machine that the receiver is added to. + */ +@property (nonatomic, copy, readonly) NSString *name; + +///---------------------------------- +/// @name Configuring Block Callbacks +///---------------------------------- + +/** + Sets a block to be executed before the state machine transitions into the state modeled by the receiver. + + @param block The block to executed before a state machine enters the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setWillEnterStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed after the state machine has transitioned into the state modeled by the receiver. + + @param block The block to executed after a state machine enters the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setDidEnterStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed before the state machine transitions out of the state modeled by the receiver. + + @param block The block to executed before a state machine exits the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setWillExitStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed after the state machine has transitioned out of the state modeled by the receiver. + + @param block The block to executed after a state machine exit the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setDidExitStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKState.m b/Unit-2-Journal/Pods/TransitionKit/Code/TKState.m new file mode 100644 index 0000000..1566339 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKState.m @@ -0,0 +1,77 @@ +// +// TKState.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKState.h" + +@interface TKState () +@property (nonatomic, copy, readwrite) NSString *name; +@property (nonatomic, copy) void (^willEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^willExitStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didExitStateBlock)(TKState *, TKTransition *); +@end + +@implementation TKState + ++ (instancetype)stateWithName:(NSString *)name +{ + if (! [name length]) [NSException raise:NSInvalidArgumentException format:@"The `name` cannot be blank."]; + TKState *state = [TKState new]; + state.name = name; + return state; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p '%@'>", NSStringFromClass([self class]), self, self.name]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKState *copiedState = [[[self class] allocWithZone:zone] init]; + copiedState.name = self.name; + copiedState.willEnterStateBlock = self.willEnterStateBlock; + copiedState.didEnterStateBlock = self.didEnterStateBlock; + copiedState.willExitStateBlock = self.willExitStateBlock; + copiedState.didExitStateBlock = self.didExitStateBlock; + return copiedState; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.name = [aDecoder decodeObjectForKey:@"name"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.name forKey:@"name"]; +} + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.h b/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.h new file mode 100644 index 0000000..cc6b3d9 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.h @@ -0,0 +1,245 @@ +// +// TKStateMachine.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKEvent, TKState; + +/** + The `TKStateMachine` class provides an interface for modeling a state machine. The state machine supports the registration of an arbitrary number of states and events that trigger transitions between the states. + + ## Callback Sequence + + When a state machine is activated, the following callbacks are invoked: + + 1. Initial State: willEnterState - The block set with `setWillEnterStateBlock:` on the `initialState` is invoked. + 1. The `currentState` changes from `nil` to `initialState` + 1. Initial State: didEnterState - The block set with `setDidEnterStateBlock:` on the `initialState` is invoked. + + Each time an event is fired, the following callbacks are invoked: + + 1. Event: shouldFireEvent - The block set with `setShouldFireEventBlock:` on the event being fired is consulted to determine if the event can be fired. If `NO` is returned then the event is declined and no further callbacks are invoked + 1. Event: willFireEvent - The block set with `setWillFireEventBlock:` on the event being fired is invoked. + 1. Old State: willExitState - The block set with `setWillExitStateBlock:` on the outgoing state is invoked. + 1. New State: willEnterState - The block set with `setWillEnterStateBlock:` on the incoming state is invoked. + 1. The `currentState` changes from the old state to the new state. + 1. Old State: didExitState - The block set with `setDidExitStateBlock:` on the old state is invoked. + 1. New State: didEnterState - The block set with `setDidEnterStateBlock:` on the new current state is invoked. + 1. Event: didFireEvent - The block set with `setDidFireEventBlock:` on the event being fired is invoked. + 1. Notification: After the event has completed and all block callbacks + + ## Copying and Serialization Support + + The `TKStateMachine` class is both `NSCoding` and `NSCopying` compliant. When copied, a new inactive state machine instance is created with the same states, events, and initial state. All blocks associated with the events and states are copied. When archived, the current state, initial state, states, events and activation state is preserved. All block callbacks associated with the states and events become `nil`. + */ +@interface TKStateMachine : NSObject <NSCoding, NSCopying> + +///---------------------- +/// @name Managing States +///---------------------- + +/** + The set of states that have been added to the receiver. Each instance of the set is a `TKState` object. + */ +@property (nonatomic, readonly) NSSet *states; + +/** + The initial state of the receiver. + + When the machine is activated, it transitions into the initial state. + */ +@property (nonatomic, strong) TKState *initialState; + +/** + The current state of the receiver. + + When the machine is activated, the current state transitions from `nil` to the `initialState`. Subsequent state transitions are trigger by the firing of events. + + @see `fireEvent:error:` + */ +@property (nonatomic, strong, readonly) TKState *currentState; + +/** + Adds a state to the receiver. + + Before a state can be used in an event, it must be registered with the state machine. + + @param state The state to be added. + @raises TKStateMachineIsImmutableException Raised if an attempt is made to modify the state machine after it has been activated. + */ +- (void)addState:(TKState *)state; + +/** + Adds an array of state objects to the receiver. + + This is a convenience method whose implementation is equivalent to the following example code: + + for (TKState *state in arrayOfStates) { + [self addState:state]; + } + + @param arrayOfStates An array of `TKState` objects to be added to the receiver. + */ +- (void)addStates:(NSArray *)arrayOfStates; + +/** + Retrieves the state with the given name from the receiver. + + @param name The name of the state to retrieve. + @returns The state object with the given name or `nil` if it could not be found. + */ +- (TKState *)stateNamed:(NSString *)name; + +/** + Returns a Boolean value that indicates if the receiver is in the specified state. + + This is a convenience method whose functionality is equivalent to comparing the given state with the `currentState`. + + @param stateOrStateName A `TKState` object or an `NSString` object that identifies a state by name. The specified state is compared with the value of the `currentState` property. + @returns `YES` if the receiver is in the specified state, else `NO`. + @raises NSInvalidArgumentException Raised if an invalid object is given. + @raises NSInvalidArgumentException Raised if a string value is given that does not identify a registered state. + */ +- (BOOL)isInState:(id)stateOrStateName; + +///---------------------- +/// @name Managing Events +///---------------------- + +/** + The set of events that have been added to the receiver. Each instance of the set is a `TKEvent` object. + */ +@property (nonatomic, readonly) NSSet *events; + +/** + Adds an event to the receiver. + + The state objects references by the event must be registered with the receiver. + + @param event The event to be added. + @raises TKStateMachineIsImmutableException Raised if an attempt is made to modify the state machine after it has been activated. + @raises NSInternalInconsistencyException Raised if the given event references a `TKState` that has not been registered with the receiver. + */ +- (void)addEvent:(TKEvent *)event; + +/** + Adds an array of event objects to the receiver. + + This is a convenience method whose implementation is equivalent to the following example code: + + for (TKEvent *event in arrayOfEvents) { + [self addEvent:event]; + } + + @param arrayOfEvents An array of `TKEvent` objects to be added to the receiver. + */ +- (void)addEvents:(NSArray *)arrayOfEvents; + +/** + Retrieves the event with the given name from the receiver. + + @param name The name of the event to retrieve. + @returns The event object with the given name or `nil` if it could not be found. + */ +- (TKEvent *)eventNamed:(NSString *)name; + +///----------------------------------- +/// @name Activating the State Machine +///----------------------------------- + +/** + Activates the receiver by making it immutable and transitioning into the initial state. + + Once the state machine has been activated no further changes can be made to the registered events and states. Note that although callbacks will be dispatched for transition into the initial state upon activation, they will have a `nil` transition argument as no event has been fired. + */ +- (void)activate; + +/** + Returns a Boolean value that indicates if the receiver has been activated. + */ +- (BOOL)isActive; + +///-------------------- +/// @name Firing Events +///-------------------- + +/** + Returns a Boolean value that indicates if the specified event can be fired. + + @param eventOrEventName A `TKEvent` object or an `NSString` object that identifies an event by name. The source states of the specified event is compared with the current state of the receiver. If the `sourceStates` of the event is `nil`, then the event can be fired from any state. If the `sourcesStates` is not `nil`, then the event can only be fired if it includes the `currentState` of the receiver. + @return `YES` if the event can be fired, else `NO`. + */ +- (BOOL)canFireEvent:(id)eventOrEventName; + +/** + Fires an event to transition the state of the receiver. If the event fails to fire, then `NO` is returned and an error is set. + + If the receiver has not yet been activated, then the first event fired will activate it. If the specified transition is not permitted, then `NO` will be returned and an `TKInvalidTransitionError` will be created. If the `shouldFireEventBlock` of the specified event returns `NO`, then the event is declined, `NO` will be returned, and an `TKTransitionDeclinedError` will be created. + + @param eventOrEventName A `TKEvent` object or an `NSString` object that identifies an event by name. + @param userInfo An optional dictionary of user info to be delivered as part of the state transition. + @param error A pointer to an `NSError` object that will be set if the event fails to fire. + @return `YES` if the event is fired, else `NO`. + */ +- (BOOL)fireEvent:(id)eventOrEventName userInfo:(NSDictionary *)userInfo error:(NSError **)error; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + The domain for errors raised by TransitionKit. + */ +extern NSString *const TKErrorDomain; + +/** + A Notification posted when the `currentState` of a `TKStateMachine` object changes to a new value. + */ +extern NSString *const TKStateMachineDidChangeStateNotification; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the state of the machine before the transition occured. + */ +extern NSString *const TKStateMachineDidChangeStateOldStateUserInfoKey; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the state of the machine after the transition occured. + */ +extern NSString *const TKStateMachineDidChangeStateNewStateUserInfoKey; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the event that triggered the transition between states. + */ +extern NSString *const TKStateMachineDidChangeStateEventUserInfoKey; + +/** + An exception raised when an attempt is made to mutate an immutable `TKStateMachine` object. + */ +extern NSString *const TKStateMachineIsImmutableException; + +/** + Error Codes + */ +typedef enum { + TKInvalidTransitionError = 1000, // An invalid transition was attempted. + TKTransitionDeclinedError = 1001, // The transition was declined by the `shouldFireEvent` guard block. +} TKErrorCode; diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.m b/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.m new file mode 100644 index 0000000..31a89fb --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKStateMachine.m @@ -0,0 +1,304 @@ +// +// TKStateMachine.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKStateMachine.h" +#import "TKState.h" +#import "TKEvent.h" +#import "TKTransition.h" + +@interface TKEvent () +@property (nonatomic, copy) BOOL (^shouldFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^willFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^didFireEventBlock)(TKEvent *, TKTransition *); +@end + +@interface TKState () +@property (nonatomic, copy) void (^willEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^willExitStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didExitStateBlock)(TKState *, TKTransition *); +@end + +NSString *const TKErrorDomain = @"org.blakewatters.TransitionKit.errors"; +NSString *const TKStateMachineDidChangeStateNotification = @"TKStateMachineDidChangeStateNotification"; +NSString *const TKStateMachineDidChangeStateOldStateUserInfoKey = @"old"; +NSString *const TKStateMachineDidChangeStateNewStateUserInfoKey = @"new"; +NSString *const TKStateMachineDidChangeStateEventUserInfoKey = @"event"; + +NSString *const TKStateMachineIsImmutableException = @"TKStateMachineIsImmutableException"; + +#define TKRaiseIfActive() \ + if ([self isActive]) [NSException raise:TKStateMachineIsImmutableException format:@"Unable to modify state machine: The state machine has already been activated."]; + +static NSString *TKQuoteString(NSString *string) +{ + return string ? [NSString stringWithFormat:@"'%@'", string] : nil; +} + +@interface TKStateMachine () +@property (nonatomic, strong) NSMutableSet *mutableStates; +@property (nonatomic, strong) NSMutableSet *mutableEvents; +@property (nonatomic, assign, getter = isActive) BOOL active; +@property (nonatomic, strong, readwrite) TKState *currentState; +@property (nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation TKStateMachine + ++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key +{ + NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; + + if ([key isEqualToString:@"states"]) { + NSSet *affectingKey = [NSSet setWithObject:@"mutableStates"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + return keyPaths; + } else if ([key isEqualToString:@"events"]) { + NSSet *affectingKey = [NSSet setWithObject:@"mutableEvents"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + return keyPaths; + } + + return keyPaths; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.mutableStates = [NSMutableSet set]; + self.mutableEvents = [NSMutableSet set]; + self.lock = [NSRecursiveLock new]; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p %ld States, %ld Events. currentState=%@, initialState='%@', isActive=%@>", + NSStringFromClass([self class]), self, (unsigned long) [self.mutableStates count], (unsigned long) [self.mutableEvents count], + TKQuoteString(self.currentState.name), self.initialState.name, self.isActive ? @"YES" : @"NO"]; +} + +- (void)setInitialState:(TKState *)initialState +{ + TKRaiseIfActive(); + _initialState = initialState; +} + +- (NSSet *)states +{ + return [NSSet setWithSet:self.mutableStates]; +} + +- (void)addState:(TKState *)state +{ + TKRaiseIfActive(); + if (! [state isKindOfClass:[TKState class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKState` object, instead got a `%@` (%@)", [state class], state]; + if ([self stateNamed: state.name]) [NSException raise:NSInvalidArgumentException format:@"State with name `%@` already exists", state.name]; + + if (self.initialState == nil) self.initialState = state; + [self.mutableStates addObject:state]; +} + +- (void)addStates:(NSArray *)arrayOfStates +{ + TKRaiseIfActive(); + for (TKState *state in arrayOfStates) { + [self addState:state]; + } +} + +- (TKState *)stateNamed:(NSString *)name +{ + for (TKState *state in self.mutableStates) { + if ([state.name isEqualToString:name]) return state; + } + return nil; +} + +- (BOOL)isInState:(id)stateOrStateName +{ + if (! [stateOrStateName isKindOfClass:[TKState class]] && ![stateOrStateName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKState` object or `NSString` object specifying the name of a state, instead got a `%@` (%@)", [stateOrStateName class], stateOrStateName]; + TKState *state = [stateOrStateName isKindOfClass:[TKState class]] ? stateOrStateName : [self stateNamed:stateOrStateName]; + if (! state) [NSException raise:NSInvalidArgumentException format:@"Cannot find a State named '%@'", stateOrStateName]; + return [self.currentState isEqual:state]; +} + +- (NSSet *)events +{ + return [NSSet setWithSet:self.mutableEvents]; +} + +- (void)addEvent:(TKEvent *)event +{ + TKRaiseIfActive(); + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot add a `nil` event to the state machine."]; + if (event.sourceStates) { + for (TKState *state in event.sourceStates) { + if (! [self.mutableStates containsObject:state]) { + [NSException raise:NSInternalInconsistencyException format:@"Cannot add event '%@' to the state machine: the event references a state '%@', which has not been added to the state machine.", event.name, state.name]; + } + } + } + if (! [self.mutableStates containsObject:event.destinationState]) [NSException raise:NSInternalInconsistencyException format:@"Cannot add event '%@' to the state machine: the event references a state '%@', which has not been added to the state machine.", event.name, event.destinationState.name]; + [self.mutableEvents addObject:event]; +} + +- (void)addEvents:(NSArray *)arrayOfEvents +{ + TKRaiseIfActive(); + for (TKEvent *event in arrayOfEvents) { + [self addEvent:event]; + } +} + +- (TKEvent *)eventNamed:(NSString *)name +{ + for (TKEvent *event in self.mutableEvents) { + if ([event.name isEqualToString:name]) return event; + } + return nil; +} + +- (void)activate +{ + if (self.isActive) [NSException raise:NSInternalInconsistencyException format:@"The state machine has already been activated."]; + [self.lock lock]; + self.active = YES; + + // Dispatch callbacks to establish initial state + if (self.initialState.willEnterStateBlock) self.initialState.willEnterStateBlock(self.initialState, nil); + self.currentState = self.initialState; + if (self.initialState.didEnterStateBlock) self.initialState.didEnterStateBlock(self.initialState, nil); + [self.lock unlock]; +} + +- (BOOL)canFireEvent:(id)eventOrEventName +{ + if (! [eventOrEventName isKindOfClass:[TKEvent class]] && ![eventOrEventName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKEvent` object or `NSString` object specifying the name of an event, instead got a `%@` (%@)", [eventOrEventName class], eventOrEventName]; + TKEvent *event = [eventOrEventName isKindOfClass:[TKEvent class]] ? eventOrEventName : [self eventNamed:eventOrEventName]; + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot find an Event named '%@'", eventOrEventName]; + return [event.sourceStates containsObject:self.currentState]; +} + +- (BOOL)fireEvent:(id)eventOrEventName userInfo:(NSDictionary *)userInfo error:(NSError *__autoreleasing *)error +{ + [self.lock lock]; + if (! self.isActive) [self activate]; + if (! [eventOrEventName isKindOfClass:[TKEvent class]] && ![eventOrEventName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKEvent` object or `NSString` object specifying the name of an event, instead got a `%@` (%@)", [eventOrEventName class], eventOrEventName]; + TKEvent *event = [eventOrEventName isKindOfClass:[TKEvent class]] ? eventOrEventName : [self eventNamed:eventOrEventName]; + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot find an Event named '%@'", eventOrEventName]; + + // Check that this transition is permitted + if (event.sourceStates != nil && ![event.sourceStates containsObject:self.currentState]) { + NSString *failureReason = [NSString stringWithFormat:@"An attempt was made to fire the '%@' event while in the '%@' state, but the event can only be fired from the following states: %@", event.name, self.currentState.name, [[event.sourceStates valueForKey:@"name"] componentsJoinedByString:@", "]]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"The event cannot be fired from the current state.", NSLocalizedFailureReasonErrorKey: failureReason }; + if (error) *error = [NSError errorWithDomain:TKErrorDomain code:TKInvalidTransitionError userInfo:userInfo]; + [self.lock unlock]; + return NO; + } + + TKTransition *transition = [TKTransition transitionForEvent:event fromState:self.currentState inStateMachine:self userInfo:userInfo]; + if (event.shouldFireEventBlock) { + if (! event.shouldFireEventBlock(event, transition)) { + NSString *failureReason = [NSString stringWithFormat:@"An attempt to fire the '%@' event was declined because `shouldFireEventBlock` returned `NO`.", event.name]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"The event declined to be fired.", NSLocalizedFailureReasonErrorKey: failureReason }; + if (error) *error = [NSError errorWithDomain:TKErrorDomain code:TKTransitionDeclinedError userInfo:userInfo]; + [self.lock unlock]; + return NO; + } + } + + TKState *oldState = self.currentState; + TKState *newState = event.destinationState; + + if (event.willFireEventBlock) event.willFireEventBlock(event, transition); + + if (oldState.willExitStateBlock) oldState.willExitStateBlock(oldState, transition); + if (newState.willEnterStateBlock) newState.willEnterStateBlock(newState, transition); + self.currentState = newState; + if (oldState.didExitStateBlock) oldState.didExitStateBlock(oldState, transition); + if (newState.didEnterStateBlock) newState.didEnterStateBlock(newState, transition); + + if (event.didFireEventBlock) event.didFireEventBlock(event, transition); + [self.lock unlock]; + + NSMutableDictionary *notificationInfo = [userInfo mutableCopy] ?: [NSMutableDictionary dictionary]; + [notificationInfo addEntriesFromDictionary:@{ TKStateMachineDidChangeStateOldStateUserInfoKey: oldState, + TKStateMachineDidChangeStateNewStateUserInfoKey: newState, + TKStateMachineDidChangeStateEventUserInfoKey: event }]; + [[NSNotificationCenter defaultCenter] postNotificationName:TKStateMachineDidChangeStateNotification object:self userInfo:notificationInfo]; + + return YES; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.initialState = [aDecoder decodeObjectForKey:@"initialState"]; + self.currentState =[aDecoder decodeObjectForKey:@"currentState"]; + self.mutableStates = [[aDecoder decodeObjectForKey:@"states"] mutableCopy]; + self.mutableEvents = [[aDecoder decodeObjectForKey:@"events"] mutableCopy]; + self.active = [aDecoder decodeBoolForKey:@"isActive"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.initialState forKey:@"initialState"]; + [aCoder encodeObject:self.currentState forKey:@"currentState"]; + [aCoder encodeObject:self.states forKey:@"states"]; + [aCoder encodeObject:self.events forKey:@"events"]; + [aCoder encodeBool:self.isActive forKey:@"isActive"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKStateMachine *copiedStateMachine = [[[self class] allocWithZone:zone] init]; + copiedStateMachine.active = NO; + copiedStateMachine.currentState = nil; + copiedStateMachine.initialState = self.initialState; + + for (TKState *state in self.states) { + [copiedStateMachine addState:[state copy]]; + } + + for (TKEvent *event in self.events) { + NSMutableArray *sourceStates = [NSMutableArray arrayWithCapacity:[event.sourceStates count]]; + for (TKState *sourceState in event.sourceStates) { + [sourceStates addObject:[copiedStateMachine stateNamed:sourceState.name]]; + } + TKState *destinationState = [copiedStateMachine stateNamed:event.destinationState.name]; + TKEvent *copiedEvent = [TKEvent eventWithName:event.name transitioningFromStates:sourceStates toState:destinationState]; + [copiedStateMachine addEvent:copiedEvent]; + } + return copiedStateMachine; +} + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.h b/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.h new file mode 100644 index 0000000..91c5aa6 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.h @@ -0,0 +1,73 @@ +// +// TKTransition.h +// TransitionKit +// +// Created by Blake Watters on 10/11/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKEvent, TKState, TKStateMachine; + +/** + The `TKTransition` class models a state change in response to an event firing within a state machine. It encapsulates all details about the change and is yielded as an argument to all block callbacks within TransitionKit. The optional dictionary of `userInfo` can be used to broadcast arbitrary data across callbacks. + */ +@interface TKTransition : NSObject + +///---------------------------- +/// @name Creating a Transition +///---------------------------- + +/** + Creates and returns a new transition object describing a state change occuring within a state machine in response to the firing of an event. + + @param event The event being fired that is causing the transition to occur. + @param sourceState The state of the machine when the event was fired. + @param stateMachine The state machine in which the transition is occurirng. + @param userInfo An optional dictionary of user info supplied with the event when it was fired. + */ ++ (instancetype)transitionForEvent:(TKEvent *)event fromState:(TKState *)sourceState inStateMachine:(TKStateMachine *)stateMachine userInfo:(NSDictionary *)userInfo; + +///----------------------------------- +/// @name Accessing Transition Details +///----------------------------------- + +/** + The event that was fired, causing the transition to occur. + */ +@property (nonatomic, strong, readonly) TKEvent *event; + +/** + The state of the state machine when the transition starts. + */ +@property (nonatomic, strong, readonly) TKState *sourceState; + +/** + The state of the state machine after the transition finishes. + */ +@property (nonatomic, strong, readonly) TKState *destinationState; + +/** + The state machine in which the transition is occurring. + */ +@property (nonatomic, strong, readonly) TKStateMachine *stateMachine; + +/** + An optional dictionary of user info supplied with the event when fired. + */ +@property (nonatomic, copy, readonly) NSDictionary *userInfo; + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.m b/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.m new file mode 100644 index 0000000..21cb35c --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TKTransition.m @@ -0,0 +1,49 @@ +// +// TKTransition.m +// TransitionKit +// +// Created by Blake Watters on 10/11/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKTransition.h" +#import "TKEvent.h" + +@interface TKTransition () + +@property (nonatomic, strong, readwrite) TKEvent *event; +@property (nonatomic, strong, readwrite) TKState *sourceState; +@property (nonatomic, strong, readwrite) TKStateMachine *stateMachine; +@property (nonatomic, copy, readwrite) NSDictionary *userInfo; +@end + +@implementation TKTransition + ++ (instancetype)transitionForEvent:(TKEvent *)event fromState:(TKState *)sourceState inStateMachine:(TKStateMachine *)stateMachine userInfo:(NSDictionary *)userInfo +{ + TKTransition *transition = [self new]; + transition.event = event; + transition.sourceState = sourceState; + transition.stateMachine = stateMachine; + transition.userInfo = userInfo; + return transition; +} + +- (TKState *)destinationState +{ + return self.event.destinationState; +} + +@end diff --git a/Unit-2-Journal/Pods/TransitionKit/Code/TransitionKit.h b/Unit-2-Journal/Pods/TransitionKit/Code/TransitionKit.h new file mode 100644 index 0000000..2505ad9 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/Code/TransitionKit.h @@ -0,0 +1,29 @@ +// +// TransitionKit.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef TransitionKit_TransitionKit_h +#define TransitionKit_TransitionKit_h + +#import "TKStateMachine.h" +#import "TKEvent.h" +#import "TKState.h" +#import "TKTransition.h" + +#endif diff --git a/Unit-2-Journal/Pods/TransitionKit/LICENSE b/Unit-2-Journal/Pods/TransitionKit/LICENSE new file mode 100644 index 0000000..eb8d4bc --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Unit-2-Journal/Pods/TransitionKit/README.md b/Unit-2-Journal/Pods/TransitionKit/README.md new file mode 100644 index 0000000..299f983 --- /dev/null +++ b/Unit-2-Journal/Pods/TransitionKit/README.md @@ -0,0 +1,126 @@ +TransitionKit +============= + +[![Build Status](https://travis-ci.org/blakewatters/TransitionKit.png?branch=master,development)](https://travis-ci.org/blakewatters/TransitionKit) +![Pod Version](https://cocoapod-badges.herokuapp.com/v/TransitionKit/badge.png) +![Pod Platform](https://cocoapod-badges.herokuapp.com/p/TransitionKit/badge.png) + +**A simple, elegantly designed block based API for implementing State Machines in Objective-C** + +TransitionKit is a small Cocoa library that provides an API for implementing a state machine in Objective C. It is full-featured, completely documented, and very thoroughly unit tested. State machines are a great way to manage complexity in your application and TransitionKit provides you with an elegant API for implementing state machines in your next iOS or Mac OS X application. + +### Features + +* Supports an arbitrary number of States and Events. +* States and Events support a thorough set of block based callbacks for responding to state transitions. +* States, Events, and State Machines are NSCopying and NSCoding compliant, enabling easy integration with archiving and copying in your custom classes. +* Strongly enforced. The state machine includes numerous runtime checks for misconfigurations, making it easy to debug and trust your state machines. +* Transitions support the inclusion of arbitrary user data via a `userInfo` dictionary, making it easy to broadcast metadata across callbacks. +* Completely Documented. The entire library is marked up with Appledoc. +* Thorougly unit tested. You know it works and can make changes with confidence. +* Lightweight. TransitionKit has no dependencies beyond the Foundation library and works on iOS and Mac OS X. + +## Installation via CocoaPods + +The recommended approach for installing TransitionKit is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.16.0** using Git **>= 1.8.0** installed via Homebrew. + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add TransitionKit: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'TransitionKit', '~> 2.0.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +## Examples + +#### Simple Example + +The following example is a simple state machine that models the state of a Message in an Inbox. + +```objc +TKStateMachine *inboxStateMachine = [TKStateMachine new]; + +TKState *unread = [TKState stateWithName:@"Unread"]; +[unread setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [self incrementUnreadCount]; +}]; +TKState *read = [TKState stateWithName:@"Read"]; +[read setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [self decrementUnreadCount]; +}]; +TKState *deleted = [TKState stateWithName:@"Deleted"]; +[deleted setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [self moveMessageToTrash]; +}]; + +[inboxStateMachine addStates:@[ unread, read, deleted ]]; +inboxStateMachine.initialState = unread; + +TKEvent *viewMessage = [TKEvent eventWithName:@"View Message" transitioningFromStates:@[ unread ] toState:read]; +TKEvent *deleteMessage = [TKEvent eventWithName:@"Delete Message" transitioningFromStates:@[ read, unread ] toState:deleted]; +TKEvent *markAsUnread = [TKEvent eventWithName:@"Mark as Unread" transitioningFromStates:@[ read, deleted ] toState:unread]; + +[inboxStateMachine addEvents:@[ viewMessage, deleteMessage, markAsUnread ]]; + +// Activate the state machine +[inboxStateMachine activate]; + +[inboxStateMachine isInState:@"Unread"]; // YES, the initial state + +// Fire some events +NSDictionary *userInfo = nil; +NSError *error = nil; +BOOL success = [inboxStateMachine fireEvent:@"View Message" userInfo:userInfo error:&error]; // YES +success = [inboxStateMachine fireEvent:@"Delete Message" userInfo:userInfo error:&error]; // YES +success = [inboxStateMachine fireEvent:@"Mark as Unread" userInfo:userInfo error:&error]; // YES + +success = [inboxStateMachine canFireEvent:@"Mark as Unread"]; // NO + +// Error. Cannot mark an Unread message as Unread +success = [inboxStateMachine fireEvent:@"Mark as Unread" userInfo:nil error:&error]; // NO + +// error is an TKInvalidTransitionError with a descriptive error message and failure reason +``` + +## Unit Tests + +TransitionKit is tested using the [Kiwi](https://github.com/allending/Kiwi) BDD library. In order to run the tests, you must do the following: + +1. Install the dependencies via CocoaPods: `pod install` +1. Open the workspace: `open TransitionKit.xcworkspace` +1. Run the specs via the **Product** menu > **Test** + +## Contact + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +## License + +TransitionKit is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/Unit-2-Journal/Pods/pop/LICENSE b/Unit-2-Journal/Pods/pop/LICENSE new file mode 100644 index 0000000..642126f --- /dev/null +++ b/Unit-2-Journal/Pods/pop/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Pop software + +Copyright (c) 2014, 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. diff --git a/Unit-2-Journal/Pods/pop/README.md b/Unit-2-Journal/Pods/pop/README.md new file mode 100644 index 0000000..addb18a --- /dev/null +++ b/Unit-2-Journal/Pods/pop/README.md @@ -0,0 +1,203 @@ +![pop](https://github.com/facebook/pop/blob/master/Images/pop.gif?raw=true) + +Pop is an extensible animation engine for iOS and OS X. In addition to basic static animations, it supports spring and decay dynamic animations, making it useful for building realistic, physics-based interactions. The API allows quick integration with existing Objective-C codebases and enables the animation of any property on any object. It's a mature and well-tested framework that drives all the animations and transitions in [Paper](http://www.facebook.com/paper). + +[![Build Status](https://travis-ci.org/facebook/pop.svg)](https://travis-ci.org/facebook/pop) + +## Installation + +Pop is available on [CocoaPods](http://cocoapods.org). Just add the following to your project Podfile: + +```ruby +pod 'pop', '~> 1.0' +``` + +Bugs are first fixed in master and then made available via a designated release. If you tend to live on the bleeding edge, you can use Pop from master with the following Podfile entry: + +```ruby +pod 'pop', :git => 'https://github.com/facebook/pop.git' +``` + +## Non-CocoaPods Installation + +### iOS 8 Embedded Framework +By adding the project to your project and adding pop.embedded framework to the Embedded Binaries section on the General tab of your app's target, you can set up pop in seconds! This also enables `@import pop` syntax with header modules. + +**Note**: because of some awkward limitations with Xcode, embedded binaries must share the same name as the module and must have `.framework` as an extension. This means that you'll see two pop.frameworks when adding embedded binaries (one for OS X, and one for iOS). You'll need to be sure to add the iOS one, and since this list is populated in order of targets, it's safe to assume it's the second one. You can verify the correct one was chosen by checking the path next to the framework listed: `Debug-iphoneos`. + +![Embedded Binaries](Images/EmbeddedBinaries.png?raw=true) + +**Note 2**: this method does not currently play nicely with workspaces. For some unknown reason, Xcode simply rejects adding pop.framework as an embedded binary when pop.xcodeproj is placed in the workspace. This only works when pop.xcodeproj is added as a subproject to the current target's project. + +### Advanced +Alternatively, you can add the project to your workspace and adopt the provided configuration files or manually copy the files under the pop subdirectory into your project. If installing manually, ensure the C++ standard library is also linked by including `-lc++` to your project linker flags. + +## Usage + +Pop adopts the Core Animation explicit animation programming model. Use by including the following import: + +```objective-c +#import <pop/POP.h> +``` + +or if you're using the embedded framework: + +```objective-c +@import pop; +``` + +### Start, Stop & Update + +To start an animation, add it to the object you wish to animate: + +```objective-c +POPSpringAnimation *anim = [POPSpringAnimation animation]; +... +[layer pop_addAnimation:anim forKey:@"myKey"]; +``` + +To stop an animation, remove it from the object referencing the key specified on start: + +```objective-c +[layer pop_removeAnimationForKey:@"myKey"]; +``` + +The key can also be used to query for the existence of an animation. Updating the toValue of a running animation can provide the most seamless way to change course: + +```objective-c +anim = [layer pop_animationForKey:@"myKey"]; +if (anim) { + /* update to value to new destination */ + anim.toValue = @(42.0); +} else { + /* create and start a new animation */ + .... +} +``` + +While a layer was used in the above examples, the Pop interface is implemented as a category addition on NSObject. Any NSObject or subclass can be animated. + +### Types + +There are four concrete animation types: spring, decay, basic and custom. + +Spring animations can be used to give objects a delightful bounce. In this example, we use a spring animation to animate a layer's bounds from its current value to (0, 0, 400, 400): + +```objective-c +POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds]; +anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 400, 400)]; +[layer pop_addAnimation:anim forKey:@"size"]; +``` +Decay animations can be used to gradually slow an object to a halt. In this example, we decay a layer's positionX from it's current value and velocity 1000pts per second: + +```objective-c +POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX]; +anim.velocity = @(1000.); +[layer pop_addAnimation:anim forKey:@"slide"]; +``` + +Basic animations can be used to interpolate values over a specified time period. To use an ease-in ease-out animation to animate a view's alpha from 0.0 to 1.0 over the default duration: +```objective-c +POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha]; +anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; +anim.fromValue = @(0.0); +anim.toValue = @(1.0); +[view pop_addAnimation:anim forKey:@"fade"]; +``` +`POPCustomAnimation` makes creating custom animations and transitions easier by handling CADisplayLink and associated time-step management. See header for more details. + + +### Properties + +The property animated is specified by the `POPAnimatableProperty` class. In this example we create a spring animation and explicitly set the animatable property corresponding to `-[CALayer bounds]`: + +```objective-c +POPSpringAnimation *anim = [POPSpringAnimation animation]; +anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerBounds]; +``` + +The framework provides many common layer and view animatable properties out of box. You can animate a custom property by creating a new instance of the class. In this example, we declare a custom volume property: + +```objective-c +prop = [POPAnimatableProperty propertyWithName:@"com.foo.radio.volume" initializer:^(POPMutableAnimatableProperty *prop) { + // read value + prop.readBlock = ^(id obj, CGFloat values[]) { + values[0] = [obj volume]; + }; + // write value + prop.writeBlock = ^(id obj, const CGFloat values[]) { + [obj setVolume:values[0]]; + }; + // dynamics threshold + prop.threshold = 0.01; +}]; + +anim.property = prop; +``` + +For a complete listing of provided animatable properties, as well more information on declaring custom properties see `POPAnimatableProperty.h`. + + +### Debugging + +Here are a few tips when debugging. Pop obeys the Simulator's Toggle Slow Animations setting. Try enabling it to slow down animations and more easily observe interactions. + +Consider naming your animations. This will allow you to more easily identify them when referencing them, either via logging or in the debugger: + +```objective-c +anim.name = @"springOpen"; +``` + +Each animation comes with an associated tracer. The tracer allows you to record all animation-related events, in a fast and efficient manner, allowing you to query and analyze them after animation completion. The below example starts the tracer and configures it to log all events on animation completion: + +```objective-c +POPAnimationTracer *tracer = anim.tracer; +tracer.shouldLogAndResetOnCompletion = YES; +[tracer start]; +``` + +See `POPAnimationTracer.h` for more details. + +## Testing + +Pop has extensive unit test coverage. To install test dependencies, navigate to the root pop directory and type: + +```sh +pod install +``` + +Assuming CocoaPods is installed, this will include the necessary OCMock dependency to the unit test targets. + +## SceneKit + +Due to SceneKit requiring iOS 8 and OS X 10.9, POP's SceneKit extensions aren't provided out of box. Unfortunately, [weakly linked frameworks](https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html) cannot be used due to issues mentioned in the [Xcode 6.1 Release Notes](https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html). + +To remedy this, you can easily opt-in to use SceneKit! Simply add this to the Preprocessor Macros section of your Xcode Project: + +``` +POP_USE_SCENEKIT=1 +``` + +## Resources + +A collection of links to external resources that may prove valuable: + +* [AGGeometryKit+POP - Animating Quadrilaterals with Pop](https://github.com/hfossli/aggeometrykit-pop) +* [Apple – Core Animation Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html) +* [iOS Development Tips – UIScrollView-like deceleration with Pop](http://iosdevtips.co/post/84571595353/replicating-uiscrollviews-deceleration-with-facebook) +* [Pop Playground – Repository of Pop animation examples](https://github.com/callmeed/pop-playground) +* [Pop Playground 2 – Playing with Facebook's framework](http://victorbaro.com/2014/05/pop-playground-playing-with-facebooks-framework/) +* [POP-MCAnimate – Concise syntax for the Pop animation framework](https://github.com/matthewcheok/POP-MCAnimate) +* [Popping - Great examples in one project](https://github.com/schneiderandre/popping) +* [Rebound – Spring Animations for Android](http://facebook.github.io/rebound/) +* [Tapity Tutorial – Getting Started with Pop](http://tapity.com/tutorial-getting-started-with-pop/) +* [Tweaks – Easily adjust parameters for iOS apps in development](https://github.com/facebook/tweaks) +* [POP Tutorial in 5 steps](https://github.com/maxmyers/FacebookPop) +* [VBFPopFlatButton – Flat animatable button, using Pop to transition between states](https://github.com/victorBaro/VBFPopFlatButton) + +## Contributing +See the CONTRIBUTING file for how to help out. + +## License + +Pop is released under a BSD License. See LICENSE file for details. diff --git a/Unit-2-Journal/Pods/pop/pop/POP.h b/Unit-2-Journal/Pods/pop/pop/POP.h new file mode 100644 index 0000000..72adba7 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POP.h @@ -0,0 +1,29 @@ +/** + Copyright (c) 2014-present, 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. + */ + +#ifndef POP_POP_H +#define POP_POP_H + +#import <pop/POPDefines.h> + +#import <pop/POPAnimatableProperty.h> +#import <pop/POPAnimation.h> +#import <pop/POPAnimationEvent.h> +#import <pop/POPAnimationExtras.h> +#import <pop/POPAnimationTracer.h> +#import <pop/POPAnimator.h> +#import <pop/POPBasicAnimation.h> +#import <pop/POPCustomAnimation.h> +#import <pop/POPDecayAnimation.h> +#import <pop/POPGeometry.h> +#import <pop/POPLayerExtras.h> +#import <pop/POPPropertyAnimation.h> +#import <pop/POPSpringAnimation.h> + +#endif /* POP_POP_H */ diff --git a/Unit-2-Journal/Pods/pop/pop/POPAction.h b/Unit-2-Journal/Pods/pop/pop/POPAction.h new file mode 100644 index 0000000..85cca19 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAction.h @@ -0,0 +1,67 @@ +/** + Copyright (c) 2014-present, 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. + */ + +#ifndef POPACTION_H +#define POPACTION_H + +#import <QuartzCore/CATransaction.h> + +#import <pop/POPDefines.h> + +#ifdef __cplusplus + +namespace POP { + + /** + @abstract Disables Core Animation actions using RAII. + @discussion The disablement of actions is scoped to the current transaction. + */ + class ActionDisabler + { + BOOL state; + + public: + ActionDisabler() POP_NOTHROW + { + state = [CATransaction disableActions]; + [CATransaction setDisableActions:YES]; + } + + ~ActionDisabler() + { + [CATransaction setDisableActions:state]; + } + }; + + /** + @abstract Enables Core Animation actions using RAII. + @discussion The enablement of actions is scoped to the current transaction. + */ + class ActionEnabler + { + BOOL state; + + public: + ActionEnabler() POP_NOTHROW + { + state = [CATransaction disableActions]; + [CATransaction setDisableActions:NO]; + } + + ~ActionEnabler() + { + [CATransaction setDisableActions:state]; + } + }; + +} + +#endif /* __cplusplus */ + +#endif /* POPACTION_H */ diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.h b/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.h new file mode 100644 index 0000000..1636783 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.h @@ -0,0 +1,249 @@ +/** + Copyright (c) 2014-present, 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 <CoreGraphics/CoreGraphics.h> + +#import <Foundation/NSObject.h> + +#import <pop/POPDefines.h> + +@class POPMutableAnimatableProperty; + +/** + @abstract Describes an animatable property. + */ +@interface POPAnimatableProperty : NSObject <NSCopying, NSMutableCopying> + +/** + @abstract Property accessor. + @param name The name of the property. + @return The animatable property with that name or nil if it does not exist. + @discussion Common animatable properties are included by default. Use the provided constants to reference. + */ ++ (id)propertyWithName:(NSString *)name; + +/** + @abstract The designated initializer. + @param name The name of the property. + @param block The block used to configure the property on creation. + @return The animatable property with name if it exists, otherwise a newly created instance configured by block. + @discussion Custom properties should use reverse-DNS naming. A newly created instance is only mutable in the scope of block. Once constructed, a property becomes immutable. + */ ++ (id)propertyWithName:(NSString *)name initializer:(void (^)(POPMutableAnimatableProperty *prop))block; + +/** + @abstract The name of the property. + @discussion Used to uniquely identify an animatable property. + */ +@property (readonly, nonatomic, copy) NSString *name; + +/** + @abstract Block used to read values from a property into an array of floats. + */ +@property (readonly, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]); + +/** + @abstract Block used to write values from an array of floats into a property. + */ +@property (readonly, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]); + +/** + @abstract The threshold value used when determining completion of dynamics simulations. + */ +@property (readonly, nonatomic, assign) CGFloat threshold; + +@end + +/** + @abstract A mutable animatable property intended for configuration. + */ +@interface POPMutableAnimatableProperty : POPAnimatableProperty + +/** + @abstract A read-write version of POPAnimatableProperty name property. + */ +@property (readwrite, nonatomic, copy) NSString *name; + +/** + @abstract A read-write version of POPAnimatableProperty readBlock property. + */ +@property (readwrite, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]); + +/** + @abstract A read-write version of POPAnimatableProperty writeBlock property. + */ +@property (readwrite, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]); + +/** + @abstract A read-write version of POPAnimatableProperty threshold property. + */ +@property (readwrite, nonatomic, assign) CGFloat threshold; + +@end + +/** + Common CALayer property names. + */ +extern NSString * const kPOPLayerBackgroundColor; +extern NSString * const kPOPLayerBounds; +extern NSString * const kPOPLayerCornerRadius; +extern NSString * const kPOPLayerBorderWidth; +extern NSString * const kPOPLayerBorderColor; +extern NSString * const kPOPLayerOpacity; +extern NSString * const kPOPLayerPosition; +extern NSString * const kPOPLayerPositionX; +extern NSString * const kPOPLayerPositionY; +extern NSString * const kPOPLayerRotation; +extern NSString * const kPOPLayerRotationX; +extern NSString * const kPOPLayerRotationY; +extern NSString * const kPOPLayerScaleX; +extern NSString * const kPOPLayerScaleXY; +extern NSString * const kPOPLayerScaleY; +extern NSString * const kPOPLayerSize; +extern NSString * const kPOPLayerSubscaleXY; +extern NSString * const kPOPLayerSubtranslationX; +extern NSString * const kPOPLayerSubtranslationXY; +extern NSString * const kPOPLayerSubtranslationY; +extern NSString * const kPOPLayerSubtranslationZ; +extern NSString * const kPOPLayerTranslationX; +extern NSString * const kPOPLayerTranslationXY; +extern NSString * const kPOPLayerTranslationY; +extern NSString * const kPOPLayerTranslationZ; +extern NSString * const kPOPLayerZPosition; +extern NSString * const kPOPLayerShadowColor; +extern NSString * const kPOPLayerShadowOffset; +extern NSString * const kPOPLayerShadowOpacity; +extern NSString * const kPOPLayerShadowRadius; + +/** + Common CAShapeLayer property names. + */ +extern NSString * const kPOPShapeLayerStrokeStart; +extern NSString * const kPOPShapeLayerStrokeEnd; +extern NSString * const kPOPShapeLayerStrokeColor; +extern NSString * const kPOPShapeLayerFillColor; +extern NSString * const kPOPShapeLayerLineWidth; + +/** + Common NSLayoutConstraint property names. + */ +extern NSString * const kPOPLayoutConstraintConstant; + + +#if TARGET_OS_IPHONE + +/** + Common UIView property names. + */ +extern NSString * const kPOPViewAlpha; +extern NSString * const kPOPViewBackgroundColor; +extern NSString * const kPOPViewBounds; +extern NSString * const kPOPViewCenter; +extern NSString * const kPOPViewFrame; +extern NSString * const kPOPViewScaleX; +extern NSString * const kPOPViewScaleXY; +extern NSString * const kPOPViewScaleY; +extern NSString * const kPOPViewSize; +extern NSString * const kPOPViewTintColor; + +/** + Common UIScrollView property names. + */ +extern NSString * const kPOPScrollViewContentOffset; +extern NSString * const kPOPScrollViewContentSize; +extern NSString * const kPOPScrollViewZoomScale; +extern NSString * const kPOPScrollViewContentInset; + +/** + Common UITableView property names. + */ +extern NSString * const kPOPTableViewContentOffset; +extern NSString * const kPOPTableViewContentSize; + +/** + Common UICollectionView property names. + */ +extern NSString * const kPOPCollectionViewContentOffset; +extern NSString * const kPOPCollectionViewContentSize; + +/** + Common UINavigationBar property names. + */ +extern NSString * const kPOPNavigationBarBarTintColor; + +/** + Common UIToolbar property names. + */ +extern NSString * const kPOPToolbarBarTintColor; + +/** + Common UITabBar property names. + */ +extern NSString * const kPOPTabBarBarTintColor; + +/** + Common UILabel property names. + */ +extern NSString * const kPOPLabelTextColor; + +#else + +/** + Common NSView property names. + */ +extern NSString * const kPOPViewFrame; +extern NSString * const kPOPViewBounds; +extern NSString * const kPOPViewAlphaValue; +extern NSString * const kPOPViewFrameRotation; +extern NSString * const kPOPViewFrameCenterRotation; +extern NSString * const kPOPViewBoundsRotation; + +/** + Common NSWindow property names. + */ +extern NSString * const kPOPWindowFrame; +extern NSString * const kPOPWindowAlphaValue; +extern NSString * const kPOPWindowBackgroundColor; + +#endif + +#if SCENEKIT_SDK_AVAILABLE + +/** + Common SceneKit property names. + */ +extern NSString * const kPOPSCNNodePosition; +extern NSString * const kPOPSCNNodePositionX; +extern NSString * const kPOPSCNNodePositionY; +extern NSString * const kPOPSCNNodePositionZ; +extern NSString * const kPOPSCNNodeTranslation; +extern NSString * const kPOPSCNNodeTranslationX; +extern NSString * const kPOPSCNNodeTranslationY; +extern NSString * const kPOPSCNNodeTranslationZ; +extern NSString * const kPOPSCNNodeRotation; +extern NSString * const kPOPSCNNodeRotationX; +extern NSString * const kPOPSCNNodeRotationY; +extern NSString * const kPOPSCNNodeRotationZ; +extern NSString * const kPOPSCNNodeRotationW; +extern NSString * const kPOPSCNNodeEulerAngles; +extern NSString * const kPOPSCNNodeEulerAnglesX; +extern NSString * const kPOPSCNNodeEulerAnglesY; +extern NSString * const kPOPSCNNodeEulerAnglesZ; +extern NSString * const kPOPSCNNodeOrientation; +extern NSString * const kPOPSCNNodeOrientationX; +extern NSString * const kPOPSCNNodeOrientationY; +extern NSString * const kPOPSCNNodeOrientationZ; +extern NSString * const kPOPSCNNodeOrientationW; +extern NSString * const kPOPSCNNodeScale; +extern NSString * const kPOPSCNNodeScaleX; +extern NSString * const kPOPSCNNodeScaleY; +extern NSString * const kPOPSCNNodeScaleZ; +extern NSString * const kPOPSCNNodeScaleXY; + +#endif diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.mm new file mode 100644 index 0000000..c8b3130 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimatableProperty.mm @@ -0,0 +1,1282 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimatableProperty.h" + +#import <QuartzCore/QuartzCore.h> + +#import "POPAnimationRuntime.h" +#import "POPCGUtils.h" +#import "POPDefines.h" +#import "POPLayerExtras.h" + +// common threshold definitions +static CGFloat const kPOPThresholdColor = 0.01; +static CGFloat const kPOPThresholdPoint = 1.0; +static CGFloat const kPOPThresholdOpacity = 0.01; +static CGFloat const kPOPThresholdScale = 0.005; +static CGFloat const kPOPThresholdRotation = 0.01; +static CGFloat const kPOPThresholdRadius = 0.01; + +#pragma mark - Static + +// CALayer +NSString * const kPOPLayerBackgroundColor = @"backgroundColor"; +NSString * const kPOPLayerBounds = @"bounds"; +NSString * const kPOPLayerCornerRadius = @"cornerRadius"; +NSString * const kPOPLayerBorderWidth = @"borderWidth"; +NSString * const kPOPLayerBorderColor = @"borderColor"; +NSString * const kPOPLayerOpacity = @"opacity"; +NSString * const kPOPLayerPosition = @"position"; +NSString * const kPOPLayerPositionX = @"positionX"; +NSString * const kPOPLayerPositionY = @"positionY"; +NSString * const kPOPLayerRotation = @"rotation"; +NSString * const kPOPLayerRotationX = @"rotationX"; +NSString * const kPOPLayerRotationY = @"rotationY"; +NSString * const kPOPLayerScaleX = @"scaleX"; +NSString * const kPOPLayerScaleXY = @"scaleXY"; +NSString * const kPOPLayerScaleY = @"scaleY"; +NSString * const kPOPLayerSize = @"size"; +NSString * const kPOPLayerSubscaleXY = @"subscaleXY"; +NSString * const kPOPLayerSubtranslationX = @"subtranslationX"; +NSString * const kPOPLayerSubtranslationXY = @"subtranslationXY"; +NSString * const kPOPLayerSubtranslationY = @"subtranslationY"; +NSString * const kPOPLayerSubtranslationZ = @"subtranslationZ"; +NSString * const kPOPLayerTranslationX = @"translationX"; +NSString * const kPOPLayerTranslationXY = @"translationXY"; +NSString * const kPOPLayerTranslationY = @"translationY"; +NSString * const kPOPLayerTranslationZ = @"translationZ"; +NSString * const kPOPLayerZPosition = @"zPosition"; +NSString * const kPOPLayerShadowColor = @"shadowColor"; +NSString * const kPOPLayerShadowOffset = @"shadowOffset"; +NSString * const kPOPLayerShadowOpacity = @"shadowOpacity"; +NSString * const kPOPLayerShadowRadius = @"shadowRadius"; + +// CAShapeLayer +NSString * const kPOPShapeLayerStrokeStart = @"shapeLayer.strokeStart"; +NSString * const kPOPShapeLayerStrokeEnd = @"shapeLayer.strokeEnd"; +NSString * const kPOPShapeLayerStrokeColor = @"shapeLayer.strokeColor"; +NSString * const kPOPShapeLayerFillColor = @"shapeLayer.fillColor"; +NSString * const kPOPShapeLayerLineWidth = @"shapeLayer.lineWidth"; + +// NSLayoutConstraint +NSString * const kPOPLayoutConstraintConstant = @"layoutConstraint.constant"; + +#if TARGET_OS_IPHONE + +// UIView +NSString * const kPOPViewAlpha = @"view.alpha"; +NSString * const kPOPViewBackgroundColor = @"view.backgroundColor"; +NSString * const kPOPViewBounds = kPOPLayerBounds; +NSString * const kPOPViewCenter = @"view.center"; +NSString * const kPOPViewFrame = @"view.frame"; +NSString * const kPOPViewScaleX = @"view.scaleX"; +NSString * const kPOPViewScaleXY = @"view.scaleXY"; +NSString * const kPOPViewScaleY = @"view.scaleY"; +NSString * const kPOPViewSize = kPOPLayerSize; +NSString * const kPOPViewTintColor = @"view.tintColor"; + +// UIScrollView +NSString * const kPOPScrollViewContentOffset = @"scrollView.contentOffset"; +NSString * const kPOPScrollViewContentSize = @"scrollView.contentSize"; +NSString * const kPOPScrollViewZoomScale = @"scrollView.zoomScale"; +NSString * const kPOPScrollViewContentInset = @"scrollView.contentInset"; + +// UITableView +NSString * const kPOPTableViewContentOffset = kPOPScrollViewContentOffset; +NSString * const kPOPTableViewContentSize = kPOPScrollViewContentSize; + +// UICollectionView +NSString * const kPOPCollectionViewContentOffset = kPOPScrollViewContentOffset; +NSString * const kPOPCollectionViewContentSize = kPOPScrollViewContentSize; + +// UINavigationBar +NSString * const kPOPNavigationBarBarTintColor = @"navigationBar.barTintColor"; + +// UIToolbar +NSString * const kPOPToolbarBarTintColor = kPOPNavigationBarBarTintColor; + +// UITabBar +NSString * const kPOPTabBarBarTintColor = kPOPNavigationBarBarTintColor; + +// UILabel +NSString * const kPOPLabelTextColor = @"label.textColor"; + +#else + +// NSView +NSString * const kPOPViewFrame = @"view.frame"; +NSString * const kPOPViewBounds = @"view.bounds"; +NSString * const kPOPViewAlphaValue = @"view.alphaValue"; +NSString * const kPOPViewFrameRotation = @"view.frameRotation"; +NSString * const kPOPViewFrameCenterRotation = @"view.frameCenterRotation"; +NSString * const kPOPViewBoundsRotation = @"view.boundsRotation"; + +// NSWindow +NSString * const kPOPWindowFrame = @"window.frame"; +NSString * const kPOPWindowAlphaValue = @"window.alphaValue"; +NSString * const kPOPWindowBackgroundColor = @"window.backgroundColor"; + +#endif + +#if SCENEKIT_SDK_AVAILABLE + +// SceneKit +NSString * const kPOPSCNNodePosition = @"scnode.position"; +NSString * const kPOPSCNNodePositionX = @"scnnode.position.x"; +NSString * const kPOPSCNNodePositionY = @"scnnode.position.y"; +NSString * const kPOPSCNNodePositionZ = @"scnnode.position.z"; +NSString * const kPOPSCNNodeTranslation = @"scnnode.translation"; +NSString * const kPOPSCNNodeTranslationX = @"scnnode.translation.x"; +NSString * const kPOPSCNNodeTranslationY = @"scnnode.translation.y"; +NSString * const kPOPSCNNodeTranslationZ = @"scnnode.translation.z"; +NSString * const kPOPSCNNodeRotation = @"scnnode.rotation"; +NSString * const kPOPSCNNodeRotationX = @"scnnode.rotation.x"; +NSString * const kPOPSCNNodeRotationY = @"scnnode.rotation.y"; +NSString * const kPOPSCNNodeRotationZ = @"scnnode.rotation.z"; +NSString * const kPOPSCNNodeRotationW = @"scnnode.rotation.w"; +NSString * const kPOPSCNNodeEulerAngles = @"scnnode.eulerAngles"; +NSString * const kPOPSCNNodeEulerAnglesX = @"scnnode.eulerAngles.x"; +NSString * const kPOPSCNNodeEulerAnglesY = @"scnnode.eulerAngles.y"; +NSString * const kPOPSCNNodeEulerAnglesZ = @"scnnode.eulerAngles.z"; +NSString * const kPOPSCNNodeOrientation = @"scnnode.orientation"; +NSString * const kPOPSCNNodeOrientationX = @"scnnode.orientation.x"; +NSString * const kPOPSCNNodeOrientationY = @"scnnode.orientation.y"; +NSString * const kPOPSCNNodeOrientationZ = @"scnnode.orientation.z"; +NSString * const kPOPSCNNodeOrientationW = @"scnnode.orientation.w"; +NSString * const kPOPSCNNodeScale = @"scnnode.scale"; +NSString * const kPOPSCNNodeScaleX = @"scnnode.scale.x"; +NSString * const kPOPSCNNodeScaleY = @"scnnode.scale.y"; +NSString * const kPOPSCNNodeScaleZ = @"scnnode.scale.z"; +NSString * const kPOPSCNNodeScaleXY = @"scnnode.scale.xy"; + +#endif + +/** + State structure internal to static animatable property. + */ +typedef struct +{ + NSString *name; + pop_animatable_read_block readBlock; + pop_animatable_write_block writeBlock; + CGFloat threshold; +} _POPStaticAnimatablePropertyState; +typedef _POPStaticAnimatablePropertyState POPStaticAnimatablePropertyState; + +static POPStaticAnimatablePropertyState _staticStates[] = +{ + /* CALayer */ + + {kPOPLayerBackgroundColor, + ^(CALayer *obj, CGFloat values[]) { + POPCGColorGetRGBAComponents(obj.backgroundColor, values); + }, + ^(CALayer *obj, const CGFloat values[]) { + CGColorRef color = POPCGColorRGBACreate(values); + [obj setBackgroundColor:color]; + CGColorRelease(color); + }, + kPOPThresholdColor + }, + + {kPOPLayerBounds, + ^(CALayer *obj, CGFloat values[]) { + values_from_rect(values, [obj bounds]); + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setBounds:values_to_rect(values)]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerCornerRadius, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj cornerRadius]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setCornerRadius:values[0]]; + }, + kPOPThresholdRadius + }, + + {kPOPLayerBorderWidth, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj borderWidth]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setBorderWidth:values[0]]; + }, + 0.01 + }, + + {kPOPLayerBorderColor, + ^(CALayer *obj, CGFloat values[]) { + POPCGColorGetRGBAComponents(obj.borderColor, values); + }, + ^(CALayer *obj, const CGFloat values[]) { + CGColorRef color = POPCGColorRGBACreate(values); + [obj setBorderColor:color]; + CGColorRelease(color); + }, + kPOPThresholdColor + }, + + {kPOPLayerPosition, + ^(CALayer *obj, CGFloat values[]) { + values_from_point(values, [(CALayer *)obj position]); + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setPosition:values_to_point(values)]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerPositionX, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [(CALayer *)obj position].x; + }, + ^(CALayer *obj, const CGFloat values[]) { + CGPoint p = [(CALayer *)obj position]; + p.x = values[0]; + [obj setPosition:p]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerPositionY, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [(CALayer *)obj position].y; + }, + ^(CALayer *obj, const CGFloat values[]) { + CGPoint p = [(CALayer *)obj position]; + p.y = values[0]; + [obj setPosition:p]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerOpacity, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj opacity]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setOpacity:((float)values[0])]; + }, + kPOPThresholdOpacity + }, + + {kPOPLayerScaleX, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetScaleX(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetScaleX(obj, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPLayerScaleY, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetScaleY(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetScaleY(obj, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPLayerScaleXY, + ^(CALayer *obj, CGFloat values[]) { + values_from_point(values, POPLayerGetScaleXY(obj)); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetScaleXY(obj, values_to_point(values)); + }, + kPOPThresholdScale + }, + + {kPOPLayerSubscaleXY, + ^(CALayer *obj, CGFloat values[]) { + values_from_point(values, POPLayerGetSubScaleXY(obj)); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetSubScaleXY(obj, values_to_point(values)); + }, + kPOPThresholdScale + }, + + {kPOPLayerTranslationX, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetTranslationX(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetTranslationX(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerTranslationY, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetTranslationY(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetTranslationY(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerTranslationZ, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetTranslationZ(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetTranslationZ(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerTranslationXY, + ^(CALayer *obj, CGFloat values[]) { + values_from_point(values, POPLayerGetTranslationXY(obj)); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetTranslationXY(obj, values_to_point(values)); + }, + kPOPThresholdPoint + }, + + {kPOPLayerSubtranslationX, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetSubTranslationX(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetSubTranslationX(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerSubtranslationY, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetSubTranslationY(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetSubTranslationY(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerSubtranslationZ, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetSubTranslationZ(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetSubTranslationZ(obj, values[0]); + }, + kPOPThresholdPoint + }, + + {kPOPLayerSubtranslationXY, + ^(CALayer *obj, CGFloat values[]) { + values_from_point(values, POPLayerGetSubTranslationXY(obj)); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetSubTranslationXY(obj, values_to_point(values)); + }, + kPOPThresholdPoint + }, + + {kPOPLayerZPosition, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj zPosition]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setZPosition:values[0]]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerSize, + ^(CALayer *obj, CGFloat values[]) { + values_from_size(values, [obj bounds].size); + }, + ^(CALayer *obj, const CGFloat values[]) { + CGSize size = values_to_size(values); + if (size.width < 0. || size.height < 0.) + return; + + CGRect b = [obj bounds]; + b.size = size; + [obj setBounds:b]; + }, + kPOPThresholdPoint + }, + + {kPOPLayerRotation, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetRotation(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetRotation(obj, values[0]); + }, + kPOPThresholdRotation + }, + + {kPOPLayerRotationY, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetRotationY(obj); + }, + ^(id obj, const CGFloat values[]) { + POPLayerSetRotationY(obj, values[0]); + }, + kPOPThresholdRotation + }, + + {kPOPLayerRotationX, + ^(CALayer *obj, CGFloat values[]) { + values[0] = POPLayerGetRotationX(obj); + }, + ^(CALayer *obj, const CGFloat values[]) { + POPLayerSetRotationX(obj, values[0]); + }, + kPOPThresholdRotation + }, + + {kPOPLayerShadowColor, + ^(CALayer *obj, CGFloat values[]) { + POPCGColorGetRGBAComponents(obj.shadowColor, values); + }, + ^(CALayer *obj, const CGFloat values[]) { + CGColorRef color = POPCGColorRGBACreate(values); + [obj setShadowColor:color]; + CGColorRelease(color); + }, + 0.01 + }, + + {kPOPLayerShadowOffset, + ^(CALayer *obj, CGFloat values[]) { + values_from_size(values, [obj shadowOffset]); + }, + ^(CALayer *obj, const CGFloat values[]) { + CGSize size = values_to_size(values); + [obj setShadowOffset:size]; + }, + 0.01 + }, + + {kPOPLayerShadowOpacity, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj shadowOpacity]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setShadowOpacity:values[0]]; + }, + kPOPThresholdOpacity + }, + + {kPOPLayerShadowRadius, + ^(CALayer *obj, CGFloat values[]) { + values[0] = [obj shadowRadius]; + }, + ^(CALayer *obj, const CGFloat values[]) { + [obj setShadowRadius:values[0]]; + }, + kPOPThresholdRadius + }, + + /* CAShapeLayer */ + + {kPOPShapeLayerStrokeStart, + ^(CAShapeLayer *obj, CGFloat values[]) { + values[0] = obj.strokeStart; + }, + ^(CAShapeLayer *obj, const CGFloat values[]) { + obj.strokeStart = values[0]; + }, + 0.01 + }, + + {kPOPShapeLayerStrokeEnd, + ^(CAShapeLayer *obj, CGFloat values[]) { + values[0] = obj.strokeEnd; + }, + ^(CAShapeLayer *obj, const CGFloat values[]) { + obj.strokeEnd = values[0]; + }, + 0.01 + }, + + {kPOPShapeLayerStrokeColor, + ^(CAShapeLayer *obj, CGFloat values[]) { + POPCGColorGetRGBAComponents(obj.strokeColor, values); + }, + ^(CAShapeLayer *obj, const CGFloat values[]) { + CGColorRef color = POPCGColorRGBACreate(values); + [obj setStrokeColor:color]; + CGColorRelease(color); + }, + kPOPThresholdColor + }, + + {kPOPShapeLayerFillColor, + ^(CAShapeLayer *obj, CGFloat values[]) { + POPCGColorGetRGBAComponents(obj.fillColor, values); + }, + ^(CAShapeLayer *obj, const CGFloat values[]) { + CGColorRef color = POPCGColorRGBACreate(values); + [obj setFillColor:color]; + CGColorRelease(color); + }, + kPOPThresholdColor + }, + + {kPOPShapeLayerLineWidth, + ^(CAShapeLayer *obj, CGFloat values[]) { + values[0] = obj.lineWidth; + }, + ^(CAShapeLayer *obj, const CGFloat values[]) { + obj.lineWidth = values[0]; + }, + 0.01 + }, + + {kPOPLayoutConstraintConstant, + ^(NSLayoutConstraint *obj, CGFloat values[]) { + values[0] = obj.constant; + }, + ^(NSLayoutConstraint *obj, const CGFloat values[]) { + obj.constant = values[0]; + }, + 0.01 + }, + +#if TARGET_OS_IPHONE + + /* UIView */ + + {kPOPViewAlpha, + ^(UIView *obj, CGFloat values[]) { + values[0] = obj.alpha; + }, + ^(UIView *obj, const CGFloat values[]) { + obj.alpha = values[0]; + }, + kPOPThresholdOpacity + }, + + {kPOPViewBackgroundColor, + ^(UIView *obj, CGFloat values[]) { + POPUIColorGetRGBAComponents(obj.backgroundColor, values); + }, + ^(UIView *obj, const CGFloat values[]) { + obj.backgroundColor = POPUIColorRGBACreate(values); + }, + kPOPThresholdColor + }, + + {kPOPViewCenter, + ^(UIView *obj, CGFloat values[]) { + values_from_point(values, obj.center); + }, + ^(UIView *obj, const CGFloat values[]) { + obj.center = values_to_point(values); + }, + kPOPThresholdPoint + }, + + {kPOPViewFrame, + ^(UIView *obj, CGFloat values[]) { + values_from_rect(values, obj.frame); + }, + ^(UIView *obj, const CGFloat values[]) { + obj.frame = values_to_rect(values); + }, + kPOPThresholdPoint + }, + + {kPOPViewScaleX, + ^(UIView *obj, CGFloat values[]) { + values[0] = POPLayerGetScaleX(obj.layer); + }, + ^(UIView *obj, const CGFloat values[]) { + POPLayerSetScaleX(obj.layer, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPViewScaleY, + ^(UIView *obj, CGFloat values[]) { + values[0] = POPLayerGetScaleY(obj.layer); + }, + ^(UIView *obj, const CGFloat values[]) { + POPLayerSetScaleY(obj.layer, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPViewScaleXY, + ^(UIView *obj, CGFloat values[]) { + values_from_point(values, POPLayerGetScaleXY(obj.layer)); + }, + ^(UIView *obj, const CGFloat values[]) { + POPLayerSetScaleXY(obj.layer, values_to_point(values)); + }, + kPOPThresholdScale + }, + + {kPOPViewTintColor, + ^(UIView *obj, CGFloat values[]) { + POPUIColorGetRGBAComponents(obj.tintColor, values); + }, + ^(UIView *obj, const CGFloat values[]) { + obj.tintColor = POPUIColorRGBACreate(values); + }, + kPOPThresholdColor + }, + + /* UIScrollView */ + + {kPOPScrollViewContentOffset, + ^(UIScrollView *obj, CGFloat values[]) { + values_from_point(values, obj.contentOffset); + }, + ^(UIScrollView *obj, const CGFloat values[]) { + [obj setContentOffset:values_to_point(values) animated:NO]; + }, + kPOPThresholdPoint + }, + + {kPOPScrollViewContentSize, + ^(UIScrollView *obj, CGFloat values[]) { + values_from_size(values, obj.contentSize); + }, + ^(UIScrollView *obj, const CGFloat values[]) { + obj.contentSize = values_to_size(values); + }, + kPOPThresholdPoint + }, + + {kPOPScrollViewZoomScale, + ^(UIScrollView *obj, CGFloat values[]) { + values[0]=obj.zoomScale; + }, + ^(UIScrollView *obj, const CGFloat values[]) { + obj.zoomScale=values[0]; + }, + kPOPThresholdScale + }, + + {kPOPScrollViewContentInset, + ^(UIScrollView *obj, CGFloat values[]) { + values[0] = obj.contentInset.top; + values[1] = obj.contentInset.left; + values[2] = obj.contentInset.bottom; + values[3] = obj.contentInset.right; + }, + ^(UIScrollView *obj, const CGFloat values[]) { + obj.contentInset = values_to_edge_insets(values); + }, + kPOPThresholdPoint + }, + + /* UINavigationBar */ + + {kPOPNavigationBarBarTintColor, + ^(UINavigationBar *obj, CGFloat values[]) { + POPUIColorGetRGBAComponents(obj.barTintColor, values); + }, + ^(UINavigationBar *obj, const CGFloat values[]) { + obj.barTintColor = POPUIColorRGBACreate(values); + }, + kPOPThresholdColor + }, + + /* UILabel */ + + {kPOPLabelTextColor, + ^(UILabel *obj, CGFloat values[]) { + POPUIColorGetRGBAComponents(obj.textColor, values); + }, + ^(UILabel *obj, const CGFloat values[]) { + obj.textColor = POPUIColorRGBACreate(values); + }, + kPOPThresholdColor + }, + +#else + + /* NSView */ + + {kPOPViewFrame, + ^(NSView *obj, CGFloat values[]) { + values_from_rect(values, NSRectToCGRect(obj.frame)); + }, + ^(NSView *obj, const CGFloat values[]) { + obj.frame = NSRectFromCGRect(values_to_rect(values)); + }, + kPOPThresholdPoint + }, + + {kPOPViewBounds, + ^(NSView *obj, CGFloat values[]) { + values_from_rect(values, NSRectToCGRect(obj.frame)); + }, + ^(NSView *obj, const CGFloat values[]) { + obj.bounds = NSRectFromCGRect(values_to_rect(values)); + }, + kPOPThresholdPoint + }, + + {kPOPViewAlphaValue, + ^(NSView *obj, CGFloat values[]) { + values[0] = obj.alphaValue; + }, + ^(NSView *obj, const CGFloat values[]) { + obj.alphaValue = values[0]; + }, + kPOPThresholdOpacity + }, + + {kPOPViewFrameRotation, + ^(NSView *obj, CGFloat values[]) { + values[0] = obj.frameRotation; + }, + ^(NSView *obj, const CGFloat values[]) { + obj.frameRotation = values[0]; + }, + kPOPThresholdRotation + }, + + {kPOPViewFrameCenterRotation, + ^(NSView *obj, CGFloat values[]) { + values[0] = obj.frameCenterRotation; + }, + ^(NSView *obj, const CGFloat values[]) { + obj.frameCenterRotation = values[0]; + }, + kPOPThresholdRotation + }, + + {kPOPViewBoundsRotation, + ^(NSView *obj, CGFloat values[]) { + values[0] = obj.boundsRotation; + }, + ^(NSView *obj, const CGFloat values[]) { + obj.boundsRotation = values[0]; + }, + kPOPThresholdRotation + }, + + /* NSWindow */ + + {kPOPWindowFrame, + ^(NSWindow *obj, CGFloat values[]) { + values_from_rect(values, NSRectToCGRect(obj.frame)); + }, + ^(NSWindow *obj, const CGFloat values[]) { + [obj setFrame:NSRectFromCGRect(values_to_rect(values)) display:YES]; + }, + kPOPThresholdPoint + }, + + {kPOPWindowAlphaValue, + ^(NSWindow *obj, CGFloat values[]) { + values[0] = obj.alphaValue; + }, + ^(NSWindow *obj, const CGFloat values[]) { + obj.alphaValue = values[0]; + }, + kPOPThresholdOpacity + }, + + {kPOPWindowBackgroundColor, + ^(NSWindow *obj, CGFloat values[]) { + POPNSColorGetRGBAComponents(obj.backgroundColor, values); + }, + ^(NSWindow *obj, const CGFloat values[]) { + obj.backgroundColor = POPNSColorRGBACreate(values); + }, + kPOPThresholdColor + }, + +#endif + +#if SCENEKIT_SDK_AVAILABLE + + /* SceneKit */ + + {kPOPSCNNodePosition, + ^(SCNNode *obj, CGFloat values[]) { + values_from_vec3(values, obj.position); + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.position = values_to_vec3(values); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodePositionX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.position.x; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.position = SCNVector3Make(values[0], obj.position.y, obj.position.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodePositionY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.position.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.position = SCNVector3Make(obj.position.x, values[0], obj.position.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodePositionZ, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.position.z; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.position = SCNVector3Make(obj.position.x, obj.position.y, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeTranslation, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.transform.m41; + values[1] = obj.transform.m42; + values[2] = obj.transform.m43; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.transform = SCNMatrix4MakeTranslation(values[0], values[1], values[2]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeTranslationX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.transform.m41; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.transform = SCNMatrix4MakeTranslation(values[0], obj.transform.m42, obj.transform.m43); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeTranslationY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.transform.m42; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.transform = SCNMatrix4MakeTranslation(obj.transform.m41, values[0], obj.transform.m43); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeTranslationY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.transform.m43; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.transform = SCNMatrix4MakeTranslation(obj.transform.m41, obj.transform.m42, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeRotation, + ^(SCNNode *obj, CGFloat values[]) { + values_from_vec4(values, obj.rotation); + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.rotation = values_to_vec4(values); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeRotationX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.rotation.x; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.rotation = SCNVector4Make(1.0, obj.rotation.y, obj.rotation.z, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeRotationY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.rotation.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.rotation = SCNVector4Make(obj.rotation.x, 1.0, obj.rotation.z, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeRotationZ, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.rotation.z; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.rotation = SCNVector4Make(obj.rotation.x, obj.rotation.y, 1.0, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeRotationW, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.rotation.w; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.rotation = SCNVector4Make(obj.rotation.x, obj.rotation.y, obj.rotation.z, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeEulerAngles, + ^(SCNNode *obj, CGFloat values[]) { + values_from_vec3(values, obj.eulerAngles); + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.eulerAngles = values_to_vec3(values); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeEulerAnglesX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.eulerAngles.x; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.eulerAngles = SCNVector3Make(values[0], obj.eulerAngles.y, obj.eulerAngles.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeEulerAnglesY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.eulerAngles.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.eulerAngles = SCNVector3Make(obj.eulerAngles.x, values[0], obj.eulerAngles.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeEulerAnglesZ, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.eulerAngles.z; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.eulerAngles = SCNVector3Make(obj.eulerAngles.x, obj.eulerAngles.y, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeOrientation, + ^(SCNNode *obj, CGFloat values[]) { + values_from_vec4(values, obj.orientation); + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.orientation = values_to_vec4(values); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeOrientationX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.orientation.x; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.orientation = SCNVector4Make(values[0], obj.orientation.y, obj.orientation.z, obj.orientation.w); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeOrientationY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.orientation.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.orientation = SCNVector4Make(obj.orientation.x, values[0], obj.orientation.z, obj.orientation.w); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeOrientationZ, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.orientation.z; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.orientation = SCNVector4Make(obj.orientation.x, obj.orientation.y, values[0], obj.orientation.w); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeOrientationW, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.orientation.w; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.orientation = SCNVector4Make(obj.orientation.x, obj.orientation.y, obj.orientation.z, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeScale, + ^(SCNNode *obj, CGFloat values[]) { + values_from_vec3(values, obj.scale); + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.scale = values_to_vec3(values); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeScaleX, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.scale.x; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.scale = SCNVector3Make(values[0], obj.scale.y, obj.scale.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeScaleY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.scale.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.position = SCNVector3Make(obj.scale.x, values[0], obj.scale.z); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeScaleZ, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.scale.z; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.scale = SCNVector3Make(obj.scale.x, obj.scale.y, values[0]); + }, + kPOPThresholdScale + }, + + {kPOPSCNNodeScaleXY, + ^(SCNNode *obj, CGFloat values[]) { + values[0] = obj.scale.x; + values[1] = obj.scale.y; + }, + ^(SCNNode *obj, const CGFloat values[]) { + obj.scale = SCNVector3Make(values[0], values[1], obj.scale.z); + }, + kPOPThresholdScale + }, + +#endif + +}; + +static NSUInteger staticIndexWithName(NSString *aName) +{ + NSUInteger idx = 0; + + while (idx < POP_ARRAY_COUNT(_staticStates)) { + if ([_staticStates[idx].name isEqualToString:aName]) + return idx; + idx++; + } + + return NSNotFound; +} + +/** + Concrete static property class. + */ +@interface POPStaticAnimatableProperty : POPAnimatableProperty +{ +@public + POPStaticAnimatablePropertyState *_state; +} +@end + +@implementation POPStaticAnimatableProperty + +- (NSString *)name +{ + return _state->name; +} + +- (pop_animatable_read_block)readBlock +{ + return _state->readBlock; +} + +- (pop_animatable_write_block)writeBlock +{ + return _state->writeBlock; +} + +- (CGFloat)threshold +{ + return _state->threshold; +} + +@end + +#pragma mark - Concrete + +/** + Concrete immutable property class. + */ +@interface POPConcreteAnimatableProperty : POPAnimatableProperty +- (instancetype)initWithName:(NSString *)name readBlock:(pop_animatable_read_block)read writeBlock:(pop_animatable_write_block)write threshold:(CGFloat)threshold; +@end + +@implementation POPConcreteAnimatableProperty + +// default synthesis +@synthesize name, readBlock, writeBlock, threshold; + +- (instancetype)initWithName:(NSString *)aName readBlock:(pop_animatable_read_block)aReadBlock writeBlock:(pop_animatable_write_block)aWriteBlock threshold:(CGFloat)aThreshold +{ + self = [super init]; + if (nil != self) { + name = [aName copy]; + readBlock = [aReadBlock copy]; + writeBlock = [aWriteBlock copy]; + threshold = aThreshold; + } + return self; +} +@end + +#pragma mark - Mutable + +@implementation POPMutableAnimatableProperty + +// default synthesis +@synthesize name, readBlock, writeBlock, threshold; + +@end + +#pragma mark - Cluster + +/** + Singleton placeholder property class to support class cluster. + */ +@interface POPPlaceholderAnimatableProperty : POPAnimatableProperty + +@end + +@implementation POPPlaceholderAnimatableProperty + +// default synthesis +@synthesize name, readBlock, writeBlock, threshold; + +@end + +/** + Cluster class. + */ +@implementation POPAnimatableProperty + +// avoid creating backing ivars +@dynamic name, readBlock, writeBlock, threshold; + +static POPAnimatableProperty *placeholder = nil; + ++ (void)initialize +{ + if (self == [POPAnimatableProperty class]) { + placeholder = [POPPlaceholderAnimatableProperty alloc]; + } +} + ++ (id)allocWithZone:(struct _NSZone *)zone +{ + if (self == [POPAnimatableProperty class]) { + if (nil == placeholder) { + placeholder = [super allocWithZone:zone]; + } + return placeholder; + } + return [super allocWithZone:zone]; +} + +- (id)copyWithZone:(NSZone *)zone +{ + if ([self isKindOfClass:[POPMutableAnimatableProperty class]]) { + POPConcreteAnimatableProperty *copyProperty = [[POPConcreteAnimatableProperty alloc] initWithName:self.name readBlock:self.readBlock writeBlock:self.writeBlock threshold:self.threshold]; + return copyProperty; + } else { + return self; + } +} + +- (id)mutableCopyWithZone:(NSZone *)zone +{ + POPMutableAnimatableProperty *copyProperty = [[POPMutableAnimatableProperty alloc] init]; + copyProperty.name = self.name; + copyProperty.readBlock = self.readBlock; + copyProperty.writeBlock = self.writeBlock; + copyProperty.threshold = self.threshold; + return copyProperty; +} + ++ (id)propertyWithName:(NSString *)aName +{ + return [self propertyWithName:aName initializer:NULL]; +} + ++ (id)propertyWithName:(NSString *)aName initializer:(void (^)(POPMutableAnimatableProperty *prop))aBlock +{ + POPAnimatableProperty *prop = nil; + + static NSMutableDictionary *_propertyDict = nil; + if (nil == _propertyDict) { + _propertyDict = [[NSMutableDictionary alloc] initWithCapacity:10]; + } + + prop = _propertyDict[aName]; + if (nil != prop) { + return prop; + } + + NSUInteger staticIdx = staticIndexWithName(aName); + + if (NSNotFound != staticIdx) { + POPStaticAnimatableProperty *staticProp = [[POPStaticAnimatableProperty alloc] init]; + staticProp->_state = &_staticStates[staticIdx]; + _propertyDict[aName] = staticProp; + prop = staticProp; + } else if (NULL != aBlock) { + POPMutableAnimatableProperty *mutableProp = [[POPMutableAnimatableProperty alloc] init]; + mutableProp.name = aName; + mutableProp.threshold = 1.0; + aBlock(mutableProp); + prop = [mutableProp copy]; + } + + return prop; +} + +- (NSString *)description +{ + NSMutableString *s = [NSMutableString stringWithFormat:@"%@ name:%@ threshold:%f", super.description, self.name, self.threshold]; + return s; +} + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPAnimation.h new file mode 100644 index 0000000..3c710f2 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimation.h @@ -0,0 +1,188 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/NSObject.h> + +#import <pop/POPAnimationTracer.h> +#import <pop/POPGeometry.h> + +@class CAMediaTimingFunction; + +/** + @abstract The abstract animation base class. + @discussion Instantiate and use one of the concrete animation subclasses. + */ +@interface POPAnimation : NSObject + +/** + @abstract The name of the animation. + @discussion Optional property to help identify the animation. + */ +@property (copy, nonatomic) NSString *name; + +/** + @abstract The beginTime of the animation in media time. + @discussion Defaults to 0 and starts immediately. + */ +@property (assign, nonatomic) CFTimeInterval beginTime; + +/** + @abstract The animation delegate. + @discussion See {@ref POPAnimationDelegate} for details. + */ +@property (weak, nonatomic) id delegate; + +/** + @abstract The animation tracer. + @discussion Returns the existing tracer, creating one if needed. Call start/stop on the tracer to toggle event collection. + */ +@property (readonly, nonatomic) POPAnimationTracer *tracer; + +/** + @abstract Optional block called on animation start. + */ +@property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim); + +/** + @abstract Optional block called when value meets or exceeds to value. + */ +@property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim); + +/** + @abstract Optional block called on animation completion. + */ +@property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished); + +/** + @abstract Optional block called each frame animation is applied. + */ +@property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim); + +/** + @abstract Flag indicating whether animation should be removed on completion. + @discussion Setting to NO can facilitate animation reuse. Defaults to YES. + */ +@property (assign, nonatomic) BOOL removedOnCompletion; + +/** + @abstract Flag indicating whether animation is paused. + @discussion A paused animation is excluded from the list of active animations. On initial creation, defaults to YES. On animation addition, the animation is implicity unpaused. On animation completion, the animation is implicity paused including for animations with removedOnCompletion set to NO. + */ +@property (assign, nonatomic, getter = isPaused) BOOL paused; + +/** + @abstract Flag indicating whether animation autoreverses. + @discussion An animation that autoreverses will have twice the duration before it is considered finished. It will animate to the toValue, stop, then animate back to the original fromValue. The delegate methods are called as follows: + + 1) animationDidStart: is called at the beginning, as usual, and then after each toValue is reached and the autoreverse is going to start. + 2) animationDidReachToValue: is called every time the toValue is reached. The toValue is swapped with the fromValue at the end of each animation segment. This means that with autoreverses set to YES, the animationDidReachToValue: delegate method will be called a minimum of twice. + 3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete. + */ +@property (assign, nonatomic) BOOL autoreverses; + +/** + @abstract The number of times to repeat the animation. + @discussion A repeatCount of 0 or 1 means that the animation will not repeat, just like Core Animation. A repeatCount of 2 or greater means that the animation will run that many times before stopping. The delegate methods are called as follows: + + 1) animationDidStart: is called at the beginning of each animation repeat. + 2) animationDidReachToValue: is called every time the toValue is reached. + 3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete. + +When combined with the autoreverses property, a singular animation is effectively twice as long. + */ +@property (assign, nonatomic) NSInteger repeatCount; + +/** + @abstract Repeat the animation forever. + @discussion This property will make the animation repeat forever. The value of the repeatCount property is undefined when this property is set. The finished parameter of the delegate callback animationDidStop:finished: will always be NO. + */ +@property (assign, nonatomic) BOOL repeatForever; + +@end + +/** + @abstract The animation delegate. + */ +@protocol POPAnimationDelegate <NSObject> +@optional + +/** + @abstract Called on animation start. + @param anim The relevant animation. + */ +- (void)pop_animationDidStart:(POPAnimation *)anim; + +/** + @abstract Called when value meets or exceeds to value. + @param anim The relevant animation. + */ +- (void)pop_animationDidReachToValue:(POPAnimation *)anim; + +/** + @abstract Called on animation stop. + @param anim The relevant animation. + @param finished Flag indicating finished state. Flag is true if the animation reached completion before being removed. + */ +- (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished; + +/** + @abstract Called each frame animation is applied. + @param anim The relevant animation. + */ +- (void)pop_animationDidApply:(POPAnimation *)anim; + +@end + + +@interface NSObject (POP) + +/** + @abstract Add an animation to the reciver. + @param anim The animation to add. + @param key The key used to identify the animation. + @discussion The 'key' may be any string such that only one animation per unique key is added per object. + */ +- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key; + +/** + @abstract Remove all animations attached to the receiver. + */ +- (void)pop_removeAllAnimations; + +/** + @abstract Remove any animation attached to the receiver for 'key'. + @param key The key used to identify the animation. + */ +- (void)pop_removeAnimationForKey:(NSString *)key; + +/** + @abstract Returns an array containing the keys of all animations currently attached to the receiver. + @param The order of keys reflects the order in which animations will be applied. + */ +- (NSArray *)pop_animationKeys; + +/** + @abstract Returns any animation attached to the receiver. + @param key The key used to identify the animation. + @returns The animation currently attached, or nil if no such animation exists. + */ +- (id)pop_animationForKey:(NSString *)key; + +@end + +/** + * This implementation of NSCopying does not do any copying of animation's state, but only configuration. + * i.e. you cannot copy an animation and expect to apply it to a view and have the copied animation pick up where the original left off. + * Two common uses of copying animations: + * * you need to apply the same animation to multiple different views. + * * you need to absolutely ensure that the the caller of your function cannot mutate the animation once it's been passed in. + */ +@interface POPAnimation (NSCopying) <NSCopying> + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimation.mm new file mode 100644 index 0000000..75bdeb1 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimation.mm @@ -0,0 +1,303 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationExtras.h" +#import "POPAnimationInternal.h" + +#import <objc/runtime.h> + +#import "POPAction.h" +#import "POPAnimationRuntime.h" +#import "POPAnimationTracerInternal.h" +#import "POPAnimatorPrivate.h" + +using namespace POP; + +#pragma mark - POPAnimation + +@implementation POPAnimation +@synthesize solver = _solver; +@synthesize currentValue = _currentValue; +@synthesize progressMarkers = _progressMarkers; + +#pragma mark - Lifecycle + +- (id)init +{ + [NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."]; + return nil; +} + +- (id)_init +{ + self = [super init]; + if (nil != self) { + [self _initState]; + } + return self; +} + +- (void)_initState +{ + _state = new POPAnimationState(self); +} + +- (void)dealloc +{ + if (_state) { + delete _state; + _state = NULL; + }; +} + +#pragma mark - Properties + +- (id)delegate +{ + return _state->delegate; +} + +- (void)setDelegate:(id)delegate +{ + _state->setDelegate(delegate); +} + +- (BOOL)isPaused +{ + return _state->paused; +} + +- (void)setPaused:(BOOL)paused +{ + _state->setPaused(paused ? true : false); +} + +- (NSInteger)repeatCount +{ + if (_state->autoreverses) { + return _state->repeatCount / 2; + } else { + return _state->repeatCount; + } +} + +- (void)setRepeatCount:(NSInteger)repeatCount +{ + if (repeatCount > 0) { + if (repeatCount > NSIntegerMax / 2) { + repeatCount = NSIntegerMax / 2; + } + + if (_state->autoreverses) { + _state->repeatCount = (repeatCount * 2); + } else { + _state->repeatCount = repeatCount; + } + } +} + +- (BOOL)autoreverses +{ + return _state->autoreverses; +} + +- (void)setAutoreverses:(BOOL)autoreverses +{ + _state->autoreverses = autoreverses; + if (autoreverses) { + if (_state->repeatCount == 0) { + [self setRepeatCount:1]; + } + } +} + +FB_PROPERTY_GET(POPAnimationState, type, POPAnimationType); +DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidStartBlock, setAnimationDidStartBlock:, POPAnimationDidStartBlock); +DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidReachToValueBlock, setAnimationDidReachToValueBlock:, POPAnimationDidReachToValueBlock); +DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, completionBlock, setCompletionBlock:, POPAnimationCompletionBlock); +DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidApplyBlock, setAnimationDidApplyBlock:, POPAnimationDidApplyBlock); +DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, name, setName:, NSString*); +DEFINE_RW_PROPERTY(POPAnimationState, beginTime, setBeginTime:, CFTimeInterval); +DEFINE_RW_FLAG(POPAnimationState, removedOnCompletion, removedOnCompletion, setRemovedOnCompletion:); +DEFINE_RW_FLAG(POPAnimationState, repeatForever, repeatForever, setRepeatForever:); + +- (id)valueForUndefinedKey:(NSString *)key +{ + return _state->dict[key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key +{ + if (!value) { + [_state->dict removeObjectForKey:key]; + } else { + if (!_state->dict) + _state->dict = [[NSMutableDictionary alloc] init]; + _state->dict[key] = value; + } +} + +- (POPAnimationTracer *)tracer +{ + if (!_state->tracer) { + _state->tracer = [[POPAnimationTracer alloc] initWithAnimation:self]; + } + return _state->tracer; +} + +- (NSString *)description +{ + NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self]; + [self _appendDescription:s debug:NO]; + [s appendString:@">"]; + return s; +} + +- (NSString *)debugDescription +{ + NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self]; + [self _appendDescription:s debug:YES]; + [s appendString:@">"]; + return s; +} + +#pragma mark - Utility + +POPAnimationState *POPAnimationGetState(POPAnimation *a) +{ + return a->_state; +} + +- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime +{ + return YES; +} + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + if (_state->name) + [s appendFormat:@"; name = %@", _state->name]; + + if (!self.removedOnCompletion) + [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)]; + + if (debug) { + if (_state->active) + [s appendFormat:@"; active = %@", POPStringFromBOOL(_state->active)]; + + if (_state->paused) + [s appendFormat:@"; paused = %@", POPStringFromBOOL(_state->paused)]; + } + + if (_state->beginTime) { + [s appendFormat:@"; beginTime = %f", _state->beginTime]; + } + + for (NSString *key in _state->dict) { + [s appendFormat:@"; %@ = %@", key, _state->dict[key]]; + } +} + +@end + + +#pragma mark - POPPropertyAnimation + +#pragma mark - POPBasicAnimation + +#pragma mark - POPDecayAnimation + +@implementation NSObject (POP) + +- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key +{ + [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key]; +} + +- (void)pop_removeAllAnimations +{ + [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self]; +} + +- (void)pop_removeAnimationForKey:(NSString *)key +{ + [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key]; +} + +- (NSArray *)pop_animationKeys +{ + return [[POPAnimator sharedAnimator] animationKeysForObject:self]; +} + +- (id)pop_animationForKey:(NSString *)key +{ + return [[POPAnimator sharedAnimator] animationForObject:self key:key]; +} + +@end + +@implementation NSProxy (POP) + +- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key +{ + [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key]; +} + +- (void)pop_removeAllAnimations +{ + [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self]; +} + +- (void)pop_removeAnimationForKey:(NSString *)key +{ + [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key]; +} + +- (NSArray *)pop_animationKeys +{ + return [[POPAnimator sharedAnimator] animationKeysForObject:self]; +} + +- (id)pop_animationForKey:(NSString *)key +{ + return [[POPAnimator sharedAnimator] animationForObject:self key:key]; +} + +@end + +@implementation POPAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone +{ + /* + * Must use [self class] instead of POPAnimation so that subclasses can call this via super. + * Even though POPAnimation and POPPropertyAnimation throw exceptions on init, + * it's safe to call it since you can only copy objects that have been successfully created. + */ + POPAnimation *copy = [[[self class] allocWithZone:zone] init]; + + if (copy) { + copy.name = self.name; + copy.beginTime = self.beginTime; + copy.delegate = self.delegate; + copy.animationDidStartBlock = self.animationDidStartBlock; + copy.animationDidReachToValueBlock = self.animationDidReachToValueBlock; + copy.completionBlock = self.completionBlock; + copy.animationDidApplyBlock = self.animationDidApplyBlock; + copy.removedOnCompletion = self.removedOnCompletion; + + copy.autoreverses = self.autoreverses; + copy.repeatCount = self.repeatCount; + copy.repeatForever = self.repeatForever; + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.h new file mode 100644 index 0000000..e761091 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.h @@ -0,0 +1,69 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +/** + @abstract Enumeraton of animation event types. + */ +typedef NS_ENUM(NSUInteger, POPAnimationEventType) { + kPOPAnimationEventPropertyRead = 0, + kPOPAnimationEventPropertyWrite, + kPOPAnimationEventToValueUpdate, + kPOPAnimationEventFromValueUpdate, + kPOPAnimationEventVelocityUpdate, + kPOPAnimationEventBouncinessUpdate, + kPOPAnimationEventSpeedUpdate, + kPOPAnimationEventFrictionUpdate, + kPOPAnimationEventMassUpdate, + kPOPAnimationEventTensionUpdate, + kPOPAnimationEventDidStart, + kPOPAnimationEventDidStop, + kPOPAnimationEventDidReachToValue, + kPOPAnimationEventAutoreversed +}; + +/** + @abstract The base animation event class. + */ +@interface POPAnimationEvent : NSObject + +/** + @abstract The event type. See {@ref POPAnimationEventType} for possible values. + */ +@property (readonly, nonatomic, assign) POPAnimationEventType type; + +/** + @abstract The time of event. + */ +@property (readonly, nonatomic, assign) CFTimeInterval time; + +/** + @abstract Optional string describing the animation at time of event. + */ +@property (readonly, nonatomic, copy) NSString *animationDescription; + +@end + +/** + @abstract An animation event subclass for recording value and velocity. + */ +@interface POPAnimationValueEvent : POPAnimationEvent + +/** + @abstract The value recorded. + */ +@property (readonly, nonatomic, strong) id value; + +/** + @abstract The velocity recorded, if any. + */ +@property (readonly, nonatomic, strong) id velocity; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.mm new file mode 100644 index 0000000..d3a13b6 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationEvent.mm @@ -0,0 +1,108 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationEvent.h" +#import "POPAnimationEventInternal.h" + +static NSString *stringFromType(POPAnimationEventType aType) +{ + switch (aType) { + case kPOPAnimationEventPropertyRead: + return @"read"; + case kPOPAnimationEventPropertyWrite: + return @"write"; + case kPOPAnimationEventToValueUpdate: + return @"toValue"; + case kPOPAnimationEventFromValueUpdate: + return @"fromValue"; + case kPOPAnimationEventVelocityUpdate: + return @"velocity"; + case kPOPAnimationEventSpeedUpdate: + return @"speed"; + case kPOPAnimationEventBouncinessUpdate: + return @"bounciness"; + case kPOPAnimationEventFrictionUpdate: + return @"friction"; + case kPOPAnimationEventMassUpdate: + return @"mass"; + case kPOPAnimationEventTensionUpdate: + return @"tension"; + case kPOPAnimationEventDidStart: + return @"didStart"; + case kPOPAnimationEventDidStop: + return @"didStop"; + case kPOPAnimationEventDidReachToValue: + return @"didReachToValue"; + case kPOPAnimationEventAutoreversed: + return @"autoreversed"; + default: + return nil; + } +} + +@implementation POPAnimationEvent +@synthesize type = _type; +@synthesize time = _time; +@synthesize animationDescription = _animationDescription; + +- (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime +{ + self = [super init]; + if (nil != self) { + _type = aType; + _time = aTime; + } + return self; +} + +- (NSString *)description +{ + NSMutableString *s = [NSMutableString stringWithFormat:@"<POPAnimationEvent:%f; type = %@", _time, stringFromType(_type)]; + [self _appendDescription:s]; + [s appendString:@">"]; + return s; +} + +// subclass override +- (void)_appendDescription:(NSMutableString *)s +{ + if (0 != _animationDescription.length) { + [s appendFormat:@"; animation = %@", _animationDescription]; + } +} + +@end + +@implementation POPAnimationValueEvent +@synthesize value = _value; +@synthesize velocity = _velocity; + +- (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime value:(id)aValue +{ + self = [self initWithType:aType time:aTime]; + if (nil != self) { + _value = aValue; + } + return self; +} + +- (void)_appendDescription:(NSMutableString *)s +{ + [super _appendDescription:s]; + + if (nil != _value) { + [s appendFormat:@"; value = %@", _value]; + } + + if (nil != _velocity) { + [s appendFormat:@"; velocity = %@", _velocity]; + } +} + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationEventInternal.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationEventInternal.h new file mode 100644 index 0000000..398d59b --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationEventInternal.h @@ -0,0 +1,41 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#import "POPAnimationEvent.h" + +@interface POPAnimationEvent () + +/** + @abstract Default initializer. + */ +- (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time; + +/** + @abstract Readwrite redefinition of public property. + */ +@property (readwrite, nonatomic, copy) NSString *animationDescription; + +@end + +@interface POPAnimationValueEvent () + +/** + @abstract Default initializer. + */ +- (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time value:(id)value; + +/** + @abstract Readwrite redefinition of public property. + */ +@property (readwrite, nonatomic, strong) id velocity; + +@end + diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.h new file mode 100644 index 0000000..4b3d237 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.h @@ -0,0 +1,43 @@ +/** + Copyright (c) 2014-present, 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 <QuartzCore/CAAnimation.h> + +#import <pop/POPDefines.h> +#import <pop/POPSpringAnimation.h> + +/** + @abstract The current drag coefficient. + @discussion A value greater than 1.0 indicates Simulator slow-motion animations are enabled. Defaults to 1.0. + */ +extern CGFloat POPAnimationDragCoefficient(); + +@interface CAAnimation (POPAnimationExtras) + +/** + @abstract Apply the current drag coefficient to animation speed. + @discussion Convenience utility to respect Simulator slow-motion animation settings. + */ +- (void)pop_applyDragCoefficient; + +@end + +@interface POPSpringAnimation (POPAnimationExtras) + +/** + @abstract Converts from spring bounciness and speed to tension, friction and mass dynamics values. + */ ++ (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass; + +/** + @abstract Converts from dynamics tension, friction and mass to spring bounciness and speed values. + */ ++ (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.mm new file mode 100644 index 0000000..0a6d6c9 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationExtras.mm @@ -0,0 +1,117 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationExtras.h" +#import "POPAnimationPrivate.h" + +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#endif + +#if TARGET_IPHONE_SIMULATOR +UIKIT_EXTERN float UIAnimationDragCoefficient(); // UIKit private drag coeffient, use judiciously +#endif + +#import "POPMath.h" + +CGFloat POPAnimationDragCoefficient() +{ +#if TARGET_IPHONE_SIMULATOR + return UIAnimationDragCoefficient(); +#else + return 1.0; +#endif +} + +@implementation CAAnimation (POPAnimationExtras) + +- (void)pop_applyDragCoefficient +{ + CGFloat k = POPAnimationDragCoefficient(); + if (k != 0 && k != 1) + self.speed = 1 / k; +} + +@end + +@implementation POPSpringAnimation (POPAnimationExtras) + +static const CGFloat POPBouncy3NormalizationRange = 20.0; +static const CGFloat POPBouncy3NormalizationScale = 1.7; +static const CGFloat POPBouncy3BouncinessNormalizedMin = 0.0; +static const CGFloat POPBouncy3BouncinessNormalizedMax = 0.8; +static const CGFloat POPBouncy3SpeedNormalizedMin = 0.5; +static const CGFloat POPBouncy3SpeedNormalizedMax = 200; +static const CGFloat POPBouncy3FrictionInterpolationMax = 0.01; + ++ (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass +{ + double b = POPNormalize(bounciness / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange); + b = POPProjectNormal(b, POPBouncy3BouncinessNormalizedMin, POPBouncy3BouncinessNormalizedMax); + + double s = POPNormalize(speed / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange); + + CGFloat tension = POPProjectNormal(s, POPBouncy3SpeedNormalizedMin, POPBouncy3SpeedNormalizedMax); + CGFloat friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax); + + tension = POP_ANIMATION_TENSION_FOR_QC_TENSION(tension); + friction = POP_ANIMATION_FRICTION_FOR_QC_FRICTION(friction); + + if (outTension) { + *outTension = tension; + } + + if (outFriction) { + *outFriction = friction; + } + + if (outMass) { + *outMass = 1.0; + } +} + ++ (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed +{ + // Convert to QC values, in which our calculations are done. + CGFloat qcFriction = QC_FRICTION_FOR_POP_ANIMATION_FRICTION(friction); + CGFloat qcTension = QC_TENSION_FOR_POP_ANIMATION_TENSION(tension); + + // Friction is a function of bounciness and tension, according to the following: + // friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax); + // Solve for bounciness, given a tension and friction. + + CGFloat nobounceTension = POPBouncy3NoBounce(qcTension); + CGFloat bounciness1, bounciness2; + + POPQuadraticSolve((nobounceTension - POPBouncy3FrictionInterpolationMax), // a + 2 * (POPBouncy3FrictionInterpolationMax - nobounceTension), // b + (nobounceTension - qcFriction), // c + bounciness1, // x1 + bounciness2); // x2 + + + // Choose the quadratic solution within the normalized bounciness range + CGFloat projectedNormalizedBounciness = (bounciness2 < POPBouncy3BouncinessNormalizedMax) ? bounciness2 : bounciness1; + CGFloat projectedNormalizedSpeed = qcTension; + + // Reverse projection + normalization + CGFloat bounciness = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3BouncinessNormalizedMax - POPBouncy3BouncinessNormalizedMin)) * (projectedNormalizedBounciness - POPBouncy3BouncinessNormalizedMin); + CGFloat speed = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3SpeedNormalizedMax - POPBouncy3SpeedNormalizedMin)) * (projectedNormalizedSpeed - POPBouncy3SpeedNormalizedMin); + + // Write back results + if (outBounciness) { + *outBounciness = bounciness; + } + + if (outSpeed) { + *outSpeed = speed; + } +} + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationInternal.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationInternal.h new file mode 100644 index 0000000..317364f --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationInternal.h @@ -0,0 +1,505 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimation.h" + +#import <QuartzCore/CAMediaTimingFunction.h> + +#import "POPAction.h" +#import "POPAnimationRuntime.h" +#import "POPAnimationTracerInternal.h" +#import "POPSpringSolver.h" + +using namespace POP; + +/** + Enumeration of supported animation types. + */ +enum POPAnimationType +{ + kPOPAnimationSpring, + kPOPAnimationDecay, + kPOPAnimationBasic, + kPOPAnimationCustom, +}; + +typedef struct +{ + CGFloat progress; + bool reached; +} POPProgressMarker; + +typedef void (^POPAnimationDidStartBlock)(POPAnimation *anim); +typedef void (^POPAnimationDidReachToValueBlock)(POPAnimation *anim); +typedef void (^POPAnimationCompletionBlock)(POPAnimation *anim, BOOL finished); +typedef void (^POPAnimationDidApplyBlock)(POPAnimation *anim); + +@interface POPAnimation() +- (instancetype)_init; + +@property (assign, nonatomic) SpringSolver4d *solver; +@property (readonly, nonatomic) POPAnimationType type; + +/** + The current animation value, updated while animation is progressing. + */ +@property (copy, nonatomic, readonly) id currentValue; + +/** + An array of optional progress markers. For each marker specified, the animation delegate will be informed when progress meets or exceeds the value specified. Specifying values outside of the [0, 1] range will give undefined results. + */ +@property (copy, nonatomic) NSArray *progressMarkers; + +/** + Return YES to indicate animation should continue animating. + */ +- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime; + +/** + Subclass override point to append animation description. + */ +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug; + +@end + +NS_INLINE NSString *describe(VectorConstRef vec) +{ + return NULL == vec ? @"null" : vec->toString(); +} + +NS_INLINE Vector4r vector4(VectorConstRef vec) +{ + return NULL == vec ? Vector4r::Zero() : vec->vector4r(); +} + +NS_INLINE Vector4d vector4d(VectorConstRef vec) +{ + if (NULL == vec) { + return Vector4d::Zero(); + } else { + return vec->vector4r().cast<double>(); + } +} + +NS_INLINE bool vec_equal(VectorConstRef v1, VectorConstRef v2) +{ + if (v1 == v2) { + return true; + } + if (!v1 || !v2) { + return false; + } + return *v1 == *v2; +} + +NS_INLINE CGFloat * vec_data(VectorRef vec) +{ + return NULL == vec ? NULL : vec->data(); +} + +template<class T> +struct ComputeProgressFunctor { + CGFloat operator()(const T &value, const T &start, const T &end) const { + return 0; + } +}; + +template<> +struct ComputeProgressFunctor<Vector4r> { + CGFloat operator()(const Vector4r &value, const Vector4r &start, const Vector4r &end) const { + CGFloat s = (value - start).squaredNorm(); // distance from start + CGFloat e = (value - end).squaredNorm(); // distance from end + CGFloat d = (end - start).squaredNorm(); // distance from start to end + + if (0 == d) { + return 1; + } else if (s > e) { + // s -------- p ---- e OR s ------- e ---- p + return sqrtr(s/d); + } else { + // s --- p --------- e OR p ---- s ------- e + return 1 - sqrtr(e/d); + } + } +}; + +struct _POPAnimationState; +struct _POPDecayAnimationState; +struct _POPPropertyAnimationState; + +extern _POPAnimationState *POPAnimationGetState(POPAnimation *a); + + +#define FB_FLAG_GET(stype, flag, getter) \ +- (BOOL)getter { \ + return ((stype *)_state)->flag; \ +} + +#define FB_FLAG_SET(stype, flag, mutator) \ +- (void)mutator (BOOL)value { \ + if (value == ((stype *)_state)->flag) \ + return; \ + ((stype *)_state)->flag = value; \ +} + +#define DEFINE_RW_FLAG(stype, flag, getter, mutator) \ + FB_FLAG_GET (stype, flag, getter) \ + FB_FLAG_SET (stype, flag, mutator) + +#define FB_PROPERTY_GET(stype, property, ctype) \ +- (ctype)property { \ + return ((stype *)_state)->property; \ +} + +#define FB_PROPERTY_SET(stype, property, mutator, ctype, ...) \ +- (void)mutator (ctype)value { \ + if (value == ((stype *)_state)->property) \ + return; \ + ((stype *)_state)->property = value; \ + __VA_ARGS__ \ +} + +#define FB_PROPERTY_SET_OBJ_COPY(stype, property, mutator, ctype, ...) \ +- (void)mutator (ctype)value { \ + if (value == ((stype *)_state)->property) \ + return; \ + ((stype *)_state)->property = [value copy]; \ + __VA_ARGS__ \ +} + +#define DEFINE_RW_PROPERTY(stype, flag, mutator, ctype, ...) \ + FB_PROPERTY_GET (stype, flag, ctype) \ + FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__) + +#define DEFINE_RW_PROPERTY_OBJ(stype, flag, mutator, ctype, ...) \ + FB_PROPERTY_GET (stype, flag, ctype) \ + FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__) + +#define DEFINE_RW_PROPERTY_OBJ_COPY(stype, flag, mutator, ctype, ...) \ + FB_PROPERTY_GET (stype, flag, ctype) \ + FB_PROPERTY_SET_OBJ_COPY (stype, flag, mutator, ctype, __VA_ARGS__) + + +/** + Internal delegate definition. + */ +@interface NSObject (POPAnimationDelegateInternal) +- (void)pop_animation:(POPAnimation *)anim didReachProgress:(CGFloat)progress; +@end + +struct _POPAnimationState +{ + id __unsafe_unretained self; + POPAnimationType type; + NSString *name; + NSUInteger ID; + CFTimeInterval beginTime; + CFTimeInterval startTime; + CFTimeInterval lastTime; + id __weak delegate; + POPAnimationDidStartBlock animationDidStartBlock; + POPAnimationDidReachToValueBlock animationDidReachToValueBlock; + POPAnimationCompletionBlock completionBlock; + POPAnimationDidApplyBlock animationDidApplyBlock; + NSMutableDictionary *dict; + POPAnimationTracer *tracer; + CGFloat progress; + NSInteger repeatCount; + + bool active:1; + bool paused:1; + bool removedOnCompletion:1; + + bool delegateDidStart:1; + bool delegateDidStop:1; + bool delegateDidProgress:1; + bool delegateDidApply:1; + bool delegateDidReachToValue:1; + + bool additive:1; + bool didReachToValue:1; + bool tracing:1; // corresponds to tracer started + bool userSpecifiedDynamics:1; + bool autoreverses:1; + bool repeatForever:1; + bool customFinished:1; + + _POPAnimationState(id __unsafe_unretained anim) : + self(anim), + type((POPAnimationType)0), + name(nil), + ID(0), + beginTime(0), + startTime(0), + lastTime(0), + delegate(nil), + animationDidStartBlock(nil), + animationDidReachToValueBlock(nil), + completionBlock(nil), + animationDidApplyBlock(nil), + dict(nil), + tracer(nil), + progress(0), + repeatCount(0), + active(false), + paused(true), + removedOnCompletion(true), + delegateDidStart(false), + delegateDidStop(false), + delegateDidProgress(false), + delegateDidApply(false), + delegateDidReachToValue(false), + additive(false), + didReachToValue(false), + tracing(false), + userSpecifiedDynamics(false), + autoreverses(false), + repeatForever(false), + customFinished(false) {} + + virtual ~_POPAnimationState() + { + name = nil; + dict = nil; + tracer = nil; + animationDidStartBlock = NULL; + animationDidReachToValueBlock = NULL; + completionBlock = NULL; + animationDidApplyBlock = NULL; + } + + bool isCustom() { + return kPOPAnimationCustom == type; + } + + bool isStarted() { + return 0 != startTime; + } + + id getDelegate() { + return delegate; + } + + void setDelegate(id d) { + if (d != delegate) { + delegate = d; + delegateDidStart = [d respondsToSelector:@selector(pop_animationDidStart:)]; + delegateDidStop = [d respondsToSelector:@selector(pop_animationDidStop:finished:)]; + delegateDidProgress = [d respondsToSelector:@selector(pop_animation:didReachProgress:)]; + delegateDidApply = [d respondsToSelector:@selector(pop_animationDidApply:)]; + delegateDidReachToValue = [d respondsToSelector:@selector(pop_animationDidReachToValue:)]; + } + } + + bool getPaused() { + return paused; + } + + void setPaused(bool f) { + if (f != paused) { + paused = f; + if (!paused) { + reset(false); + } + } + } + + CGFloat getProgress() { + return progress; + } + + /* returns true if started */ + bool startIfNeeded(id obj, CFTimeInterval time, CFTimeInterval offset) + { + bool started = false; + + // detect start based on time + if (0 == startTime && time >= beginTime + offset) { + + // activate & unpause + active = true; + setPaused(false); + + // note start time + startTime = lastTime = time; + started = true; + } + + // ensure values for running animation + bool running = active && !paused; + if (running) { + willRun(started, obj); + } + + // handle start + if (started) { + handleDidStart(); + } + + return started; + } + + void stop(bool removing, bool done) { + if (active) + { + // delegate progress one last time + if (done) { + delegateProgress(); + } + + if (removing) { + active = false; + } + + handleDidStop(done); + } else { + + // stopped before even started + // delegate start and stop regardless; matches CA behavior + if (!isStarted()) { + handleDidStart(); + handleDidStop(false); + } + } + + setPaused(true); + } + + virtual void handleDidStart() + { + if (delegateDidStart) { + ActionEnabler enabler; + [delegate pop_animationDidStart:self]; + } + + POPAnimationDidStartBlock block = animationDidStartBlock; + if (block != NULL) { + ActionEnabler enabler; + block(self); + } + + if (tracing) { + [tracer didStart]; + } + } + + void handleDidStop(BOOL done) + { + if (delegateDidStop) { + ActionEnabler enabler; + [delegate pop_animationDidStop:self finished:done]; + } + + // add another strong reference to completion block before callout + POPAnimationCompletionBlock block = completionBlock; + if (block != NULL) { + ActionEnabler enabler; + block(self, done); + } + + if (tracing) { + [tracer didStop:done]; + } + } + + /* virtual functions */ + virtual bool isDone() { + if (isCustom()) { + return customFinished; + } + + return false; + } + + bool advanceTime(CFTimeInterval time, id obj) { + bool advanced = false; + bool computedProgress = false; + CFTimeInterval dt = time - lastTime; + + switch (type) { + case kPOPAnimationSpring: + advanced = advance(time, dt, obj); + break; + case kPOPAnimationDecay: + advanced = advance(time, dt, obj); + break; + case kPOPAnimationBasic: { + advanced = advance(time, dt, obj); + computedProgress = true; + break; + } + case kPOPAnimationCustom: { + customFinished = [self _advance:obj currentTime:time elapsedTime:dt] ? false : true; + advanced = true; + break; + } + default: + break; + } + + if (advanced) { + + // estimate progress + if (!computedProgress) { + computeProgress(); + } + + // delegate progress + delegateProgress(); + + // update time + lastTime = time; + } + + return advanced; + } + + virtual void willRun(bool started, id obj) {} + virtual bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { return false; } + virtual void computeProgress() {} + virtual void delegateProgress() {} + + virtual void delegateApply() { + if (delegateDidApply) { + ActionEnabler enabler; + [delegate pop_animationDidApply:self]; + } + + POPAnimationDidApplyBlock block = animationDidApplyBlock; + if (block != NULL) { + ActionEnabler enabler; + block(self); + } + } + + virtual void reset(bool all) { + startTime = 0; + lastTime = 0; + } +}; + +typedef struct _POPAnimationState POPAnimationState; + + +@interface POPAnimation () +{ +@protected + struct _POPAnimationState *_state; +} + +@end + +// NSProxy extensions, for testing pursposes +@interface NSProxy (POP) +- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key; +- (void)pop_removeAllAnimations; +- (void)pop_removeAnimationForKey:(NSString *)key; +- (NSArray *)pop_animationKeys; +- (POPAnimation *)pop_animationForKey:(NSString *)key; +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationPrivate.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationPrivate.h new file mode 100644 index 0000000..c0f06c5 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationPrivate.h @@ -0,0 +1,16 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPAnimation.h> + +#define POP_ANIMATION_FRICTION_FOR_QC_FRICTION(qcFriction) (25.0 + (((qcFriction - 8.0) / 2.0) * (25.0 - 19.0))) +#define POP_ANIMATION_TENSION_FOR_QC_TENSION(qcTension) (194.0 + (((qcTension - 30.0) / 50.0) * (375.0 - 194.0))) + +#define QC_FRICTION_FOR_POP_ANIMATION_FRICTION(fbFriction) (8.0 + 2.0 * ((fbFriction - 25.0)/(25.0 - 19.0))) +#define QC_TENSION_FOR_POP_ANIMATION_TENSION(fbTension) (30.0 + 50.0 * ((fbTension - 194.0)/(375.0 - 194.0))) diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.h new file mode 100644 index 0000000..902c312 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.h @@ -0,0 +1,103 @@ +/** + Copyright (c) 2014-present, 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 <objc/runtime.h> + +#import <Foundation/Foundation.h> + +#import "POPVector.h" + +enum POPValueType +{ + kPOPValueUnknown = 0, + kPOPValueInteger, + kPOPValueFloat, + kPOPValuePoint, + kPOPValueSize, + kPOPValueRect, + kPOPValueEdgeInsets, + kPOPValueAffineTransform, + kPOPValueTransform, + kPOPValueRange, + kPOPValueColor, + kPOPValueSCNVector3, + kPOPValueSCNVector4, +}; + +using namespace POP; + +/** + Returns value type based on objc type description, given list of supported value types and length. + */ +extern POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length); + +/** + Returns value type based on objc object, given a list of supported value types and length. + */ +extern POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length); + +/** + Array of all value types. + */ +extern const POPValueType kPOPAnimatableAllTypes[12]; + +/** + Array of all value types supported for animation. + */ +extern const POPValueType kPOPAnimatableSupportTypes[10]; + +/** + Returns a string description of a value type. + */ +extern NSString *POPValueTypeToString(POPValueType t); + +/** + Returns a mutable dictionary of weak pointer keys to weak pointer values. + */ +extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity) CF_RETURNS_RETAINED; + +/** + Returns a mutable dictionary of weak pointer keys to weak pointer values. + */ +extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity) CF_RETURNS_RETAINED; + +/** + Box a vector. + */ +extern id POPBox(VectorConstRef vec, POPValueType type, bool force = false); + +/** + Unbox a vector. + */ +extern VectorRef POPUnbox(id value, POPValueType &type, NSUInteger &count, bool validate); + +/** + Read/write block typedefs for convenience. + */ +typedef void(^pop_animatable_read_block)(id obj, CGFloat *value); +typedef void(^pop_animatable_write_block)(id obj, const CGFloat *value); + +/** + Read object value and return a Vector4r. + */ +NS_INLINE Vector4r read_values(pop_animatable_read_block read, id obj, size_t count) +{ + Vector4r vec = Vector4r::Zero(); + if (0 == count) + return vec; + + read(obj, vec.data()); + + return vec; +} + +NS_INLINE NSString *POPStringFromBOOL(BOOL value) +{ + return value ? @"YES" : @"NO"; +} diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.mm new file mode 100644 index 0000000..371e009 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationRuntime.mm @@ -0,0 +1,329 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationRuntime.h" + +#import <objc/objc.h> + +#import <QuartzCore/QuartzCore.h> + +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#endif + +#import "POPCGUtils.h" +#import "POPDefines.h" +#import "POPGeometry.h" +#import "POPVector.h" + +static Boolean pointerEqual(const void *ptr1, const void *ptr2) { + return ptr1 == ptr2; +} + +static CFHashCode pointerHash(const void *ptr) { + return (CFHashCode)(ptr); +} + +CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity) +{ + CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks; + + // weak, pointer keys + kcb.retain = NULL; + kcb.release = NULL; + kcb.equal = pointerEqual; + kcb.hash = pointerHash; + + CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks; + + // weak, pointer values + vcb.retain = NULL; + vcb.release = NULL; + vcb.equal = pointerEqual; + + return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb); +} + +CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity) +{ + CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks; + + // weak, pointer keys + kcb.retain = NULL; + kcb.release = NULL; + kcb.equal = pointerEqual; + kcb.hash = pointerHash; + + // strong, object values + CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks; + + return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb); +} + +static bool FBCompareTypeEncoding(const char *objctype, POPValueType type) +{ + switch (type) + { + case kPOPValueFloat: + return (strcmp(objctype, @encode(float)) == 0 + || strcmp(objctype, @encode(double)) == 0 + ); + + case kPOPValuePoint: + return (strcmp(objctype, @encode(CGPoint)) == 0 +#if !TARGET_OS_IPHONE + || strcmp(objctype, @encode(NSPoint)) == 0 +#endif + ); + + case kPOPValueSize: + return (strcmp(objctype, @encode(CGSize)) == 0 +#if !TARGET_OS_IPHONE + || strcmp(objctype, @encode(NSSize)) == 0 +#endif + ); + + case kPOPValueRect: + return (strcmp(objctype, @encode(CGRect)) == 0 +#if !TARGET_OS_IPHONE + || strcmp(objctype, @encode(NSRect)) == 0 +#endif + ); + case kPOPValueEdgeInsets: +#if TARGET_OS_IPHONE + return strcmp(objctype, @encode(UIEdgeInsets)) == 0; +#else + return false; +#endif + + case kPOPValueAffineTransform: + return strcmp(objctype, @encode(CGAffineTransform)) == 0; + + case kPOPValueTransform: + return strcmp(objctype, @encode(CATransform3D)) == 0; + + case kPOPValueRange: + return strcmp(objctype, @encode(CFRange)) == 0 + || strcmp(objctype, @encode (NSRange)) == 0; + + case kPOPValueInteger: + return (strcmp(objctype, @encode(int)) == 0 + || strcmp(objctype, @encode(unsigned int)) == 0 + || strcmp(objctype, @encode(short)) == 0 + || strcmp(objctype, @encode(unsigned short)) == 0 + || strcmp(objctype, @encode(long)) == 0 + || strcmp(objctype, @encode(unsigned long)) == 0 + || strcmp(objctype, @encode(long long)) == 0 + || strcmp(objctype, @encode(unsigned long long)) == 0 + ); + + case kPOPValueSCNVector3: +#if SCENEKIT_SDK_AVAILABLE + return strcmp(objctype, @encode(SCNVector3)) == 0; +#else + return false; +#endif + + case kPOPValueSCNVector4: +#if SCENEKIT_SDK_AVAILABLE + return strcmp(objctype, @encode(SCNVector4)) == 0; +#else + return false; +#endif + + default: + return false; + } +} + +POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length) +{ + if (NULL != objctype) { + for (size_t idx = 0; idx < length; idx++) { + if (FBCompareTypeEncoding(objctype, types[idx])) + return types[idx]; + } + } + return kPOPValueUnknown; +} + +POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length) +{ + if ([obj isKindOfClass:[NSValue class]]) { + return POPSelectValueType([obj objCType], types, length); + } else if (NULL != POPCGColorWithColor(obj)) { + return kPOPValueColor; + } + return kPOPValueUnknown; +} + +const POPValueType kPOPAnimatableAllTypes[12] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueAffineTransform, kPOPValueTransform, kPOPValueRange, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4}; + +const POPValueType kPOPAnimatableSupportTypes[10] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4}; + +NSString *POPValueTypeToString(POPValueType t) +{ + switch (t) { + case kPOPValueUnknown: + return @"unknown"; + case kPOPValueInteger: + return @"int"; + case kPOPValueFloat: + return @"CGFloat"; + case kPOPValuePoint: + return @"CGPoint"; + case kPOPValueSize: + return @"CGSize"; + case kPOPValueRect: + return @"CGRect"; + case kPOPValueEdgeInsets: + return @"UIEdgeInsets"; + case kPOPValueAffineTransform: + return @"CGAffineTransform"; + case kPOPValueTransform: + return @"CATransform3D"; + case kPOPValueRange: + return @"CFRange"; + case kPOPValueColor: + return @"CGColorRef"; + case kPOPValueSCNVector3: + return @"SCNVector3"; + case kPOPValueSCNVector4: + return @"SCNVector4"; + default: + return nil; + } +} + +id POPBox(VectorConstRef vec, POPValueType type, bool force) +{ + if (NULL == vec) + return nil; + + switch (type) { + case kPOPValueInteger: + case kPOPValueFloat: + return @(vec->data()[0]); + break; + case kPOPValuePoint: + return [NSValue valueWithCGPoint:vec->cg_point()]; + break; + case kPOPValueSize: + return [NSValue valueWithCGSize:vec->cg_size()]; + break; + case kPOPValueRect: + return [NSValue valueWithCGRect:vec->cg_rect()]; + break; +#if TARGET_OS_IPHONE + case kPOPValueEdgeInsets: + return [NSValue valueWithUIEdgeInsets:vec->ui_edge_insets()]; + break; +#endif + case kPOPValueColor: { + return (__bridge_transfer id)vec->cg_color(); + break; + } +#if SCENEKIT_SDK_AVAILABLE + case kPOPValueSCNVector3: { + return [NSValue valueWithSCNVector3:vec->scn_vector3()]; + break; + } + case kPOPValueSCNVector4: { + return [NSValue valueWithSCNVector4:vec->scn_vector4()]; + break; + } +#endif + default: + return force ? [NSValue valueWithCGPoint:vec->cg_point()] : nil; + break; + } +} + +static VectorRef vectorize(id value, POPValueType type) +{ + Vector *vec = NULL; + + switch (type) { + case kPOPValueInteger: + case kPOPValueFloat: +#if CGFLOAT_IS_DOUBLE + vec = Vector::new_cg_float([value doubleValue]); +#else + vec = Vector::new_cg_float([value floatValue]); +#endif + break; + case kPOPValuePoint: + vec = Vector::new_cg_point([value CGPointValue]); + break; + case kPOPValueSize: + vec = Vector::new_cg_size([value CGSizeValue]); + break; + case kPOPValueRect: + vec = Vector::new_cg_rect([value CGRectValue]); + break; +#if TARGET_OS_IPHONE + case kPOPValueEdgeInsets: + vec = Vector::new_ui_edge_insets([value UIEdgeInsetsValue]); + break; +#endif + case kPOPValueAffineTransform: + vec = Vector::new_cg_affine_transform([value CGAffineTransformValue]); + break; + case kPOPValueColor: + vec = Vector::new_cg_color(POPCGColorWithColor(value)); + break; +#if SCENEKIT_SDK_AVAILABLE + case kPOPValueSCNVector3: + vec = Vector::new_scn_vector3([value SCNVector3Value]); + break; + case kPOPValueSCNVector4: + vec = Vector::new_scn_vector4([value SCNVector4Value]); + break; +#endif + default: + break; + } + + return VectorRef(vec); +} + +VectorRef POPUnbox(id value, POPValueType &animationType, NSUInteger &count, bool validate) +{ + if (nil == value) { + count = 0; + return VectorRef(NULL); + } + + // determine type of value + POPValueType valueType = POPSelectValueType(value, kPOPAnimatableSupportTypes, POP_ARRAY_COUNT(kPOPAnimatableSupportTypes)); + + // handle unknown types + if (kPOPValueUnknown == valueType) { + NSString *valueDesc = [[value class] description]; + [NSException raise:@"Unsuported value" format:@"Animating %@ values is not supported", valueDesc]; + } + + // vectorize + VectorRef vec = vectorize(value, valueType); + + if (kPOPValueUnknown == animationType || 0 == count) { + // update animation type based on value type + animationType = valueType; + if (NULL != vec) { + count = vec->size(); + } + } else if (validate) { + // allow for mismatched types, so long as vector size matches + if (count != vec->size()) { + [NSException raise:@"Invalid value" format:@"%@ should be of type %@", value, POPValueTypeToString(animationType)]; + } + } + + return vec; +} diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.h new file mode 100644 index 0000000..72b26c3 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.h @@ -0,0 +1,60 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#import <pop/POPAnimationEvent.h> + +@class POPAnimation; + +/** + @abstract Tracer of animation events to fasciliate unit testing & debugging. + */ +@interface POPAnimationTracer : NSObject + +/** + @abstract Start recording events. + */ +- (void)start; + +/** + @abstract Stop recording events. + */ +- (void)stop; + +/** + @abstract Resets any recoded events. Continues recording events if already started. + */ +- (void)reset; + +/** + @abstract Property representing all recorded events. + @discussion Events are returned in order of occurence. + */ +@property (nonatomic, assign, readonly) NSArray *allEvents; + +/** + @abstract Property representing all recorded write events for convenience. + @discussion Events are returned in order of occurence. + */ +@property (nonatomic, assign, readonly) NSArray *writeEvents; + +/** + @abstract Queries for events of specified type. + @param type The type of event to return. + @returns An array of events of specified type in order of occurence. + */ +- (NSArray *)eventsWithType:(POPAnimationEventType)type; + +/** + @abstract Property indicating whether tracer should automatically log events and reset collection on animation completion. + */ +@property (nonatomic, assign) BOOL shouldLogAndResetOnCompletion; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.mm new file mode 100644 index 0000000..243fb9b --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracer.mm @@ -0,0 +1,191 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationTracer.h" + +#import <QuartzCore/QuartzCore.h> + +#import "POPAnimationEventInternal.h" +#import "POPAnimationInternal.h" +#import "POPSpringAnimation.h" + +@implementation POPAnimationTracer +{ + __weak POPAnimation *_animation; + POPAnimationState *_animationState; + NSMutableArray *_events; + BOOL _animationHasVelocity; +} +@synthesize shouldLogAndResetOnCompletion = _shouldLogAndResetOnCompletion; + +static POPAnimationEvent *create_event(POPAnimationTracer *self, POPAnimationEventType type, id value = nil, bool recordAnimation = false) +{ + bool useLocalTime = 0 != self->_animationState->startTime; + CFTimeInterval time = useLocalTime + ? self->_animationState->lastTime - self->_animationState->startTime + : self->_animationState->lastTime; + + POPAnimationEvent *event; + + if (!value) { + event = [[POPAnimationEvent alloc] initWithType:type time:time]; + } else { + event = [[POPAnimationValueEvent alloc] initWithType:type time:time value:value]; + if (self->_animationHasVelocity) { + [(POPAnimationValueEvent *)event setVelocity:[(POPSpringAnimation *)self->_animation velocity]]; + } + } + + if (recordAnimation) { + event.animationDescription = [self->_animation description]; + } + + return event; +} + +- (id)initWithAnimation:(POPAnimation *)anAnim +{ + self = [super init]; + if (nil != self) { + _animation = anAnim; + _animationState = POPAnimationGetState(anAnim); + _events = [[NSMutableArray alloc] initWithCapacity:50]; + _animationHasVelocity = [anAnim respondsToSelector:@selector(velocity)]; + } + return self; +} + +- (void)readPropertyValue:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyRead, aValue); + [_events addObject:event]; +} + +- (void)writePropertyValue:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyWrite, aValue); + [_events addObject:event]; +} + +- (void)updateToValue:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventToValueUpdate, aValue); + [_events addObject:event]; +} + +- (void)updateFromValue:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventFromValueUpdate, aValue); + [_events addObject:event]; +} + +- (void)updateVelocity:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventVelocityUpdate, aValue); + [_events addObject:event]; +} + +- (void)updateSpeed:(float)aFloat +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventSpeedUpdate, @(aFloat)); + [_events addObject:event]; +} + +- (void)updateBounciness:(float)aFloat +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventBouncinessUpdate, @(aFloat)); + [_events addObject:event]; +} + +- (void)updateFriction:(float)aFloat +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventFrictionUpdate, @(aFloat)); + [_events addObject:event]; +} + +- (void)updateMass:(float)aFloat +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventMassUpdate, @(aFloat)); + [_events addObject:event]; +} + +- (void)updateTension:(float)aFloat +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventTensionUpdate, @(aFloat)); + [_events addObject:event]; +} + +- (void)didStart +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStart, nil, true); + [_events addObject:event]; +} + +- (void)didStop:(BOOL)finished +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStop, @(finished), true); + [_events addObject:event]; + + if (_shouldLogAndResetOnCompletion) { + NSLog(@"events:%@", self.allEvents); + [self reset]; + } +} + +- (void)didReachToValue:(id)aValue +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidReachToValue, aValue); + [_events addObject:event]; +} + +- (void)autoreversed +{ + POPAnimationEvent *event = create_event(self, kPOPAnimationEventAutoreversed); + [_events addObject:event]; +} + +- (void)start +{ + POPAnimationState *s = POPAnimationGetState(_animation); + s->tracing = true; +} + +- (void)stop +{ + POPAnimationState *s = POPAnimationGetState(_animation); + s->tracing = false; +} + +- (void)reset +{ + [_events removeAllObjects]; +} + +- (NSArray *)allEvents +{ + return [_events copy]; +} + +- (NSArray *)writeEvents +{ + return [self eventsWithType:kPOPAnimationEventPropertyWrite]; +} + +- (NSArray *)eventsWithType:(POPAnimationEventType)aType +{ + NSMutableArray *array = [NSMutableArray array]; + for (POPAnimationEvent *event in _events) { + if (aType == event.type) { + [array addObject:event]; + } + } + return array; +} + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimationTracerInternal.h b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracerInternal.h new file mode 100644 index 0000000..00958e1 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimationTracerInternal.h @@ -0,0 +1,96 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#import <pop/POPAnimationTracer.h> + +@interface POPAnimationTracer (Internal) + +/** + @abstract Designated initalizer. Pass the animation being traced. + */ +- (instancetype)initWithAnimation:(POPAnimation *)anAnim; + +/** + @abstract Records read value. + */ +- (void)readPropertyValue:(id)aValue; + +/** + @abstract Records write value. + */ +- (void)writePropertyValue:(id)aValue; + +/** + Records to value update. + */ +- (void)updateToValue:(id)aValue; + +/** + @abstract Records from value update. + */ +- (void)updateFromValue:(id)aValue; + +/** + @abstract Records from value update. + */ +- (void)updateVelocity:(id)aValue; + +/** + @abstract Records bounciness update. + */ +- (void)updateBounciness:(float)aFloat; + +/** + @abstract Records speed update. + */ +- (void)updateSpeed:(float)aFloat; + +/** + @abstract Records friction update. + */ +- (void)updateFriction:(float)aFloat; + +/** + @abstract Records mass update. + */ +- (void)updateMass:(float)aFloat; + +/** + @abstract Records tension update. + */ +- (void)updateTension:(float)aFloat; + +/** + @abstract Records did add. + */ +- (void)didAdd; + +/** + @abstract Records did start. + */ +- (void)didStart; + +/** + @abstract Records did stop. + */ +- (void)didStop:(BOOL)finished; + +/** + @abstract Records did reach to value. + */ +- (void)didReachToValue:(id)aValue; + +/** + @abstract Records when an autoreverse animation takes place. + */ +- (void)autoreversed; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimator.h b/Unit-2-Journal/Pods/pop/pop/POPAnimator.h new file mode 100644 index 0000000..5310bed --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimator.h @@ -0,0 +1,47 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +@protocol POPAnimatorDelegate; + +/** + @abstract The animator class renders animations. + */ +@interface POPAnimator : NSObject + +/** + @abstract The shared animator instance. + @discussion Consumers should generally use the shared instance in lieu of creating new instances. + */ ++ (instancetype)sharedAnimator; + +/** + @abstract The optional animator delegate. + */ +@property (weak, nonatomic) id<POPAnimatorDelegate> delegate; + +@end + +/** + @abstract The animator delegate. + */ +@protocol POPAnimatorDelegate <NSObject> + +/** + @abstract Called on each frame before animation application. + */ +- (void)animatorWillAnimate:(POPAnimator *)animator; + +/** + @abstract Called on each frame after animation application. + */ +- (void)animatorDidAnimate:(POPAnimator *)animator; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimator.mm b/Unit-2-Journal/Pods/pop/pop/POPAnimator.mm new file mode 100644 index 0000000..6b2a770 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimator.mm @@ -0,0 +1,806 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimator.h" +#import "POPAnimatorPrivate.h" + +#import <list> +#import <vector> + +#if !TARGET_OS_IPHONE +#import <libkern/OSAtomic.h> +#endif + +#import <objc/objc-auto.h> + +#import <QuartzCore/QuartzCore.h> + +#import "POPAnimation.h" +#import "POPAnimationExtras.h" +#import "POPBasicAnimationInternal.h" +#import "POPDecayAnimation.h" + +using namespace std; +using namespace POP; + +#define ENABLE_LOGGING_DEBUG 0 +#define ENABLE_LOGGING_INFO 0 + +#if ENABLE_LOGGING_DEBUG +#define FBLogAnimDebug NSLog +#else +#define FBLogAnimDebug(...) +#endif + +#if ENABLE_LOGGING_INFO +#define FBLogAnimInfo NSLog +#else +#define FBLogAnimInfo(...) +#endif + +class POPAnimatorItem +{ +public: + id __weak object; + NSString *key; + POPAnimation *animation; + NSInteger refCount; + id __unsafe_unretained unretainedObject; + + POPAnimatorItem(id o, NSString *k, POPAnimation *a) POP_NOTHROW + { + object = o; + key = [k copy]; + animation = a; + refCount = 1; + unretainedObject = o; + } + + ~POPAnimatorItem() + { + } + + bool operator==(const POPAnimatorItem& o) const { + return unretainedObject == o.unretainedObject && animation == o.animation && [key isEqualToString:o.key]; + } + +}; + +typedef std::shared_ptr<POPAnimatorItem> POPAnimatorItemRef; +typedef std::shared_ptr<const POPAnimatorItem> POPAnimatorItemConstRef; + +typedef std::list<POPAnimatorItemRef> POPAnimatorItemList; +typedef POPAnimatorItemList::iterator POPAnimatorItemListIterator; +typedef POPAnimatorItemList::const_iterator POPAnimatorItemListConstIterator; + +static BOOL _disableBackgroundThread = YES; + +@interface POPAnimator () +{ +#if TARGET_OS_IPHONE + CADisplayLink *_displayLink; +#else + CVDisplayLinkRef _displayLink; + int32_t _enqueuedRender; +#endif + POPAnimatorItemList _list; + CFMutableDictionaryRef _dict; + NSMutableArray *_observers; + POPAnimatorItemList _pendingList; + CFRunLoopObserverRef _pendingListObserver; + CFTimeInterval _slowMotionStartTime; + CFTimeInterval _slowMotionLastTime; + CFTimeInterval _slowMotionAccumulator; + CFTimeInterval _beginTime; + OSSpinLock _lock; + BOOL _disableDisplayLink; +} +@end + +@implementation POPAnimator +@synthesize delegate = _delegate; +@synthesize disableDisplayLink = _disableDisplayLink; +@synthesize beginTime = _beginTime; + +#if !TARGET_OS_IPHONE +static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *context) +{ + if (_disableBackgroundThread) { + __unsafe_unretained POPAnimator *pa = (__bridge POPAnimator *)context; + int32_t* enqueuedRender = &pa->_enqueuedRender; + if (*enqueuedRender == 0) { + OSAtomicIncrement32(enqueuedRender); + dispatch_async(dispatch_get_main_queue(), ^{ + [(__bridge POPAnimator*)context render]; + OSAtomicDecrement32(enqueuedRender); + }); + } + } else { + [(__bridge POPAnimator*)context render]; + } + return kCVReturnSuccess; +} +#endif + +// call while holding lock +static void updateDisplayLink(POPAnimator *self) +{ + BOOL paused = (0 == self->_observers.count && self->_list.empty()) || self->_disableDisplayLink; + +#if TARGET_OS_IPHONE + if (paused != self->_displayLink.paused) { + FBLogAnimInfo(paused ? @"pausing display link" : @"unpausing display link"); + self->_displayLink.paused = paused; + } +#else + if (paused == CVDisplayLinkIsRunning(self->_displayLink)) { + FBLogAnimInfo(paused ? @"pausing display link" : @"unpausing display link"); + if (paused) { + CVDisplayLinkStop(self->_displayLink); + } else { + CVDisplayLinkStart(self->_displayLink); + } + } +#endif +} + +static void updateAnimatable(id obj, POPPropertyAnimationState *anim, bool shouldAvoidExtraneousWrite = false) +{ + // handle user-initiated stop or pause; hault animation + if (!anim->active || anim->paused) + return; + + if (anim->hasValue()) { + pop_animatable_write_block write = anim->property.writeBlock; + if (NULL == write) + return; + + // current animation value + VectorRef currentVec = anim->currentValue(); + + if (!anim->additive) { + + // if avoiding extraneous writes and we have a read block defined + if (shouldAvoidExtraneousWrite) { + + pop_animatable_read_block read = anim->property.readBlock; + if (read) { + // compare current animation value with object value + Vector4r currentValue = currentVec->vector4r(); + Vector4r objectValue = read_values(read, obj, anim->valueCount); + if (objectValue == currentValue) { + return; + } + } + } + + // update previous values; support animation convergence + anim->previous2Vec = anim->previousVec; + anim->previousVec = currentVec; + + // write value + write(obj, currentVec->data()); + if (anim->tracing) { + [anim->tracer writePropertyValue:POPBox(currentVec, anim->valueType, true)]; + } + } else { + pop_animatable_read_block read = anim->property.readBlock; + NSCAssert(read, @"additive requires an animatable property readBlock"); + if (NULL == read) { + return; + } + + // object value + Vector4r objectValue = read_values(read, obj, anim->valueCount); + + // current value + Vector4r currentValue = currentVec->vector4r(); + + // determine animation change + if (anim->previousVec) { + Vector4r previousValue = anim->previousVec->vector4r(); + currentValue -= previousValue; + } + + // avoid writing no change + if (shouldAvoidExtraneousWrite && currentValue == Vector4r::Zero()) { + return; + } + + // add to object value + currentValue += objectValue; + + // update previous values; support animation convergence + anim->previous2Vec = anim->previousVec; + anim->previousVec = currentVec; + + // write value + write(obj, currentValue.data()); + if (anim->tracing) { + [anim->tracer writePropertyValue:POPBox(currentVec, anim->valueType, true)]; + } + } + } +} + +static void applyAnimationTime(id obj, POPAnimationState *state, CFTimeInterval time) +{ + if (!state->advanceTime(time, obj)) { + return; + } + + POPPropertyAnimationState *ps = dynamic_cast<POPPropertyAnimationState*>(state); + if (NULL != ps) { + updateAnimatable(obj, ps); + } + + state->delegateApply(); +} + +static void applyAnimationToValue(id obj, POPAnimationState *state) +{ + POPPropertyAnimationState *ps = dynamic_cast<POPPropertyAnimationState*>(state); + + if (NULL != ps) { + + // finalize progress + ps->finalizeProgress(); + + // write to value, updating only if needed + updateAnimatable(obj, ps, true); + } + + state->delegateApply(); +} + +static POPAnimation *deleteDictEntry(POPAnimator *self, id __unsafe_unretained obj, NSString *key, BOOL cleanup = YES) +{ + POPAnimation *anim = nil; + + // lock + OSSpinLockLock(&self->_lock); + + NSMutableDictionary *keyAnimationsDict = (__bridge id)CFDictionaryGetValue(self->_dict, (__bridge void *)obj); + if (keyAnimationsDict) { + + anim = keyAnimationsDict[key]; + if (anim) { + + // remove key + [keyAnimationsDict removeObjectForKey:key]; + + // cleanup empty dictionaries + if (cleanup && 0 == keyAnimationsDict.count) { + CFDictionaryRemoveValue(self->_dict, (__bridge void *)obj); + } + } + } + + // unlock + OSSpinLockUnlock(&self->_lock); + return anim; +} + +static void stopAndCleanup(POPAnimator *self, POPAnimatorItemRef item, bool shouldRemove, bool finished) +{ + // remove + if (shouldRemove) { + deleteDictEntry(self, item->unretainedObject, item->key); + } + + // stop + POPAnimationState *state = POPAnimationGetState(item->animation); + state->stop(shouldRemove, finished); + + if (shouldRemove) { + // lock + OSSpinLockLock(&self->_lock); + + // find item in list + // may have already been removed on animationDidStop: + POPAnimatorItemListIterator find_iter = find(self->_list.begin(), self->_list.end(), item); + BOOL found = find_iter != self->_list.end(); + + if (found) { + self->_list.erase(find_iter); + } + + // unlock + OSSpinLockUnlock(&self->_lock); + } +} + ++ (id)sharedAnimator +{ + static POPAnimator* _animator = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _animator = [[POPAnimator alloc] init]; + }); + return _animator; +} + ++ (BOOL)disableBackgroundThread +{ + return _disableBackgroundThread; +} + ++ (void)setDisableBackgroundThread:(BOOL)flag +{ + _disableBackgroundThread = flag; +} + +#pragma mark - Lifecycle + +- (id)init +{ + self = [super init]; + if (nil == self) return nil; + +#if TARGET_OS_IPHONE + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)]; + _displayLink.paused = YES; + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; +#else + CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); + CVDisplayLinkSetOutputCallback(_displayLink, displayLinkCallback, (__bridge void *)self); +#endif + + _dict = POPDictionaryCreateMutableWeakPointerToStrongObject(5); + _lock = OS_SPINLOCK_INIT; + + return self; +} + +- (void)dealloc +{ +#if TARGET_OS_IPHONE + [_displayLink invalidate]; +#else + CVDisplayLinkStop(_displayLink); + CVDisplayLinkRelease(_displayLink); +#endif + [self _clearPendingListObserver]; +} + +#pragma mark - Utility + +- (void)_processPendingList +{ + // rendering pending animations + CFTimeInterval time = [self _currentRenderTime]; + [self _renderTime:(0 != _beginTime) ? _beginTime : time items:_pendingList]; + + // lock + OSSpinLockLock(&_lock); + + // clear list and observer + _pendingList.clear(); + [self _clearPendingListObserver]; + + // unlock + OSSpinLockUnlock(&_lock); +} + +- (void)_clearPendingListObserver +{ + if (_pendingListObserver) { + CFRunLoopRemoveObserver(CFRunLoopGetMain(), _pendingListObserver, kCFRunLoopCommonModes); + CFRelease(_pendingListObserver); + _pendingListObserver = NULL; + } +} + +- (void)_scheduleProcessPendingList +{ + // see WebKit for magic numbers, eg http://trac.webkit.org/changeset/166540 + static const CFIndex CATransactionCommitRunLoopOrder = 2000000; + static const CFIndex POPAnimationApplyRunLoopOrder = CATransactionCommitRunLoopOrder - 1; + + // lock + OSSpinLockLock(&_lock); + + if (!_pendingListObserver) { + __weak POPAnimator *weakSelf = self; + + _pendingListObserver = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting | kCFRunLoopExit, false, POPAnimationApplyRunLoopOrder, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { + [weakSelf _processPendingList]; + }); + + if (_pendingListObserver) { + CFRunLoopAddObserver(CFRunLoopGetMain(), _pendingListObserver, kCFRunLoopCommonModes); + } + } + + // unlock + OSSpinLockUnlock(&_lock); +} + +- (void)_renderTime:(CFTimeInterval)time items:(std::list<POPAnimatorItemRef>)items +{ + // begin transaction with actions disabled + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + + // notify delegate + __strong __typeof__(_delegate) delegate = _delegate; + [delegate animatorWillAnimate:self]; + + // lock + OSSpinLockLock(&_lock); + + // count active animations + const NSUInteger count = items.size(); + if (0 == count) { + // unlock + OSSpinLockUnlock(&_lock); + } else { + // copy list into vector + std::vector<POPAnimatorItemRef> vector{ items.begin(), items.end() }; + + // unlock + OSSpinLockUnlock(&_lock); + + for (auto item : vector) { + [self _renderTime:time item:item]; + } + } + + // notify observers + for (id observer in self.observers) { + [observer animatorDidAnimate:(id)self]; + } + + // lock + OSSpinLockLock(&_lock); + + // update display link + updateDisplayLink(self); + + // unlock + OSSpinLockUnlock(&_lock); + + // notify delegate and commit + [delegate animatorDidAnimate:self]; + [CATransaction commit]; +} + +- (void)_renderTime:(CFTimeInterval)time item:(POPAnimatorItemRef)item +{ + id obj = item->object; + POPAnimation *anim = item->animation; + POPAnimationState *state = POPAnimationGetState(anim); + + if (nil == obj) { + // object exists not; stop animating + NSAssert(item->unretainedObject, @"object should exist"); + stopAndCleanup(self, item, true, false); + } else { + + // start if needed + state->startIfNeeded(obj, time, _slowMotionAccumulator); + + // only run active, not paused animations + if (state->active && !state->paused) { + // object exists; animate + applyAnimationTime(obj, state, time); + + FBLogAnimDebug(@"time:%f running:%@", time, item->animation); + if (state->isDone()) { + // set end value + applyAnimationToValue(obj, state); + + state->repeatCount--; + if (state->repeatForever || state->repeatCount > 0) { + if ([anim isKindOfClass:[POPPropertyAnimation class]]) { + POPPropertyAnimation *propAnim = (POPPropertyAnimation *)anim; + id oldFromValue = propAnim.fromValue; + propAnim.fromValue = propAnim.toValue; + + if (state->autoreverses) { + if (state->tracing) { + [state->tracer autoreversed]; + } + + if (state->type == kPOPAnimationDecay) { + POPDecayAnimation *decayAnimation = (POPDecayAnimation *)propAnim; + decayAnimation.velocity = [decayAnimation reversedVelocity]; + } else { + propAnim.toValue = oldFromValue; + } + } else { + if (state->type == kPOPAnimationDecay) { + POPDecayAnimation *decayAnimation = (POPDecayAnimation *)propAnim; + id originalVelocity = decayAnimation.originalVelocity; + decayAnimation.velocity = originalVelocity; + } else { + propAnim.fromValue = oldFromValue; + } + } + } + + state->stop(NO, NO); + state->reset(true); + + state->startIfNeeded(obj, time, _slowMotionAccumulator); + } else { + stopAndCleanup(self, item, state->removedOnCompletion, YES); + } + } + } + } +} + +#pragma mark - API + +- (NSArray *)observers +{ + // lock + OSSpinLockLock(&_lock); + + // get observers + NSArray *observers = 0 != _observers.count ? [_observers copy] : nil; + + // unlock + OSSpinLockUnlock(&_lock); + return observers; +} + +- (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key +{ + if (!anim || !obj) { + return; + } + + // support arbitrarily many nil keys + if (!key) { + key = [[NSUUID UUID] UUIDString]; + } + + // lock + OSSpinLockLock(&_lock); + + // get key, animation dict associated with object + NSMutableDictionary *keyAnimationDict = (__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj); + + // update associated animation state + if (nil == keyAnimationDict) { + keyAnimationDict = [NSMutableDictionary dictionary]; + CFDictionarySetValue(_dict, (__bridge void *)obj, (__bridge void *)keyAnimationDict); + } else { + // if the animation instance already exists, avoid cancelling only to restart + POPAnimation *existingAnim = keyAnimationDict[key]; + if (existingAnim) { + // unlock + OSSpinLockUnlock(&_lock); + + if (existingAnim == anim) { + return; + } + [self removeAnimationForObject:obj key:key cleanupDict:NO]; + + // lock + OSSpinLockLock(&_lock); + } + } + keyAnimationDict[key] = anim; + + // create entry after potential removal + POPAnimatorItemRef item(new POPAnimatorItem(obj, key, anim)); + + // add to list and pending list + _list.push_back(item); + _pendingList.push_back(item); + + // support animation re-use, reset all animation state + POPAnimationGetState(anim)->reset(true); + + // update display link + updateDisplayLink(self); + + // unlock + OSSpinLockUnlock(&_lock); + + // schedule runloop processing of pending animations + [self _scheduleProcessPendingList]; +} + +- (void)removeAllAnimationsForObject:(id)obj +{ + // lock + OSSpinLockLock(&_lock); + + NSArray *animations = [(__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj) allValues]; + CFDictionaryRemoveValue(_dict, (__bridge void *)obj); + + // unlock + OSSpinLockUnlock(&_lock); + + if (0 == animations.count) { + return; + } + + NSHashTable *animationSet = [[NSHashTable alloc] initWithOptions:NSHashTableObjectPointerPersonality capacity:animations.count]; + for (id animation in animations) { + [animationSet addObject:animation]; + } + + // lock + OSSpinLockLock(&_lock); + + POPAnimatorItemRef item; + for (auto iter = _list.begin(); iter != _list.end();) { + item = *iter; + if(![animationSet containsObject:item->animation]) { + iter++; + } else { + iter = _list.erase(iter); + } + } + + // unlock + OSSpinLockUnlock(&_lock); + + for (POPAnimation *anim in animations) { + POPAnimationState *state = POPAnimationGetState(anim); + state->stop(true, !state->active); + } +} + +- (void)removeAnimationForObject:(id)obj key:(NSString *)key cleanupDict:(BOOL)cleanupDict +{ + POPAnimation *anim = deleteDictEntry(self, obj, key, cleanupDict); + if (nil == anim) { + return; + } + + // lock + OSSpinLockLock(&_lock); + + // remove from list + POPAnimatorItemRef item; + for (auto iter = _list.begin(); iter != _list.end();) { + item = *iter; + if(anim == item->animation) { + _list.erase(iter); + break; + } else { + iter++; + } + } + + // remove from pending list + for (auto iter = _pendingList.begin(); iter != _pendingList.end();) { + item = *iter; + if(anim == item->animation) { + _pendingList.erase(iter); + break; + } else { + iter++; + } + } + + // unlock + OSSpinLockUnlock(&_lock); + + // stop animation and callout + POPAnimationState *state = POPAnimationGetState(anim); + state->stop(true, (!state->active && !state->paused)); +} + +- (void)removeAnimationForObject:(id)obj key:(NSString *)key +{ + [self removeAnimationForObject:obj key:key cleanupDict:YES]; +} + +- (NSArray *)animationKeysForObject:(id)obj +{ + // lock + OSSpinLockLock(&_lock); + + // get keys + NSArray *keys = [(__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj) allKeys]; + + // unlock + OSSpinLockUnlock(&_lock); + return keys; +} + +- (id)animationForObject:(id)obj key:(NSString *)key +{ + // lock + OSSpinLockLock(&_lock); + + // lookup animation + NSDictionary *keyAnimationsDict = (__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj); + POPAnimation *animation = keyAnimationsDict[key]; + + // unlock + OSSpinLockUnlock(&_lock); + return animation; +} + +- (CFTimeInterval)_currentRenderTime +{ + CFTimeInterval time = CACurrentMediaTime(); + +#if TARGET_IPHONE_SIMULATOR + // support slow-motion animations + time += _slowMotionAccumulator; + float f = POPAnimationDragCoefficient(); + + if (f > 1.0) { + if (!_slowMotionStartTime) { + _slowMotionStartTime = time; + } else { + time = (time - _slowMotionStartTime) / f + _slowMotionStartTime; + _slowMotionLastTime = time; + } + } else if (_slowMotionStartTime) { + CFTimeInterval dt = (_slowMotionLastTime - time); + time += dt; + _slowMotionAccumulator += dt; + _slowMotionStartTime = 0; + } +#endif + + return time; +} + +- (void)render +{ + CFTimeInterval time = [self _currentRenderTime]; + [self renderTime:time]; +} + +- (void)renderTime:(CFTimeInterval)time +{ + [self _renderTime:time items:_list]; +} + +- (void)addObserver:(id<POPAnimatorObserving>)observer +{ + NSAssert(nil != observer, @"attempting to add nil %@ observer", self); + if (nil == observer) { + return; + } + + // lock + OSSpinLockLock(&_lock); + + if (!_observers) { + // use ordered collection for deterministic callout + _observers = [[NSMutableArray alloc] initWithCapacity:1]; + } + + [_observers addObject:observer]; + updateDisplayLink(self); + + // unlock + OSSpinLockUnlock(&_lock); +} + +- (void)removeObserver:(id<POPAnimatorObserving>)observer +{ + NSAssert(nil != observer, @"attempting to remove nil %@ observer", self); + if (nil == observer) { + return; + } + + // lock + OSSpinLockLock(&_lock); + + [_observers removeObject:observer]; + updateDisplayLink(self); + + // unlock + OSSpinLockUnlock(&_lock); +} + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPAnimatorPrivate.h b/Unit-2-Journal/Pods/pop/pop/POPAnimatorPrivate.h new file mode 100644 index 0000000..5fba912 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPAnimatorPrivate.h @@ -0,0 +1,68 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPAnimator.h> + +@class POPAnimation; + +@protocol POPAnimatorObserving <NSObject> +@required + +/** + @abstract Called on each observer after animator has advanced. Core Animation actions are disabled by default. + */ +- (void)animatorDidAnimate:(POPAnimator *)animator; + +@end + +@interface POPAnimator () + +#if !TARGET_OS_IPHONE +/** + Determines whether or not to use a high priority background thread for animation updates. Using a background thread can result in faster, more responsive updates, but may be less compatible. Defaults to YES. + */ ++ (BOOL)disableBackgroundThread; ++ (void)setDisableBackgroundThread:(BOOL)flag; +#endif + +/** + Used for externally driven animator instances. + */ +@property (assign, nonatomic) BOOL disableDisplayLink; + +/** + Time used when starting animations. Defaults to 0 meaning current media time is used. Exposed for unit testing. + */ +@property (assign, nonatomic) CFTimeInterval beginTime; + +/** + Exposed for unit testing. + */ +- (void)renderTime:(CFTimeInterval)time; + +/** + Funnel methods for category additions. + */ +- (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key; +- (void)removeAllAnimationsForObject:(id)obj; +- (void)removeAnimationForObject:(id)obj key:(NSString *)key; +- (NSArray *)animationKeysForObject:(id)obj; +- (POPAnimation *)animationForObject:(id)obj key:(NSString *)key; + +/** + @abstract Add an animator observer. Observer will be notified of each subsequent animator advance until removal. + */ +- (void)addObserver:(id<POPAnimatorObserving>)observer; + +/** + @abstract Remove an animator observer. + */ +- (void)removeObserver:(id<POPAnimatorObserving>)observer; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.h new file mode 100644 index 0000000..ce2e23a --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.h @@ -0,0 +1,71 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPPropertyAnimation.h> + +/** + @abstract A concrete basic animation class. + @discussion Animation is achieved through interpolation. + */ +@interface POPBasicAnimation : POPPropertyAnimation + +/** + @abstract The designated initializer. + @returns An instance of a basic animation. + */ ++ (instancetype)animation; + +/** + @abstract Convenience initializer that returns an animation with animatable property of name. + @param name The name of the animatable property. + @returns An instance of a basic animation configured with specified animatable property. + */ ++ (instancetype)animationWithPropertyNamed:(NSString *)name; + +/** + @abstract Convenience constructor. + @returns Returns a basic animation with kCAMediaTimingFunctionDefault timing function. + */ ++ (instancetype)defaultAnimation; + +/** + @abstract Convenience constructor. + @returns Returns a basic animation with kCAMediaTimingFunctionLinear timing function. + */ ++ (instancetype)linearAnimation; + +/** + @abstract Convenience constructor. + @returns Returns a basic animation with kCAMediaTimingFunctionEaseIn timing function. + */ ++ (instancetype)easeInAnimation; + +/** + @abstract Convenience constructor. + @returns Returns a basic animation with kCAMediaTimingFunctionEaseOut timing function. + */ ++ (instancetype)easeOutAnimation; + +/** + @abstract Convenience constructor. + @returns Returns a basic animation with kCAMediaTimingFunctionEaseInEaseOut timing function. + */ ++ (instancetype)easeInEaseOutAnimation; + +/** + @abstract The duration in seconds. Defaults to 0.4. + */ +@property (assign, nonatomic) CFTimeInterval duration; + +/** + @abstract A timing function defining the pacing of the animation. Defaults to nil indicating pacing according to kCAMediaTimingFunctionDefault. + */ +@property (strong, nonatomic) CAMediaTimingFunction *timingFunction; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.mm new file mode 100644 index 0000000..2843c99 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimation.mm @@ -0,0 +1,106 @@ +/** + Copyright (c) 2014-present, 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 "POPBasicAnimationInternal.h" + +@implementation POPBasicAnimation + +#undef __state +#define __state ((POPBasicAnimationState *)_state) + +#pragma mark - Lifecycle + ++ (instancetype)animation +{ + return [[self alloc] init]; +} + ++ (instancetype)animationWithPropertyNamed:(NSString *)aName +{ + POPBasicAnimation *anim = [self animation]; + anim.property = [POPAnimatableProperty propertyWithName:aName]; + return anim; +} + +- (void)_initState +{ + _state = new POPBasicAnimationState(self); +} + ++ (instancetype)linearAnimation +{ + POPBasicAnimation *anim = [self animation]; + anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + return anim; +} + ++ (instancetype)easeInAnimation +{ + POPBasicAnimation *anim = [self animation]; + anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; + return anim; +} + ++ (instancetype)easeOutAnimation +{ + POPBasicAnimation *anim = [self animation]; + anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + return anim; +} + ++ (instancetype)easeInEaseOutAnimation +{ + POPBasicAnimation *anim = [self animation]; + anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + return anim; +} + ++ (instancetype)defaultAnimation +{ + POPBasicAnimation *anim = [self animation]; + anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; + return anim; +} + +- (id)init +{ + return [self _init]; +} + +#pragma mark - Properties + +DEFINE_RW_PROPERTY(POPBasicAnimationState, duration, setDuration:, CFTimeInterval); +DEFINE_RW_PROPERTY_OBJ(POPBasicAnimationState, timingFunction, setTimingFunction:, CAMediaTimingFunction*, __state->updatedTimingFunction();); + +#pragma mark - Utility + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + [super _appendDescription:s debug:debug]; + if (__state->duration) + [s appendFormat:@"; duration = %f", __state->duration]; +} + +@end + +@implementation POPBasicAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone { + + POPBasicAnimation *copy = [super copyWithZone:zone]; + + if (copy) { + copy.duration = self.duration; + copy.timingFunction = self.timingFunction; // not a 'copy', but timing functions are publicly immutable. + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPBasicAnimationInternal.h b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimationInternal.h new file mode 100644 index 0000000..1027670 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPBasicAnimationInternal.h @@ -0,0 +1,97 @@ +/** + Copyright (c) 2014-present, 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 "POPBasicAnimation.h" + +#import "POPPropertyAnimationInternal.h" + +// default animation duration +static CGFloat const kPOPAnimationDurationDefault = 0.4; + +// progress threshold for computing done +static CGFloat const kPOPProgressThreshold = 1e-6; + +static void interpolate(POPValueType valueType, NSUInteger count, const CGFloat *fromVec, const CGFloat *toVec, CGFloat *outVec, CGFloat p) +{ + switch (valueType) { + case kPOPValueInteger: + case kPOPValueFloat: + case kPOPValuePoint: + case kPOPValueSize: + case kPOPValueRect: + case kPOPValueEdgeInsets: + case kPOPValueColor: + POPInterpolateVector(count, outVec, fromVec, toVec, p); + break; + default: + NSCAssert(false, @"unhandled type %d", valueType); + break; + } +} + +struct _POPBasicAnimationState : _POPPropertyAnimationState +{ + CAMediaTimingFunction *timingFunction; + double timingControlPoints[4]; + CFTimeInterval duration; + CFTimeInterval timeProgress; + + _POPBasicAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim), + timingFunction(nil), + timingControlPoints{0.}, + duration(kPOPAnimationDurationDefault), + timeProgress(0.) + { + type = kPOPAnimationBasic; + } + + bool isDone() { + if (_POPPropertyAnimationState::isDone()) { + return true; + } + return timeProgress + kPOPProgressThreshold >= 1.; + } + + void updatedTimingFunction() + { + float vec[4] = {0.}; + [timingFunction getControlPointAtIndex:1 values:&vec[0]]; + [timingFunction getControlPointAtIndex:2 values:&vec[2]]; + for (NSUInteger idx = 0; idx < POP_ARRAY_COUNT(vec); idx++) { + timingControlPoints[idx] = vec[idx]; + } + } + + bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { + // default timing function + if (!timingFunction) { + ((POPBasicAnimation *)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; + } + + // solve for normalized time, aka progresss [0, 1] + CGFloat p = 1.0f; + if (duration > 0.0f) { + // cap local time to duration + CFTimeInterval t = MIN(time - startTime, duration) / duration; + p = POPTimingFunctionSolve(timingControlPoints, t, SOLVE_EPS(duration)); + timeProgress = t; + } else { + timeProgress = 1.; + } + + // interpolate and advance + interpolate(valueType, valueCount, fromVec->data(), toVec->data(), currentVec->data(), p); + progress = p; + clampCurrentValue(); + + return true; + } +}; + +typedef struct _POPBasicAnimationState POPBasicAnimationState; diff --git a/Unit-2-Journal/Pods/pop/pop/POPCGUtils.h b/Unit-2-Journal/Pods/pop/pop/POPCGUtils.h new file mode 100644 index 0000000..c843947 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPCGUtils.h @@ -0,0 +1,152 @@ +/** + Copyright (c) 2014-present, 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 <CoreGraphics/CoreGraphics.h> + +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#else +#import <AppKit/AppKit.h> +#endif + +#import "POPDefines.h" + +#if SCENEKIT_SDK_AVAILABLE +#import <SceneKit/SceneKit.h> +#endif + +POP_EXTERN_C_BEGIN + +NS_INLINE CGPoint values_to_point(const CGFloat values[]) +{ + return CGPointMake(values[0], values[1]); +} + +NS_INLINE CGSize values_to_size(const CGFloat values[]) +{ + return CGSizeMake(values[0], values[1]); +} + +NS_INLINE CGRect values_to_rect(const CGFloat values[]) +{ + return CGRectMake(values[0], values[1], values[2], values[3]); +} + +#if SCENEKIT_SDK_AVAILABLE +NS_INLINE SCNVector3 values_to_vec3(const CGFloat values[]) +{ + return SCNVector3Make(values[0], values[1], values[2]); +} + +NS_INLINE SCNVector4 values_to_vec4(const CGFloat values[]) +{ + return SCNVector4Make(values[0], values[1], values[2], values[3]); +} +#endif + +#if TARGET_OS_IPHONE + +NS_INLINE UIEdgeInsets values_to_edge_insets(const CGFloat values[]) +{ + return UIEdgeInsetsMake(values[0], values[1], values[2], values[3]); +} + +#endif + +NS_INLINE void values_from_point(CGFloat values[], CGPoint p) +{ + values[0] = p.x; + values[1] = p.y; +} + +NS_INLINE void values_from_size(CGFloat values[], CGSize s) +{ + values[0] = s.width; + values[1] = s.height; +} + +NS_INLINE void values_from_rect(CGFloat values[], CGRect r) +{ + values[0] = r.origin.x; + values[1] = r.origin.y; + values[2] = r.size.width; + values[3] = r.size.height; +} + +#if SCENEKIT_SDK_AVAILABLE +NS_INLINE void values_from_vec3(CGFloat values[], SCNVector3 v) +{ + values[0] = v.x; + values[1] = v.y; + values[2] = v.z; +} + +NS_INLINE void values_from_vec4(CGFloat values[], SCNVector4 v) +{ + values[0] = v.x; + values[1] = v.y; + values[2] = v.z; + values[3] = v.w; +} +#endif + +#if TARGET_OS_IPHONE + +NS_INLINE void values_from_edge_insets(CGFloat values[], UIEdgeInsets i) +{ + values[0] = i.top; + values[1] = i.left; + values[2] = i.bottom; + values[3] = i.right; +} + +#endif + +/** + Takes a CGColorRef and converts it into RGBA components, if necessary. + */ +extern void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]); + +/** + Takes RGBA components and returns a CGColorRef. + */ +extern CGColorRef POPCGColorRGBACreate(const CGFloat components[]) CF_RETURNS_RETAINED; + +/** + Takes a color reference and returns a CGColor. + */ +extern CGColorRef POPCGColorWithColor(id color) CF_RETURNS_NOT_RETAINED; + +#if TARGET_OS_IPHONE + +/** + Takes a UIColor and converts it into RGBA components, if necessary. + */ +extern void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]); + +/** + Takes RGBA components and returns a UIColor. + */ +extern UIColor *POPUIColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED; + +#else + +/** + Takes a NSColor and converts it into RGBA components, if necessary. + */ +extern void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[]); + +/** + Takes RGBA components and returns a NSColor. + */ +extern NSColor *POPNSColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED; + +#endif + +POP_EXTERN_C_END diff --git a/Unit-2-Journal/Pods/pop/pop/POPCGUtils.mm b/Unit-2-Journal/Pods/pop/pop/POPCGUtils.mm new file mode 100644 index 0000000..72a2d36 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPCGUtils.mm @@ -0,0 +1,150 @@ +/** + Copyright (c) 2014-present, 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 "POPCGUtils.h" + +#import <objc/runtime.h> + +void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]) +{ + if (color) { + const CGFloat *colors = CGColorGetComponents(color); + size_t count = CGColorGetNumberOfComponents(color); + + if (4 == count) { + // RGB colorspace + components[0] = colors[0]; + components[1] = colors[1]; + components[2] = colors[2]; + components[3] = colors[3]; + } else if (2 == count) { + // Grey colorspace + components[0] = components[1] = components[2] = colors[0]; + components[3] = colors[1]; + } else { + // Use CI to convert + CIColor *ciColor = [CIColor colorWithCGColor:color]; + components[0] = ciColor.red; + components[1] = ciColor.green; + components[2] = ciColor.blue; + components[3] = ciColor.alpha; + } + } else { + memset(components, 0, 4 * sizeof(components[0])); + } +} + +CGColorRef POPCGColorRGBACreate(const CGFloat components[]) +{ +#if TARGET_OS_IPHONE + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGColorRef color = CGColorCreate(space, components); + CGColorSpaceRelease(space); + return color; +#else + return CGColorCreateGenericRGB(components[0], components[1], components[2], components[3]); +#endif +} + +CGColorRef POPCGColorWithColor(id color) +{ + if (CFGetTypeID((__bridge CFTypeRef)color) == CGColorGetTypeID()) { + return ((__bridge CGColorRef)color); + } +#if TARGET_OS_IPHONE + else if ([color isKindOfClass:[UIColor class]]) { + return [color CGColor]; + } +#else + else if ([color isKindOfClass:[NSColor class]]) { + // -[NSColor CGColor] is only supported since OSX 10.8+ + if ([color respondsToSelector:@selector(CGColor)]) { + return [color CGColor]; + } + + /* + * Otherwise create a CGColorRef manually. + * + * The original accessor is (or would be) declared as: + * @property(readonly) CGColorRef CGColor; + * - (CGColorRef)CGColor NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED; + * + * (Please note that OSX' accessor is atomic, while iOS' isn't.) + * + * The access to the NSColor object must thus be synchronized + * and the CGColorRef be stored as an associated object, + * to return a reference which doesn't need to be released manually. + */ + @synchronized(color) { + static const void* key = &key; + + CGColorRef colorRef = (__bridge CGColorRef)objc_getAssociatedObject(color, key); + + if (!colorRef) { + size_t numberOfComponents = [color numberOfComponents]; + CGFloat components[numberOfComponents]; + CGColorSpaceRef colorSpace = [[color colorSpace] CGColorSpace]; + + [color getComponents:components]; + + colorRef = CGColorCreate(colorSpace, components); + + objc_setAssociatedObject(color, key, (__bridge id)colorRef, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + CGColorRelease(colorRef); + } + + return colorRef; + } + } +#endif + return nil; +} + +#if TARGET_OS_IPHONE + +void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]) +{ + return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components); +} + +UIColor *POPUIColorRGBACreate(const CGFloat components[]) +{ + CGColorRef colorRef = POPCGColorRGBACreate(components); + UIColor *color = [[UIColor alloc] initWithCGColor:colorRef]; + CGColorRelease(colorRef); + return color; +} + +#else + +void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[]) +{ + return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components); +} + +NSColor *POPNSColorRGBACreate(const CGFloat components[]) +{ + CGColorRef colorRef = POPCGColorRGBACreate(components); + NSColor *color = nil; + + if (colorRef) { + if ([NSColor respondsToSelector:@selector(colorWithCGColor:)]) { + color = [NSColor colorWithCGColor:colorRef]; + } else { + color = [NSColor colorWithCIColor:[CIColor colorWithCGColor:colorRef]]; + } + + CGColorRelease(colorRef); + } + + return color; +} + +#endif + diff --git a/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.h new file mode 100644 index 0000000..501a755 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.h @@ -0,0 +1,46 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPAnimation.h> + +@class POPCustomAnimation; + +/** + @abstract POPCustomAnimationBlock is the callback block of a custom animation. + @discussion This block will be executed for each animation frame and should update the property or properties being animated based on current timing. + @param target The object being animated. Reference the passed in target to help avoid retain loops. + @param animation The custom animation instance. Use to determine the current and elapsed time since last callback. Reference the passed in animation to help avoid retain loops. + @return Flag indicating whether the animation should continue animating. Return NO to indicate animation is done. + */ +typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation); + +/** + @abstract POPCustomAnimation is a concrete animation subclass for custom animations. + */ +@interface POPCustomAnimation : POPAnimation + +/** +@abstract Creates and returns an initialized custom animation instance. +@discussion This is the designated initializer. +@param block The custom animation callback block. See {@ref POPCustomAnimationBlock}. +@return The initialized custom animation instance. +*/ ++ (instancetype)animationWithBlock:(POPCustomAnimationBlock)block; + +/** + @abstract The current animation time at time of callback. + */ +@property (readonly, nonatomic) CFTimeInterval currentTime; + +/** + @abstract The elapsed animation time since last callback. + */ +@property (readonly, nonatomic) CFTimeInterval elapsedTime; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.mm new file mode 100644 index 0000000..8cb7913 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPCustomAnimation.mm @@ -0,0 +1,75 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationInternal.h" + +#import "POPCustomAnimation.h" + +@interface POPCustomAnimation () +@property (nonatomic, copy) POPCustomAnimationBlock animate; +@end + +@implementation POPCustomAnimation +@synthesize currentTime = _currentTime; +@synthesize elapsedTime = _elapsedTime; +@synthesize animate = _animate; + ++ (instancetype)animationWithBlock:(BOOL(^)(id target, POPCustomAnimation *))block +{ + POPCustomAnimation *b = [[self alloc] _init]; + b.animate = block; + return b; +} + +- (id)_init +{ + self = [super _init]; + if (nil != self) { + _state->type = kPOPAnimationCustom; + } + return self; +} + +- (CFTimeInterval)beginTime +{ + POPAnimationState *s = POPAnimationGetState(self); + return s->startTime > 0 ? s->startTime : s->beginTime; +} + +- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime +{ + _currentTime = currentTime; + _elapsedTime = elapsedTime; + return _animate(object, self); +} + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + [s appendFormat:@"; elapsedTime = %f; currentTime = %f;", _elapsedTime, _currentTime]; +} + +@end + +/** + * Note that only the animate block is copied, but not the current/elapsed times + */ +@implementation POPCustomAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone { + + POPCustomAnimation *copy = [super copyWithZone:zone]; + + if (copy) { + copy.animate = self.animate; + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.h new file mode 100644 index 0000000..92c6b60 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.h @@ -0,0 +1,66 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPPropertyAnimation.h> + +/** + @abstract A concrete decay animation class. + @discussion Animation is achieved through gradual decay of animation value. + */ +@interface POPDecayAnimation : POPPropertyAnimation + +/** + @abstract The designated initializer. + @returns An instance of a decay animation. + */ ++ (instancetype)animation; + +/** + @abstract Convenience initializer that returns an animation with animatable property of name. + @param name The name of the animatable property. + @returns An instance of a decay animation configured with specified animatable property. + */ ++ (instancetype)animationWithPropertyNamed:(NSString *)name; + +/** + @abstract The current velocity value. + @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second. The only POPValueTypes supported for velocity are: kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, and kPOPValueSize. + */ +@property (copy, nonatomic) id velocity; + +/** + @abstract The original velocity value. + @discussion Since the velocity property is modified as the animation progresses, this property stores the original, passed in velocity to support autoreverse and repeatCount. + */ +@property (copy, nonatomic, readonly) id originalVelocity; + +/** + @abstract The deceleration factor. + @discussion Values specifies should be in the range [0, 1]. Lower values results in faster deceleration. Defaults to 0.998. + */ +@property (assign, nonatomic) CGFloat deceleration; + +/** + @abstract The expected duration. + @discussion Derived based on input velocity and deceleration values. + */ +@property (readonly, assign, nonatomic) CFTimeInterval duration; + +/** + The to value is derived based on input velocity and deceleration. + */ +- (void)setToValue:(id)toValue NS_UNAVAILABLE; + +/** + @abstract The reversed velocity. + @discussion The reversed velocity based on the originalVelocity when the animation was set up. + */ +- (id)reversedVelocity; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.mm new file mode 100644 index 0000000..4698fd0 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimation.mm @@ -0,0 +1,203 @@ +/** + Copyright (c) 2014-present, 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 "POPDecayAnimationInternal.h" + +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#endif + +const POPValueType supportedVelocityTypes[6] = { kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, kPOPValueSize, kPOPValueEdgeInsets }; + +@implementation POPDecayAnimation + +#pragma mark - Lifecycle + +#undef __state +#define __state ((POPDecayAnimationState *)_state) + ++ (instancetype)animation +{ + return [[self alloc] init]; +} + ++ (instancetype)animationWithPropertyNamed:(NSString *)aName +{ + POPDecayAnimation *anim = [self animation]; + anim.property = [POPAnimatableProperty propertyWithName:aName]; + return anim; +} + +- (id)init +{ + return [self _init]; +} + +- (void)_initState +{ + _state = new POPDecayAnimationState(self); +} + +#pragma mark - Properties + +DEFINE_RW_PROPERTY(POPDecayAnimationState, deceleration, setDeceleration:, CGFloat, __state->toVec = NULL;); + +@dynamic velocity; + +- (id)toValue +{ + [self _ensureComputedProperties]; + return POPBox(__state->toVec, __state->valueType); +} + +- (CFTimeInterval)duration +{ + [self _ensureComputedProperties]; + return __state->duration; +} + +- (void)setFromValue:(id)fromValue +{ + super.fromValue = fromValue; + [self _invalidateComputedProperties]; +} + +- (void)setToValue:(id)aValue +{ + // no-op + NSLog(@"ignoring to value on decay animation %@", self); +} + +- (id)reversedVelocity +{ + id reversedVelocity = nil; + + POPValueType velocityType = POPSelectValueType(self.originalVelocity, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); + if (velocityType == kPOPValueFloat) { +#if CGFLOAT_IS_DOUBLE + CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity doubleValue]; +#else + CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity floatValue]; +#endif + NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityFloat); + reversedVelocity = negativeOriginalVelocityNumber; + } else if (velocityType == kPOPValueInteger) { + NSInteger originalVelocityInteger = [(NSNumber *)self.originalVelocity integerValue]; + NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityInteger); + reversedVelocity = negativeOriginalVelocityNumber; + } else if (velocityType == kPOPValuePoint) { + CGPoint originalVelocityPoint = [self.originalVelocity CGPointValue]; + CGPoint negativeOriginalVelocityPoint = CGPointMake(-originalVelocityPoint.x, -originalVelocityPoint.y); + reversedVelocity = [NSValue valueWithCGPoint:negativeOriginalVelocityPoint]; + } else if (velocityType == kPOPValueRect) { + CGRect originalVelocityRect = [self.originalVelocity CGRectValue]; + CGRect negativeOriginalVelocityRect = CGRectMake(-originalVelocityRect.origin.x, -originalVelocityRect.origin.y, -originalVelocityRect.size.width, -originalVelocityRect.size.height); + reversedVelocity = [NSValue valueWithCGRect:negativeOriginalVelocityRect]; + } else if (velocityType == kPOPValueSize) { + CGSize originalVelocitySize = [self.originalVelocity CGSizeValue]; + CGSize negativeOriginalVelocitySize = CGSizeMake(-originalVelocitySize.width, -originalVelocitySize.height); + reversedVelocity = [NSValue valueWithCGSize:negativeOriginalVelocitySize]; + } else if (velocityType == kPOPValueEdgeInsets) { +#if TARGET_OS_IPHONE + UIEdgeInsets originalVelocityInsets = [self.originalVelocity UIEdgeInsetsValue]; + UIEdgeInsets negativeOriginalVelocityInsets = UIEdgeInsetsMake(-originalVelocityInsets.top, -originalVelocityInsets.left, -originalVelocityInsets.bottom, -originalVelocityInsets.right); + reversedVelocity = [NSValue valueWithUIEdgeInsets:negativeOriginalVelocityInsets]; +#endif + } + + return reversedVelocity; +} + +- (id)originalVelocity +{ + return POPBox(__state->originalVelocityVec, __state->valueType); +} + +- (id)velocity +{ + return POPBox(__state->velocityVec, __state->valueType); +} + +- (void)setVelocity:(id)aValue +{ + POPValueType valueType = POPSelectValueType(aValue, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); + if (valueType != kPOPValueUnknown) { + VectorRef vec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); + VectorRef origVec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); + + if (!vec_equal(vec, __state->velocityVec)) { + __state->velocityVec = vec; + __state->originalVelocityVec = origVec; + + if (__state->tracing) { + [__state->tracer updateVelocity:aValue]; + } + + [self _invalidateComputedProperties]; + + // automatically unpause active animations + if (__state->active && __state->paused) { + __state->fromVec = NULL; + __state->setPaused(false); + } + } + } else { + __state->velocityVec = NULL; + NSLog(@"Invalid velocity value for the decayAnimation: %@", aValue); + } +} + +#pragma mark - Utility + +- (void)_ensureComputedProperties +{ + if (NULL == __state->toVec) { + __state->computeDuration(); + __state->computeToValue(); + } +} + +- (void)_invalidateComputedProperties +{ + __state->toVec = NULL; + __state->duration = 0; +} + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + [super _appendDescription:s debug:debug]; + + if (0 != self.duration) { + [s appendFormat:@"; duration = %f", self.duration]; + } + + if (__state->deceleration) { + [s appendFormat:@"; deceleration = %f", __state->deceleration]; + } +} + +@end + +@implementation POPDecayAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone { + + POPDecayAnimation *copy = [super copyWithZone:zone]; + + if (copy) { + // Set the velocity to the animation's original velocity, not its current. + copy.velocity = self.originalVelocity; + copy.deceleration = self.deceleration; + + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPDecayAnimationInternal.h b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimationInternal.h new file mode 100644 index 0000000..c101761 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPDecayAnimationInternal.h @@ -0,0 +1,127 @@ +/** + Copyright (c) 2014-present, 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 "POPDecayAnimation.h" + +#import <cmath> + +#import "POPPropertyAnimationInternal.h" + +// minimal velocity factor before decay animation is considered complete, in units / s +static CGFloat kPOPAnimationDecayMinimalVelocityFactor = 5.; + +// default decay animation deceleration +static CGFloat kPOPAnimationDecayDecelerationDefault = 0.998; + +static void decay_position(CGFloat *x, CGFloat *v, NSUInteger count, CFTimeInterval dt, CGFloat deceleration) +{ + dt *= 1000; + + // v0 = v / 1000 + // v = v0 * powf(deceleration, dt); + // v = v * 1000; + + // x0 = x; + // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration) + float v0[count]; + float kv = powf(deceleration, dt); + float kx = deceleration * (1 - kv) / (1 - deceleration); + + for (NSUInteger idx = 0; idx < count; idx++) { + v0[idx] = v[idx] / 1000.; + v[idx] = v0[idx] * kv * 1000.; + x[idx] = x[idx] + v0[idx] * kx; + } +} + +struct _POPDecayAnimationState : _POPPropertyAnimationState +{ + double deceleration; + CFTimeInterval duration; + + _POPDecayAnimationState(id __unsafe_unretained anim) : + _POPPropertyAnimationState(anim), + deceleration(kPOPAnimationDecayDecelerationDefault), + duration(0) + { + type = kPOPAnimationDecay; + } + + bool isDone() { + if (_POPPropertyAnimationState::isDone()) { + return true; + } + + CGFloat f = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor; + const CGFloat *velocityValues = vec_data(velocityVec); + for (NSUInteger idx = 0; idx < valueCount; idx++) { + if (std::abs((velocityValues[idx])) >= f) + return false; + } + return true; + + } + + void computeDuration() { + + // compute duration till threshold velocity + Vector4r scaledVelocity = vector4(velocityVec) / 1000.; + + double k = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor / 1000.; + double vx = k / scaledVelocity.x; + double vy = k / scaledVelocity.y; + double vz = k / scaledVelocity.z; + double vw = k / scaledVelocity.w; + double d = log(deceleration) * 1000.; + duration = MAX(MAX(MAX(log(fabs(vx)) / d, log(fabs(vy)) / d), log(fabs(vz)) / d), log(fabs(vw)) / d); + + // ensure velocity threshold is exceeded + if (std::isnan(duration) || duration < 0) { + duration = 0; + } + } + + void computeToValue() { + // to value assuming final velocity as a factor of dynamics threshold + // derived from v' = v * d^dt used in decay_position + // to compute the to value with maximal dt, p' = p + (v * d) / (1 - d) + VectorRef fromValue = NULL != currentVec ? currentVec : fromVec; + if (!fromValue) { + return; + } + + // ensure duration is computed + if (0 == duration) { + computeDuration(); + } + + // compute to value + VectorRef toValue(Vector::new_vector(fromValue.get())); + Vector4r velocity = velocityVec->vector4r(); + decay_position(toValue->data(), velocity.data(), valueCount, duration, deceleration); + toVec = toValue; + } + + bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { + // advance past not yet initialized animations + if (NULL == currentVec) { + return false; + } + + decay_position(currentVec->data(), velocityVec->data(), valueCount, dt, deceleration); + + // clamp to compute end value; avoid possibility of decaying past + clampCurrentValue(kPOPAnimationClampEnd | clampMode); + + return true; + } + +}; + +typedef struct _POPDecayAnimationState POPDecayAnimationState; diff --git a/Unit-2-Journal/Pods/pop/pop/POPDefines.h b/Unit-2-Journal/Pods/pop/pop/POPDefines.h new file mode 100644 index 0000000..eb28781 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPDefines.h @@ -0,0 +1,37 @@ +/** + Copyright (c) 2014-present, 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. + */ + +#ifndef POP_POPDefines_h +#define POP_POPDefines_h + +#import <Availability.h> + +#ifdef __cplusplus +# define POP_EXTERN_C_BEGIN extern "C" { +# define POP_EXTERN_C_END } +#else +# define POP_EXTERN_C_BEGIN +# define POP_EXTERN_C_END +#endif + +#define POP_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0]) + +#if defined (__cplusplus) && defined (__GNUC__) +# define POP_NOTHROW __attribute__ ((nothrow)) +#else +# define POP_NOTHROW +#endif + +#if TARGET_OS_MAC + #define SCENEKIT_SDK_AVAILABLE defined(POP_USE_SCENEKIT) +#elif TARGET_OS_IPHONE + #define SCENEKIT_SDK_AVAILABLE defined(POP_USE_SCENEKIT) +#endif + +#endif diff --git a/Unit-2-Journal/Pods/pop/pop/POPGeometry.h b/Unit-2-Journal/Pods/pop/pop/POPGeometry.h new file mode 100644 index 0000000..8ba07e3 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPGeometry.h @@ -0,0 +1,73 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#if TARGET_OS_IPHONE +#import <UIKit/UIGeometry.h> +#endif + +#if !TARGET_OS_IPHONE + +/** NSValue extensions to support animatable types. */ +@interface NSValue (POP) + +/** + @abstract Creates an NSValue given a CGPoint. + */ ++ (NSValue *)valueWithCGPoint:(CGPoint)point; + +/** + @abstract Creates an NSValue given a CGSize. + */ ++ (NSValue *)valueWithCGSize:(CGSize)size; + +/** + @abstract Creates an NSValue given a CGRect. + */ ++ (NSValue *)valueWithCGRect:(CGRect)rect; + +/** + @abstract Creates an NSValue given a CFRange. + */ ++ (NSValue *)valueWithCFRange:(CFRange)range; + +/** + @abstract Creates an NSValue given a CGAffineTransform. + */ ++ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform; + +/** + @abstract Returns the underlying CGPoint value. + */ +- (CGPoint)CGPointValue; + +/** + @abstract Returns the underlying CGSize value. + */ +- (CGSize)CGSizeValue; + +/** + @abstract Returns the underlying CGRect value. + */ +- (CGRect)CGRectValue; + +/** + @abstract Returns the underlying CFRange value. + */ +- (CFRange)CFRangeValue; + +/** + @abstract Returns the underlying CGAffineTransform value. + */ +- (CGAffineTransform)CGAffineTransformValue; + +@end + +#endif diff --git a/Unit-2-Journal/Pods/pop/pop/POPGeometry.mm b/Unit-2-Journal/Pods/pop/pop/POPGeometry.mm new file mode 100644 index 0000000..41998b1 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPGeometry.mm @@ -0,0 +1,94 @@ +/** + Copyright (c) 2014-present, 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 "POPGeometry.h" + +#if !TARGET_OS_IPHONE +@implementation NSValue (POP) + ++ (NSValue *)valueWithCGPoint:(CGPoint)point { + return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)]; +} + ++ (NSValue *)valueWithCGSize:(CGSize)size { + return [NSValue valueWithBytes:&size objCType:@encode(CGSize)]; +} + ++ (NSValue *)valueWithCGRect:(CGRect)rect { + return [NSValue valueWithBytes:&rect objCType:@encode(CGRect)]; +} + ++ (NSValue *)valueWithCFRange:(CFRange)range { + return [NSValue valueWithBytes:&range objCType:@encode(CFRange)]; +} + ++ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform +{ + return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)]; +} + +- (CGPoint)CGPointValue { + CGPoint result; + [self getValue:&result]; + return result; +} + +- (CGSize)CGSizeValue { + CGSize result; + [self getValue:&result]; + return result; +} + +- (CGRect)CGRectValue { + CGRect result; + [self getValue:&result]; + return result; +} + +- (CFRange)CFRangeValue { + CFRange result; + [self getValue:&result]; + return result; +} + +- (CGAffineTransform)CGAffineTransformValue { + CGAffineTransform result; + [self getValue:&result]; + return result; +} +@end + +#endif + +#if TARGET_OS_IPHONE +#import "POPDefines.h" + +#if SCENEKIT_SDK_AVAILABLE +#import <SceneKit/SceneKit.h> + +/** + Dirty hacks because iOS is weird and decided to define both SCNVector3's and SCNVector4's objCType as "t". However @encode(SCNVector3) and @encode(SCNVector4) both return the proper definition ("{SCNVector3=fff}" and "{SCNVector4=ffff}" respectively) + + [[NSValue valueWithSCNVector3:SCNVector3Make(0.0, 0.0, 0.0)] objcType] returns "t", whereas it should return "{SCNVector3=fff}". + + *flips table* + */ +@implementation NSValue (SceneKitFixes) + ++ (NSValue *)valueWithSCNVector3:(SCNVector3)vec3 { + return [NSValue valueWithBytes:&vec3 objCType:@encode(SCNVector3)]; +} + ++ (NSValue *)valueWithSCNVector4:(SCNVector4)vec4 { + return [NSValue valueWithBytes:&vec4 objCType:@encode(SCNVector4)]; +} + +@end +#endif +#endif diff --git a/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.h b/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.h new file mode 100644 index 0000000..ec4c29a --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.h @@ -0,0 +1,196 @@ +/** + Copyright (c) 2014-present, 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 <QuartzCore/QuartzCore.h> + +#import <pop/POPDefines.h> + +POP_EXTERN_C_BEGIN + +#pragma mark - Scale + +/** + @abstract Returns layer scale factor for the x axis. + */ +extern CGFloat POPLayerGetScaleX(CALayer *l); + +/** + @abstract Set layer scale factor for the x axis. + */ +extern void POPLayerSetScaleX(CALayer *l, CGFloat f); + +/** + @abstract Returns layer scale factor for the y axis. + */ +extern CGFloat POPLayerGetScaleY(CALayer *l); + +/** + @abstract Set layer scale factor for the y axis. + */ +extern void POPLayerSetScaleY(CALayer *l, CGFloat f); + +/** + @abstract Returns layer scale factor for the z axis. + */ +extern CGFloat POPLayerGetScaleZ(CALayer *l); + +/** + @abstract Set layer scale factor for the z axis. + */ +extern void POPLayerSetScaleZ(CALayer *l, CGFloat f); + +/** + @abstract Returns layer scale factors for x and y access as point. + */ +extern CGPoint POPLayerGetScaleXY(CALayer *l); + +/** + @abstract Sets layer x and y scale factors given point. + */ +extern void POPLayerSetScaleXY(CALayer *l, CGPoint p); + +#pragma mark - Translation + +/** + @abstract Returns layer translation factor for the x axis. + */ +extern CGFloat POPLayerGetTranslationX(CALayer *l); + +/** + @abstract Set layer translation factor for the x axis. + */ +extern void POPLayerSetTranslationX(CALayer *l, CGFloat f); + +/** + @abstract Returns layer translation factor for the y axis. + */ +extern CGFloat POPLayerGetTranslationY(CALayer *l); + +/** + @abstract Set layer translation factor for the y axis. + */ +extern void POPLayerSetTranslationY(CALayer *l, CGFloat f); + +/** + @abstract Returns layer translation factor for the z axis. + */ +extern CGFloat POPLayerGetTranslationZ(CALayer *l); + +/** + @abstract Set layer translation factor for the z axis. + */ +extern void POPLayerSetTranslationZ(CALayer *l, CGFloat f); + +/** + @abstract Returns layer translation factors for x and y access as point. + */ +extern CGPoint POPLayerGetTranslationXY(CALayer *l); + +/** + @abstract Sets layer x and y translation factors given point. + */ +extern void POPLayerSetTranslationXY(CALayer *l, CGPoint p); + +#pragma mark - Rotation + +/** + @abstract Returns layer rotation, in radians, in the X axis. + */ +extern CGFloat POPLayerGetRotationX(CALayer *l); + +/** + @abstract Sets layer rotation, in radians, in the X axis. + */ +extern void POPLayerSetRotationX(CALayer *l, CGFloat f); + +/** + @abstract Returns layer rotation, in radians, in the Y axis. + */ +extern CGFloat POPLayerGetRotationY(CALayer *l); + +/** + @abstract Sets layer rotation, in radians, in the Y axis. + */ +extern void POPLayerSetRotationY(CALayer *l, CGFloat f); + +/** + @abstract Returns layer rotation, in radians, in the Z axis. + */ +extern CGFloat POPLayerGetRotationZ(CALayer *l); + +/** + @abstract Sets layer rotation, in radians, in the Z axis. + */ +extern void POPLayerSetRotationZ(CALayer *l, CGFloat f); + +/** + @abstract Returns layer rotation, in radians, in the Z axis. + */ +extern CGFloat POPLayerGetRotation(CALayer *l); + +/** + @abstract Sets layer rotation, in radians, in the Z axis. + */ +extern void POPLayerSetRotation(CALayer *l, CGFloat f); + +#pragma mark - Sublayer Scale + +/** + @abstract Returns sublayer scale factors for x and y access as point. + */ +extern CGPoint POPLayerGetSubScaleXY(CALayer *l); + +/** + @abstract Sets sublayer x and y scale factors given point. + */ +extern void POPLayerSetSubScaleXY(CALayer *l, CGPoint p); + +#pragma mark - Sublayer Translation + +/** + @abstract Returns sublayer translation factor for the x axis. + */ +extern CGFloat POPLayerGetSubTranslationX(CALayer *l); + +/** + @abstract Set sublayer translation factor for the x axis. + */ +extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f); + +/** + @abstract Returns sublayer translation factor for the y axis. + */ +extern CGFloat POPLayerGetSubTranslationY(CALayer *l); + +/** + @abstract Set sublayer translation factor for the y axis. + */ +extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f); + +/** + @abstract Returns sublayer translation factor for the z axis. + */ +extern CGFloat POPLayerGetSubTranslationZ(CALayer *l); + +/** + @abstract Set sublayer translation factor for the z axis. + */ +extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f); + +/** + @abstract Returns sublayer translation factors for x and y access as point. + */ +extern CGPoint POPLayerGetSubTranslationXY(CALayer *l); + +/** + @abstract Sets sublayer x and y translation factors given point. + */ +extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p); + +POP_EXTERN_C_END diff --git a/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.mm b/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.mm new file mode 100644 index 0000000..c8ad7f9 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPLayerExtras.mm @@ -0,0 +1,288 @@ +/** + Copyright (c) 2014-present, 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 "POPLayerExtras.h" + +#include "TransformationMatrix.h" + +using namespace WebCore; + +#define DECOMPOSE_TRANSFORM(L) \ + TransformationMatrix _m(L.transform); \ + TransformationMatrix::DecomposedType _d; \ + _m.decompose(_d); + +#define RECOMPOSE_TRANSFORM(L) \ + _m.recompose(_d); \ + L.transform = _m.transform3d(); + +#define RECOMPOSE_ROT_TRANSFORM(L) \ + _m.recompose(_d, true); \ + L.transform = _m.transform3d(); + +#define DECOMPOSE_SUBLAYER_TRANSFORM(L) \ + TransformationMatrix _m(L.sublayerTransform); \ + TransformationMatrix::DecomposedType _d; \ + _m.decompose(_d); + +#define RECOMPOSE_SUBLAYER_TRANSFORM(L) \ + _m.recompose(_d); \ + L.sublayerTransform = _m.transform3d(); + +#pragma mark - Scale + +NS_INLINE void ensureNonZeroValue(CGFloat &f) +{ + if (f == 0) { + f = 1e-6; + } +} + +NS_INLINE void ensureNonZeroValue(CGPoint &p) +{ + if (p.x == 0 && p.y == 0) { + p.x = 1e-6; + p.y = 1e-6; + } +} + +CGFloat POPLayerGetScaleX(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.scaleX; +} + +void POPLayerSetScaleX(CALayer *l, CGFloat f) +{ + ensureNonZeroValue(f); + DECOMPOSE_TRANSFORM(l); + _d.scaleX = f; + RECOMPOSE_TRANSFORM(l); +} + +CGFloat POPLayerGetScaleY(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.scaleY; +} + +void POPLayerSetScaleY(CALayer *l, CGFloat f) +{ + ensureNonZeroValue(f); + DECOMPOSE_TRANSFORM(l); + _d.scaleY = f; + RECOMPOSE_TRANSFORM(l); +} + +CGFloat POPLayerGetScaleZ(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.scaleZ; +} + +void POPLayerSetScaleZ(CALayer *l, CGFloat f) +{ + ensureNonZeroValue(f); + DECOMPOSE_TRANSFORM(l); + _d.scaleZ = f; + RECOMPOSE_TRANSFORM(l); +} + +CGPoint POPLayerGetScaleXY(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return CGPointMake(_d.scaleX, _d.scaleY); +} + +void POPLayerSetScaleXY(CALayer *l, CGPoint p) +{ + ensureNonZeroValue(p); + DECOMPOSE_TRANSFORM(l); + _d.scaleX = p.x; + _d.scaleY = p.y; + RECOMPOSE_TRANSFORM(l); +} + +#pragma mark - Translation + +CGFloat POPLayerGetTranslationX(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.translateX; +} + +void POPLayerSetTranslationX(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.translateX = f; + RECOMPOSE_TRANSFORM(l); +} + +CGFloat POPLayerGetTranslationY(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.translateY; +} + +void POPLayerSetTranslationY(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.translateY = f; + RECOMPOSE_TRANSFORM(l); +} + +CGFloat POPLayerGetTranslationZ(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.translateZ; +} + +void POPLayerSetTranslationZ(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.translateZ = f; + RECOMPOSE_TRANSFORM(l); +} + +CGPoint POPLayerGetTranslationXY(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return CGPointMake(_d.translateX, _d.translateY); +} + +void POPLayerSetTranslationXY(CALayer *l, CGPoint p) +{ + DECOMPOSE_TRANSFORM(l); + _d.translateX = p.x; + _d.translateY = p.y; + RECOMPOSE_TRANSFORM(l); +} + +#pragma mark - Rotation + +CGFloat POPLayerGetRotationX(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.rotateX; +} + +void POPLayerSetRotationX(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.rotateX = f; + RECOMPOSE_ROT_TRANSFORM(l); +} + +CGFloat POPLayerGetRotationY(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.rotateY; +} + +void POPLayerSetRotationY(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.rotateY = f; + RECOMPOSE_ROT_TRANSFORM(l); +} + +CGFloat POPLayerGetRotationZ(CALayer *l) +{ + DECOMPOSE_TRANSFORM(l); + return _d.rotateZ; +} + +void POPLayerSetRotationZ(CALayer *l, CGFloat f) +{ + DECOMPOSE_TRANSFORM(l); + _d.rotateZ = f; + RECOMPOSE_ROT_TRANSFORM(l); +} + +CGFloat POPLayerGetRotation(CALayer *l) +{ + return POPLayerGetRotationZ(l); +} + +void POPLayerSetRotation(CALayer *l, CGFloat f) +{ + POPLayerSetRotationZ(l, f); +} + +#pragma mark - Sublayer Scale + +CGPoint POPLayerGetSubScaleXY(CALayer *l) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + return CGPointMake(_d.scaleX, _d.scaleY); +} + +void POPLayerSetSubScaleXY(CALayer *l, CGPoint p) +{ + ensureNonZeroValue(p); + DECOMPOSE_SUBLAYER_TRANSFORM(l); + _d.scaleX = p.x; + _d.scaleY = p.y; + RECOMPOSE_SUBLAYER_TRANSFORM(l); +} + +#pragma mark - Sublayer Translation + +extern CGFloat POPLayerGetSubTranslationX(CALayer *l) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + return _d.translateX; +} + +extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + _d.translateX = f; + RECOMPOSE_SUBLAYER_TRANSFORM(l); +} + +extern CGFloat POPLayerGetSubTranslationY(CALayer *l) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + return _d.translateY; +} + +extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + _d.translateY = f; + RECOMPOSE_SUBLAYER_TRANSFORM(l); +} + +extern CGFloat POPLayerGetSubTranslationZ(CALayer *l) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + return _d.translateZ; +} + +extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + _d.translateZ = f; + RECOMPOSE_SUBLAYER_TRANSFORM(l); +} + +extern CGPoint POPLayerGetSubTranslationXY(CALayer *l) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + return CGPointMake(_d.translateX, _d.translateY); +} + +extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p) +{ + DECOMPOSE_SUBLAYER_TRANSFORM(l); + _d.translateX = p.x; + _d.translateY = p.y; + RECOMPOSE_SUBLAYER_TRANSFORM(l); +} diff --git a/Unit-2-Journal/Pods/pop/pop/POPMath.h b/Unit-2-Journal/Pods/pop/pop/POPMath.h new file mode 100644 index 0000000..0c6f5e2 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPMath.h @@ -0,0 +1,56 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#import <CoreGraphics/CoreGraphics.h> + +#import "POPDefines.h" +#import "POPVector.h" + +NS_INLINE CGFloat sqrtr(CGFloat f) +{ +#if CGFLOAT_IS_DOUBLE + return sqrt(f); +#else + return sqrtf(f); +#endif +} + +// round to nearest sub; pass 2.0 to round to every 0.5 (eg: retina pixels) +NS_INLINE CGFloat POPSubRound(CGFloat f, CGFloat sub) +{ + return round(f * sub) / sub; +} + +#define MIX(a, b, f) ((a) + (f) * ((b) - (a))) + +// the longer the duration, the higher the necessary precision +#define SOLVE_EPS(dur) (1. / (1000. * (dur))) + +#define _EQLF_(x, y, epsilon) (fabsf ((x) - (y)) < epsilon) + +extern void POPInterpolateVector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, CGFloat f); + +extern double POPTimingFunctionSolve(const double vec[4], double t, double eps); + +// quadratic mapping of t [0, 1] to [start, end] +extern double POPQuadraticOutInterpolation(double t, double start, double end); + +// normalize value to [0, 1] based on its range [startValue, endValue] +extern double POPNormalize(double value, double startValue, double endValue); + +// project a normalized value [0, 1] to a given range [start, end] +extern double POPProjectNormal(double n, double start, double end); + +// solve a quadratic equation of the form a * x^2 + b * x + c = 0 +extern void POPQuadraticSolve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2); + +// for a given tension return the bouncy 3 friction that produces no bounce +extern double POPBouncy3NoBounce(double tension); diff --git a/Unit-2-Journal/Pods/pop/pop/POPMath.mm b/Unit-2-Journal/Pods/pop/pop/POPMath.mm new file mode 100644 index 0000000..69a506a --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPMath.mm @@ -0,0 +1,83 @@ +/** + Copyright (c) 2014-present, 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 "POPMath.h" + +#import "POPAnimationPrivate.h" +#import "UnitBezier.h" + +void POPInterpolateVector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, CGFloat f) +{ + for (NSUInteger idx = 0; idx < count; idx++) { + dst[idx] = MIX(from[idx], to[idx], f); + } +} + +double POPTimingFunctionSolve(const double vec[4], double t, double eps) +{ + WebCore::UnitBezier bezier(vec[0], vec[1], vec[2], vec[3]); + return bezier.solve(t, eps); +} + +double POPNormalize(double value, double startValue, double endValue) +{ + return (value - startValue) / (endValue - startValue); +} + +double POPProjectNormal(double n, double start, double end) +{ + return start + (n * (end - start)); +} + +static double linear_interpolation(double t, double start, double end) +{ + return t * end + (1.f - t) * start; +} + +double POPQuadraticOutInterpolation(double t, double start, double end) +{ + return linear_interpolation(2*t - t*t, start, end); +} + +static double b3_friction1(double x) +{ + return (0.0007 * pow(x, 3)) - (0.031 * pow(x, 2)) + 0.64 * x + 1.28; +} + +static double b3_friction2(double x) +{ + return (0.000044 * pow(x, 3)) - (0.006 * pow(x, 2)) + 0.36 * x + 2.; +} + +static double b3_friction3(double x) +{ + return (0.00000045 * pow(x, 3)) - (0.000332 * pow(x, 2)) + 0.1078 * x + 5.84; +} + +double POPBouncy3NoBounce(double tension) +{ + double friction = 0; + if (tension <= 18.) { + friction = b3_friction1(tension); + } else if (tension > 18 && tension <= 44) { + friction = b3_friction2(tension); + } else if (tension > 44) { + friction = b3_friction3(tension); + } else { + assert(false); + } + return friction; +} + +void POPQuadraticSolve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2) +{ + CGFloat discriminant = sqrt(b * b - 4 * a * c); + x1 = (-b + discriminant) / (2 * a); + x2 = (-b - discriminant) / (2 * a); +} diff --git a/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.h new file mode 100644 index 0000000..2861665 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.h @@ -0,0 +1,65 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPAnimatableProperty.h> +#import <pop/POPAnimation.h> + +/** + @abstract Flags for clamping animation values. + @discussion Animation values can optionally be clamped to avoid overshoot. kPOPAnimationClampStart ensures values are more than fromValue and kPOPAnimationClampEnd ensures values are less than toValue. + */ +typedef NS_OPTIONS(NSUInteger, POPAnimationClampFlags) +{ + kPOPAnimationClampNone = 0, + kPOPAnimationClampStart = 1UL << 0, + kPOPAnimationClampEnd = 1UL << 1, + kPOPAnimationClampBoth = kPOPAnimationClampStart | kPOPAnimationClampEnd, +}; + +/** + @abstract The semi-concrete property animation subclass. + */ +@interface POPPropertyAnimation : POPAnimation + +/** + @abstract The property to animate. + */ +@property (strong, nonatomic) POPAnimatableProperty *property; + +/** + @abstract The value to animate from. + @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start. + */ +@property (copy, nonatomic) id fromValue; + +/** + @abstract The value to animate to. + @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start. + */ +@property (copy, nonatomic) id toValue; + +/** + @abstract The rounding factor applied to the current animated value. + @discussion Specify 1.0 to animate between integral values. Defaults to 0 meaning no rounding. + */ +@property (assign, nonatomic) CGFloat roundingFactor; + +/** + @abstract The clamp mode applied to the current animated value. + @discussion See {@ref POPAnimationClampFlags} for possible values. Defaults to kPOPAnimationClampNone. + */ +@property (assign, nonatomic) NSUInteger clampMode; + +/** + @abstract The flag indicating whether values should be "added" each frame, rather than set. + @discussion Addition may be type dependent. Defaults to NO. + */ +@property (assign, nonatomic, getter = isAdditive) BOOL additive; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.mm new file mode 100644 index 0000000..56a9e5c --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimation.mm @@ -0,0 +1,125 @@ +/** + Copyright (c) 2014-present, 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 "POPPropertyAnimationInternal.h" + +@implementation POPPropertyAnimation + +#pragma mark - Lifecycle + +#undef __state +#define __state ((POPPropertyAnimationState *)_state) + +- (void)_initState +{ + _state = new POPPropertyAnimationState(self); +} + +#pragma mark - Properties + +DEFINE_RW_FLAG(POPPropertyAnimationState, additive, isAdditive, setAdditive:); +DEFINE_RW_PROPERTY(POPPropertyAnimationState, roundingFactor, setRoundingFactor:, CGFloat); +DEFINE_RW_PROPERTY(POPPropertyAnimationState, clampMode, setClampMode:, NSUInteger); +DEFINE_RW_PROPERTY_OBJ(POPPropertyAnimationState, property, setProperty:, POPAnimatableProperty*, ((POPPropertyAnimationState*)_state)->updatedDynamicsThreshold();); +DEFINE_RW_PROPERTY_OBJ_COPY(POPPropertyAnimationState, progressMarkers, setProgressMarkers:, NSArray*, ((POPPropertyAnimationState*)_state)->updatedProgressMarkers();); + +- (id)fromValue +{ + return POPBox(__state->fromVec, __state->valueType); +} + +- (void)setFromValue:(id)aValue +{ + POPPropertyAnimationState *s = __state; + VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); + if (!vec_equal(vec, s->fromVec)) { + s->fromVec = vec; + + if (s->tracing) { + [s->tracer updateFromValue:aValue]; + } + } +} + +- (id)toValue +{ + return POPBox(__state->toVec, __state->valueType); +} + +- (void)setToValue:(id)aValue +{ + POPPropertyAnimationState *s = __state; + VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); + + if (!vec_equal(vec, s->toVec)) { + s->toVec = vec; + + // invalidate to dependent state + s->didReachToValue = false; + s->distanceVec = NULL; + + if (s->tracing) { + [s->tracer updateToValue:aValue]; + } + + // automatically unpause active animations + if (s->active && s->paused) { + s->setPaused(false); + } + } +} + +- (id)currentValue +{ + return POPBox(__state->currentValue(), __state->valueType); +} + +#pragma mark - Utility + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + [s appendFormat:@"; from = %@; to = %@", describe(__state->fromVec), describe(__state->toVec)]; + + if (_state->active) + [s appendFormat:@"; currentValue = %@", describe(__state->currentValue())]; + + if (__state->velocityVec && 0 != __state->velocityVec->norm()) + [s appendFormat:@"; velocity = %@", describe(__state->velocityVec)]; + + if (!self.removedOnCompletion) + [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)]; + + if (__state->progressMarkers) + [s appendFormat:@"; progressMarkers = [%@]", [__state->progressMarkers componentsJoinedByString:@", "]]; + + if (_state->active) + [s appendFormat:@"; progress = %f", __state->progress]; +} + +@end + +@implementation POPPropertyAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone { + + POPPropertyAnimation *copy = [super copyWithZone:zone]; + + if (copy) { + copy.property = [self.property copyWithZone:zone]; + copy.fromValue = self.fromValue; + copy.toValue = self.toValue; + copy.roundingFactor = self.roundingFactor; + copy.clampMode = self.clampMode; + copy.additive = self.additive; + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimationInternal.h b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimationInternal.h new file mode 100644 index 0000000..9f2aee4 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPPropertyAnimationInternal.h @@ -0,0 +1,359 @@ +/** + Copyright (c) 2014-present, 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 "POPAnimationInternal.h" +#import "POPPropertyAnimation.h" + +static void clampValue(CGFloat &value, CGFloat fromValue, CGFloat toValue, NSUInteger clamp) +{ + BOOL increasing = (toValue > fromValue); + + // Clamp start of animation. + if ((kPOPAnimationClampStart & clamp) && + ((increasing && (value < fromValue)) || (!increasing && (value > fromValue)))) { + value = fromValue; + } + + // Clamp end of animation. + if ((kPOPAnimationClampEnd & clamp) && + ((increasing && (value > toValue)) || (!increasing && (value < toValue)))) { + value = toValue; + } +} + +struct _POPPropertyAnimationState : _POPAnimationState +{ + POPAnimatableProperty *property; + POPValueType valueType; + NSUInteger valueCount; + VectorRef fromVec; + VectorRef toVec; + VectorRef currentVec; + VectorRef previousVec; + VectorRef previous2Vec; + VectorRef velocityVec; + VectorRef originalVelocityVec; + VectorRef distanceVec; + CGFloat roundingFactor; + NSUInteger clampMode; + NSArray *progressMarkers; + POPProgressMarker *progressMarkerState; + NSUInteger progressMarkerCount; + NSUInteger nextProgressMarkerIdx; + CGFloat dynamicsThreshold; + + _POPPropertyAnimationState(id __unsafe_unretained anim) : _POPAnimationState(anim), + property(nil), + valueType((POPValueType)0), + valueCount(0), + fromVec(nullptr), + toVec(nullptr), + currentVec(nullptr), + previousVec(nullptr), + previous2Vec(nullptr), + velocityVec(nullptr), + originalVelocityVec(nullptr), + distanceVec(nullptr), + roundingFactor(0), + clampMode(0), + progressMarkers(nil), + progressMarkerState(nil), + progressMarkerCount(0), + nextProgressMarkerIdx(0), + dynamicsThreshold(0) + { + type = kPOPAnimationBasic; + } + + ~_POPPropertyAnimationState() + { + if (progressMarkerState) { + free(progressMarkerState); + progressMarkerState = NULL; + } + } + + bool canProgress() { + return hasValue(); + } + + bool shouldRound() { + return 0 != roundingFactor; + } + + bool hasValue() { + return 0 != valueCount; + } + + bool isDone() { + // inherit done + if (_POPAnimationState::isDone()) { + return true; + } + + // consider an animation with no values done + if (!hasValue() && !isCustom()) { + return true; + } + + return false; + } + + // returns a copy of the currentVec, rounding if needed + VectorRef currentValue() { + VectorRef vec = VectorRef(Vector::new_vector(currentVec.get())); + if (shouldRound()) { + vec->subRound(1 / roundingFactor); + } + return vec; + } + + void resetProgressMarkerState() + { + for (NSUInteger idx = 0; idx < progressMarkerCount; idx++) + progressMarkerState[idx].reached = false; + + nextProgressMarkerIdx = 0; + } + + void updatedProgressMarkers() + { + if (progressMarkerState) { + free(progressMarkerState); + progressMarkerState = NULL; + } + + progressMarkerCount = progressMarkers.count; + + if (0 != progressMarkerCount) { + progressMarkerState = (POPProgressMarker *)malloc(progressMarkerCount * sizeof(POPProgressMarker)); + [progressMarkers enumerateObjectsUsingBlock:^(NSNumber *progressMarker, NSUInteger idx, BOOL *stop) { + progressMarkerState[idx].reached = false; + progressMarkerState[idx].progress = [progressMarker floatValue]; + }]; + } + + nextProgressMarkerIdx = 0; + } + + virtual void updatedDynamicsThreshold() + { + dynamicsThreshold = property.threshold; + } + + void finalizeProgress() + { + progress = 1.0; + NSUInteger count = valueCount; + VectorRef outVec(Vector::new_vector(count, NULL)); + + if (outVec && toVec) { + *outVec = *toVec; + } + + currentVec = outVec; + clampCurrentValue(); + delegateProgress(); + } + + void computeProgress() { + if (!canProgress()) { + return; + } + + static ComputeProgressFunctor<Vector4r> func; + Vector4r v = vector4(currentVec); + Vector4r f = vector4(fromVec); + Vector4r t = vector4(toVec); + progress = func(v, f, t); + } + + void delegateProgress() { + if (!canProgress()) { + return; + } + + if (delegateDidProgress && progressMarkerState) { + + while (nextProgressMarkerIdx < progressMarkerCount) { + if (progress < progressMarkerState[nextProgressMarkerIdx].progress) + break; + + if (!progressMarkerState[nextProgressMarkerIdx].reached) { + ActionEnabler enabler; + [delegate pop_animation:self didReachProgress:progressMarkerState[nextProgressMarkerIdx].progress]; + progressMarkerState[nextProgressMarkerIdx].reached = true; + } + + nextProgressMarkerIdx++; + } + } + + if (!didReachToValue) { + bool didReachToValue = false; + if (0 == valueCount) { + didReachToValue = true; + } else { + Vector4r distance = toVec->vector4r(); + distance -= currentVec->vector4r(); + + if (0 == distance.squaredNorm()) { + didReachToValue = true; + } else { + // components + if (distanceVec) { + didReachToValue = true; + const CGFloat *distanceValues = distanceVec->data(); + for (NSUInteger idx = 0; idx < valueCount; idx++) { + didReachToValue &= (signbit(distance[idx]) != signbit(distanceValues[idx])); + } + } + } + } + + if (didReachToValue) { + handleDidReachToValue(); + } + } + } + + void handleDidReachToValue() { + didReachToValue = true; + + if (delegateDidReachToValue) { + ActionEnabler enabler; + [delegate pop_animationDidReachToValue:self]; + } + + POPAnimationDidReachToValueBlock block = animationDidReachToValueBlock; + if (block != NULL) { + ActionEnabler enabler; + block(self); + } + + if (tracing) { + [tracer didReachToValue:POPBox(currentValue(), valueType, true)]; + } + } + + void readObjectValue(VectorRef *ptrVec, id obj) + { + // use current object value as from value + pop_animatable_read_block read = property.readBlock; + if (NULL != read) { + + Vector4r vec = read_values(read, obj, valueCount); + *ptrVec = VectorRef(Vector::new_vector(valueCount, vec)); + + if (tracing) { + [tracer readPropertyValue:POPBox(*ptrVec, valueType, true)]; + } + } + } + + virtual void willRun(bool started, id obj) { + // ensure from value initialized + if (NULL == fromVec) { + readObjectValue(&fromVec, obj); + } + + // ensure to value initialized + if (NULL == toVec) { + // compute decay to value + if (kPOPAnimationDecay == type) { + [self toValue]; + } else { + // read to value + readObjectValue(&toVec, obj); + } + } + + // handle one time value initialization on start + if (started) { + + // initialize current vec + if (!currentVec) { + currentVec = VectorRef(Vector::new_vector(valueCount, NULL)); + + // initialize current value with from value + // only do this on initial creation to avoid overwriting current value + // on paused animation continuation + if (currentVec && fromVec) { + *currentVec = *fromVec; + } + } + + // ensure velocity values + if (!velocityVec) { + velocityVec = VectorRef(Vector::new_vector(valueCount, NULL)); + } + if (!originalVelocityVec) { + originalVelocityVec = VectorRef(Vector::new_vector(valueCount, NULL)); + } + } + + // ensure distance value initialized + // depends on current value set on one time start + if (NULL == distanceVec) { + + // not yet started animations may not have current value + VectorRef fromVec2 = NULL != currentVec ? currentVec : fromVec; + + if (fromVec2 && toVec) { + Vector4r distance = toVec->vector4r(); + distance -= fromVec2->vector4r(); + + if (0 != distance.squaredNorm()) { + distanceVec = VectorRef(Vector::new_vector(valueCount, distance)); + } + } + } + } + + virtual void reset(bool all) { + _POPAnimationState::reset(all); + + if (all) { + currentVec = NULL; + previousVec = NULL; + previous2Vec = NULL; + } + progress = 0; + resetProgressMarkerState(); + didReachToValue = false; + distanceVec = NULL; + } + + void clampCurrentValue(NSUInteger clamp) + { + if (kPOPAnimationClampNone == clamp) + return; + + // Clamp all vector values + CGFloat *currentValues = currentVec->data(); + const CGFloat *fromValues = fromVec->data(); + const CGFloat *toValues = toVec->data(); + + for (NSUInteger idx = 0; idx < valueCount; idx++) { + clampValue(currentValues[idx], fromValues[idx], toValues[idx], clamp); + } + } + + void clampCurrentValue() + { + clampCurrentValue(clampMode); + } +}; + +typedef struct _POPPropertyAnimationState POPPropertyAnimationState; + +@interface POPPropertyAnimation () + +@end + diff --git a/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.h b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.h new file mode 100644 index 0000000..a22cd5b --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.h @@ -0,0 +1,67 @@ +/** + Copyright (c) 2014-present, 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 <pop/POPPropertyAnimation.h> + +/** + @abstract A concrete spring animation class. + @discussion Animation is achieved through modeling spring dynamics. + */ +@interface POPSpringAnimation : POPPropertyAnimation + +/** + @abstract The designated initializer. + @returns An instance of a spring animation. + */ ++ (instancetype)animation; + +/** + @abstract Convenience initializer that returns an animation with animatable property of name. + @param name The name of the animatable property. + @returns An instance of a spring animation configured with specified animatable property. + */ ++ (instancetype)animationWithPropertyNamed:(NSString *)name; + +/** + @abstract The current velocity value. + @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second. + */ +@property (copy, nonatomic) id velocity; + +/** + @abstract The effective bounciness. + @discussion Use in conjunction with 'springSpeed' to change animation effect. Values are converted into corresponding dynamics constants. Higher values increase spring movement range resulting in more oscillations and springiness. Defined as a value in the range [0, 20]. Defaults to 4. + */ +@property (assign, nonatomic) CGFloat springBounciness; + +/** + @abstract The effective speed. + @discussion Use in conjunction with 'springBounciness' to change animation effect. Values are converted into corresponding dynamics constants. Higher values increase the dampening power of the spring resulting in a faster initial velocity and more rapid bounce slowdown. Defined as a value in the range [0, 20]. Defaults to 12. + */ +@property (assign, nonatomic) CGFloat springSpeed; + +/** + @abstract The tension used in the dynamics simulation. + @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. + */ +@property (assign, nonatomic) CGFloat dynamicsTension; + +/** + @abstract The friction used in the dynamics simulation. + @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. + */ +@property (assign, nonatomic) CGFloat dynamicsFriction; + +/** + @abstract The mass used in the dynamics simulation. + @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. + */ +@property (assign, nonatomic) CGFloat dynamicsMass; + +@end diff --git a/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.mm b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.mm new file mode 100644 index 0000000..d299770 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimation.mm @@ -0,0 +1,192 @@ +/** + Copyright (c) 2014-present, 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 "POPSpringAnimationInternal.h" + +@implementation POPSpringAnimation + +#pragma mark - Lifecycle + +#undef __state +#define __state ((POPSpringAnimationState *)_state) + ++ (instancetype)animation +{ + return [[self alloc] init]; +} + ++ (instancetype)animationWithPropertyNamed:(NSString *)aName +{ + POPSpringAnimation *anim = [self animation]; + anim.property = [POPAnimatableProperty propertyWithName:aName]; + return anim; +} + +- (void)_initState +{ + _state = new POPSpringAnimationState(self); +} + +- (id)init +{ + self = [super _init]; + if (nil != self) { + __state->solver = new SpringSolver4d(1, 1, 1); + __state->updatedDynamicsThreshold(); + __state->updatedBouncinessAndSpeed(); + } + return self; +} + +- (void)dealloc +{ + if (__state) { + delete __state->solver; + __state->solver = NULL; + } +} + +#pragma mark - Properties + +- (id)velocity +{ + return POPBox(__state->velocityVec, __state->valueType); +} + +- (void)setVelocity:(id)aValue +{ + POPPropertyAnimationState *s = __state; + VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); + VectorRef origVec = POPUnbox(aValue, s->valueType, s->valueCount, YES); + if (!vec_equal(vec, s->velocityVec)) { + s->velocityVec = vec; + s->originalVelocityVec = origVec; + + if (s->tracing) { + [s->tracer updateVelocity:aValue]; + } + } +} + +DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsTension, setDynamicsTension:, CGFloat, [self _updatedDynamicsTension];); +DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsFriction, setDynamicsFriction:, CGFloat, [self _updatedDynamicsFriction];); +DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsMass, setDynamicsMass:, CGFloat, [self _updatedDynamicsMass];); + +FB_PROPERTY_GET(POPSpringAnimationState, springSpeed, CGFloat); +- (void)setSpringSpeed:(CGFloat)aFloat +{ + POPSpringAnimationState *s = __state; + if (s->userSpecifiedDynamics || aFloat != s->springSpeed) { + s->springSpeed = aFloat; + s->userSpecifiedDynamics = false; + s->updatedBouncinessAndSpeed(); + if (s->tracing) { + [s->tracer updateSpeed:aFloat]; + } + } +} + +FB_PROPERTY_GET(POPSpringAnimationState, springBounciness, CGFloat); +- (void)setSpringBounciness:(CGFloat)aFloat +{ + POPSpringAnimationState *s = __state; + if (s->userSpecifiedDynamics || aFloat != s->springBounciness) { + s->springBounciness = aFloat; + s->userSpecifiedDynamics = false; + s->updatedBouncinessAndSpeed(); + if (s->tracing) { + [s->tracer updateBounciness:aFloat]; + } + } +} + +- (SpringSolver4d *)solver +{ + return __state->solver; +} + +- (void)setSolver:(SpringSolver4d *)aSolver +{ + if (aSolver != __state->solver) { + if (__state->solver) { + delete(__state->solver); + } + __state->solver = aSolver; + } +} + +#pragma mark - Utility + +- (void)_updatedDynamicsTension +{ + __state->userSpecifiedDynamics = true; + if(__state->tracing) { + [__state->tracer updateTension:__state->dynamicsTension]; + } + __state->updatedDynamics(); +} + +- (void)_updatedDynamicsFriction +{ + __state->userSpecifiedDynamics = true; + if(__state->tracing) { + [__state->tracer updateFriction:__state->dynamicsFriction]; + } + __state->updatedDynamics(); +} + +- (void)_updatedDynamicsMass +{ + __state->userSpecifiedDynamics = true; + if(__state->tracing) { + [__state->tracer updateMass:__state->dynamicsMass]; + } + __state->updatedDynamics(); +} + +- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug +{ + [super _appendDescription:s debug:debug]; + + if (debug) { + if (_state->userSpecifiedDynamics) { + [s appendFormat:@"; dynamics = (tension:%f, friction:%f, mass:%f)", __state->dynamicsTension, __state->dynamicsFriction, __state->dynamicsMass]; + } else { + [s appendFormat:@"; bounciness = %f; speed = %f", __state->springBounciness, __state->springSpeed]; + } + } +} + +@end + +@implementation POPSpringAnimation (NSCopying) + +- (instancetype)copyWithZone:(NSZone *)zone { + + POPSpringAnimation *copy = [super copyWithZone:zone]; + + if (copy) { + id velocity = POPBox(__state->originalVelocityVec, __state->valueType); + + // If velocity never gets set, then POPBox will return nil, messing up __state->valueCount. + if (velocity) { + copy.velocity = velocity; + } + + copy.springBounciness = self.springBounciness; + copy.springSpeed = self.springSpeed; + copy.dynamicsTension = self.dynamicsTension; + copy.dynamicsFriction = self.dynamicsFriction; + copy.dynamicsMass = self.dynamicsMass; + } + + return copy; +} + +@end \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/POPSpringAnimationInternal.h b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimationInternal.h new file mode 100644 index 0000000..6a72a43 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPSpringAnimationInternal.h @@ -0,0 +1,132 @@ +/** + Copyright (c) 2014-present, 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 <cmath> + +#import "POPAnimationExtras.h" +#import "POPPropertyAnimationInternal.h" + +struct _POPSpringAnimationState : _POPPropertyAnimationState +{ + SpringSolver4d *solver; + CGFloat springSpeed; + CGFloat springBounciness; // normalized springiness + CGFloat dynamicsTension; // tension + CGFloat dynamicsFriction; // friction + CGFloat dynamicsMass; // mass + + _POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim), + solver(nullptr), + springSpeed(12.), + springBounciness(4.), + dynamicsTension(0), + dynamicsFriction(0), + dynamicsMass(0) + { + type = kPOPAnimationSpring; + } + + bool hasConverged() + { + NSUInteger count = valueCount; + if (shouldRound()) { + return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec); + } else { + if (!previousVec || !previous2Vec) + return false; + + CGFloat t = dynamicsThreshold / 5; + + const CGFloat *toValues = toVec->data(); + const CGFloat *previousValues = previousVec->data(); + const CGFloat *previous2Values = previous2Vec->data(); + + for (NSUInteger idx = 0; idx < count; idx++) { + if ((std::abs(toValues[idx] - previousValues[idx]) >= t) || (std::abs(previous2Values[idx] - previousValues[idx]) >= t)) { + return false; + } + } + return true; + } + } + + bool isDone() { + if (_POPPropertyAnimationState::isDone()) { + return true; + } + return solver->started() && (hasConverged() || solver->hasConverged()); + } + + void updatedDynamics() + { + if (NULL != solver) { + solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass); + } + } + + void updatedDynamicsThreshold() + { + _POPPropertyAnimationState::updatedDynamicsThreshold(); + if (NULL != solver) { + solver->setThreshold(dynamicsThreshold); + } + } + + void updatedBouncinessAndSpeed() { + [POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass]; + updatedDynamics(); + } + + bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { + // advance past not yet initialized animations + if (NULL == currentVec) { + return false; + } + + CFTimeInterval localTime = time - startTime; + + Vector4d value = vector4d(currentVec); + Vector4d toValue = vector4d(toVec); + Vector4d velocity = vector4d(velocityVec); + + SSState4d state; + state.p = toValue - value; + + // the solver assumes a spring of size zero + // flip the velocity from user perspective to solver perspective + state.v = velocity * -1; + + solver->advance(state, localTime, dt); + value = toValue - state.p; + + // flip velocity back to user perspective + velocity = state.v * -1; + + *currentVec = value; + + if (velocityVec) { + *velocityVec = velocity; + } + + clampCurrentValue(); + + return true; + } + + virtual void reset(bool all) { + _POPPropertyAnimationState::reset(all); + + if (solver) { + solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass); + solver->reset(); + } + } +}; + +typedef struct _POPSpringAnimationState POPSpringAnimationState; diff --git a/Unit-2-Journal/Pods/pop/pop/POPSpringSolver.h b/Unit-2-Journal/Pods/pop/pop/POPSpringSolver.h new file mode 100644 index 0000000..df485bf --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPSpringSolver.h @@ -0,0 +1,190 @@ +/** + Copyright (c) 2014-present, 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 <Foundation/Foundation.h> + +#import "POPVector.h" + +namespace POP { + + template <typename T> + struct SSState + { + T p; + T v; + }; + + template <typename T> + struct SSDerivative + { + T dp; + T dv; + }; + + typedef SSState<Vector4d> SSState4d; + typedef SSDerivative<Vector4d> SSDerivative4d; + + const CFTimeInterval solverDt = 0.001f; + const CFTimeInterval maxSolverDt = 30.0f; + + /** + Templated spring solver class. + */ + template <typename T> + class SpringSolver + { + double _k; // stiffness + double _b; // dampening + double _m; // mass + + double _tp; // threshold + double _tv; // threshold velocity + double _ta; // threshold acceleration + + CFTimeInterval _accumulatedTime; + SSState<T> _lastState; + T _lastDv; + bool _started; + + public: + SpringSolver(double k, double b, double m = 1) : _k(k), _b(b), _m(m), _started(false) + { + _accumulatedTime = 0; + _lastState.p = T::Zero(); + _lastState.v = T::Zero(); + _lastDv = T::Zero(); + setThreshold(1.); + } + + ~SpringSolver() + { + } + + bool started() + { + return _started; + } + + void setConstants(double k, double b, double m) + { + _k = k; + _b = b; + _m = m; + } + + void setThreshold(double t) + { + _tp = t / 2; // half a unit + _tv = 25.0 * t; // 5 units per second, squared for comparison + _ta = 625.0 * t * t; // 5 units per second squared, squared for comparison + } + + T acceleration(const SSState<T> &state, double t) + { + return state.p*(-_k/_m) - state.v*(_b/_m); + } + + SSDerivative<T> evaluate(const SSState<T> &initial, double t) + { + SSDerivative<T> output; + output.dp = initial.v; + output.dv = acceleration(initial, t); + return output; + } + + SSDerivative<T> evaluate(const SSState<T> &initial, double t, double dt, const SSDerivative<T> &d) + { + SSState<T> state; + state.p = initial.p + d.dp*dt; + state.v = initial.v + d.dv*dt; + SSDerivative<T> output; + output.dp = state.v; + output.dv = acceleration(state, t+dt); + return output; + } + + void integrate(SSState<T> &state, double t, double dt) + { + SSDerivative<T> a = evaluate(state, t); + SSDerivative<T> b = evaluate(state, t, dt*0.5, a); + SSDerivative<T> c = evaluate(state, t, dt*0.5, b); + SSDerivative<T> d = evaluate(state, t, dt, c); + + T dpdt = (a.dp + (b.dp + c.dp)*2.0 + d.dp) * (1.0/6.0); + T dvdt = (a.dv + (b.dv + c.dv)*2.0 + d.dv) * (1.0/6.0); + + state.p = state.p + dpdt*dt; + state.v = state.v + dvdt*dt; + + _lastDv = dvdt; + } + + SSState<T> interpolate(const SSState<T> &previous, const SSState<T> ¤t, double alpha) + { + SSState<T> state; + state.p = current.p*alpha + previous.p*(1-alpha); + state.v = current.v*alpha + previous.v*(1-alpha); + return state; + } + + void advance(SSState<T> &state, double t, double dt) + { + _started = true; + + if (dt > maxSolverDt) { + // excessive time step, force shut down + _lastDv = _lastState.v = _lastState.p = T::Zero(); + } else { + _accumulatedTime += dt; + + SSState<T> previousState = state, currentState = state; + while (_accumulatedTime >= solverDt) { + previousState = currentState; + this->integrate(currentState, t, solverDt); + t += solverDt; + _accumulatedTime -= solverDt; + } + CFTimeInterval alpha = _accumulatedTime / solverDt; + _lastState = state = this->interpolate(previousState, currentState, alpha); + } + } + + bool hasConverged() + { + if (!_started) { + return false; + } + + for (size_t idx = 0; idx < _lastState.p.size(); idx++) { + if (fabs(_lastState.p(idx)) >= _tp) { + return false; + } + } + + return (_lastState.v.squaredNorm() < _tv) && (_lastDv.squaredNorm() < _ta); + } + + void reset() + { + _accumulatedTime = 0; + _lastState.p = T::Zero(); + _lastState.v = T::Zero(); + _lastDv = T::Zero(); + _started = false; + } + }; + + /** + Convenience spring solver type definitions. + */ + typedef SpringSolver<Vector2d> SpringSolver2d; + typedef SpringSolver<Vector3d> SpringSolver3d; + typedef SpringSolver<Vector4d> SpringSolver4d; +} + diff --git a/Unit-2-Journal/Pods/pop/pop/POPVector.h b/Unit-2-Journal/Pods/pop/pop/POPVector.h new file mode 100644 index 0000000..44d4e9f --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPVector.h @@ -0,0 +1,394 @@ +/** + Copyright (c) 2014-present, 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. + */ + +#ifndef __POP__FBVector__ +#define __POP__FBVector__ + +#include <iostream> +#include <vector> + +#import <objc/NSObjCRuntime.h> + +#import <CoreGraphics/CoreGraphics.h> + +#import "POPDefines.h" + +#if SCENEKIT_SDK_AVAILABLE +#import <SceneKit/SceneKit.h> +#endif + +#if TARGET_OS_IPHONE +#import <UIKit/UIKit.h> +#endif + +#import "POPMath.h" + +namespace POP { + + /** Fixed two-size vector class */ + template <typename T> + struct Vector2 + { + private: + typedef T Vector2<T>::* const _data[2]; + static const _data _v; + + public: + T x; + T y; + + // Zero vector + static const Vector2 Zero() { return Vector2(0); } + + // Constructors + Vector2() {} + explicit Vector2(T v) { x = v; y = v; }; + explicit Vector2(T x0, T y0) : x(x0), y(y0) {}; + explicit Vector2(const CGPoint &p) : x(p.x), y (p.y) {} + explicit Vector2(const CGSize &s) : x(s.width), y (s.height) {} + + // Copy constructor + template<typename U> explicit Vector2(const Vector2<U> &v) : x(v.x), y(v.y) {} + + // Index operators + const T& operator[](size_t i) const { return this->*_v[i]; } + T& operator[](size_t i) { return this->*_v[i]; } + const T& operator()(size_t i) const { return this->*_v[i]; } + T& operator()(size_t i) { return this->*_v[i]; } + + // Backing data + T * data() { return &(this->*_v[0]); } + const T * data() const { return &(this->*_v[0]); } + + // Size + inline size_t size() const { return 2; } + + // Assignment + Vector2 &operator= (T v) { x = v; y = v; return *this;} + template<typename U> Vector2 &operator= (const Vector2<U> &v) { x = v.x; y = v.y; return *this;} + + // Negation + Vector2 operator- (void) const { return Vector2<T>(-x, -y); } + + // Equality + bool operator== (T v) const { return (x == v && y == v); } + bool operator== (const Vector2 &v) const { return (x == v.x && y == v.y); } + + // Inequality + bool operator!= (T v) const {return (x != v || y != v); } + bool operator!= (const Vector2 &v) const { return (x != v.x || y != v.y); } + + // Scalar Math + Vector2 operator+ (T v) const { return Vector2(x + v, y + v); } + Vector2 operator- (T v) const { return Vector2(x - v, y - v); } + Vector2 operator* (T v) const { return Vector2(x * v, y * v); } + Vector2 operator/ (T v) const { return Vector2(x / v, y / v); } + Vector2 &operator+= (T v) { x += v; y += v; return *this; }; + Vector2 &operator-= (T v) { x -= v; y -= v; return *this; }; + Vector2 &operator*= (T v) { x *= v; y *= v; return *this; }; + Vector2 &operator/= (T v) { x /= v; y /= v; return *this; }; + + // Vector Math + Vector2 operator+ (const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator- (const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } + Vector2 &operator+= (const Vector2 &v) { x += v.x; y += v.y; return *this; }; + Vector2 &operator-= (const Vector2 &v) { x -= v.x; y -= v.y; return *this; }; + + // Norms + CGFloat norm() const { return sqrtr(squaredNorm()); } + CGFloat squaredNorm() const { return x * x + y * y; } + + // Cast + template<typename U> Vector2<U> cast() const { return Vector2<U>(x, y); } + CGPoint cg_point() const { return CGPointMake(x, y); }; + }; + + template<typename T> + const typename Vector2<T>::_data Vector2<T>::_v = { &Vector2<T>::x, &Vector2<T>::y }; + + /** Fixed three-size vector class */ + template <typename T> + struct Vector3 + { + private: + typedef T Vector3<T>::* const _data[3]; + static const _data _v; + + public: + T x; + T y; + T z; + + // Zero vector + static const Vector3 Zero() { return Vector3(0); }; + + // Constructors + Vector3() {} + explicit Vector3(T v) : x(v), y(v), z(v) {}; + explicit Vector3(T x0, T y0, T z0) : x(x0), y(y0), z(z0) {}; + + // Copy constructor + template<typename U> explicit Vector3(const Vector3<U> &v) : x(v.x), y(v.y), z(v.z) {} + + // Index operators + const T& operator[](size_t i) const { return this->*_v[i]; } + T& operator[](size_t i) { return this->*_v[i]; } + const T& operator()(size_t i) const { return this->*_v[i]; } + T& operator()(size_t i) { return this->*_v[i]; } + + // Backing data + T * data() { return &(this->*_v[0]); } + const T * data() const { return &(this->*_v[0]); } + + // Size + inline size_t size() const { return 3; } + + // Assignment + Vector3 &operator= (T v) { x = v; y = v; z = v; return *this;} + template<typename U> Vector3 &operator= (const Vector3<U> &v) { x = v.x; y = v.y; z = v.z; return *this;} + + // Negation + Vector3 operator- (void) const { return Vector3<T>(-x, -y, -z); } + + // Equality + bool operator== (T v) const { return (x == v && y == v && z = v); } + bool operator== (const Vector3 &v) const { return (x == v.x && y == v.y && z == v.z); } + + // Inequality + bool operator!= (T v) const {return (x != v || y != v || z != v); } + bool operator!= (const Vector3 &v) const { return (x != v.x || y != v.y || z != v.z); } + + // Scalar Math + Vector3 operator+ (T v) const { return Vector3(x + v, y + v, z + v); } + Vector3 operator- (T v) const { return Vector3(x - v, y - v, z - v); } + Vector3 operator* (T v) const { return Vector3(x * v, y * v, z * v); } + Vector3 operator/ (T v) const { return Vector3(x / v, y / v, z / v); } + Vector3 &operator+= (T v) { x += v; y += v; z += v; return *this; }; + Vector3 &operator-= (T v) { x -= v; y -= v; z -= v; return *this; }; + Vector3 &operator*= (T v) { x *= v; y *= v; z *= v; return *this; }; + Vector3 &operator/= (T v) { x /= v; y /= v; z /= v; return *this; }; + + // Vector Math + Vector3 operator+ (const Vector3 &v) const { return Vector3(x + v.x, y + v.y, z + v.z); } + Vector3 operator- (const Vector3 &v) const { return Vector3(x - v.x, y - v.y, z - v.z); } + Vector3 &operator+= (const Vector3 &v) { x += v.x; y += v.y; z += v.z; return *this; }; + Vector3 &operator-= (const Vector3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }; + + // Norms + CGFloat norm() const { return sqrtr(squaredNorm()); } + CGFloat squaredNorm() const { return x * x + y * y + z * z; } + + // Cast + template<typename U> Vector3<U> cast() const { return Vector3<U>(x, y, z); } + }; + + template<typename T> + const typename Vector3<T>::_data Vector3<T>::_v = { &Vector3<T>::x, &Vector3<T>::y, &Vector3<T>::z }; + + /** Fixed four-size vector class */ + template <typename T> + struct Vector4 + { + private: + typedef T Vector4<T>::* const _data[4]; + static const _data _v; + + public: + T x; + T y; + T z; + T w; + + // Zero vector + static const Vector4 Zero() { return Vector4(0); }; + + // Constructors + Vector4() {} + explicit Vector4(T v) : x(v), y(v), z(v), w(v) {}; + explicit Vector4(T x0, T y0, T z0, T w0) : x(x0), y(y0), z(z0), w(w0) {}; + + // Copy constructor + template<typename U> explicit Vector4(const Vector4<U> &v) : x(v.x), y(v.y), z(v.z), w(v.w) {} + + // Index operators + const T& operator[](size_t i) const { return this->*_v[i]; } + T& operator[](size_t i) { return this->*_v[i]; } + const T& operator()(size_t i) const { return this->*_v[i]; } + T& operator()(size_t i) { return this->*_v[i]; } + + // Backing data + T * data() { return &(this->*_v[0]); } + const T * data() const { return &(this->*_v[0]); } + + // Size + inline size_t size() const { return 4; } + + // Assignment + Vector4 &operator= (T v) { x = v; y = v; z = v; w = v; return *this;} + template<typename U> Vector4 &operator= (const Vector4<U> &v) { x = v.x; y = v.y; z = v.z; w = v.w; return *this;} + + // Negation + Vector4 operator- (void) const { return Vector4<T>(-x, -y, -z, -w); } + + // Equality + bool operator== (T v) const { return (x == v && y == v && z = v, w = v); } + bool operator== (const Vector4 &v) const { return (x == v.x && y == v.y && z == v.z && w == v.w); } + + // Inequality + bool operator!= (T v) const {return (x != v || y != v || z != v || w != v); } + bool operator!= (const Vector4 &v) const { return (x != v.x || y != v.y || z != v.z || w != v.w); } + + // Scalar Math + Vector4 operator+ (T v) const { return Vector4(x + v, y + v, z + v, w + v); } + Vector4 operator- (T v) const { return Vector4(x - v, y - v, z - v, w - v); } + Vector4 operator* (T v) const { return Vector4(x * v, y * v, z * v, w * v); } + Vector4 operator/ (T v) const { return Vector4(x / v, y / v, z / v, w / v); } + Vector4 &operator+= (T v) { x += v; y += v; z += v; w += v; return *this; }; + Vector4 &operator-= (T v) { x -= v; y -= v; z -= v; w -= v; return *this; }; + Vector4 &operator*= (T v) { x *= v; y *= v; z *= v; w *= v; return *this; }; + Vector4 &operator/= (T v) { x /= v; y /= v; z /= v; w /= v; return *this; }; + + // Vector Math + Vector4 operator+ (const Vector4 &v) const { return Vector4(x + v.x, y + v.y, z + v.z, w + v.w); } + Vector4 operator- (const Vector4 &v) const { return Vector4(x - v.x, y - v.y, z - v.z, w - v.w); } + Vector4 &operator+= (const Vector4 &v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }; + Vector4 &operator-= (const Vector4 &v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }; + + // Norms + CGFloat norm() const { return sqrtr(squaredNorm()); } + CGFloat squaredNorm() const { return x * x + y * y + z * z + w * w; } + + // Cast + template<typename U> Vector4<U> cast() const { return Vector4<U>(x, y, z, w); } + }; + + template<typename T> + const typename Vector4<T>::_data Vector4<T>::_v = { &Vector4<T>::x, &Vector4<T>::y, &Vector4<T>::z, &Vector4<T>::w }; + + /** Convenience typedefs */ + typedef Vector2<float> Vector2f; + typedef Vector2<double> Vector2d; + typedef Vector2<CGFloat> Vector2r; + typedef Vector3<float> Vector3f; + typedef Vector3<double> Vector3d; + typedef Vector3<CGFloat> Vector3r; + typedef Vector4<float> Vector4f; + typedef Vector4<double> Vector4d; + typedef Vector4<CGFloat> Vector4r; + + /** Variable-sized vector class */ + class Vector + { + size_t _count; + CGFloat *_values; + + private: + Vector(size_t); + Vector(const Vector& other); + + public: + ~Vector(); + + // Creates a new vector instance of count with values. Initializing a vector of size 0 returns NULL. + static Vector *new_vector(NSUInteger count, const CGFloat *values); + + // Creates a new vector given a pointer to another. Can return NULL. + static Vector *new_vector(const Vector * const other); + + // Creates a variable size vector given a static vector and count. + static Vector *new_vector(NSUInteger count, Vector4r vec); + + // Size of vector + NSUInteger size() const { return _count; } + + // Returns array of values + CGFloat *data () { return _values; } + const CGFloat *data () const { return _values; }; + + // Vector2r support + Vector2r vector2r() const; + + // Vector4r support + Vector4r vector4r() const; + + // CGFloat support + static Vector *new_cg_float(CGFloat f); + + // CGPoint support + CGPoint cg_point() const; + static Vector *new_cg_point(const CGPoint &p); + + // CGSize support + CGSize cg_size() const; + static Vector *new_cg_size(const CGSize &s); + + // CGRect support + CGRect cg_rect() const; + static Vector *new_cg_rect(const CGRect &r); + +#if TARGET_OS_IPHONE + // UIEdgeInsets support + UIEdgeInsets ui_edge_insets() const; + static Vector *new_ui_edge_insets(const UIEdgeInsets &i); +#endif + + // CGAffineTransform support + CGAffineTransform cg_affine_transform() const; + static Vector *new_cg_affine_transform(const CGAffineTransform &t); + + // CGColorRef support + CGColorRef cg_color() const CF_RETURNS_RETAINED; + static Vector *new_cg_color(CGColorRef color); + +#if SCENEKIT_SDK_AVAILABLE + // SCNVector3 support + SCNVector3 scn_vector3() const; + static Vector *new_scn_vector3(const SCNVector3 &vec3); + + // SCNVector4 support + SCNVector4 scn_vector4() const; + static Vector *new_scn_vector4(const SCNVector4 &vec4); +#endif + + // operator overloads + CGFloat &operator[](size_t i) const { + NSCAssert(size() > i, @"unexpected vector size:%lu", (unsigned long)size()); + return _values[i]; + } + + // Returns the mathematical length + CGFloat norm() const; + CGFloat squaredNorm() const; + + // Round to nearest sub + void subRound(CGFloat sub); + + // Returns string description + NSString * toString() const; + + // Operator overloads + template<typename U> Vector& operator= (const Vector4<U>& other) { + size_t count = MIN(_count, other.size()); + for (size_t i = 0; i < count; i++) { + _values[i] = other[i]; + } + return *this; + } + Vector& operator= (const Vector& other); + void swap(Vector &first, Vector &second); + bool operator==(const Vector &other) const; + bool operator!=(const Vector &other) const; + }; + + /** Convenience typedefs */ + typedef std::shared_ptr<Vector> VectorRef; + typedef std::shared_ptr<const Vector> VectorConstRef; + +} +#endif /* defined(__POP__FBVector__) */ diff --git a/Unit-2-Journal/Pods/pop/pop/POPVector.mm b/Unit-2-Journal/Pods/pop/pop/POPVector.mm new file mode 100644 index 0000000..96cee24 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/POPVector.mm @@ -0,0 +1,334 @@ +/** + Copyright (c) 2014-present, 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 "POPVector.h" + +#import "POPDefines.h" +#import "POPCGUtils.h" + +namespace POP +{ + + Vector::Vector(const size_t count) + { + _count = count; + _values = 0 != count ? (CGFloat *)calloc(count, sizeof(CGFloat)) : NULL; + } + + Vector::Vector(const Vector& other) + { + _count = other.size(); + _values = 0 != _count ? (CGFloat *)calloc(_count, sizeof(CGFloat)) : NULL; + if (0 != _count) { + memcpy(_values, other.data(), _count * sizeof(CGFloat)); + } + } + + Vector::~Vector() + { + if (NULL != _values) { + free(_values); + _values = NULL; + } + _count = 0; + } + + void Vector::swap(Vector &first, Vector &second) + { + using std::swap; + swap(first._count, second._count); + swap(first._values, second._values); + } + + Vector& Vector::operator=(const Vector& other) + { + Vector temp(other); + swap(*this, temp); + return *this; + } + + bool Vector::operator==(const Vector &other) const { + if (_count != other.size()) { + return false; + } + + const CGFloat * const values = other.data(); + + for (NSUInteger idx = 0; idx < _count; idx++) { + if (_values[idx] != values[idx]) { + return false; + } + } + + return true; + } + + bool Vector::operator!=(const Vector &other) const { + if (_count == other.size()) { + return false; + } + + const CGFloat * const values = other.data(); + + for (NSUInteger idx = 0; idx < _count; idx++) { + if (_values[idx] != values[idx]) { + return false; + } + } + + return true; + } + + Vector *Vector::new_vector(NSUInteger count, const CGFloat *values) + { + if (0 == count) { + return NULL; + } + + Vector *v = new Vector(count); + if (NULL != values) { + memcpy(v->_values, values, count * sizeof(CGFloat)); + } + return v; + } + + Vector *Vector::new_vector(const Vector * const other) + { + if (NULL == other) { + return NULL; + } + + return Vector::new_vector(other->size(), other->data()); + } + + Vector *Vector::new_vector(NSUInteger count, Vector4r vec) + { + if (0 == count) { + return NULL; + } + + Vector *v = new Vector(count); + + NSCAssert(count <= 4, @"unexpected count %lu", (unsigned long)count); + for (NSUInteger i = 0; i < MIN(count, (NSUInteger)4); i++) { + v->_values[i] = vec[i]; + } + + return v; + } + + Vector4r Vector::vector4r() const + { + Vector4r v = Vector4r::Zero(); + for (size_t i = 0; i < _count; i++) { + v(i) = _values[i]; + } + return v; + } + + Vector2r Vector::vector2r() const + { + Vector2r v = Vector2r::Zero(); + if (_count > 0) v(0) = _values[0]; + if (_count > 1) v(1) = _values[1]; + return v; + } + + Vector *Vector::new_cg_float(CGFloat f) + { + Vector *v = new Vector(1); + v->_values[0] = f; + return v; + } + + CGPoint Vector::cg_point () const + { + Vector2r v = vector2r(); + return CGPointMake(v(0), v(1)); + } + + Vector *Vector::new_cg_point(const CGPoint &p) + { + Vector *v = new Vector(2); + v->_values[0] = p.x; + v->_values[1] = p.y; + return v; + } + + CGSize Vector::cg_size () const + { + Vector2r v = vector2r(); + return CGSizeMake(v(0), v(1)); + } + + Vector *Vector::new_cg_size(const CGSize &s) + { + Vector *v = new Vector(2); + v->_values[0] = s.width; + v->_values[1] = s.height; + return v; + } + + CGRect Vector::cg_rect() const + { + return _count < 4 ? CGRectZero : CGRectMake(_values[0], _values[1], _values[2], _values[3]); + } + + Vector *Vector::new_cg_rect(const CGRect &r) + { + Vector *v = new Vector(4); + v->_values[0] = r.origin.x; + v->_values[1] = r.origin.y; + v->_values[2] = r.size.width; + v->_values[3] = r.size.height; + return v; + } + +#if TARGET_OS_IPHONE + + UIEdgeInsets Vector::ui_edge_insets() const + { + return _count < 4 ? UIEdgeInsetsZero : UIEdgeInsetsMake(_values[0], _values[1], _values[2], _values[3]); + } + + Vector *Vector::new_ui_edge_insets(const UIEdgeInsets &i) + { + Vector *v = new Vector(4); + v->_values[0] = i.top; + v->_values[1] = i.left; + v->_values[2] = i.bottom; + v->_values[3] = i.right; + return v; + } + +#endif + + CGAffineTransform Vector::cg_affine_transform() const + { + if (_count < 6) { + return CGAffineTransformIdentity; + } + + NSCAssert(size() >= 6, @"unexpected vector size:%lu", (unsigned long)size()); + CGAffineTransform t; + t.a = _values[0]; + t.b = _values[1]; + t.c = _values[2]; + t.d = _values[3]; + t.tx = _values[4]; + t.ty = _values[5]; + return t; + } + + Vector *Vector::new_cg_affine_transform(const CGAffineTransform &t) + { + Vector *v = new Vector(6); + v->_values[0] = t.a; + v->_values[1] = t.b; + v->_values[2] = t.c; + v->_values[3] = t.d; + v->_values[4] = t.tx; + v->_values[5] = t.ty; + return v; + } + + CGColorRef Vector::cg_color() const + { + if (_count < 4) { + return NULL; + } + return POPCGColorRGBACreate(_values); + } + + Vector *Vector::new_cg_color(CGColorRef color) + { + CGFloat rgba[4]; + POPCGColorGetRGBAComponents(color, rgba); + return new_vector(4, rgba); + } + +#if SCENEKIT_SDK_AVAILABLE + SCNVector3 Vector::scn_vector3() const + { + return _count < 3 ? SCNVector3Make(0.0, 0.0, 0.0) : SCNVector3Make(_values[0], _values[1], _values[2]); + } + + Vector *Vector::new_scn_vector3(const SCNVector3 &vec3) + { + Vector *v = new Vector(3); + v->_values[0] = vec3.x; + v->_values[1] = vec3.y; + v->_values[2] = vec3.z; + return v; + } + + SCNVector4 Vector::scn_vector4() const + { + return _count < 4 ? SCNVector4Make(0.0, 0.0, 0.0, 0.0) : SCNVector4Make(_values[0], _values[1], _values[2], _values[3]); + } + + Vector *Vector::new_scn_vector4(const SCNVector4 &vec4) + { + Vector *v = new Vector(4); + v->_values[0] = vec4.x; + v->_values[1] = vec4.y; + v->_values[2] = vec4.z; + v->_values[3] = vec4.w; + return v; + } +#endif + + void Vector::subRound(CGFloat sub) + { + for (NSUInteger idx = 0; idx < _count; idx++) { + _values[idx] = POPSubRound(_values[idx], sub); + } + } + + CGFloat Vector::norm() const + { + return sqrtr(squaredNorm()); + } + + CGFloat Vector::squaredNorm() const + { + CGFloat d = 0; + for (NSUInteger idx = 0; idx < _count; idx++) { + d += (_values[idx] * _values[idx]); + } + return d; + } + + NSString * Vector::toString() const + { + if (0 == _count) + return @"()"; + + if (1 == _count) + return [NSString stringWithFormat:@"%f", _values[0]]; + + if (2 == _count) + return [NSString stringWithFormat:@"(%.3f, %.3f)", _values[0], _values[1]]; + + NSMutableString *s = [NSMutableString stringWithCapacity:10]; + + for (NSUInteger idx = 0; idx < _count; idx++) { + if (0 == idx) { + [s appendFormat:@"[%.3f", _values[idx]]; + } else if (idx == _count - 1) { + [s appendFormat:@", %.3f]", _values[idx]]; + } else { + [s appendFormat:@", %.3f", _values[idx]]; + } + } + + return s; + + } +} diff --git a/Unit-2-Journal/Pods/pop/pop/WebCore/FloatConversion.h b/Unit-2-Journal/Pods/pop/pop/WebCore/FloatConversion.h new file mode 100644 index 0000000..4a16166 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/WebCore/FloatConversion.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 Apple 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifndef FloatConversion_h +#define FloatConversion_h + +#include <CoreGraphics/CGBase.h> + +namespace WebCore { + + template<typename T> + float narrowPrecisionToFloat(T); + + template<> + inline float narrowPrecisionToFloat(double number) + { + return static_cast<float>(number); + } + + template<typename T> + CGFloat narrowPrecisionToCGFloat(T); + + template<> + inline CGFloat narrowPrecisionToCGFloat(double number) + { + return static_cast<CGFloat>(number); + } + +} // namespace WebCore + +#endif // FloatConversion_h diff --git a/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.cpp b/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.cpp new file mode 100644 index 0000000..7264ab5 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.cpp @@ -0,0 +1,1074 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. + */ + +#include "TransformationMatrix.h" + +#include <math.h> + +#include "FloatConversion.h" + +inline double deg2rad(double d) { return d * M_PI / 180.0; } +inline double rad2deg(double r) { return r * 180.0 / M_PI; } +inline double deg2grad(double d) { return d * 400.0 / 360.0; } +inline double grad2deg(double g) { return g * 360.0 / 400.0; } +inline double turn2deg(double t) { return t * 360.0; } +inline double deg2turn(double d) { return d / 360.0; } +inline double rad2grad(double r) { return r * 200.0 / M_PI; } +inline double grad2rad(double g) { return g * M_PI / 200.0; } + +//using namespace std; + +namespace WebCore { + + // + // Supporting Math Functions + // + // This is a set of function from various places (attributed inline) to do things like + // inversion and decomposition of a 4x4 matrix. They are used throughout the code + // + + // + // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>. + + // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code + // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial + // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there + // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or + // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes + // with no guarantee. + + // A clarification about the storage of matrix elements + // + // This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into + // the array refers to the column that the element lies in; the second index refers to the row. + // + // In other words, this is the layout of the matrix: + // + // | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] | + // | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] | + // | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] | + // | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] | + + typedef double Vector4[4]; + typedef double Vector3[3]; + + const double SMALL_NUMBER = 1.e-8; + + // inverse(original_matrix, inverse_matrix) + // + // calculate the inverse of a 4x4 matrix + // + // -1 + // A = ___1__ adjoint A + // det A + + // double = determinant2x2(double a, double b, double c, double d) + // + // calculate the determinant of a 2x2 matrix. + + static double determinant2x2(double a, double b, double c, double d) + { + return a * d - b * c; + } + + // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) + // + // Calculate the determinant of a 3x3 matrix + // in the form + // + // | a1, b1, c1 | + // | a2, b2, c2 | + // | a3, b3, c3 | + + static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) + { + return a1 * determinant2x2(b2, b3, c2, c3) + - b1 * determinant2x2(a2, a3, c2, c3) + + c1 * determinant2x2(a2, a3, b2, b3); + } + + // double = determinant4x4(matrix) + // + // calculate the determinant of a 4x4 matrix. + + static double determinant4x4(const TransformationMatrix::Matrix4& m) + { + // Assign to individual variable names to aid selecting + // correct elements + + double a1 = m[0][0]; + double b1 = m[0][1]; + double c1 = m[0][2]; + double d1 = m[0][3]; + + double a2 = m[1][0]; + double b2 = m[1][1]; + double c2 = m[1][2]; + double d2 = m[1][3]; + + double a3 = m[2][0]; + double b3 = m[2][1]; + double c3 = m[2][2]; + double d3 = m[2][3]; + + double a4 = m[3][0]; + double b4 = m[3][1]; + double c4 = m[3][2]; + double d4 = m[3][3]; + + return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) + - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) + - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); + } + + // adjoint( original_matrix, inverse_matrix ) + // + // calculate the adjoint of a 4x4 matrix + // + // Let a denote the minor determinant of matrix A obtained by + // ij + // + // deleting the ith row and jth column from A. + // + // i+j + // Let b = (-1) a + // ij ji + // + // The matrix B = (b ) is the adjoint of A + // ij + + static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) + { + // Assign to individual variable names to aid + // selecting correct values + double a1 = matrix[0][0]; + double b1 = matrix[0][1]; + double c1 = matrix[0][2]; + double d1 = matrix[0][3]; + + double a2 = matrix[1][0]; + double b2 = matrix[1][1]; + double c2 = matrix[1][2]; + double d2 = matrix[1][3]; + + double a3 = matrix[2][0]; + double b3 = matrix[2][1]; + double c3 = matrix[2][2]; + double d3 = matrix[2][3]; + + double a4 = matrix[3][0]; + double b4 = matrix[3][1]; + double c4 = matrix[3][2]; + double d4 = matrix[3][3]; + + // Row column labeling reversed since we transpose rows & columns + result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); + result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); + result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); + result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); + + result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); + result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); + result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); + result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); + + result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); + result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); + result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); + result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); + + result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); + result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); + result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); + result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); + } + + // Returns false if the matrix is not invertible + static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) + { + // Calculate the adjoint matrix + adjoint(matrix, result); + + // Calculate the 4x4 determinant + // If the determinant is zero, + // then the inverse matrix is not unique. + double det = determinant4x4(matrix); + + if (fabs(det) < SMALL_NUMBER) + return false; + + // Scale the adjoint matrix to get the inverse + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + result[i][j] = result[i][j] / det; + + return true; + } + + // End of code adapted from Matrix Inversion by Richard Carling + + // Perform a decomposition on the passed matrix, return false if unsuccessful + // From Graphics Gems: unmatrix.c + + // Transpose rotation portion of matrix a, return b + static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + b[i][j] = a[j][i]; + } + + // Multiply a homogeneous point by a matrix and return the transformed point + static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result) + { + result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + + (p[2] * m[2][0]) + (p[3] * m[3][0]); + result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + + (p[2] * m[2][1]) + (p[3] * m[3][1]); + result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + + (p[2] * m[2][2]) + (p[3] * m[3][2]); + result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + + (p[2] * m[2][3]) + (p[3] * m[3][3]); + } + + static double v3Length(Vector3 a) + { + return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2])); + } + + static void v3Scale(Vector3 v, double desiredLength) + { + double len = v3Length(v); + if (len != 0) { + double l = desiredLength / len; + v[0] *= l; + v[1] *= l; + v[2] *= l; + } + } + + static double v3Dot(const Vector3 a, const Vector3 b) + { + return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); + } + + // Make a linear combination of two vectors and return the result. + // result = (a * ascl) + (b * bscl) + static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl) + { + result[0] = (ascl * a[0]) + (bscl * b[0]); + result[1] = (ascl * a[1]) + (bscl * b[1]); + result[2] = (ascl * a[2]) + (bscl * b[2]); + } + + // Return the cross product result = a cross b */ + static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result) + { + result[0] = (a[1] * b[2]) - (a[2] * b[1]); + result[1] = (a[2] * b[0]) - (a[0] * b[2]); + result[2] = (a[0] * b[1]) - (a[1] * b[0]); + } + + static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result) + { + TransformationMatrix::Matrix4 localMatrix; + memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); + + // Normalize the matrix. + if (localMatrix[3][3] == 0) + return false; + + int i, j; + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + localMatrix[i][j] /= localMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + TransformationMatrix::Matrix4 perspectiveMatrix; + memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)); + for (i = 0; i < 3; i++) + perspectiveMatrix[i][3] = 0; + perspectiveMatrix[3][3] = 1; + + if (determinant4x4(perspectiveMatrix) == 0) + return false; + + // First, isolate perspective. This is the messiest. + if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) { + // rightHandSide is the right hand side of the equation. + Vector4 rightHandSide; + rightHandSide[0] = localMatrix[0][3]; + rightHandSide[1] = localMatrix[1][3]; + rightHandSide[2] = localMatrix[2][3]; + rightHandSide[3] = localMatrix[3][3]; + + // Solve the equation by inverting perspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix; + inverse(perspectiveMatrix, inversePerspectiveMatrix); + transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Vector4 perspectivePoint; + v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + result.perspectiveX = perspectivePoint[0]; + result.perspectiveY = perspectivePoint[1]; + result.perspectiveZ = perspectivePoint[2]; + result.perspectiveW = perspectivePoint[3]; + + // Clear the perspective partition + localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; + localMatrix[3][3] = 1; + } else { + // No perspective. + result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; + result.perspectiveW = 1; + } + + // Next take care of translation (easy). + result.translateX = localMatrix[3][0]; + localMatrix[3][0] = 0; + result.translateY = localMatrix[3][1]; + localMatrix[3][1] = 0; + result.translateZ = localMatrix[3][2]; + localMatrix[3][2] = 0; + + // Vector4 type and functions need to be added to the common set. + Vector3 row[3], pdum3; + + // Now get scale and shear. + for (i = 0; i < 3; i++) { + row[i][0] = localMatrix[i][0]; + row[i][1] = localMatrix[i][1]; + row[i][2] = localMatrix[i][2]; + } + + // Compute X scale factor and normalize first row. + result.scaleX = v3Length(row[0]); + v3Scale(row[0], 1.0); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + result.skewXY = v3Dot(row[0], row[1]); + v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY); + + // Now, compute Y scale and normalize 2nd row. + result.scaleY = v3Length(row[1]); + v3Scale(row[1], 1.0); + result.skewXY /= result.scaleY; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + result.skewXZ = v3Dot(row[0], row[2]); + v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ); + result.skewYZ = v3Dot(row[1], row[2]); + v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ); + + // Next, get Z scale and normalize 3rd row. + result.scaleZ = v3Length(row[2]); + v3Scale(row[2], 1.0); + result.skewXZ /= result.scaleZ; + result.skewYZ /= result.scaleZ; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + v3Cross(row[1], row[2], pdum3); + if (v3Dot(row[0], pdum3) < 0) { + + result.scaleX *= -1; + result.scaleY *= -1; + result.scaleZ *= -1; + + for (i = 0; i < 3; i++) { + row[i][0] *= -1; + row[i][1] *= -1; + row[i][2] *= -1; + } + } + + // Now, get the rotations out, as described in the gem. + + result.rotateY = asin(-row[0][2]); + if (cos(result.rotateY) != 0) { + result.rotateX = atan2(row[1][2], row[2][2]); + result.rotateZ = atan2(row[0][1], row[0][0]); + } else { + result.rotateX = atan2(-row[2][0], row[1][1]); + result.rotateZ = 0; + } + + double s, t, x, y, z, w; + + t = row[0][0] + row[1][1] + row[2][2] + 1.0; + + if (t > 1e-4) { + s = 0.5 / sqrt(t); + w = 0.25 / s; + x = (row[2][1] - row[1][2]) * s; + y = (row[0][2] - row[2][0]) * s; + z = (row[1][0] - row[0][1]) * s; + } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { + s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx + x = 0.25 * s; + y = (row[0][1] + row[1][0]) / s; + z = (row[0][2] + row[2][0]) / s; + w = (row[2][1] - row[1][2]) / s; + } else if (row[1][1] > row[2][2]) { + s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy + x = (row[0][1] + row[1][0]) / s; + y = 0.25 * s; + z = (row[1][2] + row[2][1]) / s; + w = (row[0][2] - row[2][0]) / s; + } else { + s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz + x = (row[0][2] + row[2][0]) / s; + y = (row[1][2] + row[2][1]) / s; + z = 0.25 * s; + w = (row[1][0] - row[0][1]) / s; + } + + result.quaternionX = x; + result.quaternionY = y; + result.quaternionZ = z; + result.quaternionW = w; + + return true; + } + + // Perform a spherical linear interpolation between the two + // passed quaternions with 0 <= t <= 1 + static void slerp(double qa[4], const double qb[4], double t) + { + double ax, ay, az, aw; + double bx, by, bz, bw; + double cx, cy, cz, cw; + double angle; + double th, invth, scale, invscale; + + ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3]; + bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3]; + + angle = ax * bx + ay * by + az * bz + aw * bw; + + if (angle < 0.0) { + ax = -ax; ay = -ay; + az = -az; aw = -aw; + angle = -angle; + } + + if (angle + 1.0 > .05) { + if (1.0 - angle >= .05) { + th = acos (angle); + invth = 1.0 / sin (th); + scale = sin (th * (1.0 - t)) * invth; + invscale = sin (th * t) * invth; + } else { + scale = 1.0 - t; + invscale = t; + } + } else { + bx = -ay; + by = ax; + bz = -aw; + bw = az; + scale = sin(M_PI * (.5 - t)); + invscale = sin (M_PI * t); + } + + cx = ax * scale + bx * invscale; + cy = ay * scale + by * invscale; + cz = az * scale + bz * invscale; + cw = aw * scale + bw * invscale; + + qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw; + } + + // End of Supporting Math Functions + + TransformationMatrix::TransformationMatrix(const CGAffineTransform& t) + { + setMatrix(t.a, t.b, t.c, t.d, t.tx, t.ty); + } + + TransformationMatrix::TransformationMatrix(const CATransform3D& t) + { + setMatrix( + t.m11, t.m12, t.m13, t.m14, + t.m21, t.m22, t.m23, t.m24, + t.m31, t.m32, t.m33, t.m34, + t.m41, t.m42, t.m43, t.m44); + } + + CATransform3D TransformationMatrix::transform3d() const + { + CATransform3D t; + t.m11 = narrowPrecisionToFloat(m11()); + t.m12 = narrowPrecisionToFloat(m12()); + t.m13 = narrowPrecisionToFloat(m13()); + t.m14 = narrowPrecisionToFloat(m14()); + t.m21 = narrowPrecisionToFloat(m21()); + t.m22 = narrowPrecisionToFloat(m22()); + t.m23 = narrowPrecisionToFloat(m23()); + t.m24 = narrowPrecisionToFloat(m24()); + t.m31 = narrowPrecisionToFloat(m31()); + t.m32 = narrowPrecisionToFloat(m32()); + t.m33 = narrowPrecisionToFloat(m33()); + t.m34 = narrowPrecisionToFloat(m34()); + t.m41 = narrowPrecisionToFloat(m41()); + t.m42 = narrowPrecisionToFloat(m42()); + t.m43 = narrowPrecisionToFloat(m43()); + t.m44 = narrowPrecisionToFloat(m44()); + return t; + } + + CGAffineTransform TransformationMatrix::affineTransform () const + { + CGAffineTransform t; + t.a = narrowPrecisionToFloat(m11()); + t.b = narrowPrecisionToFloat(m12()); + t.c = narrowPrecisionToFloat(m21()); + t.d = narrowPrecisionToFloat(m22()); + t.tx = narrowPrecisionToFloat(m41()); + t.ty = narrowPrecisionToFloat(m42()); + return t; + } + + TransformationMatrix::operator CATransform3D() const + { + return transform3d(); + } + + TransformationMatrix& TransformationMatrix::scale(double s) + { + return scaleNonUniform(s, s); + } + + TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) + { + return rotate(rad2deg(atan2(y, x))); + } + + TransformationMatrix& TransformationMatrix::flipX() + { + return scaleNonUniform(-1.0, 1.0); + } + + TransformationMatrix& TransformationMatrix::flipY() + { + return scaleNonUniform(1.0, -1.0); + } + + TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy) + { + m_matrix[0][0] *= sx; + m_matrix[0][1] *= sx; + m_matrix[0][2] *= sx; + m_matrix[0][3] *= sx; + + m_matrix[1][0] *= sy; + m_matrix[1][1] *= sy; + m_matrix[1][2] *= sy; + m_matrix[1][3] *= sy; + return *this; + } + + TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz) + { + scaleNonUniform(sx, sy); + + m_matrix[2][0] *= sz; + m_matrix[2][1] *= sz; + m_matrix[2][2] *= sz; + m_matrix[2][3] *= sz; + return *this; + } + + TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle) + { + // Normalize the axis of rotation + double length = sqrt(x * x + y * y + z * z); + if (length == 0) { + // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied. + return *this; + } else if (length != 1) { + x /= length; + y /= length; + z /= length; + } + + // Angles are in degrees. Switch to radians. + angle = deg2rad(angle); + + double sinTheta = sin(angle); + double cosTheta = cos(angle); + + TransformationMatrix mat; + + // Optimize cases where the axis is along a major axis + if (x == 1.0 && y == 0.0 && z == 0.0) { + mat.m_matrix[0][0] = 1.0; + mat.m_matrix[0][1] = 0.0; + mat.m_matrix[0][2] = 0.0; + mat.m_matrix[1][0] = 0.0; + mat.m_matrix[1][1] = cosTheta; + mat.m_matrix[1][2] = sinTheta; + mat.m_matrix[2][0] = 0.0; + mat.m_matrix[2][1] = -sinTheta; + mat.m_matrix[2][2] = cosTheta; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + } else if (x == 0.0 && y == 1.0 && z == 0.0) { + mat.m_matrix[0][0] = cosTheta; + mat.m_matrix[0][1] = 0.0; + mat.m_matrix[0][2] = -sinTheta; + mat.m_matrix[1][0] = 0.0; + mat.m_matrix[1][1] = 1.0; + mat.m_matrix[1][2] = 0.0; + mat.m_matrix[2][0] = sinTheta; + mat.m_matrix[2][1] = 0.0; + mat.m_matrix[2][2] = cosTheta; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + } else if (x == 0.0 && y == 0.0 && z == 1.0) { + mat.m_matrix[0][0] = cosTheta; + mat.m_matrix[0][1] = sinTheta; + mat.m_matrix[0][2] = 0.0; + mat.m_matrix[1][0] = -sinTheta; + mat.m_matrix[1][1] = cosTheta; + mat.m_matrix[1][2] = 0.0; + mat.m_matrix[2][0] = 0.0; + mat.m_matrix[2][1] = 0.0; + mat.m_matrix[2][2] = 1.0; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + } else { + // This case is the rotation about an arbitrary unit vector. + // + // Formula is adapted from Wikipedia article on Rotation matrix, + // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle + // + // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/ + // + double oneMinusCosTheta = 1 - cosTheta; + mat.m_matrix[0][0] = cosTheta + x * x * oneMinusCosTheta; + mat.m_matrix[0][1] = y * x * oneMinusCosTheta + z * sinTheta; + mat.m_matrix[0][2] = z * x * oneMinusCosTheta - y * sinTheta; + mat.m_matrix[1][0] = x * y * oneMinusCosTheta - z * sinTheta; + mat.m_matrix[1][1] = cosTheta + y * y * oneMinusCosTheta; + mat.m_matrix[1][2] = z * y * oneMinusCosTheta + x * sinTheta; + mat.m_matrix[2][0] = x * z * oneMinusCosTheta + y * sinTheta; + mat.m_matrix[2][1] = y * z * oneMinusCosTheta - x * sinTheta; + mat.m_matrix[2][2] = cosTheta + z * z * oneMinusCosTheta; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + } + multiply(mat); + return *this; + } + + TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz) + { + // Angles are in degrees. Switch to radians. + rx = deg2rad(rx); + ry = deg2rad(ry); + rz = deg2rad(rz); + + TransformationMatrix mat; + + double sinTheta = sin(rz); + double cosTheta = cos(rz); + + mat.m_matrix[0][0] = cosTheta; + mat.m_matrix[0][1] = sinTheta; + mat.m_matrix[0][2] = 0.0; + mat.m_matrix[1][0] = -sinTheta; + mat.m_matrix[1][1] = cosTheta; + mat.m_matrix[1][2] = 0.0; + mat.m_matrix[2][0] = 0.0; + mat.m_matrix[2][1] = 0.0; + mat.m_matrix[2][2] = 1.0; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + + TransformationMatrix rmat(mat); + + sinTheta = sin(ry); + cosTheta = cos(ry); + + mat.m_matrix[0][0] = cosTheta; + mat.m_matrix[0][1] = 0.0; + mat.m_matrix[0][2] = -sinTheta; + mat.m_matrix[1][0] = 0.0; + mat.m_matrix[1][1] = 1.0; + mat.m_matrix[1][2] = 0.0; + mat.m_matrix[2][0] = sinTheta; + mat.m_matrix[2][1] = 0.0; + mat.m_matrix[2][2] = cosTheta; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + + rmat.multiply(mat); + + sinTheta = sin(rx); + cosTheta = cos(rx); + + mat.m_matrix[0][0] = 1.0; + mat.m_matrix[0][1] = 0.0; + mat.m_matrix[0][2] = 0.0; + mat.m_matrix[1][0] = 0.0; + mat.m_matrix[1][1] = cosTheta; + mat.m_matrix[1][2] = sinTheta; + mat.m_matrix[2][0] = 0.0; + mat.m_matrix[2][1] = -sinTheta; + mat.m_matrix[2][2] = cosTheta; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0; + mat.m_matrix[3][3] = 1.0; + + rmat.multiply(mat); + + multiply(rmat); + return *this; + } + + TransformationMatrix& TransformationMatrix::translate(double tx, double ty) + { + m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; + m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; + m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; + m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; + return *this; + } + + TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) + { + m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; + m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; + m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; + m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; + return *this; + } + + TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty) + { + if (tx != 0) { + m_matrix[0][0] += m_matrix[0][3] * tx; + m_matrix[1][0] += m_matrix[1][3] * tx; + m_matrix[2][0] += m_matrix[2][3] * tx; + m_matrix[3][0] += m_matrix[3][3] * tx; + } + + if (ty != 0) { + m_matrix[0][1] += m_matrix[0][3] * ty; + m_matrix[1][1] += m_matrix[1][3] * ty; + m_matrix[2][1] += m_matrix[2][3] * ty; + m_matrix[3][1] += m_matrix[3][3] * ty; + } + + return *this; + } + + TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz) + { + translateRight(tx, ty); + if (tz != 0) { + m_matrix[0][2] += m_matrix[0][3] * tz; + m_matrix[1][2] += m_matrix[1][3] * tz; + m_matrix[2][2] += m_matrix[2][3] * tz; + m_matrix[3][2] += m_matrix[3][3] * tz; + } + + return *this; + } + + TransformationMatrix& TransformationMatrix::skew(double sx, double sy) + { + // angles are in degrees. Switch to radians + sx = deg2rad(sx); + sy = deg2rad(sy); + + TransformationMatrix mat; + mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row + mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row + + multiply(mat); + return *this; + } + + TransformationMatrix& TransformationMatrix::applyPerspective(double p) + { + TransformationMatrix mat; + if (p != 0) + mat.m_matrix[2][3] = -1/p; + + multiply(mat); + return *this; + } + + // this = mat * this. + TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat) + { + Matrix4 tmp; + + tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0] + + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]); + tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1] + + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]); + tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2] + + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]); + tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3] + + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]); + + tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0] + + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]); + tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1] + + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]); + tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2] + + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]); + tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3] + + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]); + + tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0] + + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]); + tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1] + + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]); + tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2] + + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]); + tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3] + + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]); + + tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0] + + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]); + tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1] + + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]); + tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2] + + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]); + tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3] + + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]); + + setMatrix(tmp); + return *this; + } + + void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const + { + resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0]; + resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1]; + double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3]; + if (w != 1 && w != 0) { + resultX /= w; + resultY /= w; + } + } + + void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const + { + resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; + resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; + resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2]; + double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3]; + if (w != 1 && w != 0) { + resultX /= w; + resultY /= w; + resultZ /= w; + } + } + + bool TransformationMatrix::isInvertible() const + { + if (isIdentityOrTranslation()) + return true; + + double det = WebCore::determinant4x4(m_matrix); + + if (fabs(det) < SMALL_NUMBER) + return false; + + return true; + } + + TransformationMatrix TransformationMatrix::inverse() const + { + if (isIdentityOrTranslation()) { + // identity matrix + if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) + return TransformationMatrix(); + + // translation + return TransformationMatrix(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); + } + + TransformationMatrix invMat; + bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); + if (!inverted) + return TransformationMatrix(); + + return invMat; + } + + void TransformationMatrix::makeAffine() + { + m_matrix[0][2] = 0; + m_matrix[0][3] = 0; + + m_matrix[1][2] = 0; + m_matrix[1][3] = 0; + + m_matrix[2][0] = 0; + m_matrix[2][1] = 0; + m_matrix[2][2] = 1; + m_matrix[2][3] = 0; + + m_matrix[3][2] = 0; + m_matrix[3][3] = 1; + } + + static inline void blendFloat(double& from, double to, double progress) + { + if (from != to) + from = from + (to - from) * progress; + } + + void TransformationMatrix::blend(const TransformationMatrix& from, double progress) + { + if (from.isIdentity() && isIdentity()) + return; + + // decompose + DecomposedType fromDecomp; + DecomposedType toDecomp; + from.decompose(fromDecomp); + decompose(toDecomp); + + // interpolate + blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress); + blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress); + blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress); + blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress); + blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress); + blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress); + blendFloat(fromDecomp.translateX, toDecomp.translateX, progress); + blendFloat(fromDecomp.translateY, toDecomp.translateY, progress); + blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress); + blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress); + blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress); + blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress); + blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress); + + slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress); + + // recompose + recompose(fromDecomp); + } + + bool TransformationMatrix::decompose(DecomposedType& decomp) const + { + if (isIdentity()) { + memset(&decomp, 0, sizeof(decomp)); + decomp.perspectiveW = 1; + decomp.scaleX = 1; + decomp.scaleY = 1; + decomp.scaleZ = 1; + } + + if (!WebCore::decompose(m_matrix, decomp)) + return false; + return true; + } + + void TransformationMatrix::recompose(const DecomposedType& decomp, bool useEulerAngle) + { + makeIdentity(); + + // first apply perspective + m_matrix[0][3] = decomp.perspectiveX; + m_matrix[1][3] = decomp.perspectiveY; + m_matrix[2][3] = decomp.perspectiveZ; + m_matrix[3][3] = decomp.perspectiveW; + + // now translate + translate3d(decomp.translateX, decomp.translateY, decomp.translateZ); + + if (!useEulerAngle) { + // apply rotation + double xx = decomp.quaternionX * decomp.quaternionX; + double xy = decomp.quaternionX * decomp.quaternionY; + double xz = decomp.quaternionX * decomp.quaternionZ; + double xw = decomp.quaternionX * decomp.quaternionW; + double yy = decomp.quaternionY * decomp.quaternionY; + double yz = decomp.quaternionY * decomp.quaternionZ; + double yw = decomp.quaternionY * decomp.quaternionW; + double zz = decomp.quaternionZ * decomp.quaternionZ; + double zw = decomp.quaternionZ * decomp.quaternionW; + + // Construct a composite rotation matrix from the quaternion values + TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, + 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, + 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, + 0, 0, 0, 1); + + multiply(rotationMatrix); + } else { + rotate3d(1.0, 0.0, 0.0, rad2deg(decomp.rotateX)); + rotate3d(0.0, 1.0, 0.0, rad2deg(decomp.rotateY)); + rotate3d(0.0, 0.0, 1.0, rad2deg(decomp.rotateZ)); + } + + // now apply skew + if (decomp.skewYZ) { + TransformationMatrix tmp; + tmp.setM32(decomp.skewYZ); + multiply(tmp); + } + + if (decomp.skewXZ) { + TransformationMatrix tmp; + tmp.setM31(decomp.skewXZ); + multiply(tmp); + } + + if (decomp.skewXY) { + TransformationMatrix tmp; + tmp.setM21(decomp.skewXY); + multiply(tmp); + } + + // finally, apply scale + scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ); + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.h b/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.h new file mode 100644 index 0000000..b99ae89 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/WebCore/TransformationMatrix.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. + */ + +#ifndef TransformationMatrix_h +#define TransformationMatrix_h + +#include <string.h> //for memcpy + +#include <CoreGraphics/CGAffineTransform.h> + +#include <QuartzCore/QuartzCore.h> + +namespace WebCore { + + class TransformationMatrix { + public: + + typedef double Matrix4[4][4]; + + TransformationMatrix() { makeIdentity(); } + TransformationMatrix(const TransformationMatrix& t) { *this = t; } + TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); } + TransformationMatrix(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double m41, double m42, double m43, double m44) + { + setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44); + } + + void setMatrix(double a, double b, double c, double d, double e, double f) + { + m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0; + m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0; + m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0; + m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1; + } + + void setMatrix(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double m41, double m42, double m43, double m44) + { + m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14; + m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24; + m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34; + m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44; + } + + TransformationMatrix& operator =(const TransformationMatrix &t) + { + setMatrix(t.m_matrix); + return *this; + } + + TransformationMatrix& makeIdentity() + { + setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + return *this; + } + + bool isIdentity() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && + m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && + m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && + m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1; + } + + // This form preserves the double math from input to output + void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); } + + double m11() const { return m_matrix[0][0]; } + void setM11(double f) { m_matrix[0][0] = f; } + double m12() const { return m_matrix[0][1]; } + void setM12(double f) { m_matrix[0][1] = f; } + double m13() const { return m_matrix[0][2]; } + void setM13(double f) { m_matrix[0][2] = f; } + double m14() const { return m_matrix[0][3]; } + void setM14(double f) { m_matrix[0][3] = f; } + double m21() const { return m_matrix[1][0]; } + void setM21(double f) { m_matrix[1][0] = f; } + double m22() const { return m_matrix[1][1]; } + void setM22(double f) { m_matrix[1][1] = f; } + double m23() const { return m_matrix[1][2]; } + void setM23(double f) { m_matrix[1][2] = f; } + double m24() const { return m_matrix[1][3]; } + void setM24(double f) { m_matrix[1][3] = f; } + double m31() const { return m_matrix[2][0]; } + void setM31(double f) { m_matrix[2][0] = f; } + double m32() const { return m_matrix[2][1]; } + void setM32(double f) { m_matrix[2][1] = f; } + double m33() const { return m_matrix[2][2]; } + void setM33(double f) { m_matrix[2][2] = f; } + double m34() const { return m_matrix[2][3]; } + void setM34(double f) { m_matrix[2][3] = f; } + double m41() const { return m_matrix[3][0]; } + void setM41(double f) { m_matrix[3][0] = f; } + double m42() const { return m_matrix[3][1]; } + void setM42(double f) { m_matrix[3][1] = f; } + double m43() const { return m_matrix[3][2]; } + void setM43(double f) { m_matrix[3][2] = f; } + double m44() const { return m_matrix[3][3]; } + void setM44(double f) { m_matrix[3][3] = f; } + + double a() const { return m_matrix[0][0]; } + void setA(double a) { m_matrix[0][0] = a; } + + double b() const { return m_matrix[0][1]; } + void setB(double b) { m_matrix[0][1] = b; } + + double c() const { return m_matrix[1][0]; } + void setC(double c) { m_matrix[1][0] = c; } + + double d() const { return m_matrix[1][1]; } + void setD(double d) { m_matrix[1][1] = d; } + + double e() const { return m_matrix[3][0]; } + void setE(double e) { m_matrix[3][0] = e; } + + double f() const { return m_matrix[3][1]; } + void setF(double f) { m_matrix[3][1] = f; } + + // this = this * mat + TransformationMatrix& multiply(const TransformationMatrix&); + + TransformationMatrix& scale(double); + TransformationMatrix& scaleNonUniform(double sx, double sy); + TransformationMatrix& scale3d(double sx, double sy, double sz); + + TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); } + TransformationMatrix& rotateFromVector(double x, double y); + TransformationMatrix& rotate3d(double rx, double ry, double rz); + + // The vector (x,y,z) is normalized if it's not already. A vector of + // (0,0,0) uses a vector of (0,0,1). + TransformationMatrix& rotate3d(double x, double y, double z, double angle); + + TransformationMatrix& translate(double tx, double ty); + TransformationMatrix& translate3d(double tx, double ty, double tz); + + // translation added with a post-multiply + TransformationMatrix& translateRight(double tx, double ty); + TransformationMatrix& translateRight3d(double tx, double ty, double tz); + + TransformationMatrix& flipX(); + TransformationMatrix& flipY(); + TransformationMatrix& skew(double angleX, double angleY); + TransformationMatrix& skewX(double angle) { return skew(angle, 0); } + TransformationMatrix& skewY(double angle) { return skew(0, angle); } + + TransformationMatrix& applyPerspective(double p); + bool hasPerspective() const { return m_matrix[2][3] != 0.0f; } + + bool isInvertible() const; + + // This method returns the identity matrix if it is not invertible. + // Use isInvertible() before calling this if you need to know. + TransformationMatrix inverse() const; + + // decompose the matrix into its component parts + typedef struct { + double scaleX, scaleY, scaleZ; + double skewXY, skewXZ, skewYZ; + double rotateX, rotateY, rotateZ; + double quaternionX, quaternionY, quaternionZ, quaternionW; + double translateX, translateY, translateZ; + double perspectiveX, perspectiveY, perspectiveZ, perspectiveW; + } DecomposedType; + + bool decompose(DecomposedType& decomp) const; + void recompose(const DecomposedType& decomp, bool useEulerAngle = false); + + void blend(const TransformationMatrix& from, double progress); + + bool isAffine() const + { + return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && + m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1); + } + + // Throw away the non-affine parts of the matrix (lossy!) + void makeAffine(); + + bool operator==(const TransformationMatrix& m2) const + { + return (m_matrix[0][0] == m2.m_matrix[0][0] && + m_matrix[0][1] == m2.m_matrix[0][1] && + m_matrix[0][2] == m2.m_matrix[0][2] && + m_matrix[0][3] == m2.m_matrix[0][3] && + m_matrix[1][0] == m2.m_matrix[1][0] && + m_matrix[1][1] == m2.m_matrix[1][1] && + m_matrix[1][2] == m2.m_matrix[1][2] && + m_matrix[1][3] == m2.m_matrix[1][3] && + m_matrix[2][0] == m2.m_matrix[2][0] && + m_matrix[2][1] == m2.m_matrix[2][1] && + m_matrix[2][2] == m2.m_matrix[2][2] && + m_matrix[2][3] == m2.m_matrix[2][3] && + m_matrix[3][0] == m2.m_matrix[3][0] && + m_matrix[3][1] == m2.m_matrix[3][1] && + m_matrix[3][2] == m2.m_matrix[3][2] && + m_matrix[3][3] == m2.m_matrix[3][3]); + } + + bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } + + // *this = *this * t (i.e., a multRight) + TransformationMatrix& operator*=(const TransformationMatrix& t) + { + return multiply(t); + } + + // result = *this * t (i.e., a multRight) + TransformationMatrix operator*(const TransformationMatrix& t) + { + TransformationMatrix result = *this; + result.multiply(t); + return result; + } + + CATransform3D transform3d () const; + CGAffineTransform affineTransform () const; + + TransformationMatrix(const CATransform3D&); + operator CATransform3D() const; + + TransformationMatrix(const CGAffineTransform&); + operator CGAffineTransform() const; + + private: + + // multiply passed 2D point by matrix (assume z=0) + void multVecMatrix(double x, double y, double& dstX, double& dstY) const; + + // multiply passed 3D point by matrix + void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const; + + void setMatrix(const Matrix4 m) + { + if (m && m != m_matrix) + memcpy(m_matrix, m, sizeof(Matrix4)); + } + + bool isIdentityOrTranslation() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && + m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && + m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && + m_matrix[3][3] == 1; + } + + Matrix4 m_matrix; + }; + +} // namespace WebCore + +#endif // TransformationMatrix_h diff --git a/Unit-2-Journal/Pods/pop/pop/WebCore/UnitBezier.h b/Unit-2-Journal/Pods/pop/pop/WebCore/UnitBezier.h new file mode 100644 index 0000000..0f847a0 --- /dev/null +++ b/Unit-2-Journal/Pods/pop/pop/WebCore/UnitBezier.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008 Apple 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + */ + +#ifndef UnitBezier_h +#define UnitBezier_h + +#include <math.h> + +namespace WebCore { + + struct UnitBezier { + UnitBezier(double p1x, double p1y, double p2x, double p2y) + { + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx -bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; + } + + double sampleCurveX(double t) + { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + } + + double sampleCurveY(double t) + { + return ((ay * t + by) * t + cy) * t; + } + + double sampleCurveDerivativeX(double t) + { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + } + + // Given an x value, find a parametric value it came from. + double solveCurveX(double x, double epsilon) + { + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (fabs (x2) < epsilon) + return t2; + d2 = sampleCurveDerivativeX(t2); + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + + // Failure. + return t2; + } + + double solve(double x, double epsilon) + { + return sampleCurveY(solveCurveX(x, epsilon)); + } + + private: + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; + }; +} +#endif diff --git a/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.pbxproj b/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e4a955a --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.pbxproj @@ -0,0 +1,605 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4D0030BC1BD6AF7C00BC7BD9 /* WatchedWishListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D0030BB1BD6AF7C00BC7BD9 /* WatchedWishListViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4D7FE2941BCC12050036E58E /* TabBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7FE2931BCC12050036E58E /* TabBarViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4D7FE29D1BCC32170036E58E /* SearchAPITableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7FE29B1BCC32170036E58E /* SearchAPITableViewCell.m */; settings = {ASSET_TAGS = (); }; }; + 4D7FE29E1BCC32170036E58E /* SearchAPITableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D7FE29C1BCC32170036E58E /* SearchAPITableViewCell.xib */; settings = {ASSET_TAGS = (); }; }; + 4D7FE2A61BCC41A00036E58E /* WishListTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D7FE2A41BCC41A00036E58E /* WishListTableViewCell.xib */; settings = {ASSET_TAGS = (); }; }; + 4D9B60511BD8723B004A52E4 /* JournalHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D9B60501BD8723B004A52E4 /* JournalHeaderView.xib */; settings = {ASSET_TAGS = (); }; }; + 4D9B60541BD8731F004A52E4 /* WishListTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D9B60531BD8731F004A52E4 /* WishListTableViewCell.m */; settings = {ASSET_TAGS = (); }; }; + 4D9B60571BD8733B004A52E4 /* JournalHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D9B60561BD8733B004A52E4 /* JournalHeaderView.m */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1321BC98EF90075BA2C /* JournalMainCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCBE1311BC98EF90075BA2C /* JournalMainCollectionViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4DCBE13C1BC9943D0075BA2C /* big_nerd_ranch.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1331BC9943D0075BA2C /* big_nerd_ranch.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE13D1BC9943D0075BA2C /* destroyer.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1341BC9943D0075BA2C /* destroyer.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE13E1BC9943D0075BA2C /* drake.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1351BC9943D0075BA2C /* drake.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE13F1BC9943D0075BA2C /* lean_startup.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1361BC9943D0075BA2C /* lean_startup.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1401BC9943D0075BA2C /* run_the_jewels.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1371BC9943D0075BA2C /* run_the_jewels.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1411BC9943D0075BA2C /* sleater_kinney.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1381BC9943D0075BA2C /* sleater_kinney.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1421BC9943D0075BA2C /* talking_heads.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE1391BC9943D0075BA2C /* talking_heads.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1431BC9943D0075BA2C /* true_detective.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE13A1BC9943D0075BA2C /* true_detective.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1441BC9943D0075BA2C /* x-files.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DCBE13B1BC9943D0075BA2C /* x-files.png */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1471BC9AD6A0075BA2C /* SearchAPIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCBE1461BC9AD6A0075BA2C /* SearchAPIViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4DCBE14A1BC9ADAE0075BA2C /* CreateJournalEntryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCBE1491BC9ADAE0075BA2C /* CreateJournalEntryViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4DCBE14D1BC9ADE00075BA2C /* WishListTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCBE14C1BC9ADE00075BA2C /* WishListTableViewController.m */; settings = {ASSET_TAGS = (); }; }; + 4DCBE1501BC9BD800075BA2C /* ViewCompletedEntryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCBE14F1BC9BD800075BA2C /* ViewCompletedEntryViewController.m */; settings = {ASSET_TAGS = (); }; }; + 5A50331A1BC8D0E4001CBA5C /* MainTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A5033191BC8D0E4001CBA5C /* MainTableViewController.m */; settings = {ASSET_TAGS = (); }; }; + 5A50331D1BC8D99D001CBA5C /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A50331C1BC8D99D001CBA5C /* LoginViewController.m */; settings = {ASSET_TAGS = (); }; }; + 5A5033201BC8D9B5001CBA5C /* SignUpViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A50331F1BC8D9B5001CBA5C /* SignUpViewController.m */; settings = {ASSET_TAGS = (); }; }; + 5A6A22811BD3FE31006E9FE7 /* basictitlefont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5A6A22801BD3FDFF006E9FE7 /* basictitlefont.ttf */; }; + 5A6A22851BD4393D006E9FE7 /* Akkurat Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5A6A22841BD438B4006E9FE7 /* Akkurat Regular.otf */; settings = {ASSET_TAGS = (); }; }; + 5A6A22891BD43952006E9FE7 /* Akkurat Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5A6A22861BD4394E006E9FE7 /* Akkurat Bold.otf */; settings = {ASSET_TAGS = (); }; }; + 5A6A228A1BD43955006E9FE7 /* Akkurat Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5A6A22871BD4394E006E9FE7 /* Akkurat Italic.otf */; settings = {ASSET_TAGS = (); }; }; + 5A6A228B1BD43958006E9FE7 /* Akkurat Light Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 5A6A22881BD4394E006E9FE7 /* Akkurat Light Regular.otf */; settings = {ASSET_TAGS = (); }; }; + 5A6A22911BD43A4A006E9FE7 /* CustomFontViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A6A22901BD43A4A006E9FE7 /* CustomFontViewController.m */; settings = {ASSET_TAGS = (); }; }; + 5AE959A11BD442C1007136F4 /* LaunchScreen.Storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5AE959A01BD442C1007136F4 /* LaunchScreen.Storyboard */; settings = {ASSET_TAGS = (); }; }; + 617F8769EFBE79517A02E6D0 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FAF24AD380284C55768010A2 /* libPods.a */; }; + 9A2937201BCC26FE00ACEEE0 /* JournalPost.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A29371F1BCC26FE00ACEEE0 /* JournalPost.m */; settings = {ASSET_TAGS = (); }; }; + 9A2FFC2F1BC84BF200E880D3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2FFC2E1BC84BF200E880D3 /* main.m */; }; + 9A2FFC321BC84BF200E880D3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2FFC311BC84BF200E880D3 /* AppDelegate.m */; }; + 9A2FFC381BC84BF200E880D3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A2FFC361BC84BF200E880D3 /* Main.storyboard */; }; + 9A2FFC3B1BC84BF200E880D3 /* Unit_2_Journal.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 9A2FFC391BC84BF200E880D3 /* Unit_2_Journal.xcdatamodeld */; }; + 9A2FFC3D1BC84BF200E880D3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A2FFC3C1BC84BF200E880D3 /* Assets.xcassets */; }; + 9A34656D1BCACDF40049337C /* iTunesSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A34656C1BCACDF40049337C /* iTunesSearchResult.m */; settings = {ASSET_TAGS = (); }; }; + 9A51FF311BD5DF9F00B6AE23 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A51FF301BD5DF9F00B6AE23 /* SettingsViewController.m */; settings = {ASSET_TAGS = (); }; }; + 9AAB40061BC9FABC00FD7227 /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AAB40051BC9FABC00FD7227 /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1F41A29CEEC52ED6A148CCE5 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; }; + 2BC0A6490F88476E5C31E3B1 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; }; + 4D0030BA1BD6AF7C00BC7BD9 /* WatchedWishListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WatchedWishListViewController.h; sourceTree = "<group>"; }; + 4D0030BB1BD6AF7C00BC7BD9 /* WatchedWishListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WatchedWishListViewController.m; sourceTree = "<group>"; }; + 4D7FE2921BCC12050036E58E /* TabBarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TabBarViewController.h; sourceTree = "<group>"; }; + 4D7FE2931BCC12050036E58E /* TabBarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TabBarViewController.m; sourceTree = "<group>"; }; + 4D7FE29A1BCC32170036E58E /* SearchAPITableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchAPITableViewCell.h; sourceTree = "<group>"; }; + 4D7FE29B1BCC32170036E58E /* SearchAPITableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchAPITableViewCell.m; sourceTree = "<group>"; }; + 4D7FE29C1BCC32170036E58E /* SearchAPITableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchAPITableViewCell.xib; sourceTree = "<group>"; }; + 4D7FE2A41BCC41A00036E58E /* WishListTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WishListTableViewCell.xib; sourceTree = "<group>"; }; + 4D9B60501BD8723B004A52E4 /* JournalHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JournalHeaderView.xib; sourceTree = "<group>"; }; + 4D9B60521BD8731F004A52E4 /* WishListTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WishListTableViewCell.h; sourceTree = "<group>"; }; + 4D9B60531BD8731F004A52E4 /* WishListTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WishListTableViewCell.m; sourceTree = "<group>"; }; + 4D9B60551BD8733B004A52E4 /* JournalHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JournalHeaderView.h; sourceTree = "<group>"; }; + 4D9B60561BD8733B004A52E4 /* JournalHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JournalHeaderView.m; sourceTree = "<group>"; }; + 4DCBE1301BC98EF90075BA2C /* JournalMainCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JournalMainCollectionViewController.h; sourceTree = "<group>"; }; + 4DCBE1311BC98EF90075BA2C /* JournalMainCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JournalMainCollectionViewController.m; sourceTree = "<group>"; }; + 4DCBE1331BC9943D0075BA2C /* big_nerd_ranch.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = big_nerd_ranch.png; sourceTree = "<group>"; }; + 4DCBE1341BC9943D0075BA2C /* destroyer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = destroyer.png; sourceTree = "<group>"; }; + 4DCBE1351BC9943D0075BA2C /* drake.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = drake.png; sourceTree = "<group>"; }; + 4DCBE1361BC9943D0075BA2C /* lean_startup.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lean_startup.png; sourceTree = "<group>"; }; + 4DCBE1371BC9943D0075BA2C /* run_the_jewels.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = run_the_jewels.png; sourceTree = "<group>"; }; + 4DCBE1381BC9943D0075BA2C /* sleater_kinney.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sleater_kinney.png; sourceTree = "<group>"; }; + 4DCBE1391BC9943D0075BA2C /* talking_heads.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = talking_heads.png; sourceTree = "<group>"; }; + 4DCBE13A1BC9943D0075BA2C /* true_detective.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = true_detective.png; sourceTree = "<group>"; }; + 4DCBE13B1BC9943D0075BA2C /* x-files.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "x-files.png"; sourceTree = "<group>"; }; + 4DCBE1451BC9AD6A0075BA2C /* SearchAPIViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchAPIViewController.h; sourceTree = "<group>"; }; + 4DCBE1461BC9AD6A0075BA2C /* SearchAPIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchAPIViewController.m; sourceTree = "<group>"; }; + 4DCBE1481BC9ADAE0075BA2C /* CreateJournalEntryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CreateJournalEntryViewController.h; sourceTree = "<group>"; }; + 4DCBE1491BC9ADAE0075BA2C /* CreateJournalEntryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CreateJournalEntryViewController.m; sourceTree = "<group>"; }; + 4DCBE14B1BC9ADE00075BA2C /* WishListTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WishListTableViewController.h; sourceTree = "<group>"; }; + 4DCBE14C1BC9ADE00075BA2C /* WishListTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WishListTableViewController.m; sourceTree = "<group>"; }; + 4DCBE14E1BC9BD800075BA2C /* ViewCompletedEntryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewCompletedEntryViewController.h; sourceTree = "<group>"; }; + 4DCBE14F1BC9BD800075BA2C /* ViewCompletedEntryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewCompletedEntryViewController.m; sourceTree = "<group>"; }; + 5A5033181BC8D0E4001CBA5C /* MainTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainTableViewController.h; sourceTree = "<group>"; }; + 5A5033191BC8D0E4001CBA5C /* MainTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainTableViewController.m; sourceTree = "<group>"; }; + 5A50331B1BC8D99D001CBA5C /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = "<group>"; }; + 5A50331C1BC8D99D001CBA5C /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = "<group>"; }; + 5A50331E1BC8D9B5001CBA5C /* SignUpViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignUpViewController.h; sourceTree = "<group>"; }; + 5A50331F1BC8D9B5001CBA5C /* SignUpViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignUpViewController.m; sourceTree = "<group>"; }; + 5A6A22801BD3FDFF006E9FE7 /* basictitlefont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = basictitlefont.ttf; sourceTree = "<group>"; }; + 5A6A22841BD438B4006E9FE7 /* Akkurat Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Akkurat Regular.otf"; sourceTree = "<group>"; }; + 5A6A22861BD4394E006E9FE7 /* Akkurat Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Akkurat Bold.otf"; sourceTree = "<group>"; }; + 5A6A22871BD4394E006E9FE7 /* Akkurat Italic.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Akkurat Italic.otf"; sourceTree = "<group>"; }; + 5A6A22881BD4394E006E9FE7 /* Akkurat Light Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Akkurat Light Regular.otf"; sourceTree = "<group>"; }; + 5A6A228F1BD43A4A006E9FE7 /* CustomFontViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomFontViewController.h; sourceTree = "<group>"; }; + 5A6A22901BD43A4A006E9FE7 /* CustomFontViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomFontViewController.m; sourceTree = "<group>"; }; + 5AE959A01BD442C1007136F4 /* LaunchScreen.Storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.Storyboard; sourceTree = "<group>"; }; + 9A29371E1BCC26FE00ACEEE0 /* JournalPost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JournalPost.h; sourceTree = "<group>"; }; + 9A29371F1BCC26FE00ACEEE0 /* JournalPost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JournalPost.m; sourceTree = "<group>"; }; + 9A2FFC2A1BC84BF200E880D3 /* Unit-2-Journal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Unit-2-Journal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 9A2FFC2E1BC84BF200E880D3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 9A2FFC301BC84BF200E880D3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + 9A2FFC311BC84BF200E880D3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + 9A2FFC371BC84BF200E880D3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 9A2FFC3A1BC84BF200E880D3 /* Unit_2_Journal.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Unit_2_Journal.xcdatamodel; sourceTree = "<group>"; }; + 9A2FFC3C1BC84BF200E880D3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 9A2FFC411BC84BF200E880D3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 9A34656B1BCACDF40049337C /* iTunesSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunesSearchResult.h; sourceTree = "<group>"; }; + 9A34656C1BCACDF40049337C /* iTunesSearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTunesSearchResult.m; sourceTree = "<group>"; }; + 9A51FF2F1BD5DF9F00B6AE23 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; }; + 9A51FF301BD5DF9F00B6AE23 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; }; + 9AAB40041BC9FABC00FD7227 /* APIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIManager.h; sourceTree = "<group>"; }; + 9AAB40051BC9FABC00FD7227 /* APIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APIManager.m; sourceTree = "<group>"; }; + FAF24AD380284C55768010A2 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9A2FFC271BC84BF100E880D3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 617F8769EFBE79517A02E6D0 /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2EA812FB29649A9DC9449826 /* Frameworks */ = { + isa = PBXGroup; + children = ( + FAF24AD380284C55768010A2 /* libPods.a */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + 4D64F9D01BCEBF080079086C /* Custom Views & .XIBs */ = { + isa = PBXGroup; + children = ( + 4D7FE29A1BCC32170036E58E /* SearchAPITableViewCell.h */, + 4D7FE29B1BCC32170036E58E /* SearchAPITableViewCell.m */, + 4D7FE29C1BCC32170036E58E /* SearchAPITableViewCell.xib */, + 4D9B60521BD8731F004A52E4 /* WishListTableViewCell.h */, + 4D9B60531BD8731F004A52E4 /* WishListTableViewCell.m */, + 4D7FE2A41BCC41A00036E58E /* WishListTableViewCell.xib */, + 4D9B60551BD8733B004A52E4 /* JournalHeaderView.h */, + 4D9B60561BD8733B004A52E4 /* JournalHeaderView.m */, + 4D9B60501BD8723B004A52E4 /* JournalHeaderView.xib */, + ); + name = "Custom Views & .XIBs"; + sourceTree = "<group>"; + }; + 5A43989E2A6AD60B52B523E0 /* Pods */ = { + isa = PBXGroup; + children = ( + 2BC0A6490F88476E5C31E3B1 /* Pods.debug.xcconfig */, + 1F41A29CEEC52ED6A148CCE5 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = "<group>"; + }; + 5AE224801BC8BB4D004AEB77 /* Login/SignUp */ = { + isa = PBXGroup; + children = ( + 5A5033181BC8D0E4001CBA5C /* MainTableViewController.h */, + 5A5033191BC8D0E4001CBA5C /* MainTableViewController.m */, + 5A50331B1BC8D99D001CBA5C /* LoginViewController.h */, + 5A50331C1BC8D99D001CBA5C /* LoginViewController.m */, + 5A50331E1BC8D9B5001CBA5C /* SignUpViewController.h */, + 5A50331F1BC8D9B5001CBA5C /* SignUpViewController.m */, + ); + name = Login/SignUp; + sourceTree = "<group>"; + }; + 9A2FFC211BC84BF100E880D3 = { + isa = PBXGroup; + children = ( + 9A2FFC2C1BC84BF200E880D3 /* Unit-2-Journal */, + 9A2FFC2B1BC84BF200E880D3 /* Products */, + 5A43989E2A6AD60B52B523E0 /* Pods */, + 2EA812FB29649A9DC9449826 /* Frameworks */, + ); + sourceTree = "<group>"; + }; + 9A2FFC2B1BC84BF200E880D3 /* Products */ = { + isa = PBXGroup; + children = ( + 9A2FFC2A1BC84BF200E880D3 /* Unit-2-Journal.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 9A2FFC2C1BC84BF200E880D3 /* Unit-2-Journal */ = { + isa = PBXGroup; + children = ( + 5AE224801BC8BB4D004AEB77 /* Login/SignUp */, + 9A2FFC301BC84BF200E880D3 /* AppDelegate.h */, + 9A2FFC311BC84BF200E880D3 /* AppDelegate.m */, + 9AAB40031BC9ECAA00FD7227 /* Classes & Managers */, + 4D64F9D01BCEBF080079086C /* Custom Views & .XIBs */, + 9AAB40021BC9EC7300FD7227 /* ViewControllers */, + 9A2FFC361BC84BF200E880D3 /* Main.storyboard */, + 9A2FFC3C1BC84BF200E880D3 /* Assets.xcassets */, + 5AE959A01BD442C1007136F4 /* LaunchScreen.Storyboard */, + 5A6A228F1BD43A4A006E9FE7 /* CustomFontViewController.h */, + 5A6A22901BD43A4A006E9FE7 /* CustomFontViewController.m */, + 9A2FFC411BC84BF200E880D3 /* Info.plist */, + 9A2FFC391BC84BF200E880D3 /* Unit_2_Journal.xcdatamodeld */, + 9A2FFC2D1BC84BF200E880D3 /* Supporting Files */, + ); + path = "Unit-2-Journal"; + sourceTree = "<group>"; + }; + 9A2FFC2D1BC84BF200E880D3 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5A6A22841BD438B4006E9FE7 /* Akkurat Regular.otf */, + 5A6A22861BD4394E006E9FE7 /* Akkurat Bold.otf */, + 5A6A22871BD4394E006E9FE7 /* Akkurat Italic.otf */, + 5A6A22881BD4394E006E9FE7 /* Akkurat Light Regular.otf */, + 5A6A22801BD3FDFF006E9FE7 /* basictitlefont.ttf */, + 4DCBE1331BC9943D0075BA2C /* big_nerd_ranch.png */, + 4DCBE1341BC9943D0075BA2C /* destroyer.png */, + 4DCBE1351BC9943D0075BA2C /* drake.png */, + 4DCBE1361BC9943D0075BA2C /* lean_startup.png */, + 4DCBE1371BC9943D0075BA2C /* run_the_jewels.png */, + 4DCBE1381BC9943D0075BA2C /* sleater_kinney.png */, + 4DCBE1391BC9943D0075BA2C /* talking_heads.png */, + 4DCBE13A1BC9943D0075BA2C /* true_detective.png */, + 4DCBE13B1BC9943D0075BA2C /* x-files.png */, + 9A2FFC2E1BC84BF200E880D3 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; + 9AAB40021BC9EC7300FD7227 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + 4DCBE1301BC98EF90075BA2C /* JournalMainCollectionViewController.h */, + 4DCBE1311BC98EF90075BA2C /* JournalMainCollectionViewController.m */, + 4DCBE1451BC9AD6A0075BA2C /* SearchAPIViewController.h */, + 4DCBE1461BC9AD6A0075BA2C /* SearchAPIViewController.m */, + 4DCBE1481BC9ADAE0075BA2C /* CreateJournalEntryViewController.h */, + 4DCBE1491BC9ADAE0075BA2C /* CreateJournalEntryViewController.m */, + 4DCBE14B1BC9ADE00075BA2C /* WishListTableViewController.h */, + 4DCBE14C1BC9ADE00075BA2C /* WishListTableViewController.m */, + 4D0030BA1BD6AF7C00BC7BD9 /* WatchedWishListViewController.h */, + 4D0030BB1BD6AF7C00BC7BD9 /* WatchedWishListViewController.m */, + 4DCBE14E1BC9BD800075BA2C /* ViewCompletedEntryViewController.h */, + 4DCBE14F1BC9BD800075BA2C /* ViewCompletedEntryViewController.m */, + 4D7FE2921BCC12050036E58E /* TabBarViewController.h */, + 4D7FE2931BCC12050036E58E /* TabBarViewController.m */, + 9A51FF2F1BD5DF9F00B6AE23 /* SettingsViewController.h */, + 9A51FF301BD5DF9F00B6AE23 /* SettingsViewController.m */, + ); + name = ViewControllers; + sourceTree = "<group>"; + }; + 9AAB40031BC9ECAA00FD7227 /* Classes & Managers */ = { + isa = PBXGroup; + children = ( + 9AAB40041BC9FABC00FD7227 /* APIManager.h */, + 9AAB40051BC9FABC00FD7227 /* APIManager.m */, + 9A34656B1BCACDF40049337C /* iTunesSearchResult.h */, + 9A34656C1BCACDF40049337C /* iTunesSearchResult.m */, + 9A29371E1BCC26FE00ACEEE0 /* JournalPost.h */, + 9A29371F1BCC26FE00ACEEE0 /* JournalPost.m */, + ); + name = "Classes & Managers"; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 9A2FFC291BC84BF100E880D3 /* Unit-2-Journal */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9A2FFC441BC84BF200E880D3 /* Build configuration list for PBXNativeTarget "Unit-2-Journal" */; + buildPhases = ( + 52492941416B94624F7E67A8 /* Check Pods Manifest.lock */, + 9A2FFC261BC84BF100E880D3 /* Sources */, + 9A2FFC271BC84BF100E880D3 /* Frameworks */, + 9A2FFC281BC84BF100E880D3 /* Resources */, + 7C374323F34F7199EEEEB87E /* Copy Pods Resources */, + 9B427652685F9EFC62D0C14E /* Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Unit-2-Journal"; + productName = "Unit-2-Journal"; + productReference = 9A2FFC2A1BC84BF200E880D3 /* Unit-2-Journal.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9A2FFC221BC84BF100E880D3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = "Jamaal Sedayao"; + TargetAttributes = { + 9A2FFC291BC84BF100E880D3 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = Z6GBYPK592; + }; + }; + }; + buildConfigurationList = 9A2FFC251BC84BF100E880D3 /* Build configuration list for PBXProject "Unit-2-Journal" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 9A2FFC211BC84BF100E880D3; + productRefGroup = 9A2FFC2B1BC84BF200E880D3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 9A2FFC291BC84BF100E880D3 /* Unit-2-Journal */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 9A2FFC281BC84BF100E880D3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A6A22811BD3FE31006E9FE7 /* basictitlefont.ttf in Resources */, + 4DCBE13F1BC9943D0075BA2C /* lean_startup.png in Resources */, + 5AE959A11BD442C1007136F4 /* LaunchScreen.Storyboard in Resources */, + 5A6A228A1BD43955006E9FE7 /* Akkurat Italic.otf in Resources */, + 4D7FE2A61BCC41A00036E58E /* WishListTableViewCell.xib in Resources */, + 4D7FE29E1BCC32170036E58E /* SearchAPITableViewCell.xib in Resources */, + 4DCBE1441BC9943D0075BA2C /* x-files.png in Resources */, + 4DCBE13E1BC9943D0075BA2C /* drake.png in Resources */, + 4DCBE1401BC9943D0075BA2C /* run_the_jewels.png in Resources */, + 4D9B60511BD8723B004A52E4 /* JournalHeaderView.xib in Resources */, + 5A6A228B1BD43958006E9FE7 /* Akkurat Light Regular.otf in Resources */, + 4DCBE13D1BC9943D0075BA2C /* destroyer.png in Resources */, + 4DCBE1411BC9943D0075BA2C /* sleater_kinney.png in Resources */, + 4DCBE1421BC9943D0075BA2C /* talking_heads.png in Resources */, + 9A2FFC3D1BC84BF200E880D3 /* Assets.xcassets in Resources */, + 4DCBE13C1BC9943D0075BA2C /* big_nerd_ranch.png in Resources */, + 5A6A22891BD43952006E9FE7 /* Akkurat Bold.otf in Resources */, + 9A2FFC381BC84BF200E880D3 /* Main.storyboard in Resources */, + 4DCBE1431BC9943D0075BA2C /* true_detective.png in Resources */, + 5A6A22851BD4393D006E9FE7 /* Akkurat Regular.otf in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 52492941416B94624F7E67A8 /* 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; + }; + 7C374323F34F7199EEEEB87E /* 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; + }; + 9B427652685F9EFC62D0C14E /* 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; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 9A2FFC261BC84BF100E880D3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9A2FFC321BC84BF200E880D3 /* AppDelegate.m in Sources */, + 9A34656D1BCACDF40049337C /* iTunesSearchResult.m in Sources */, + 4D0030BC1BD6AF7C00BC7BD9 /* WatchedWishListViewController.m in Sources */, + 5A6A22911BD43A4A006E9FE7 /* CustomFontViewController.m in Sources */, + 4D7FE2941BCC12050036E58E /* TabBarViewController.m in Sources */, + 4DCBE14A1BC9ADAE0075BA2C /* CreateJournalEntryViewController.m in Sources */, + 5A50331D1BC8D99D001CBA5C /* LoginViewController.m in Sources */, + 4DCBE1321BC98EF90075BA2C /* JournalMainCollectionViewController.m in Sources */, + 9A51FF311BD5DF9F00B6AE23 /* SettingsViewController.m in Sources */, + 4DCBE1471BC9AD6A0075BA2C /* SearchAPIViewController.m in Sources */, + 9A2FFC3B1BC84BF200E880D3 /* Unit_2_Journal.xcdatamodeld in Sources */, + 9A2937201BCC26FE00ACEEE0 /* JournalPost.m in Sources */, + 4DCBE14D1BC9ADE00075BA2C /* WishListTableViewController.m in Sources */, + 5A50331A1BC8D0E4001CBA5C /* MainTableViewController.m in Sources */, + 9AAB40061BC9FABC00FD7227 /* APIManager.m in Sources */, + 4D9B60541BD8731F004A52E4 /* WishListTableViewCell.m in Sources */, + 5A5033201BC8D9B5001CBA5C /* SignUpViewController.m in Sources */, + 4DCBE1501BC9BD800075BA2C /* ViewCompletedEntryViewController.m in Sources */, + 4D9B60571BD8733B004A52E4 /* JournalHeaderView.m in Sources */, + 9A2FFC2F1BC84BF200E880D3 /* main.m in Sources */, + 4D7FE29D1BCC32170036E58E /* SearchAPITableViewCell.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 9A2FFC361BC84BF200E880D3 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 9A2FFC371BC84BF200E880D3 /* Base */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 9A2FFC421BC84BF200E880D3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 9A2FFC431BC84BF200E880D3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 9A2FFC451BC84BF200E880D3 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2BC0A6490F88476E5C31E3B1 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = "Unit-2-Journal/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jamalsedayao.Unit-2-Journal"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + }; + name = Debug; + }; + 9A2FFC461BC84BF200E880D3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1F41A29CEEC52ED6A148CCE5 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = "Unit-2-Journal/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jamalsedayao.Unit-2-Journal"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 9A2FFC251BC84BF100E880D3 /* Build configuration list for PBXProject "Unit-2-Journal" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9A2FFC421BC84BF200E880D3 /* Debug */, + 9A2FFC431BC84BF200E880D3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9A2FFC441BC84BF200E880D3 /* Build configuration list for PBXNativeTarget "Unit-2-Journal" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9A2FFC451BC84BF200E880D3 /* Debug */, + 9A2FFC461BC84BF200E880D3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCVersionGroup section */ + 9A2FFC391BC84BF200E880D3 /* Unit_2_Journal.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 9A2FFC3A1BC84BF200E880D3 /* Unit_2_Journal.xcdatamodel */, + ); + currentVersion = 9A2FFC3A1BC84BF200E880D3 /* Unit_2_Journal.xcdatamodel */; + path = Unit_2_Journal.xcdatamodeld; + sourceTree = "<group>"; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = 9A2FFC221BC84BF100E880D3 /* Project object */; +} diff --git a/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d63f60 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:Unit-2-Journal.xcodeproj"> + </FileRef> +</Workspace> diff --git a/Unit-2-Journal/Unit-2-Journal.xcworkspace/contents.xcworkspacedata b/Unit-2-Journal/Unit-2-Journal.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..da3cae0 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "group:Unit-2-Journal.xcodeproj"> + </FileRef> + <FileRef + location = "group:Pods/Pods.xcodeproj"> + </FileRef> +</Workspace> diff --git a/Unit-2-Journal/Unit-2-Journal/.DS_Store b/Unit-2-Journal/Unit-2-Journal/.DS_Store new file mode 100644 index 0000000..0c888c2 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/.DS_Store differ diff --git a/Unit-2-Journal/Unit-2-Journal/APIManager.h b/Unit-2-Journal/Unit-2-Journal/APIManager.h new file mode 100644 index 0000000..4c651a6 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/APIManager.h @@ -0,0 +1,17 @@ +// +// APIManager.h +// LearnAPI +// +// Created by Jamaal Sedayao on 9/20/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface APIManager : NSObject + + ++ (void) GETRequestWithURL:(NSURL*)URL + completionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error))completionHandler; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/APIManager.m b/Unit-2-Journal/Unit-2-Journal/APIManager.m new file mode 100644 index 0000000..a7a24f4 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/APIManager.m @@ -0,0 +1,36 @@ +// +// APIManager.m +// LearnAPI +// +// Created by Jamaal Sedayao on 9/20/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "APIManager.h" + +@implementation APIManager + +//takes a url, make an http request and pop back into the main thread + +//create a class method - gives us ability to not have to call alloc init on it ++ (void) GETRequestWithURL:(NSURL*)URL + completionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error)) +completionHandler { + + NSURLSession *session = [NSURLSession sharedSession]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:URL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + completionHandler(data, response, error); + + }); + }]; + + [task resume]; +} + + + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/Akkurat Bold.otf b/Unit-2-Journal/Unit-2-Journal/Akkurat Bold.otf new file mode 100644 index 0000000..13076b6 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Akkurat Bold.otf differ diff --git a/Unit-2-Journal/Unit-2-Journal/Akkurat Italic.otf b/Unit-2-Journal/Unit-2-Journal/Akkurat Italic.otf new file mode 100644 index 0000000..f7148ef Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Akkurat Italic.otf differ diff --git a/Unit-2-Journal/Unit-2-Journal/Akkurat Light Regular.otf b/Unit-2-Journal/Unit-2-Journal/Akkurat Light Regular.otf new file mode 100644 index 0000000..dc9c1c9 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Akkurat Light Regular.otf differ diff --git a/Unit-2-Journal/Unit-2-Journal/Akkurat Regular.otf b/Unit-2-Journal/Unit-2-Journal/Akkurat Regular.otf new file mode 100644 index 0000000..a967332 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Akkurat Regular.otf differ diff --git a/Unit-2-Journal/Unit-2-Journal/AppDelegate.h b/Unit-2-Journal/Unit-2-Journal/AppDelegate.h new file mode 100644 index 0000000..cb3f367 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/AppDelegate.h @@ -0,0 +1,25 @@ +// +// AppDelegate.h +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/9/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <CoreData/CoreData.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> + +@property (strong, nonatomic) UIWindow *window; + +@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; +@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; +@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; + +- (void)saveContext; +- (NSURL *)applicationDocumentsDirectory; + + +@end + diff --git a/Unit-2-Journal/Unit-2-Journal/AppDelegate.m b/Unit-2-Journal/Unit-2-Journal/AppDelegate.m new file mode 100644 index 0000000..e8a9003 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/AppDelegate.m @@ -0,0 +1,201 @@ +// +// AppDelegate.m +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/9/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "AppDelegate.h" +#import <FBSDKCoreKit/FBSDKCoreKit.h> +#import <FBSDKLoginKit/FBSDKLoginButton.h> +#import <Parse/Parse.h> +#import "iTunesSearchResult.h" +#import "JournalPost.h" + +//for custom tab bar: +#import "YALTabBarItem.h" //model +#import "YALFoldingTabBarController.h" //controller +#import "YALAnimatingTabBarConstants.h" //helpers + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + [[FBSDKApplicationDelegate sharedInstance] application:application + didFinishLaunchingWithOptions:launchOptions];; + + [Parse setApplicationId:@"huGlqbY2KVINDuFfqju1fN0eB2QVANcqqHP0NVpY" + clientKey:@"aohlSqEhCwaXtZbji5us0j97GNzemWqq3m3EJqwG"]; + + //registering subclases to parse + [iTunesSearchResult registerSubclass]; + [JournalPost registerSubclass]; + + [self setupYALTabBarController]; // setup tab bar controller + + return YES; +} + +#pragma mark - setup custom tab bar + +- (void)setupYALTabBarController { + YALFoldingTabBarController *tabBarController = (YALFoldingTabBarController *) self.window.rootViewController; + + //prepare leftBarItems + YALTabBarItem *item1 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"idea"] + leftItemImage:nil + rightItemImage:nil]; + + + YALTabBarItem *item2 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"add"] // we can add hidden left/right buttons here + leftItemImage:nil + rightItemImage:nil]; + + tabBarController.leftBarItems = @[item1, item2]; + + //prepare rightBarItems + YALTabBarItem *item3 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"star"] + leftItemImage:nil + rightItemImage:nil]; + + + YALTabBarItem *item4 = [[YALTabBarItem alloc] initWithItemImage:[UIImage imageNamed:@"settings"] + leftItemImage:nil + rightItemImage:nil]; + + tabBarController.rightBarItems = @[item3, item4]; + + tabBarController.centerButtonImage = [UIImage imageNamed:@"plus"]; + + tabBarController.selectedIndex = 2; + + //customize tabBarView + tabBarController.tabBarView.extraTabBarItemHeight = YALExtraTabBarItemsDefaultHeight; + tabBarController.tabBarView.offsetForExtraTabBarItems = YALForExtraTabBarItemsDefaultOffset; + tabBarController.tabBarView.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:1]; + tabBarController.tabBarView.tabBarColor = [UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1]; + tabBarController.tabBarViewHeight = YALTabBarViewDefaultHeight; + tabBarController.tabBarView.tabBarViewEdgeInsets = YALTabBarViewHDefaultEdgeInsets; + tabBarController.tabBarView.tabBarItemsEdgeInsets = YALTabBarViewItemsDefaultEdgeInsets; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + + [FBSDKAppEvents activateApp]; +} +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + return [[FBSDKApplicationDelegate sharedInstance] application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + // Saves changes in the application's managed object context before the application terminates. + [self saveContext]; +} + +#pragma mark - Core Data stack + +@synthesize managedObjectContext = _managedObjectContext; +@synthesize managedObjectModel = _managedObjectModel; +@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; + +- (NSURL *)applicationDocumentsDirectory { + // The directory the application uses to store the Core Data store file. This code uses a directory named "com.jamaalsedayao.Unit_2_Journal" in the application's documents directory. + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; +} + +- (NSManagedObjectModel *)managedObjectModel { + // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model. + if (_managedObjectModel != nil) { + return _managedObjectModel; + } + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Unit_2_Journal" withExtension:@"momd"]; + _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + return _managedObjectModel; +} + +- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { + // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. + if (_persistentStoreCoordinator != nil) { + return _persistentStoreCoordinator; + } + + // Create the coordinator and store + + _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; + NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Unit_2_Journal.sqlite"]; + NSError *error = nil; + NSString *failureReason = @"There was an error creating or loading the application's saved data."; + if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { + // Report any error we got. + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data"; + dict[NSLocalizedFailureReasonErrorKey] = failureReason; + dict[NSUnderlyingErrorKey] = error; + error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict]; + // Replace this with code to handle the error appropriately. + // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + + return _persistentStoreCoordinator; +} + + +- (NSManagedObjectContext *)managedObjectContext { + // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) + if (_managedObjectContext != nil) { + return _managedObjectContext; + } + + NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; + if (!coordinator) { + return nil; + } + _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + [_managedObjectContext setPersistentStoreCoordinator:coordinator]; + return _managedObjectContext; +} + +#pragma mark - Core Data Saving support + +- (void)saveContext { + NSManagedObjectContext *managedObjectContext = self.managedObjectContext; + if (managedObjectContext != nil) { + NSError *error = nil; + if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { + // Replace this implementation with code to handle the error appropriately. + // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + NSLog(@"Unresolved error %@, %@", error, [error userInfo]); + abort(); + } + } +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon-1.appiconset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon-1.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon-1.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon.appiconset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "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" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/Contents.json new file mode 100644 index 0000000..a625689 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "add.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/add.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/add.png new file mode 100644 index 0000000..3d921ec Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/add.imageset/add.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/Contents.json new file mode 100644 index 0000000..786e343 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "idea.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/idea.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/idea.png new file mode 100644 index 0000000..e3250be Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/idea.imageset/idea.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/Contents.json new file mode 100644 index 0000000..efcc220 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "plus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/plus.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/plus.png new file mode 100644 index 0000000..e39dad6 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/plus.imageset/plus.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/Contents.json new file mode 100644 index 0000000..ec54025 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "rating_star.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/rating_star.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/rating_star.png new file mode 100644 index 0000000..24e5d0c Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star.imageset/rating_star.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/Contents.json new file mode 100644 index 0000000..89dc5b6 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "rating_star2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/rating_star2.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/rating_star2.png new file mode 100644 index 0000000..a9c3cd1 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star2.imageset/rating_star2.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/Contents.json new file mode 100644 index 0000000..a153585 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "rating_star_filled.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/rating_star_filled.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/rating_star_filled.png new file mode 100644 index 0000000..8087242 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled.imageset/rating_star_filled.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/Contents.json new file mode 100644 index 0000000..9fe890d --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "rating_star_filled2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/rating_star_filled2.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/rating_star_filled2.png new file mode 100644 index 0000000..b804593 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/rating_star_filled2.imageset/rating_star_filled2.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/Contents.json new file mode 100644 index 0000000..77b2e1f --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "settings.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/settings.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/settings.png new file mode 100644 index 0000000..351c00b Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/settings.imageset/settings.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/Contents.json b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/Contents.json new file mode 100644 index 0000000..a6b6629 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "star.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/star.png b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/star.png new file mode 100644 index 0000000..5f7f722 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Assets.xcassets/star.imageset/star.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/Base.lproj/.DS_Store b/Unit-2-Journal/Unit-2-Journal/Base.lproj/.DS_Store new file mode 100644 index 0000000..64192e7 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/Base.lproj/.DS_Store differ diff --git a/Unit-2-Journal/Unit-2-Journal/Base.lproj/Main.storyboard b/Unit-2-Journal/Unit-2-Journal/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2652388 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Base.lproj/Main.storyboard @@ -0,0 +1,1457 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="sU9-FA-LDO"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> + <capability name="Constraints to layout margins" minToolsVersion="6.0"/> + </dependencies> + <customFonts key="customFonts"> + <mutableArray key="Akkurat Bold.otf"> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + <string>Akkurat-Bold</string> + </mutableArray> + <mutableArray key="Akkurat Regular.otf"> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + <string>Akkurat</string> + </mutableArray> + </customFonts> + <scenes> + <!--Main Table View Controller--> + <scene sceneID="n2d-u0-8vM"> + <objects> + <tableViewController id="6xj-t1-H8b" customClass="MainTableViewController" sceneMemberID="viewController"> + <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="VFI-xc-uVz"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <animations/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <prototypes> + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="4Uu-0J-i5z"> + <rect key="frame" x="0.0" y="28" width="600" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4Uu-0J-i5z" id="a3N-Xk-wkT"> + <rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/> + <autoresizingMask key="autoresizingMask"/> + <animations/> + </tableViewCellContentView> + <animations/> + </tableViewCell> + </prototypes> + <connections> + <outlet property="dataSource" destination="6xj-t1-H8b" id="Cqd-eH-OxK"/> + <outlet property="delegate" destination="6xj-t1-H8b" id="fkp-WM-DBG"/> + </connections> + </tableView> + <navigationItem key="navigationItem" id="Jfc-aI-wrq"/> + <connections> + <segue destination="0hy-Gj-NgG" kind="show" identifier="showLogin" id="mTk-iy-MdK"/> + </connections> + </tableViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="Cf7-Xf-Xwf" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="1311" y="641"/> + </scene> + <!--View Controller--> + <scene sceneID="KJu-4i-aaL"> + <objects> + <viewController id="0hy-Gj-NgG" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="CWN-Uq-Wm7"/> + <viewControllerLayoutGuide type="bottom" id="7Wg-3J-aTX"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="lYY-HW-s1u"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Username" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="AKz-l6-j85"> + <rect key="frame" x="20" y="285" width="560" height="30"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits"/> + </textField> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Password" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gou-OY-Mya"> + <rect key="frame" x="20" y="341" width="560" height="30"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits" secureTextEntry="YES"/> + </textField> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0nr-1p-7za"> + <rect key="frame" x="20" y="379" width="560" height="30"/> + <animations/> + <state key="normal" title="Log In"/> + </button> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jIF-cz-Aqv"> + <rect key="frame" x="20" y="417" width="560" height="85"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Don't have an account?" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ive-nb-IEu"> + <rect key="frame" x="109" y="8" width="179" height="21"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="s8y-Iw-Nef"> + <rect key="frame" x="296" y="1" width="64" height="34"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="18"/> + <state key="normal" title="Sign Up"/> + <connections> + <segue destination="CYq-PS-xt5" kind="show" id="hen-P6-DQ4"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </view> + </subviews> + <animations/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstItem="gou-OY-Mya" firstAttribute="centerX" secondItem="lYY-HW-s1u" secondAttribute="centerX" id="6e3-M4-P2D"/> + <constraint firstItem="0nr-1p-7za" firstAttribute="leading" secondItem="lYY-HW-s1u" secondAttribute="leadingMargin" id="7Mr-xL-ScO"/> + <constraint firstItem="AKz-l6-j85" firstAttribute="leading" secondItem="lYY-HW-s1u" secondAttribute="leadingMargin" id="EoM-tm-Yst"/> + <constraint firstItem="AKz-l6-j85" firstAttribute="centerX" secondItem="lYY-HW-s1u" secondAttribute="centerX" id="HwZ-36-mTm"/> + <constraint firstItem="AKz-l6-j85" firstAttribute="centerY" secondItem="lYY-HW-s1u" secondAttribute="centerY" id="TEa-V0-5YD"/> + <constraint firstItem="AKz-l6-j85" firstAttribute="trailing" secondItem="lYY-HW-s1u" secondAttribute="trailingMargin" id="U56-Wf-zrc"/> + <constraint firstItem="jIF-cz-Aqv" firstAttribute="centerX" secondItem="lYY-HW-s1u" secondAttribute="centerX" id="bLF-u4-Cso"/> + <constraint firstItem="jIF-cz-Aqv" firstAttribute="top" secondItem="0nr-1p-7za" secondAttribute="bottom" constant="8" id="brP-0Q-H7y"/> + <constraint firstItem="gou-OY-Mya" firstAttribute="top" secondItem="AKz-l6-j85" secondAttribute="bottom" constant="26" id="c6a-82-GdY"/> + <constraint firstItem="gou-OY-Mya" firstAttribute="trailing" secondItem="lYY-HW-s1u" secondAttribute="trailingMargin" id="cFe-UW-YmZ"/> + <constraint firstItem="jIF-cz-Aqv" firstAttribute="trailing" secondItem="lYY-HW-s1u" secondAttribute="trailingMargin" id="ik7-hA-HNt"/> + <constraint firstItem="0nr-1p-7za" firstAttribute="trailing" secondItem="lYY-HW-s1u" secondAttribute="trailingMargin" id="kXc-oc-7yu"/> + <constraint firstItem="0nr-1p-7za" firstAttribute="top" secondItem="gou-OY-Mya" secondAttribute="bottom" constant="8" id="kYy-Yq-5bV"/> + <constraint firstItem="7Wg-3J-aTX" firstAttribute="top" secondItem="jIF-cz-Aqv" secondAttribute="bottom" constant="98" id="nbz-UQ-0j7"/> + <constraint firstItem="gou-OY-Mya" firstAttribute="leading" secondItem="lYY-HW-s1u" secondAttribute="leadingMargin" id="s3l-Ef-OeL"/> + <constraint firstItem="0nr-1p-7za" firstAttribute="centerX" secondItem="lYY-HW-s1u" secondAttribute="centerX" id="vHG-vW-gJO"/> + <constraint firstItem="jIF-cz-Aqv" firstAttribute="leading" secondItem="lYY-HW-s1u" secondAttribute="leadingMargin" id="z15-EN-WLs"/> + </constraints> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkX-vl-js7" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="1988" y="641"/> + </scene> + <!--Item--> + <scene sceneID="IKu-XC-hmb"> + <objects> + <collectionViewController id="Gih-78-N3X" customClass="JournalMainCollectionViewController" sceneMemberID="viewController"> + <collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="gLS-Tq-kca"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <animations/> + <gestureRecognizers/> + <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Xes-6k-xNm"> + <size key="itemSize" width="80" height="80"/> + <size key="headerReferenceSize" width="0.0" height="0.0"/> + <size key="footerReferenceSize" width="0.0" height="0.0"/> + <inset key="sectionInset" minX="5" minY="20" maxX="5" maxY="0.0"/> + </collectionViewFlowLayout> + <cells> + <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="KiH-sl-ksa"> + <rect key="frame" x="5" y="20" width="80" height="80"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> + <rect key="frame" x="0.0" y="0.0" width="80" height="80"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qle-iq-7ST"> + <rect key="frame" x="0.0" y="0.0" width="80" height="80"/> + <subviews> + <imageView userInteractionEnabled="NO" tag="100" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="U4R-a0-sR9"> + <rect key="frame" x="0.0" y="0.0" width="80" height="80"/> + <animations/> + </imageView> + </subviews> + <animations/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <gestureRecognizers/> + <constraints> + <constraint firstItem="U4R-a0-sR9" firstAttribute="top" secondItem="qle-iq-7ST" secondAttribute="top" id="4PE-QR-dPk"/> + <constraint firstAttribute="bottom" secondItem="U4R-a0-sR9" secondAttribute="bottom" id="D8Z-kw-m7g"/> + <constraint firstItem="U4R-a0-sR9" firstAttribute="leading" secondItem="qle-iq-7ST" secondAttribute="leading" id="Dfj-aw-eR8"/> + <constraint firstAttribute="trailing" secondItem="U4R-a0-sR9" secondAttribute="trailing" id="ynC-Kf-iyP"/> + </constraints> + </view> + </subviews> + <animations/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </view> + <animations/> + <constraints> + <constraint firstItem="qle-iq-7ST" firstAttribute="top" secondItem="KiH-sl-ksa" secondAttribute="top" id="GNo-Hh-7cT"/> + <constraint firstItem="qle-iq-7ST" firstAttribute="leading" secondItem="KiH-sl-ksa" secondAttribute="leading" id="L3Q-OO-kXM"/> + <constraint firstAttribute="bottom" secondItem="qle-iq-7ST" secondAttribute="bottom" id="pHl-JF-p0c"/> + <constraint firstAttribute="trailing" secondItem="qle-iq-7ST" secondAttribute="trailing" id="vRx-Mn-xec"/> + </constraints> + <connections> + <segue destination="z1K-z0-Vef" kind="show" identifier="ViewCompletedEntrySegue" id="fYZ-7d-vsv"/> + </connections> + </collectionViewCell> + </cells> + <connections> + <outlet property="dataSource" destination="Gih-78-N3X" id="Zyj-ny-uMv"/> + <outlet property="delegate" destination="Gih-78-N3X" id="TWL-m7-WCV"/> + </connections> + </collectionView> + <tabBarItem key="tabBarItem" title="Item" id="uMb-MY-8On"/> + <navigationItem key="navigationItem" id="Z1X-J6-1kq"/> + </collectionViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="blD-s8-5JB" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="537" y="2528"/> + </scene> + <!--settings--> + <scene sceneID="PlQ-SS-pZx"> + <objects> + <viewController title="settings" id="Oeh-Ah-1CX" customClass="SettingsViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="OjC-qE-o96"/> + <viewControllerLayoutGuide type="bottom" id="HPN-sF-Bn8"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="qWh-Hz-BDE"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qLr-OV-7JA"> + <rect key="frame" x="300" y="300" width="0.0" height="0.0"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="qLr-OV-7JA" firstAttribute="centerX" secondItem="qWh-Hz-BDE" secondAttribute="centerX" id="els-Ct-0Lj"/> + <constraint firstItem="qLr-OV-7JA" firstAttribute="centerY" secondItem="qWh-Hz-BDE" secondAttribute="centerY" id="iFg-8y-wzh"/> + </constraints> + </view> + <tabBarItem key="tabBarItem" title="Item" id="aF0-rA-Z24"/> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="Ure-Ti-78A" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="1233" y="2528"/> + </scene> + <!--Search --> + <scene sceneID="eAD-0s-cgb"> + <objects> + <viewController title="Search " id="0x4-Nu-mZ8" customClass="SearchAPIViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="cYU-LH-eDv"/> + <viewControllerLayoutGuide type="bottom" id="PPA-gt-rZ4"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="pfn-eQ-aux"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="twc-ko-3Rx"> + <rect key="frame" x="0.0" y="145" width="600" height="281"/> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <color key="separatorColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <prototypes> + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="APIResultsIdentifier" textLabel="wn8-3w-eKd" detailTextLabel="DsP-zu-9UZ" style="IBUITableViewCellStyleSubtitle" id="oHk-9R-1hr"> + <rect key="frame" x="0.0" y="28" width="600" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="oHk-9R-1hr" id="Q9h-u4-3sZ"> + <rect key="frame" x="0.0" y="0.0" width="600" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="wn8-3w-eKd"> + <rect key="frame" x="15" y="6" width="31.5" height="19.5"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="16"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="DsP-zu-9UZ"> + <rect key="frame" x="15" y="25.5" width="40.5" height="13.5"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="11"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + </tableViewCellContentView> + <animations/> + </tableViewCell> + </prototypes> + </tableView> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q0c-Ez-WJB"> + <rect key="frame" x="0.0" y="426" width="300" height="50"/> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="50" id="Obp-pq-hKR"/> + </constraints> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="Add to Journal"> + <color key="titleColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <segue destination="aXS-um-aw2" kind="show" identifier="pushToCreateJournalEntry" id="a4i-zx-cvK"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EJ6-uf-zLo"> + <rect key="frame" x="0.0" y="20" width="120" height="50"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstAttribute="height" constant="50" id="nSu-DZ-G40"/> + </constraints> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="music"> + <color key="titleColor" red="1" green="0.96580194144491827" blue="0.065849877366854659" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="mediaButtonTypeSelected:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="K8k-JQ-me2"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4y1-WC-sKi"> + <rect key="frame" x="120" y="20" width="120" height="50"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="movie"> + <color key="titleColor" red="0.0" green="0.98431378599999997" blue="0.31764706970000001" alpha="1" colorSpace="deviceRGB"/> + </state> + <connections> + <action selector="mediaButtonTypeSelected:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="Elw-iE-OuH"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VhT-rh-Xlh"> + <rect key="frame" x="480" y="20" width="120" height="50"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <state key="normal" title="book"> + <color key="titleColor" red="1" green="0.30034427511886808" blue="0.46572456648647631" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="mediaButtonTypeSelected:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="GWX-Np-N9z"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XjD-vV-PU3"> + <rect key="frame" x="360" y="20" width="120" height="50"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="podcast"> + <color key="titleColor" red="0.98580998180000001" green="0.62003214620000002" blue="0.067037612610000005" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="mediaButtonTypeSelected:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="D5e-mV-ILd"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pgh-XG-GUn"> + <rect key="frame" x="240" y="20" width="120" height="50"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="tv"> + <color key="titleColor" red="0.68431816999999995" green="0.90332986250000002" blue="1" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="mediaButtonTypeSelected:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="OaW-gN-Lra"/> + </connections> + </button> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4h9-oR-C40"> + <rect key="frame" x="0.0" y="70" width="600" height="75"/> + <subviews> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="search for title" textAlignment="center" clearsOnBeginEditing="YES" minimumFontSize="20" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="zob-sY-qha"> + <rect key="frame" x="40" y="23" width="520" height="30"/> + <animations/> + <constraints> + <constraint firstAttribute="width" constant="350" id="FjN-tR-Pz2"/> + </constraints> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <textInputTraits key="textInputTraits" autocapitalizationType="words" autocorrectionType="yes" spellCheckingType="yes"/> + <variation key="default"> + <mask key="constraints"> + <exclude reference="FjN-tR-Pz2"/> + </mask> + </variation> + </textField> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="zob-sY-qha" secondAttribute="trailing" constant="40" id="2d1-5l-Hn0"/> + <constraint firstItem="zob-sY-qha" firstAttribute="leading" secondItem="4h9-oR-C40" secondAttribute="leading" constant="40" id="Yg5-BR-c5k"/> + <constraint firstItem="zob-sY-qha" firstAttribute="centerX" secondItem="4h9-oR-C40" secondAttribute="centerX" id="cbv-OU-esH"/> + <constraint firstAttribute="height" constant="75" id="fyg-AW-jv6"/> + <constraint firstItem="zob-sY-qha" firstAttribute="centerY" secondItem="4h9-oR-C40" secondAttribute="centerY" id="x76-Iu-Ldy"/> + </constraints> + </view> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="i6F-Oe-4xR"> + <rect key="frame" x="300" y="426" width="300" height="50"/> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="50" id="hZN-AM-gYR"/> + </constraints> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <state key="normal" title="Add to Wish List"> + <color key="titleColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="addToWishListButtonTapped:" destination="0x4-Nu-mZ8" eventType="touchUpInside" id="pGb-oC-cak"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="i6F-Oe-4xR" secondAttribute="trailing" id="1vY-Sv-N2G"/> + <constraint firstItem="PPA-gt-rZ4" firstAttribute="top" secondItem="Q0c-Ez-WJB" secondAttribute="bottom" constant="75" id="3L8-sb-LAC"/> + <constraint firstItem="EJ6-uf-zLo" firstAttribute="leading" secondItem="pfn-eQ-aux" secondAttribute="leading" id="3fl-WU-y8e"/> + <constraint firstItem="4y1-WC-sKi" firstAttribute="width" secondItem="pgh-XG-GUn" secondAttribute="width" id="5cN-Iv-IUj"/> + <constraint firstItem="EJ6-uf-zLo" firstAttribute="top" secondItem="cYU-LH-eDv" secondAttribute="bottom" id="702-Kc-wk3"/> + <constraint firstItem="PPA-gt-rZ4" firstAttribute="top" secondItem="i6F-Oe-4xR" secondAttribute="bottom" constant="75" id="7Fe-iU-INp"/> + <constraint firstItem="4y1-WC-sKi" firstAttribute="leading" secondItem="EJ6-uf-zLo" secondAttribute="trailing" id="7qG-bN-0G6"/> + <constraint firstItem="pgh-XG-GUn" firstAttribute="leading" secondItem="4y1-WC-sKi" secondAttribute="trailing" id="CFk-7Q-TPD"/> + <constraint firstItem="twc-ko-3Rx" firstAttribute="leading" secondItem="pfn-eQ-aux" secondAttribute="leading" id="FZd-hl-gkx"/> + <constraint firstItem="4y1-WC-sKi" firstAttribute="top" secondItem="cYU-LH-eDv" secondAttribute="bottom" id="GzD-M9-fes"/> + <constraint firstItem="Q0c-Ez-WJB" firstAttribute="leading" secondItem="pfn-eQ-aux" secondAttribute="leading" id="Jbu-5t-pGE"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="top" secondItem="EJ6-uf-zLo" secondAttribute="bottom" id="KCP-pN-06l"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="top" secondItem="VhT-rh-Xlh" secondAttribute="bottom" id="L3n-uD-pBY"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="top" secondItem="pgh-XG-GUn" secondAttribute="bottom" id="ONC-I9-zux"/> + <constraint firstItem="pgh-XG-GUn" firstAttribute="width" secondItem="XjD-vV-PU3" secondAttribute="width" id="OoV-U9-MyF"/> + <constraint firstItem="VhT-rh-Xlh" firstAttribute="top" secondItem="cYU-LH-eDv" secondAttribute="bottom" id="Qdu-Ej-kde"/> + <constraint firstAttribute="trailing" secondItem="twc-ko-3Rx" secondAttribute="trailing" id="RGJ-uK-hld"/> + <constraint firstItem="i6F-Oe-4xR" firstAttribute="top" secondItem="twc-ko-3Rx" secondAttribute="bottom" id="VBu-IG-Jsg"/> + <constraint firstItem="XjD-vV-PU3" firstAttribute="top" secondItem="cYU-LH-eDv" secondAttribute="bottom" id="Wck-9n-HMh"/> + <constraint firstItem="XjD-vV-PU3" firstAttribute="width" secondItem="VhT-rh-Xlh" secondAttribute="width" id="XD2-ng-XU7"/> + <constraint firstItem="i6F-Oe-4xR" firstAttribute="leading" secondItem="Q0c-Ez-WJB" secondAttribute="trailing" id="a8H-dW-uow"/> + <constraint firstItem="pgh-XG-GUn" firstAttribute="top" secondItem="cYU-LH-eDv" secondAttribute="bottom" id="bZD-iv-nvA"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="leading" secondItem="pfn-eQ-aux" secondAttribute="leading" id="d1p-g0-bVH"/> + <constraint firstItem="XjD-vV-PU3" firstAttribute="leading" secondItem="pgh-XG-GUn" secondAttribute="trailing" id="eey-3o-tcm"/> + <constraint firstItem="4y1-WC-sKi" firstAttribute="leading" secondItem="EJ6-uf-zLo" secondAttribute="trailing" id="iCz-NF-JsT"/> + <constraint firstAttribute="trailing" secondItem="4h9-oR-C40" secondAttribute="trailing" id="ibm-d9-oMd"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="top" secondItem="XjD-vV-PU3" secondAttribute="bottom" id="jgB-OU-dbZ"/> + <constraint firstAttribute="trailing" secondItem="VhT-rh-Xlh" secondAttribute="trailing" id="mn3-hb-GIV"/> + <constraint firstItem="VhT-rh-Xlh" firstAttribute="leading" secondItem="XjD-vV-PU3" secondAttribute="trailing" id="o1q-gt-kne"/> + <constraint firstItem="i6F-Oe-4xR" firstAttribute="width" secondItem="Q0c-Ez-WJB" secondAttribute="width" id="oxZ-9t-iDE"/> + <constraint firstItem="pgh-XG-GUn" firstAttribute="leading" secondItem="4y1-WC-sKi" secondAttribute="trailing" id="rVq-84-wya"/> + <constraint firstItem="EJ6-uf-zLo" firstAttribute="width" secondItem="4y1-WC-sKi" secondAttribute="width" id="tZP-Pd-3cS"/> + <constraint firstItem="4h9-oR-C40" firstAttribute="top" secondItem="4y1-WC-sKi" secondAttribute="bottom" id="xE8-Gn-PK2"/> + <constraint firstItem="twc-ko-3Rx" firstAttribute="top" secondItem="4h9-oR-C40" secondAttribute="bottom" id="yzs-2t-Ycy"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="7qG-bN-0G6"/> + <exclude reference="CFk-7Q-TPD"/> + </mask> + </variation> + </view> + <navigationItem key="navigationItem" id="gPV-bk-VJf"/> + <connections> + <outlet property="booksButton" destination="VhT-rh-Xlh" id="lft-lw-MG6"/> + <outlet property="journalEntryButton" destination="Q0c-Ez-WJB" id="Tvu-tK-ucU"/> + <outlet property="moviesButton" destination="4y1-WC-sKi" id="MrR-aE-OEy"/> + <outlet property="musicButton" destination="EJ6-uf-zLo" id="uE7-0x-fSK"/> + <outlet property="podcastButton" destination="XjD-vV-PU3" id="056-o8-aEu"/> + <outlet property="searchTextField" destination="zob-sY-qha" id="CSN-S0-Rzp"/> + <outlet property="tableView" destination="twc-ko-3Rx" id="4Cw-TH-Ai6"/> + <outlet property="televisionButton" destination="pgh-XG-GUn" id="VIW-gO-3XS"/> + <outlet property="wishListButton" destination="i6F-Oe-4xR" id="Xi4-vP-rOj"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="jtX-Jk-aNy" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-183" y="3302"/> + </scene> + <!--Watched Wish List View Controller--> + <scene sceneID="MYV-Oh-vlV"> + <objects> + <viewController storyboardIdentifier="WishListJournalEntry" id="BAI-dU-dy0" customClass="WatchedWishListViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="O2f-ij-05W"/> + <viewControllerLayoutGuide type="bottom" id="7si-3l-1N3"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="XbP-Rr-3ea"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xM5-av-N4Q"> + <rect key="frame" x="0.0" y="25" width="600" height="125"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TLh-Y5-rQa"> + <rect key="frame" x="10" y="5" width="120" height="120"/> + <animations/> + <constraints> + <constraint firstAttribute="width" constant="120" id="F3F-8P-fTh"/> + <constraint firstAttribute="height" constant="120" id="Odq-ff-11v"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1AF-cw-sG5"> + <rect key="frame" x="138" y="108" width="442" height="17"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DWN-3U-CrL"> + <rect key="frame" x="138" y="79" width="442" height="20.5"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QXz-a4-RR1"> + <rect key="frame" x="530" y="15" width="55" height="30"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="15"/> + <state key="normal" title="Dismiss"> + <color key="titleColor" red="0.97254901960784312" green="0.5490196078431373" blue="0.062745098039215685" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="doneButtonTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="ytx-oB-uey"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="1AF-cw-sG5" secondAttribute="bottom" id="5GX-Tt-REu"/> + <constraint firstAttribute="height" constant="125" id="Bjb-7L-TcT"/> + <constraint firstAttribute="bottom" secondItem="TLh-Y5-rQa" secondAttribute="bottom" id="CMz-9o-csd"/> + <constraint firstItem="DWN-3U-CrL" firstAttribute="leading" secondItem="TLh-Y5-rQa" secondAttribute="trailing" constant="8" id="Dja-JE-F6G"/> + <constraint firstAttribute="trailing" secondItem="1AF-cw-sG5" secondAttribute="trailing" constant="20" id="Eej-kZ-bcA"/> + <constraint firstItem="QXz-a4-RR1" firstAttribute="top" secondItem="xM5-av-N4Q" secondAttribute="top" constant="15" id="WDX-NV-xCI"/> + <constraint firstItem="1AF-cw-sG5" firstAttribute="top" secondItem="DWN-3U-CrL" secondAttribute="bottom" constant="8" id="b68-5t-IM6"/> + <constraint firstItem="1AF-cw-sG5" firstAttribute="leading" secondItem="TLh-Y5-rQa" secondAttribute="trailing" constant="8" id="hiE-op-4EG"/> + <constraint firstItem="TLh-Y5-rQa" firstAttribute="leading" secondItem="xM5-av-N4Q" secondAttribute="leading" constant="10" id="mN1-xv-3p3"/> + <constraint firstAttribute="trailing" secondItem="DWN-3U-CrL" secondAttribute="trailing" constant="20" id="y28-Zf-Ecb"/> + <constraint firstAttribute="trailing" secondItem="QXz-a4-RR1" secondAttribute="trailing" constant="15" id="zda-GW-cEn"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KTC-y5-v8E"> + <rect key="frame" x="20" y="227" width="560" height="174"/> + <subviews> + <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="5dG-Gc-FlR"> + <rect key="frame" x="8" y="8" width="544" height="158"/> + <animations/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="25"/> + <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> + </textView> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="5dG-Gc-FlR" secondAttribute="trailing" constant="8" id="Hh1-So-hwM"/> + <constraint firstItem="5dG-Gc-FlR" firstAttribute="top" secondItem="KTC-y5-v8E" secondAttribute="top" constant="8" id="VQs-d1-Hne"/> + <constraint firstItem="5dG-Gc-FlR" firstAttribute="leading" secondItem="KTC-y5-v8E" secondAttribute="leading" constant="8" id="k3B-yY-bRP"/> + <constraint firstAttribute="bottom" secondItem="5dG-Gc-FlR" secondAttribute="bottom" constant="8" id="rRN-D8-uV9"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jBv-4u-rAQ"> + <rect key="frame" x="35" y="167" width="530" height="50"/> + <subviews> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RPL-cy-o0G" userLabel="star1"> + <rect key="frame" x="0.0" y="0.0" width="98" height="50"/> + <animations/> + <state key="normal" image="rating_star2"/> + <connections> + <action selector="starOneTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="Hxv-dr-2Yg"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eqY-tM-EkF" userLabel="star2"> + <rect key="frame" x="108" y="0.0" width="98" height="50"/> + <animations/> + <state key="normal" image="rating_star2"/> + <connections> + <action selector="starTwoTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="5H7-Qq-ml0"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sLK-NH-rvK" userLabel="star3"> + <rect key="frame" x="216" y="0.0" width="98" height="50"/> + <animations/> + <state key="normal" image="rating_star2"/> + <connections> + <action selector="starThreeTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="J6b-uA-EaE"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fd9-H9-lzG" userLabel="star4"> + <rect key="frame" x="324" y="0.0" width="98" height="50"/> + <animations/> + <state key="normal" image="rating_star2"/> + <connections> + <action selector="starFourTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="VdS-rq-HCy"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jzq-uK-0EF" userLabel="star5"> + <rect key="frame" x="432" y="0.0" width="98" height="50"/> + <animations/> + <state key="normal" image="rating_star2"/> + <connections> + <action selector="starFiveTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="KDM-T7-hVz"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="Jzq-uK-0EF" secondAttribute="bottom" id="1ND-Ln-y7I"/> + <constraint firstAttribute="bottom" secondItem="sLK-NH-rvK" secondAttribute="bottom" id="2hF-t7-7wW"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="centerX" secondItem="jBv-4u-rAQ" secondAttribute="centerX" id="394-gs-dlG"/> + <constraint firstItem="eqY-tM-EkF" firstAttribute="width" secondItem="RPL-cy-o0G" secondAttribute="width" id="7uL-74-ycu"/> + <constraint firstItem="RPL-cy-o0G" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="top" id="A0V-vY-Lle"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="top" id="FqZ-FC-NWu"/> + <constraint firstItem="fd9-H9-lzG" firstAttribute="leading" secondItem="sLK-NH-rvK" secondAttribute="trailing" constant="10" id="G9B-TP-o9o"/> + <constraint firstItem="Jzq-uK-0EF" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="top" id="J8G-17-dhZ"/> + <constraint firstItem="eqY-tM-EkF" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="top" id="O00-A7-gGU"/> + <constraint firstItem="RPL-cy-o0G" firstAttribute="leading" secondItem="jBv-4u-rAQ" secondAttribute="leading" id="Q3J-6O-eg2"/> + <constraint firstItem="fd9-H9-lzG" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="top" id="UnY-64-yzq"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="width" secondItem="eqY-tM-EkF" secondAttribute="width" id="VbN-QB-fcN"/> + <constraint firstAttribute="bottom" secondItem="eqY-tM-EkF" secondAttribute="bottom" id="WBs-KE-6WQ"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="width" secondItem="fd9-H9-lzG" secondAttribute="width" id="dIJ-ws-vJk"/> + <constraint firstAttribute="trailing" secondItem="Jzq-uK-0EF" secondAttribute="trailing" id="iJA-xL-wIY"/> + <constraint firstItem="Jzq-uK-0EF" firstAttribute="leading" secondItem="fd9-H9-lzG" secondAttribute="trailing" constant="10" id="kVK-Zh-R6B"/> + <constraint firstItem="eqY-tM-EkF" firstAttribute="leading" secondItem="RPL-cy-o0G" secondAttribute="trailing" constant="10" id="l4B-xb-psJ"/> + <constraint firstAttribute="bottom" secondItem="RPL-cy-o0G" secondAttribute="bottom" id="lPF-7T-h5v"/> + <constraint firstAttribute="bottom" secondItem="fd9-H9-lzG" secondAttribute="bottom" id="pmr-Eq-fse"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="centerY" secondItem="jBv-4u-rAQ" secondAttribute="centerY" id="tEX-sw-r49"/> + <constraint firstItem="fd9-H9-lzG" firstAttribute="width" secondItem="Jzq-uK-0EF" secondAttribute="width" id="ucu-U4-sbF"/> + <constraint firstAttribute="height" constant="50" id="vK1-es-HIZ"/> + <constraint firstItem="sLK-NH-rvK" firstAttribute="leading" secondItem="eqY-tM-EkF" secondAttribute="trailing" constant="10" id="zua-Yv-onU"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tNJ-35-n33"> + <rect key="frame" x="20" y="411" width="560" height="60"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1oM-DR-MwP"> + <rect key="frame" x="213" y="13" width="134" height="33"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <state key="normal" title=" Log To Journal "> + <color key="titleColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="logToJournalButtonTapped:" destination="BAI-dU-dy0" eventType="touchUpInside" id="8y5-DW-DLo"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="1oM-DR-MwP" firstAttribute="centerY" secondItem="tNJ-35-n33" secondAttribute="centerY" id="4aa-nt-gCQ"/> + <constraint firstItem="1oM-DR-MwP" firstAttribute="centerX" secondItem="tNJ-35-n33" secondAttribute="centerX" id="VcS-q4-UVW"/> + <constraint firstAttribute="height" constant="60" id="b8q-pP-86u"/> + </constraints> + </view> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="tNJ-35-n33" firstAttribute="top" secondItem="KTC-y5-v8E" secondAttribute="bottom" constant="10" id="5zc-ey-MkX"/> + <constraint firstItem="tNJ-35-n33" firstAttribute="leading" secondItem="XbP-Rr-3ea" secondAttribute="leadingMargin" id="AN1-xe-uD8"/> + <constraint firstAttribute="trailingMargin" secondItem="KTC-y5-v8E" secondAttribute="trailing" id="DAf-1a-PYo"/> + <constraint firstAttribute="trailingMargin" secondItem="xM5-av-N4Q" secondAttribute="trailing" constant="-20" id="GfT-5T-IBM"/> + <constraint firstItem="jBv-4u-rAQ" firstAttribute="top" secondItem="xM5-av-N4Q" secondAttribute="bottom" constant="17" id="Kc9-je-EFG"/> + <constraint firstItem="KTC-y5-v8E" firstAttribute="top" secondItem="jBv-4u-rAQ" secondAttribute="bottom" constant="10" id="P8N-A2-bXB"/> + <constraint firstItem="xM5-av-N4Q" firstAttribute="leading" secondItem="XbP-Rr-3ea" secondAttribute="leadingMargin" constant="-20" id="S55-Wn-Vpy"/> + <constraint firstItem="jBv-4u-rAQ" firstAttribute="leading" secondItem="XbP-Rr-3ea" secondAttribute="leadingMargin" constant="15" id="Sxg-wV-brp"/> + <constraint firstAttribute="trailingMargin" secondItem="jBv-4u-rAQ" secondAttribute="trailing" constant="15" id="Uw1-xl-Gia"/> + <constraint firstItem="KTC-y5-v8E" firstAttribute="leading" secondItem="XbP-Rr-3ea" secondAttribute="leadingMargin" id="VIe-dk-eeH"/> + <constraint firstItem="xM5-av-N4Q" firstAttribute="top" secondItem="XbP-Rr-3ea" secondAttribute="topMargin" constant="25" id="aD9-AP-CKs"/> + <constraint firstItem="7si-3l-1N3" firstAttribute="top" secondItem="tNJ-35-n33" secondAttribute="bottom" constant="80" id="cJL-Ky-MaK"/> + <constraint firstAttribute="trailingMargin" secondItem="tNJ-35-n33" secondAttribute="trailing" id="dYx-MI-P4p"/> + </constraints> + </view> + <connections> + <outlet property="doneButton" destination="QXz-a4-RR1" id="Dif-1U-4Jk"/> + <outlet property="mediaCreatorLabel" destination="1AF-cw-sG5" id="sYQ-qL-pbb"/> + <outlet property="mediaImageView" destination="TLh-Y5-rQa" id="A79-2U-4N9"/> + <outlet property="mediaTitleLabel" destination="DWN-3U-CrL" id="zKI-lT-Dki"/> + <outlet property="starFive" destination="Jzq-uK-0EF" id="Qsc-RC-7fp"/> + <outlet property="starFour" destination="fd9-H9-lzG" id="mb9-sr-5pL"/> + <outlet property="starOne" destination="RPL-cy-o0G" id="ZFR-qy-6sU"/> + <outlet property="starThree" destination="sLK-NH-rvK" id="NNl-e2-dN6"/> + <outlet property="starTwo" destination="eqY-tM-EkF" id="dZq-XK-II5"/> + <outlet property="textView" destination="5dG-Gc-FlR" id="hk4-TP-5ai"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="3VJ-9s-RSN" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-907" y="4034"/> + </scene> + <!--Create Journal Entry View Controller--> + <scene sceneID="3xO-3p-x8L"> + <objects> + <viewController id="aXS-um-aw2" customClass="CreateJournalEntryViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="35G-Te-D94"/> + <viewControllerLayoutGuide type="bottom" id="tF2-8H-bHx"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="p3u-dw-cX6"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Hz-RL-Ugz"> + <rect key="frame" x="20" y="20" width="560" height="125"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="s1u-o4-hER"> + <rect key="frame" x="0.0" y="0.0" width="120" height="120"/> + <animations/> + <constraints> + <constraint firstAttribute="width" constant="120" id="eSF-yA-Flh"/> + <constraint firstAttribute="height" constant="120" id="mgE-Dx-7HC"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f6q-RS-lgS"> + <rect key="frame" x="128" y="82" width="412" height="20.5"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HdG-mr-PTo"> + <rect key="frame" x="128" y="103" width="412" height="17"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oCt-vd-4RS"> + <rect key="frame" x="483" y="0.0" width="69" height="30"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="15"/> + <state key="normal" title=" Dismiss "> + <color key="titleColor" red="0.98580998180000001" green="0.62003214620000002" blue="0.067037612610000005" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="doneEditingTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="Yvg-fL-af4"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="HdG-mr-PTo" firstAttribute="top" secondItem="f6q-RS-lgS" secondAttribute="bottom" id="2Li-DK-Gsd"/> + <constraint firstAttribute="trailing" secondItem="oCt-vd-4RS" secondAttribute="trailing" constant="8" id="4sW-VU-zvV"/> + <constraint firstAttribute="trailing" secondItem="HdG-mr-PTo" secondAttribute="trailing" constant="20" id="BnI-5v-XDn"/> + <constraint firstAttribute="trailing" secondItem="f6q-RS-lgS" secondAttribute="trailing" constant="20" id="Cqq-zM-wXc"/> + <constraint firstItem="s1u-o4-hER" firstAttribute="top" secondItem="3Hz-RL-Ugz" secondAttribute="top" id="Ez4-MK-s7B"/> + <constraint firstAttribute="trailing" secondItem="f6q-RS-lgS" secondAttribute="trailing" id="JmH-ju-U9V"/> + <constraint firstAttribute="bottom" secondItem="s1u-o4-hER" secondAttribute="bottom" constant="5" id="Kda-pQ-Ua1"/> + <constraint firstItem="oCt-vd-4RS" firstAttribute="top" secondItem="3Hz-RL-Ugz" secondAttribute="top" id="Oez-gR-vqC"/> + <constraint firstItem="f6q-RS-lgS" firstAttribute="centerY" secondItem="s1u-o4-hER" secondAttribute="centerY" id="QTX-hv-7Fq"/> + <constraint firstItem="HdG-mr-PTo" firstAttribute="leading" secondItem="s1u-o4-hER" secondAttribute="trailing" constant="8" id="WcO-wz-iHe"/> + <constraint firstItem="HdG-mr-PTo" firstAttribute="bottom" secondItem="s1u-o4-hER" secondAttribute="bottom" id="XKV-KR-feV"/> + <constraint firstAttribute="trailing" secondItem="HdG-mr-PTo" secondAttribute="trailing" id="fa5-uD-Jqj"/> + <constraint firstItem="s1u-o4-hER" firstAttribute="centerY" secondItem="3Hz-RL-Ugz" secondAttribute="centerY" id="juK-x2-WdU"/> + <constraint firstItem="f6q-RS-lgS" firstAttribute="leading" secondItem="s1u-o4-hER" secondAttribute="trailing" constant="8" id="rIU-1n-M35"/> + <constraint firstItem="s1u-o4-hER" firstAttribute="leading" secondItem="3Hz-RL-Ugz" secondAttribute="leading" id="zY8-tn-NjM"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="juK-x2-WdU"/> + <exclude reference="JmH-ju-U9V"/> + <exclude reference="QTX-hv-7Fq"/> + <exclude reference="fa5-uD-Jqj"/> + </mask> + </variation> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BCK-ON-IjJ"> + <rect key="frame" x="15" y="153" width="570" height="50"/> + <subviews> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hue-C5-PHW"> + <rect key="frame" x="348" y="0.0" width="106" height="50"/> + <animations/> + <state key="normal" backgroundImage="rating_star2"/> + <connections> + <action selector="fourStarTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="pCL-4u-Duz"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZP9-Qg-4Le"> + <rect key="frame" x="232" y="0.0" width="106" height="50"/> + <animations/> + <state key="normal" backgroundImage="rating_star2"/> + <connections> + <action selector="threeStarTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="F0g-su-LVO"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KzN-ht-Jya"> + <rect key="frame" x="0.0" y="0.0" width="106" height="50"/> + <animations/> + <color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <state key="normal" image="rating_star2"/> + <state key="highlighted" image="rating_star_filled"/> + <connections> + <action selector="oneStarTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="5jC-Qf-LPh"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ofM-BY-Yzj"> + <rect key="frame" x="116" y="0.0" width="106" height="50"/> + <animations/> + <state key="normal" backgroundImage="rating_star2"> + <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </state> + <state key="selected" backgroundImage="rating_star_filled"/> + <state key="highlighted" backgroundImage="rating_star_filled"/> + <connections> + <action selector="twoStarTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="uc8-kM-fow"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0G1-Em-Jng"> + <rect key="frame" x="464" y="0.0" width="106" height="50"/> + <animations/> + <state key="normal" backgroundImage="rating_star2"/> + <connections> + <action selector="fiveStarTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="lF4-Jk-XCm"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="Hue-C5-PHW" firstAttribute="width" secondItem="0G1-Em-Jng" secondAttribute="width" id="2FZ-ZI-T0C"/> + <constraint firstItem="ZP9-Qg-4Le" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="top" id="2p6-Tb-6HP"/> + <constraint firstAttribute="bottom" secondItem="0G1-Em-Jng" secondAttribute="bottom" id="3x6-9s-I5h"/> + <constraint firstAttribute="bottom" secondItem="ZP9-Qg-4Le" secondAttribute="bottom" id="4vm-Tw-U3R"/> + <constraint firstItem="ZP9-Qg-4Le" firstAttribute="leading" secondItem="ofM-BY-Yzj" secondAttribute="trailing" constant="10" id="6aU-ox-HwV"/> + <constraint firstItem="Hue-C5-PHW" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="top" id="7A4-tx-MqB"/> + <constraint firstItem="0G1-Em-Jng" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="top" id="9Cb-JU-lAQ"/> + <constraint firstItem="Hue-C5-PHW" firstAttribute="leading" secondItem="ZP9-Qg-4Le" secondAttribute="trailing" constant="10" id="CSy-0o-bR0"/> + <constraint firstItem="KzN-ht-Jya" firstAttribute="width" secondItem="ofM-BY-Yzj" secondAttribute="width" id="E1G-ub-wPn"/> + <constraint firstAttribute="bottom" secondItem="KzN-ht-Jya" secondAttribute="bottom" id="EpA-1l-8jY"/> + <constraint firstItem="ofM-BY-Yzj" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="top" id="FqL-or-J5D"/> + <constraint firstItem="ofM-BY-Yzj" firstAttribute="width" secondItem="ZP9-Qg-4Le" secondAttribute="width" id="MDP-VR-C4f"/> + <constraint firstItem="ZP9-Qg-4Le" firstAttribute="width" secondItem="Hue-C5-PHW" secondAttribute="width" id="OTB-62-hNK"/> + <constraint firstAttribute="bottom" secondItem="Hue-C5-PHW" secondAttribute="bottom" id="OZH-mP-cs8"/> + <constraint firstAttribute="height" constant="50" id="R7d-D5-Gdp"/> + <constraint firstAttribute="bottom" secondItem="ofM-BY-Yzj" secondAttribute="bottom" id="Umh-F3-XTd"/> + <constraint firstAttribute="trailing" secondItem="0G1-Em-Jng" secondAttribute="trailing" id="V23-rs-yf7"/> + <constraint firstItem="ofM-BY-Yzj" firstAttribute="leading" secondItem="KzN-ht-Jya" secondAttribute="trailing" id="bsx-Dg-FWg"/> + <constraint firstItem="ofM-BY-Yzj" firstAttribute="leading" secondItem="KzN-ht-Jya" secondAttribute="trailing" constant="10" id="iK1-9j-rfy"/> + <constraint firstItem="0G1-Em-Jng" firstAttribute="leading" secondItem="Hue-C5-PHW" secondAttribute="trailing" constant="10" id="jC4-5Z-xk2"/> + <constraint firstItem="KzN-ht-Jya" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="top" id="kk9-wn-v1r"/> + <constraint firstItem="KzN-ht-Jya" firstAttribute="leading" secondItem="BCK-ON-IjJ" secondAttribute="leading" id="qZL-NM-hV9"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="bsx-Dg-FWg"/> + </mask> + </variation> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ccY-ot-FYH"> + <rect key="frame" x="0.0" y="411" width="600" height="60"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bIK-7d-Vfl"> + <rect key="frame" x="233" y="13" width="134" height="33"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <state key="normal" title=" Log To Journal "> + <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </state> + <connections> + <action selector="logToJournalButtonTapped:" destination="aXS-um-aw2" eventType="touchUpInside" id="bF7-vG-sm2"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="60" id="3us-vq-HY3"/> + <constraint firstItem="bIK-7d-Vfl" firstAttribute="centerX" secondItem="ccY-ot-FYH" secondAttribute="centerX" id="67t-uq-gMg"/> + <constraint firstItem="bIK-7d-Vfl" firstAttribute="centerY" secondItem="ccY-ot-FYH" secondAttribute="centerY" id="ZwE-L5-xQD"/> + </constraints> + </view> + <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gMh-cq-aTG"> + <rect key="frame" x="20" y="219" width="560" height="176"/> + <animations/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="25"/> + <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> + </textView> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="3Hz-RL-Ugz" firstAttribute="trailing" secondItem="p3u-dw-cX6" secondAttribute="trailingMargin" id="1b0-Cy-sHW"/> + <constraint firstItem="3Hz-RL-Ugz" firstAttribute="top" secondItem="35G-Te-D94" secondAttribute="bottom" id="CcV-Ir-Nos"/> + <constraint firstItem="3Hz-RL-Ugz" firstAttribute="top" secondItem="35G-Te-D94" secondAttribute="bottom" id="Dq8-Io-V9X"/> + <constraint firstItem="BCK-ON-IjJ" firstAttribute="leading" secondItem="p3u-dw-cX6" secondAttribute="leading" constant="15" id="PTt-IZ-aNy"/> + <constraint firstItem="tF2-8H-bHx" firstAttribute="top" secondItem="ccY-ot-FYH" secondAttribute="bottom" constant="80" id="RUt-kn-b0q"/> + <constraint firstItem="gMh-cq-aTG" firstAttribute="leading" secondItem="p3u-dw-cX6" secondAttribute="leadingMargin" id="UUx-jy-Izz"/> + <constraint firstItem="3Hz-RL-Ugz" firstAttribute="leading" secondItem="p3u-dw-cX6" secondAttribute="leadingMargin" id="Wey-Ew-9Lu"/> + <constraint firstItem="ccY-ot-FYH" firstAttribute="leading" secondItem="p3u-dw-cX6" secondAttribute="leading" id="XZc-9R-T26"/> + <constraint firstItem="gMh-cq-aTG" firstAttribute="top" secondItem="BCK-ON-IjJ" secondAttribute="bottom" constant="16" id="Yag-O4-Uh7"/> + <constraint firstAttribute="trailing" secondItem="ccY-ot-FYH" secondAttribute="trailing" id="fbk-ya-YeF"/> + <constraint firstItem="ccY-ot-FYH" firstAttribute="top" secondItem="gMh-cq-aTG" secondAttribute="bottom" id="k9n-yQ-XiX"/> + <constraint firstAttribute="trailing" secondItem="BCK-ON-IjJ" secondAttribute="trailing" constant="15" id="pcb-Is-KNU"/> + <constraint firstItem="BCK-ON-IjJ" firstAttribute="top" secondItem="3Hz-RL-Ugz" secondAttribute="bottom" constant="8" id="t6s-ES-EUU"/> + <constraint firstItem="ccY-ot-FYH" firstAttribute="top" secondItem="gMh-cq-aTG" secondAttribute="bottom" constant="16" id="v7c-f8-4aB"/> + <constraint firstItem="gMh-cq-aTG" firstAttribute="trailing" secondItem="p3u-dw-cX6" secondAttribute="trailingMargin" id="ywD-3B-vc1"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="CcV-Ir-Nos"/> + <exclude reference="k9n-yQ-XiX"/> + </mask> + </variation> + </view> + <connections> + <outlet property="artistNameLabel" destination="HdG-mr-PTo" id="xoi-ku-dfy"/> + <outlet property="artworkImageView" destination="s1u-o4-hER" id="j5D-wO-ZJP"/> + <outlet property="doneEditingButton" destination="oCt-vd-4RS" id="cQZ-Tr-B0E"/> + <outlet property="movieOrAlbumNameLabel" destination="f6q-RS-lgS" id="ify-cv-Z2Y"/> + <outlet property="starButtonFive" destination="0G1-Em-Jng" id="gsy-gR-Ohg"/> + <outlet property="starButtonFour" destination="Hue-C5-PHW" id="alq-WC-E1Z"/> + <outlet property="starButtonOne" destination="KzN-ht-Jya" id="FZL-kO-3hy"/> + <outlet property="starButtonThree" destination="ZP9-Qg-4Le" id="r3s-AV-lHf"/> + <outlet property="starButtonTwo" destination="ofM-BY-Yzj" id="lyV-o3-dHx"/> + <outlet property="textView" destination="gMh-cq-aTG" id="e7z-VE-aIf"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="TK9-37-5bs" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-183" y="4022"/> + </scene> + <!--Folding Tab Bar Controller--> + <scene sceneID="bxL-4q-Pom"> + <objects> + <tabBarController id="sU9-FA-LDO" customClass="YALFoldingTabBarController" sceneMemberID="viewController"> + <extendedEdge key="edgesForExtendedLayout" top="YES"/> + <tabBar key="tabBar" contentMode="scaleToFill" id="vp1-Fh-t9g"> + <rect key="frame" x="0.0" y="0.0" width="320" height="49"/> + <autoresizingMask key="autoresizingMask"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> + </tabBar> + <connections> + <segue destination="jRK-Je-LOr" kind="relationship" relationship="viewControllers" id="HOj-PJ-Fkd"/> + <segue destination="UUP-oh-FLI" kind="relationship" relationship="viewControllers" id="Rjg-aa-DxP"/> + <segue destination="Gih-78-N3X" kind="relationship" relationship="viewControllers" id="abK-z0-qa5"/> + <segue destination="Oeh-Ah-1CX" kind="relationship" relationship="viewControllers" id="2Xh-DK-MpE"/> + </connections> + </tabBarController> + <placeholder placeholderIdentifier="IBFirstResponder" id="1hc-eJ-lg1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="171" y="1647"/> + </scene> + <!--Item--> + <scene sceneID="cKb-7g-WEz"> + <objects> + <navigationController navigationBarHidden="YES" id="jRK-Je-LOr" sceneMemberID="viewController"> + <tabBarItem key="tabBarItem" title="Item" id="Dua-qJ-GWW"/> + <navigationBar key="navigationBar" contentMode="scaleToFill" id="kHi-Rv-LpC"> + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <animations/> + </navigationBar> + <connections> + <segue destination="WZe-UX-wgc" kind="relationship" relationship="rootViewController" id="c1X-Zg-b9I"/> + </connections> + </navigationController> + <placeholder placeholderIdentifier="IBFirstResponder" id="Bl9-pa-7aW" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-907" y="2528"/> + </scene> + <!--Wish List--> + <scene sceneID="WUv-ax-PAc"> + <objects> + <tableViewController title="Wish List" id="WZe-UX-wgc" customClass="WishListTableViewController" sceneMemberID="viewController"> + <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="64" sectionHeaderHeight="28" sectionFooterHeight="28" id="YJ5-uB-Kgw"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <view key="tableHeaderView" contentMode="scaleToFill" id="t7Q-Vo-vCQ"> + <rect key="frame" x="0.0" y="0.0" width="600" height="125"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="WISH" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Df0-BF-gAU"> + <rect key="frame" x="173" y="20" width="126" height="59"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="50"/> + <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Pix-v9-EmC"> + <rect key="frame" x="299" y="33" width="2" height="117"/> + <animations/> + <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/> + <constraints> + <constraint firstAttribute="width" constant="2" id="jRL-xR-JIZ"/> + </constraints> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LIST" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oKs-Fj-h2E"> + <rect key="frame" x="301" y="56" width="101" height="59"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="50"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="oKs-Fj-h2E" firstAttribute="top" secondItem="Df0-BF-gAU" secondAttribute="bottom" constant="-23" id="3fL-JR-23W"/> + <constraint firstItem="Pix-v9-EmC" firstAttribute="centerX" secondItem="t7Q-Vo-vCQ" secondAttribute="centerX" id="9KS-hu-Ysd"/> + <constraint firstAttribute="bottom" secondItem="Pix-v9-EmC" secondAttribute="bottom" id="Rbq-Zp-oG7"/> + <constraint firstAttribute="bottom" secondItem="oKs-Fj-h2E" secondAttribute="bottom" constant="10" id="WJ5-V2-VBg"/> + <constraint firstItem="Pix-v9-EmC" firstAttribute="top" secondItem="t7Q-Vo-vCQ" secondAttribute="top" constant="33" id="Xvf-g8-cc0"/> + <constraint firstItem="Pix-v9-EmC" firstAttribute="leading" secondItem="Df0-BF-gAU" secondAttribute="trailing" id="eeX-ya-zkq"/> + <constraint firstItem="oKs-Fj-h2E" firstAttribute="leading" secondItem="Df0-BF-gAU" secondAttribute="trailing" constant="10.5" id="k05-wH-1R7"/> + <constraint firstItem="oKs-Fj-h2E" firstAttribute="leading" secondItem="Pix-v9-EmC" secondAttribute="trailing" id="vk3-7M-cvN"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="k05-wH-1R7"/> + </mask> + </variation> + </view> + <prototypes> + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" accessoryType="disclosureIndicator" indentationWidth="10" shouldIndentWhileEditing="NO" rowHeight="64" id="Ej0-R4-rXa"> + <rect key="frame" x="0.0" y="153" width="600" height="64"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ej0-R4-rXa" id="ezU-vk-VRT"> + <rect key="frame" x="0.0" y="0.0" width="567" height="64"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="346-CT-Uvl"> + <rect key="frame" x="8" y="0.0" width="58" height="61"/> + <animations/> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bdy-xS-1Zi"> + <rect key="frame" x="74" y="0.0" width="42" height="21"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zzx-oe-N5F"> + <rect key="frame" x="74" y="40" width="42" height="21"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + </tableViewCellContentView> + <animations/> + <connections> + <segue destination="BAI-dU-dy0" kind="show" identifier="moveFromWishToJournalEntry" id="uNF-QU-YbJ"/> + </connections> + </tableViewCell> + </prototypes> + <connections> + <outlet property="dataSource" destination="WZe-UX-wgc" id="J1b-e6-bdB"/> + <outlet property="delegate" destination="WZe-UX-wgc" id="KJE-Pm-bbr"/> + </connections> + </tableView> + <tabBarItem key="tabBarItem" title="Item" id="XuX-sx-3nt"/> + <navigationItem key="navigationItem" id="wvx-LN-Wn1"/> + </tableViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="vQP-Qq-o7U" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-907" y="3308"/> + </scene> + <!--View Controller--> + <scene sceneID="Sp1-uX-mf4"> + <objects> + <viewController id="CYq-PS-xt5" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="tl8-EB-kmB"/> + <viewControllerLayoutGuide type="bottom" id="9pR-Xs-cjD"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="3VK-Vh-iXc"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Email Address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="K3E-2D-tZM"> + <rect key="frame" x="20" y="341" width="560" height="30"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits" keyboardType="emailAddress" secureTextEntry="YES"/> + </textField> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="INZ-wD-uKG"> + <rect key="frame" x="20" y="379" width="560" height="30"/> + <animations/> + <state key="normal" title="Sign Up"/> + </button> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Username" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="23H-rp-l7n"> + <rect key="frame" x="20" y="228" width="560" height="30"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits"/> + </textField> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Username" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="cD6-Fr-Z4w"> + <rect key="frame" x="20" y="285" width="560" height="30"/> + <animations/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits"/> + </textField> + </subviews> + <animations/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="Q2h-wD-5hi" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="2643" y="641"/> + </scene> + <!--View Completed Journal Entry--> + <scene sceneID="dbg-sY-EWD"> + <objects> + <viewController storyboardIdentifier="CompleteEntryVC" title="View Completed Journal Entry" id="z1K-z0-Vef" customClass="ViewCompletedEntryViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="hxi-Oa-IvU"/> + <viewControllerLayoutGuide type="bottom" id="DF9-8P-jQU"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="EZl-sI-Vwl"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bI1-9Y-Lhn" userLabel="Blue View"> + <rect key="frame" x="20" y="325" width="560" height="91"/> + <subviews> + <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="center" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="riX-qw-M2j"> + <rect key="frame" x="5" y="5" width="550" height="81"/> + <animations/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="25"/> + <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> + </textView> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="riX-qw-M2j" firstAttribute="leading" secondItem="bI1-9Y-Lhn" secondAttribute="leading" constant="5" id="9qy-ow-Nql"/> + <constraint firstAttribute="trailing" secondItem="riX-qw-M2j" secondAttribute="trailing" constant="5" id="Gsp-CD-sDk"/> + <constraint firstAttribute="bottom" secondItem="riX-qw-M2j" secondAttribute="bottom" constant="5" id="HD8-LY-0od"/> + <constraint firstItem="riX-qw-M2j" firstAttribute="top" secondItem="bI1-9Y-Lhn" secondAttribute="top" constant="5" id="LNA-Mw-l4a"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ly8-tU-R6b"> + <rect key="frame" x="35" y="416" width="530" height="50"/> + <subviews> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="M7h-zf-QrN"> + <rect key="frame" x="216" y="0.0" width="98" height="50"/> + <animations/> + </button> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="JU3-mC-wxo"> + <rect key="frame" x="324" y="0.0" width="98" height="50"/> + <animations/> + </button> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Pt8-eG-uys"> + <rect key="frame" x="432" y="0.0" width="98" height="50"/> + <animations/> + </button> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zLL-Ls-a62"> + <rect key="frame" x="108" y="0.0" width="98" height="50"/> + <animations/> + </button> + <button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rcY-Tz-IPf"> + <rect key="frame" x="0.0" y="0.0" width="98" height="50"/> + <animations/> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="JU3-mC-wxo" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="top" id="2Tf-0t-JRM"/> + <constraint firstItem="zLL-Ls-a62" firstAttribute="width" secondItem="M7h-zf-QrN" secondAttribute="width" id="BHh-BK-YdV"/> + <constraint firstItem="Pt8-eG-uys" firstAttribute="leading" secondItem="JU3-mC-wxo" secondAttribute="trailing" constant="10" id="CH4-Yy-9nS"/> + <constraint firstItem="zLL-Ls-a62" firstAttribute="leading" secondItem="rcY-Tz-IPf" secondAttribute="trailing" constant="10" id="Cq2-Md-WKu"/> + <constraint firstItem="M7h-zf-QrN" firstAttribute="centerY" secondItem="Ly8-tU-R6b" secondAttribute="centerY" id="G5T-Ag-IXG"/> + <constraint firstItem="Pt8-eG-uys" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="top" id="Gkl-ve-1CI"/> + <constraint firstAttribute="trailing" secondItem="Pt8-eG-uys" secondAttribute="trailing" id="Jt0-0A-BaN"/> + <constraint firstItem="JU3-mC-wxo" firstAttribute="leading" secondItem="M7h-zf-QrN" secondAttribute="trailing" constant="10" id="Oat-qV-Hlr"/> + <constraint firstItem="M7h-zf-QrN" firstAttribute="centerX" secondItem="Ly8-tU-R6b" secondAttribute="centerX" id="R9E-P7-EPD"/> + <constraint firstItem="M7h-zf-QrN" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="top" id="RKC-59-2Rp"/> + <constraint firstItem="rcY-Tz-IPf" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="top" id="SdJ-5x-By3"/> + <constraint firstItem="JU3-mC-wxo" firstAttribute="width" secondItem="Pt8-eG-uys" secondAttribute="width" id="bNq-hH-S4O"/> + <constraint firstAttribute="bottom" secondItem="JU3-mC-wxo" secondAttribute="bottom" id="hnm-lN-zbH"/> + <constraint firstItem="zLL-Ls-a62" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="top" id="ieb-CF-uXd"/> + <constraint firstAttribute="bottom" secondItem="M7h-zf-QrN" secondAttribute="bottom" id="kqk-W5-xgt"/> + <constraint firstAttribute="bottom" secondItem="Pt8-eG-uys" secondAttribute="bottom" id="nVH-hA-3Ay"/> + <constraint firstItem="M7h-zf-QrN" firstAttribute="leading" secondItem="zLL-Ls-a62" secondAttribute="trailing" constant="10" id="r6Z-Bw-wGo"/> + <constraint firstAttribute="bottom" secondItem="rcY-Tz-IPf" secondAttribute="bottom" id="r79-C4-zRI"/> + <constraint firstAttribute="bottom" secondItem="zLL-Ls-a62" secondAttribute="bottom" id="s6E-5N-8Tn"/> + <constraint firstAttribute="trailing" secondItem="Pt8-eG-uys" secondAttribute="trailing" id="uj3-xf-ala"/> + <constraint firstAttribute="height" constant="50" id="umD-ss-qeO"/> + <constraint firstItem="rcY-Tz-IPf" firstAttribute="leading" secondItem="Ly8-tU-R6b" secondAttribute="leading" id="vll-ua-VXC"/> + <constraint firstItem="M7h-zf-QrN" firstAttribute="width" secondItem="JU3-mC-wxo" secondAttribute="width" id="wks-Gj-E8F"/> + <constraint firstItem="rcY-Tz-IPf" firstAttribute="width" secondItem="zLL-Ls-a62" secondAttribute="width" id="yIe-IF-AG8"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="uj3-xf-ala"/> + </mask> + </variation> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="x4f-Ym-z1V"> + <rect key="frame" x="20" y="476" width="280" height="75"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1br-zx-rKo"> + <rect key="frame" x="92" y="21" width="96" height="33"/> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <state key="normal" title=" RETURN "> + <color key="titleColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + </state> + <connections> + <action selector="deleteButtonTapped:" destination="z1K-z0-Vef" eventType="touchUpInside" id="umA-zo-2bu"/> + </connections> + </button> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="100" id="4cP-Gz-KpJ"/> + <constraint firstItem="1br-zx-rKo" firstAttribute="centerX" secondItem="x4f-Ym-z1V" secondAttribute="centerX" id="97n-xh-93f"/> + <constraint firstAttribute="height" constant="75" id="JSN-NO-vFc"/> + <constraint firstItem="1br-zx-rKo" firstAttribute="centerY" secondItem="x4f-Ym-z1V" secondAttribute="centerY" id="u1x-dv-z8q"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="4cP-Gz-KpJ"/> + </mask> + </variation> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DLn-Kf-i7J" userLabel="Red View"> + <rect key="frame" x="20" y="250" width="560" height="75"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RUW-ww-VHC"> + <rect key="frame" x="10" y="26" width="540" height="17"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uPb-Kv-PyA"> + <rect key="frame" x="10" y="0.0" width="540" height="21"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Title" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eHa-Fq-bcU"> + <rect key="frame" x="10" y="48" width="540" height="22"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="uPb-Kv-PyA" secondAttribute="trailing" constant="10" id="9dy-H7-3rx"/> + <constraint firstItem="eHa-Fq-bcU" firstAttribute="top" secondItem="RUW-ww-VHC" secondAttribute="bottom" constant="5.5" id="HxD-t4-nxH"/> + <constraint firstAttribute="trailing" secondItem="RUW-ww-VHC" secondAttribute="trailing" constant="10" id="I81-DF-sUO"/> + <constraint firstAttribute="height" constant="75" id="IVL-4V-IKI"/> + <constraint firstItem="RUW-ww-VHC" firstAttribute="top" secondItem="uPb-Kv-PyA" secondAttribute="bottom" constant="5" id="NCU-bN-sFr"/> + <constraint firstItem="eHa-Fq-bcU" firstAttribute="leading" secondItem="DLn-Kf-i7J" secondAttribute="leading" constant="10" id="NfX-5o-5nc"/> + <constraint firstItem="RUW-ww-VHC" firstAttribute="leading" secondItem="DLn-Kf-i7J" secondAttribute="leading" constant="10" id="T4f-b2-xi4"/> + <constraint firstAttribute="trailing" secondItem="eHa-Fq-bcU" secondAttribute="trailing" constant="10" id="Vl9-PL-v5V"/> + <constraint firstItem="uPb-Kv-PyA" firstAttribute="top" secondItem="DLn-Kf-i7J" secondAttribute="top" id="cPx-3F-rDr"/> + <constraint firstAttribute="bottom" secondItem="eHa-Fq-bcU" secondAttribute="bottom" constant="5" id="dzZ-gQ-gFU"/> + <constraint firstItem="uPb-Kv-PyA" firstAttribute="leading" secondItem="DLn-Kf-i7J" secondAttribute="leading" constant="10" id="hqU-eA-14x"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2sS-fd-D0X" userLabel="Pink View"> + <rect key="frame" x="20" y="20" width="560" height="230"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="P8h-8Q-AZm"> + <rect key="frame" x="180" y="15" width="200" height="200"/> + <animations/> + <constraints> + <constraint firstAttribute="height" constant="200" id="1bV-mr-UNq"/> + <constraint firstAttribute="width" constant="200" id="j39-Np-9Qw"/> + <constraint firstAttribute="width" constant="250" id="qPa-Gb-BP4"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="qPa-Gb-BP4"/> + </mask> + </variation> + </imageView> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="top" constant="5" id="4Iw-Mk-e5C"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerY" secondItem="2sS-fd-D0X" secondAttribute="centerY" id="4vp-EM-f9w"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerX" secondItem="2sS-fd-D0X" secondAttribute="centerX" id="7HA-mu-ocy"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerY" secondItem="2sS-fd-D0X" secondAttribute="centerY" id="Gqe-NI-Z3C"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="top" constant="25" id="Gwt-cb-ayI"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerX" secondItem="2sS-fd-D0X" secondAttribute="centerX" id="IAe-fk-e1S"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="leading" secondItem="2sS-fd-D0X" secondAttribute="leading" id="Niy-tr-Y6J"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerY" secondItem="2sS-fd-D0X" secondAttribute="centerY" id="Ntg-Gm-9zu"/> + <constraint firstAttribute="bottom" secondItem="P8h-8Q-AZm" secondAttribute="bottom" constant="8" id="O1M-iv-PWr"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerX" secondItem="2sS-fd-D0X" secondAttribute="centerX" id="Qq8-Qh-xM5"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerX" secondItem="2sS-fd-D0X" secondAttribute="centerX" id="QtP-WJ-Had"/> + <constraint firstAttribute="height" constant="250" id="VfU-zQ-x6U"/> + <constraint firstAttribute="bottom" secondItem="P8h-8Q-AZm" secondAttribute="bottom" id="WuK-4Z-oTG"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerY" secondItem="2sS-fd-D0X" secondAttribute="centerY" id="eIg-rl-hTN"/> + <constraint firstAttribute="height" constant="125" id="pV2-le-mwS"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="centerY" secondItem="2sS-fd-D0X" secondAttribute="centerY" id="sBD-Zu-u6U"/> + <constraint firstAttribute="trailing" secondItem="P8h-8Q-AZm" secondAttribute="trailing" id="ziG-OY-chr"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="VfU-zQ-x6U"/> + <exclude reference="pV2-le-mwS"/> + <exclude reference="4Iw-Mk-e5C"/> + <exclude reference="7HA-mu-ocy"/> + <exclude reference="Gqe-NI-Z3C"/> + <exclude reference="Gwt-cb-ayI"/> + <exclude reference="IAe-fk-e1S"/> + <exclude reference="Niy-tr-Y6J"/> + <exclude reference="Ntg-Gm-9zu"/> + <exclude reference="O1M-iv-PWr"/> + <exclude reference="QtP-WJ-Had"/> + <exclude reference="WuK-4Z-oTG"/> + <exclude reference="eIg-rl-hTN"/> + <exclude reference="sBD-Zu-u6U"/> + <exclude reference="ziG-OY-chr"/> + </mask> + </variation> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="iJa-08-1GE"> + <rect key="frame" x="300" y="476" width="280" height="75"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Facebook" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qia-hv-Okp"> + <rect key="frame" x="102" y="27" width="77" height="21"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="17"/> + <color key="textColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="calibratedRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstAttribute="height" constant="100" id="DnT-BB-V1g"/> + <constraint firstItem="Qia-hv-Okp" firstAttribute="centerX" secondItem="iJa-08-1GE" secondAttribute="centerX" id="Hf4-By-8MH"/> + <constraint firstItem="Qia-hv-Okp" firstAttribute="centerY" secondItem="iJa-08-1GE" secondAttribute="centerY" id="MBF-Xt-pRY"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="DnT-BB-V1g"/> + </mask> + </variation> + </view> + </subviews> + <animations/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> + <constraints> + <constraint firstItem="Ly8-tU-R6b" firstAttribute="leading" secondItem="EZl-sI-Vwl" secondAttribute="leadingMargin" constant="15" id="1T0-Ze-kQC"/> + <constraint firstItem="iJa-08-1GE" firstAttribute="width" secondItem="x4f-Ym-z1V" secondAttribute="width" id="2eT-qx-CF9"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="bottom" id="3c5-ik-Auq"/> + <constraint firstItem="DF9-8P-jQU" firstAttribute="top" secondItem="x4f-Ym-z1V" secondAttribute="bottom" id="4Fa-3M-oyp"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="bottom" id="4JK-ES-1ri"/> + <constraint firstItem="x4f-Ym-z1V" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="bottom" constant="10" id="5op-S4-Rvd"/> + <constraint firstItem="2sS-fd-D0X" firstAttribute="top" secondItem="hxi-Oa-IvU" secondAttribute="bottom" id="6j7-Pw-W91"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="top" secondItem="hxi-Oa-IvU" secondAttribute="bottom" constant="15" id="8ZM-iZ-FzX"/> + <constraint firstItem="DLn-Kf-i7J" firstAttribute="leading" secondItem="EZl-sI-Vwl" secondAttribute="leadingMargin" id="EXX-9N-Oxk"/> + <constraint firstItem="2sS-fd-D0X" firstAttribute="trailing" secondItem="EZl-sI-Vwl" secondAttribute="trailingMargin" id="HN0-Bi-dhn"/> + <constraint firstItem="iJa-08-1GE" firstAttribute="top" secondItem="Ly8-tU-R6b" secondAttribute="bottom" constant="10" id="HUk-f2-mkx"/> + <constraint firstItem="2sS-fd-D0X" firstAttribute="top" secondItem="hxi-Oa-IvU" secondAttribute="bottom" id="KCf-gF-e0e"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="trailing" secondItem="EZl-sI-Vwl" secondAttribute="trailingMargin" id="N93-6I-U69"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="width" secondItem="EZl-sI-Vwl" secondAttribute="width" id="OFO-ZK-Q4N"/> + <constraint firstItem="Ly8-tU-R6b" firstAttribute="top" secondItem="EZl-sI-Vwl" secondAttribute="top" constant="410" id="S8h-Yj-9gp"/> + <constraint firstItem="DLn-Kf-i7J" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="bottom" id="UE2-tj-Agp"/> + <constraint firstItem="DF9-8P-jQU" firstAttribute="top" secondItem="iJa-08-1GE" secondAttribute="bottom" id="VWC-OE-anb"/> + <constraint firstItem="2sS-fd-D0X" firstAttribute="leading" secondItem="EZl-sI-Vwl" secondAttribute="leadingMargin" id="WUr-xg-D5x"/> + <constraint firstItem="Ly8-tU-R6b" firstAttribute="top" secondItem="bI1-9Y-Lhn" secondAttribute="bottom" id="Zqz-eo-C42"/> + <constraint firstItem="iJa-08-1GE" firstAttribute="leading" secondItem="x4f-Ym-z1V" secondAttribute="trailing" id="boO-Nt-gih"/> + <constraint firstItem="iJa-08-1GE" firstAttribute="height" secondItem="x4f-Ym-z1V" secondAttribute="height" id="cQv-ly-Jaj"/> + <constraint firstItem="P8h-8Q-AZm" firstAttribute="width" secondItem="EZl-sI-Vwl" secondAttribute="width" id="dan-ER-otn"/> + <constraint firstItem="Ly8-tU-R6b" firstAttribute="trailing" secondItem="EZl-sI-Vwl" secondAttribute="trailingMargin" constant="-15" id="fGr-sx-IUP"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="leading" secondItem="EZl-sI-Vwl" secondAttribute="leadingMargin" id="flc-is-VEs"/> + <constraint firstItem="DLn-Kf-i7J" firstAttribute="trailing" secondItem="EZl-sI-Vwl" secondAttribute="trailingMargin" id="gEr-xm-jxi"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="top" secondItem="2sS-fd-D0X" secondAttribute="bottom" id="gL3-nR-tUc"/> + <constraint firstItem="x4f-Ym-z1V" firstAttribute="leading" secondItem="EZl-sI-Vwl" secondAttribute="leadingMargin" id="jwd-au-VUD"/> + <constraint firstItem="x4f-Ym-z1V" firstAttribute="trailing" secondItem="EZl-sI-Vwl" secondAttribute="trailingMargin" id="mnC-Mc-ilI"/> + <constraint firstAttribute="trailingMargin" secondItem="iJa-08-1GE" secondAttribute="trailing" id="sA6-1W-UsV"/> + <constraint firstItem="bI1-9Y-Lhn" firstAttribute="top" secondItem="DLn-Kf-i7J" secondAttribute="bottom" id="yhw-F7-jIa"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="OFO-ZK-Q4N"/> + <exclude reference="dan-ER-otn"/> + <exclude reference="3c5-ik-Auq"/> + <exclude reference="4JK-ES-1ri"/> + <exclude reference="gL3-nR-tUc"/> + <exclude reference="S8h-Yj-9gp"/> + <exclude reference="mnC-Mc-ilI"/> + </mask> + </variation> + </view> + <connections> + <outlet property="completedCreatorLabel" destination="RUW-ww-VHC" id="qVi-vs-rrs"/> + <outlet property="completedDateLabel" destination="eHa-Fq-bcU" id="V3N-n4-xzw"/> + <outlet property="completedImageView" destination="P8h-8Q-AZm" id="sk9-0A-QLf"/> + <outlet property="completedReviewTextView" destination="riX-qw-M2j" id="UdV-2Z-9cW"/> + <outlet property="completedTitleLabel" destination="uPb-Kv-PyA" id="FcS-Tt-BME"/> + <outlet property="facebookView" destination="iJa-08-1GE" id="OOL-Xh-9Cp"/> + <outlet property="starFive" destination="Pt8-eG-uys" id="s1N-26-ZG1"/> + <outlet property="starFour" destination="JU3-mC-wxo" id="PvC-UX-v3N"/> + <outlet property="starOne" destination="rcY-Tz-IPf" id="WMP-nm-ES0"/> + <outlet property="starThree" destination="M7h-zf-QrN" id="NMy-EE-7f9"/> + <outlet property="starTwo" destination="zLL-Ls-a62" id="I3n-Tl-VqR"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="gKL-Ix-enk" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="537" y="3302"/> + </scene> + <!--Item--> + <scene sceneID="lqz-ju-jUl"> + <objects> + <navigationController automaticallyAdjustsScrollViewInsets="NO" navigationBarHidden="YES" id="UUP-oh-FLI" sceneMemberID="viewController"> + <tabBarItem key="tabBarItem" title="Item" id="DsW-2U-fk2"/> + <toolbarItems/> + <navigationBar key="navigationBar" contentMode="scaleToFill" id="H6d-AU-tTl"> + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <animations/> + </navigationBar> + <nil name="viewControllers"/> + <connections> + <segue destination="0x4-Nu-mZ8" kind="relationship" relationship="rootViewController" id="Thc-kb-GNn"/> + </connections> + </navigationController> + <placeholder placeholderIdentifier="IBFirstResponder" id="1ok-11-KLp" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-183" y="2528"/> + </scene> + </scenes> + <resources> + <image name="rating_star2" width="128" height="128"/> + <image name="rating_star_filled" width="128" height="128"/> + </resources> +</document> diff --git a/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.h b/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.h new file mode 100644 index 0000000..cb2d1b7 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.h @@ -0,0 +1,16 @@ +// +// CreateJournalEntryViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "iTunesSearchResult.h" + +@interface CreateJournalEntryViewController : UIViewController + +@property (nonatomic) iTunesSearchResult *postSearchResult; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.m b/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.m new file mode 100644 index 0000000..8961b81 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CreateJournalEntryViewController.m @@ -0,0 +1,229 @@ +// +// CreateJournalEntryViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "CreateJournalEntryViewController.h" +#import "JournalPost.h" +#import "TabBarViewController.h" +#import "JournalMainCollectionViewController.h" +#import <pop/POP.h> +#import <Parse/Parse.h> + +@interface CreateJournalEntryViewController () <UITextViewDelegate> + +@property (strong, nonatomic) IBOutlet UILabel *movieOrAlbumNameLabel; +@property (strong, nonatomic) IBOutlet UILabel *artistNameLabel; +@property (strong, nonatomic) IBOutlet UIImageView *artworkImageView; +@property (strong, nonatomic) IBOutlet UITextView *textView; +@property (strong, nonatomic) IBOutlet UIButton *doneEditingButton; + +@property (strong, nonatomic) IBOutlet UIButton *starButtonOne; +@property (strong, nonatomic) IBOutlet UIButton *starButtonTwo; +@property (strong, nonatomic) IBOutlet UIButton *starButtonThree; +@property (strong, nonatomic) IBOutlet UIButton *starButtonFour; +@property (strong, nonatomic) IBOutlet UIButton *starButtonFive; +@property (strong, nonatomic) NSNumber *rating; + +@property (nonatomic) JournalPost *journalPost; +@property (nonatomic) NSMutableArray *journalPostArray; + +@end + +@implementation CreateJournalEntryViewController + +- (void)viewDidLoad { + + [super viewDidLoad]; + + self.journalPostArray = [[NSMutableArray alloc]init]; + + // NSLog(@"Data has been passed: %@",self.postSearchResult); + + self.doneEditingButton.hidden = YES; + + //manage textview + self.textView.delegate = self; + self.textView.text = @"Write your thoughts here..."; + self.textView.textColor = [UIColor grayColor]; + self.textView.layer.borderWidth = 1.0f; + self.textView.layer.cornerRadius = 5.0f; + self.textView.layer.borderColor = [UIColor blackColor].CGColor; + + //populate journal header + self.movieOrAlbumNameLabel.text = self.postSearchResult.albumOrMovieName; + self.artistNameLabel.text = self.postSearchResult.artistName; + NSURL *artworkURL = [NSURL URLWithString:self.postSearchResult.artworkURL]; + NSData *artworkData = [NSData dataWithContentsOfURL:artworkURL]; + UIImage *artworkImage = [UIImage imageWithData:artworkData]; + self.artworkImageView.image = artworkImage; + + //round image corners + self.artworkImageView.clipsToBounds = YES; + self.artworkImageView.layer.borderColor = [UIColor blackColor].CGColor; + self.artworkImageView.layer.borderWidth = 2.0; + self.artworkImageView.layer.cornerRadius = 25.0; +} + +- (void) textViewDidBeginEditing:(UITextView *)textView { + + self.textView.text = @""; + + self.textView.textColor = [UIColor whiteColor]; + + self.doneEditingButton.hidden = NO; +} + +- (IBAction)doneEditingTapped:(id)sender { + + self.doneEditingButton.hidden = YES; + + [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; +} + +#pragma mark - star rating + +- (IBAction)oneStarTapped:(id)sender { + + [self resetStars]; + [self oneStarRating]; + [self startAnimation]; +} + +- (IBAction)twoStarTapped:(id)sender { + + [self resetStars]; + [self twoStarRating]; + [self startAnimation]; +} + +- (IBAction)threeStarTapped:(id)sender { + + [self resetStars]; + [self threeStarRating]; + [self startAnimation]; +} + +- (IBAction)fourStarTapped:(id)sender { + + [self resetStars]; + [self fourStarRating]; + [self startAnimation]; +} +- (IBAction)fiveStarTapped:(id)sender { + + [self resetStars]; + [self fiveStarRating]; + [self startAnimation]; +} + +- (void)resetStars { + + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starButtonTwo setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starButtonThree setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starButtonFour setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starButtonFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; +} + +- (void)oneStarRating { + + self.rating = @1; // assign rating for parse + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)twoStarRating { + + self.rating = @2; // assign rating for parse + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)threeStarRating { + + self.rating = @3; // assign rating for parse + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)fourStarRating { + + self.rating = @4; // assign rating for parse + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)fiveStarRating { + self.rating = @5; // assign rating for parse + [self.starButtonOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starButtonFive setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +#pragma mark - animate all + +- (void)startAnimation { + + POPSpringAnimation *spin = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation]; + + spin.fromValue = @(M_PI / 4); + spin.toValue = @(5); + spin.springBounciness = 5; + spin.velocity = @(1); + + [self.starButtonOne.layer pop_addAnimation:spin forKey:nil]; + [self.starButtonTwo.layer pop_addAnimation:spin forKey:nil]; + [self.starButtonThree.layer pop_addAnimation:spin forKey:nil]; + [self.starButtonFour.layer pop_addAnimation:spin forKey:nil]; + [self.starButtonFive.layer pop_addAnimation:spin forKey:nil]; +} + +#pragma mark - save items + +- (IBAction)logToJournalButtonTapped:(id)sender { + + JournalPost *journalPost = [[JournalPost alloc]init]; + + journalPost.postText = self.textView.text; + journalPost.postSubject = self.postSearchResult; + + self.journalPost = journalPost; + + [self.journalPostArray addObject:self.journalPost]; + + // NSLog(@"Journal Post: %@",self.journalPost); + + [self.navigationController popToRootViewControllerAnimated:YES]; // pop back to root controller + + [self.tabBarController setSelectedIndex:2]; // send to correct tab + + // NSLog(@"my journal text is: %@", self.textView.text); + + // when we log the journal entry, SAVE it all to Parse + JournalPost *myJournalPost = [[JournalPost alloc] init]; // most of this is a repeat of above. + + if ([self.textView.text isEqualToString:@"Write your thoughts here..."]){ + self.textView.text = @""; + } + + myJournalPost[@"postText"] = self.textView.text; + myJournalPost[@"starRating"] = self.rating; + myJournalPost[@"title"] = self.postSearchResult.albumOrMovieName; + myJournalPost[@"creator"] = self.postSearchResult.artistName; + myJournalPost[@"dateEntered"] = [NSDate date]; + myJournalPost[@"typeOfMedia"] = self.postSearchResult.mediaType; + myJournalPost[@"imageForMedia"] = self.postSearchResult.artworkURL; + myJournalPost[@"reviewed"] = [NSNumber numberWithBool:YES]; + + [myJournalPost saveEventually]; // save your entry, even if offline +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/CustomFont.h b/Unit-2-Journal/Unit-2-Journal/CustomFont.h new file mode 100644 index 0000000..ac74ad8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CustomFont.h @@ -0,0 +1,13 @@ +// +// CustomFont.h +// Unit-2-Journal +// +// Created by Brian Blanco on 10/18/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface CustomFont : UIView + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/CustomFont.m b/Unit-2-Journal/Unit-2-Journal/CustomFont.m new file mode 100644 index 0000000..3cfaaa8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CustomFont.m @@ -0,0 +1,21 @@ +// +// CustomFont.m +// Unit-2-Journal +// +// Created by Brian Blanco on 10/18/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "CustomFont.h" + +@implementation CustomFont + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.h b/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.h new file mode 100644 index 0000000..9e7c667 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.h @@ -0,0 +1,13 @@ +// +// CustomFontViewController.h +// Unit-2-Journal +// +// Created by Brian Blanco on 10/18/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface CustomFontViewController : UIViewController + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.m b/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.m new file mode 100644 index 0000000..d73d2ac --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/CustomFontViewController.m @@ -0,0 +1,39 @@ +// +// CustomFontViewController.m +// Unit-2-Journal +// +// Created by Brian Blanco on 10/18/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "CustomFontViewController.h" + +@interface CustomFontViewController () + +@property (weak, nonatomic) IBOutlet UILabel *launchLabel; + +@end + +@implementation CustomFontViewController + + +- (void)viewDidLoad { + [super viewDidLoad]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/Info.plist b/Unit-2-Journal/Unit-2-Journal/Info.plist new file mode 100644 index 0000000..aadec80 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Info.plist @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleURLSchemes</key> + <array> + <string>fb762432797195822</string> + </array> + </dict> + </array> + <key>CFBundleVersion</key> + <string>1</string> + <key>FacebookAppID</key> + <string>762432797195822</string> + <key>FacebookDisplayName</key> + <string>Unit-2-Journal</string> + <key>LSApplicationQueriesSchemes</key> + <array> + <string>fbauth2</string> + </array> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSAllowsArbitraryLoads</key> + <true/> + <key>NSExceptionDomains</key> + <dict> + <key>akamaihd.net</key> + <dict> + <key>NSExceptionRequiresForwardSecrecy</key> + <false/> + <key>NSIncludesSubdomains</key> + <true/> + </dict> + <key>facebook.com</key> + <dict> + <key>NSExceptionRequiresForwardSecrecy</key> + <false/> + <key>NSIncludesSubdomains</key> + <true/> + </dict> + <key>fbcdn.net</key> + <dict> + <key>NSExceptionRequiresForwardSecrecy</key> + <false/> + <key>NSIncludesSubdomains</key> + <true/> + </dict> + </dict> + </dict> + <key>UIAppFonts</key> + <array> + <string>basictitlefont.ttf</string> + <string>Akkurat Light Regular.otf</string> + <string>Akkurat Bold.otf</string> + </array> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> diff --git a/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.h b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.h new file mode 100644 index 0000000..a254231 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.h @@ -0,0 +1,13 @@ +// +// JournalHeaderView.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/21/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface JournalHeaderView : UICollectionReusableView + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.m b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.m new file mode 100644 index 0000000..2d3784a --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.m @@ -0,0 +1,13 @@ +// +// JournalHeaderView.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/21/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "JournalHeaderView.h" + +@implementation JournalHeaderView + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.xib b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.xib new file mode 100644 index 0000000..d600e07 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalHeaderView.xib @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> + </dependencies> + <customFonts key="customFonts"> + <mutableArray key="Akkurat Bold.otf"> + <string>Akkurat-Bold</string> + </mutableArray> + </customFonts> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="JournalHeaderView"> + <rect key="frame" x="0.0" y="0.0" width="600" height="125"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="JOURNAL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="r2f-XV-NbP"> + <rect key="frame" x="190" y="41" width="221.5" height="59"/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="50"/> + <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/> + <accessibility key="accessibilityConfiguration" identifier="HeaderView"/> + <constraints> + <constraint firstItem="r2f-XV-NbP" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="9IL-fw-Xbi"/> + <constraint firstItem="r2f-XV-NbP" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="IS4-NX-b27"/> + <constraint firstAttribute="bottom" secondItem="r2f-XV-NbP" secondAttribute="bottom" constant="25" id="zgT-2s-llL"/> + </constraints> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <variation key="default"> + <mask key="constraints"> + <exclude reference="9IL-fw-Xbi"/> + </mask> + </variation> + <point key="canvasLocation" x="318" y="228"/> + </view> + </objects> +</document> diff --git a/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.h b/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.h new file mode 100644 index 0000000..a1021f1 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.h @@ -0,0 +1,24 @@ +// +// JournalMainCollectionViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "JournalPost.h" +#import "CreateJournalEntryViewController.h" + + + +@interface JournalMainCollectionViewController : UICollectionViewController +{ + NSMutableArray *collectionImages; +} + +@property (nonatomic) NSMutableArray *allJournalPosts; +@property (nonatomic) JournalPost *journalPostToAdd; +@property (nonatomic) JournalPost *journalPostToPass; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.m b/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.m new file mode 100644 index 0000000..7673fdf --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalMainCollectionViewController.m @@ -0,0 +1,177 @@ +// +// JournalMainCollectionViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "JournalMainCollectionViewController.h" +#import <Parse/Parse.h> +#import "ViewCompletedEntryViewController.h" +#import "JournalHeaderView.h" + +@interface JournalMainCollectionViewController () + +//<UICollectionViewDelegateFlowLayout> + +@end + +@implementation JournalMainCollectionViewController + +- (void) viewDidAppear:(BOOL)animated { + + [self runQuery]; +} + +- (void)viewDidLoad { + + [super viewDidLoad]; + + if (self.allJournalPosts == nil){ + self.allJournalPosts = [[NSMutableArray alloc]init]; + } else { + nil; + } + + // NSLog(@"Current Journal Post: %@", self.journalPostToAdd); + + if (self.journalPostToAdd != nil){ + [self. allJournalPosts addObject:self.journalPostToAdd]; + } + + // NSLog(@"All Journal Posts: %@", self.allJournalPosts); + + self.collectionView.alwaysBounceVertical = YES; + + UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout; + layout.headerReferenceSize = CGSizeMake(0, 150.0); + + // set up custom cell .xib + UINib *nib = [UINib nibWithNibName:@"JournalHeaderView" bundle:nil]; + [self.collectionView registerNib:nib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + + [self runQuery]; // run Parse query to fetch saved data +} + +#pragma mark - fetch saved data from Parse + +- (void)runQuery { + + // __weak typeof(self) weakSelf = self; // prevent memory leakage? + + PFQuery *query = [PFQuery queryWithClassName:@"JournalPost"]; + [query whereKey:@"reviewed" equalTo:[NSNumber numberWithBool:YES]]; + [query orderByDescending:@"updatedAt"]; + + [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) { + + // create a for loop and iterate through the objects array and push only the posts that are marked with True to "self.allJournalPosts" + + [self.allJournalPosts removeAllObjects]; // clear to prevent doubles + + for (JournalPost *object in objects) { +// if (object.reviewed) { + [self.allJournalPosts addObject:object]; +// [self.allJournalPosts insertObject:object atIndex:0]; +// } + } + + // NSLog(@"info fetched from parse: %@", self.allJournalPosts); // test it! + + [self.collectionView reloadData]; // reload tableView + }]; +} + + +//- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { +// +// UICollectionReusableView *reusableview = nil; +// +// if (kind == UICollectionElementKindSectionHeader) { +// +// JournalHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; +// +//// NSString *title = [[NSString alloc]initWithFormat:@"Recipe Group #%i", indexPath.section + 1]; +//// headerView.title.text = title; +//// UIImage *headerImage = [UIImage imageNamed:@"header_banner.png"]; +//// headerView.backgroundImage.image = headerImage; +// +// reusableview = headerView; +// } +// return reusableview; +//} + +#pragma mark <UICollectionViewDataSource> + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return 1; // change to months +} + + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.allJournalPosts.count; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + static NSString *identifier = @"Cell"; + + UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; + + PFObject *post = self.allJournalPosts[indexPath.row]; // pulling out parse data here + + + PFFile *file = post[@"imageForMedia"]; // this returns urls for each image + + + NSString *fileString = [NSString stringWithFormat:@"%@",file]; + NSURL *fileURL = [NSURL URLWithString:fileString]; + NSData *fileData = [NSData dataWithContentsOfURL:fileURL]; + UIImage *fileImage = [UIImage imageWithData:fileData]; + + UIImageView *collectionImageView = (UIImageView *)[cell viewWithTag:100]; + + //collectionImageView.image = [UIImage imageNamed:[collectionImages objectAtIndex:indexPath.row]]; + + JournalPost *thisResult = self.allJournalPosts[indexPath.row]; + iTunesSearchResult *iTunes = thisResult.postSubject; + + NSString *imageString = iTunes.artworkURL; + NSURL *imageURL = [NSURL URLWithString:imageString]; + NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; + // UIImage *image = [UIImage imageWithData:imageData]; + + collectionImageView.image = fileImage; + + // round corners + cell.layer.borderWidth = 2.0; + cell.layer.borderColor = [UIColor blackColor].CGColor; + cell.layer.cornerRadius = 30.0; + + return cell; +} + +- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { + JournalHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + + // configure outlets for .xib here if necessary + + return headerView; + } + return nil; +} + +#pragma mark Navigation + +-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ + + if ([[segue identifier] isEqualToString:@"ViewCompletedEntrySegue"]){ + NSIndexPath *selectedIndexPath = [self.collectionView indexPathForCell:sender]; + ViewCompletedEntryViewController *viewController = segue.destinationViewController; + JournalPost *thisPost = self.allJournalPosts[selectedIndexPath.row]; + viewController.journalPostDetail = thisPost; + } +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/JournalPost.h b/Unit-2-Journal/Unit-2-Journal/JournalPost.h new file mode 100644 index 0000000..ce24eaf --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalPost.h @@ -0,0 +1,26 @@ +// +// JournalPost.h +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <Parse/Parse.h> +#import "iTunesSearchResult.h" + +@interface JournalPost : PFObject <PFSubclassing> + +@property (nonatomic) NSString *postText; +@property (nonatomic) iTunesSearchResult *postSubject; + +// added +@property (nonatomic) NSString *title; +@property (nonatomic) NSString *creator; // artist, writer, director +@property (nonatomic) NSDate *dateEntered; +@property (nonatomic) NSNumber *starRating; +@property (nonatomic) NSString *typeOfMedia; // ie book, album, movie, tv +@property (nonatomic) NSString *imageForMedia; +@property (nonatomic) BOOL reviewed; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/JournalPost.m b/Unit-2-Journal/Unit-2-Journal/JournalPost.m new file mode 100644 index 0000000..00a003a --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/JournalPost.m @@ -0,0 +1,29 @@ +// +// JournalPost.m +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "JournalPost.h" + +@implementation JournalPost + +@dynamic postText; +@dynamic postSubject; + +// added +@dynamic title; +@dynamic creator; // artist, writer, director +@dynamic dateEntered; +@dynamic starRating; +@dynamic typeOfMedia; // ie book, album, movie, tv +@dynamic imageForMedia; +@dynamic reviewed; + ++(NSString *)parseClassName { + return @"JournalPost"; +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/LaunchScreen.Storyboard b/Unit-2-Journal/Unit-2-Journal/LaunchScreen.Storyboard new file mode 100644 index 0000000..673e0f7 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/LaunchScreen.Storyboard @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/> + </dependencies> + <scenes/> +</document> diff --git a/Unit-2-Journal/Unit-2-Journal/LoginViewController.h b/Unit-2-Journal/Unit-2-Journal/LoginViewController.h new file mode 100644 index 0000000..da4cd09 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/LoginViewController.h @@ -0,0 +1,13 @@ +// +// LoginViewController.h +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface LoginViewController : UIViewController + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/LoginViewController.m b/Unit-2-Journal/Unit-2-Journal/LoginViewController.m new file mode 100644 index 0000000..4d53657 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/LoginViewController.m @@ -0,0 +1,37 @@ +// +// LoginViewController.m +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "LoginViewController.h" + +@interface LoginViewController () + +@end + +@implementation LoginViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/MainTableViewController.h b/Unit-2-Journal/Unit-2-Journal/MainTableViewController.h new file mode 100644 index 0000000..6484b56 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/MainTableViewController.h @@ -0,0 +1,13 @@ +// +// MainTableViewController.h +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface MainTableViewController : UITableViewController + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/MainTableViewController.m b/Unit-2-Journal/Unit-2-Journal/MainTableViewController.m new file mode 100644 index 0000000..c42d9f8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/MainTableViewController.m @@ -0,0 +1,41 @@ +// +// MainTableViewController.m +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "MainTableViewController.h" +#import <Parse/Parse.h> + +@interface MainTableViewController () + +@end + +@implementation MainTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + PFObject *testObject = [PFObject objectWithClassName:@"TestObject"]; + testObject[@"foo"] = @"bar"; + [testObject saveInBackground]; + + [self performSegueWithIdentifier:@"showLogin" sender:self]; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + + return 0; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + return 0; +} + + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.h b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.h new file mode 100644 index 0000000..35f2df8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.h @@ -0,0 +1,17 @@ +// +// SearchAPITableViewCell.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface SearchAPITableViewCell : UITableViewCell + +@property (weak, nonatomic) IBOutlet UILabel *titleLabel; +@property (weak, nonatomic) IBOutlet UILabel *authorArtistDirectorLabel; +@property (weak, nonatomic) IBOutlet UIImageView *artworkImage; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.m b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.m new file mode 100644 index 0000000..fe3832c --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.m @@ -0,0 +1,51 @@ +// +// SearchAPITableViewCell.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "SearchAPITableViewCell.h" +#import <pop/POP.h> + +@implementation SearchAPITableViewCell + +- (void)awakeFromNib { + + // round corners + self.artworkImage.clipsToBounds = YES; + self.artworkImage.layer.borderColor = [UIColor blackColor].CGColor; + self.artworkImage.layer.borderWidth = 2.0; + self.artworkImage.layer.cornerRadius = 25.0; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; +} + +// animate custom cells +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { + + [super setHighlighted:highlighted animated:animated]; + + if (self.highlighted) { + POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewScaleXY]; + scaleAnimation.duration = 0.1; + scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1, 1)]; + [self.titleLabel pop_addAnimation:scaleAnimation forKey:nil]; + [self.authorArtistDirectorLabel pop_addAnimation:scaleAnimation forKey:nil]; + [self.artworkImage pop_addAnimation:scaleAnimation forKey:nil]; + + } else { + POPSpringAnimation *sprintAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY]; + sprintAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)]; + sprintAnimation.velocity = [NSValue valueWithCGPoint:CGPointMake(2, 2)]; + sprintAnimation.springBounciness = 20.f; + [self.titleLabel pop_addAnimation:sprintAnimation forKey:nil]; + [self.authorArtistDirectorLabel pop_addAnimation:sprintAnimation forKey:nil]; + [self.artworkImage pop_addAnimation:sprintAnimation forKey:nil]; + } +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.xib b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.xib new file mode 100644 index 0000000..d25bee8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SearchAPITableViewCell.xib @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> + <capability name="Constraints to layout margins" minToolsVersion="6.0"/> + </dependencies> + <customFonts key="customFonts"> + <mutableArray key="Akkurat Bold.otf"> + <string>Akkurat-Bold</string> + </mutableArray> + <mutableArray key="Akkurat Regular.otf"> + <string>Akkurat</string> + </mutableArray> + </customFonts> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="SearchAPITableViewCellIdentifier" rowHeight="101" id="KGk-i7-Jjw" customClass="SearchAPITableViewCell"> + <rect key="frame" x="0.0" y="0.0" width="340" height="125"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> + <rect key="frame" x="0.0" y="0.0" width="340" height="124.5"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Fq8-dI-Pdu"> + <rect key="frame" x="18" y="33" width="60" height="60"/> + <animations/> + <constraints> + <constraint firstAttribute="width" constant="60" id="TzC-rK-Lse"/> + <constraint firstAttribute="height" constant="60" id="VZE-5H-hlD"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Author/Director/Artist" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y9p-St-OV6"> + <rect key="frame" x="86" y="62" width="254" height="46"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TITLE" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Sl4-bL-ILp"> + <rect key="frame" x="86" y="16" width="254" height="46"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <color key="textColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/> + <constraints> + <constraint firstAttribute="bottomMargin" secondItem="y9p-St-OV6" secondAttribute="bottom" constant="8" id="77R-9I-uAO"/> + <constraint firstItem="Fq8-dI-Pdu" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="10" id="BKX-nf-3UF"/> + <constraint firstItem="Fq8-dI-Pdu" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="Gzs-0c-Laa"/> + <constraint firstItem="y9p-St-OV6" firstAttribute="leading" secondItem="Fq8-dI-Pdu" secondAttribute="trailing" constant="8" id="MQL-JE-6d4"/> + <constraint firstItem="y9p-St-OV6" firstAttribute="top" secondItem="Sl4-bL-ILp" secondAttribute="bottom" constant="14" id="V0g-po-TYt"/> + <constraint firstItem="y9p-St-OV6" firstAttribute="top" secondItem="Sl4-bL-ILp" secondAttribute="bottom" id="bHZ-Z7-z2l"/> + <constraint firstItem="Sl4-bL-ILp" firstAttribute="trailing" secondItem="H2p-sc-9uM" secondAttribute="trailingMargin" constant="8" id="kgx-qh-5UO"/> + <constraint firstItem="y9p-St-OV6" firstAttribute="top" secondItem="Sl4-bL-ILp" secondAttribute="bottom" id="le4-IJ-Wvq"/> + <constraint firstItem="Sl4-bL-ILp" firstAttribute="leading" secondItem="Fq8-dI-Pdu" secondAttribute="trailing" constant="8" id="vU8-rv-A7q"/> + <constraint firstItem="y9p-St-OV6" firstAttribute="trailing" secondItem="H2p-sc-9uM" secondAttribute="trailingMargin" constant="8" id="xks-nZ-DDK"/> + <constraint firstItem="Sl4-bL-ILp" firstAttribute="height" secondItem="y9p-St-OV6" secondAttribute="height" id="y4H-0j-aNh"/> + <constraint firstItem="Sl4-bL-ILp" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="8" id="zAg-1w-DVm"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="V0g-po-TYt"/> + <exclude reference="bHZ-Z7-z2l"/> + </mask> + </variation> + </tableViewCellContentView> + <animations/> + <accessibility key="accessibilityConfiguration" identifier=""/> + <connections> + <outlet property="artworkImage" destination="Fq8-dI-Pdu" id="vEj-X3-ezi"/> + <outlet property="authorArtistDirectorLabel" destination="y9p-St-OV6" id="8CJ-K5-qPV"/> + <outlet property="titleLabel" destination="Sl4-bL-ILp" id="npm-fk-f0W"/> + </connections> + <point key="canvasLocation" x="622" y="497.5"/> + </tableViewCell> + </objects> +</document> diff --git a/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.h b/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.h new file mode 100644 index 0000000..0e4dbcf --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.h @@ -0,0 +1,15 @@ +// +// SearchAPIViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +#import "YALTabBarInteracting.h" + +@interface SearchAPIViewController : UIViewController <YALTabBarInteracting> + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.m b/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.m new file mode 100644 index 0000000..3e9814a --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SearchAPIViewController.m @@ -0,0 +1,390 @@ +// +// SearchAPIViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "SearchAPIViewController.h" +#import <AFNetworking/AFNetworking.h> +#import "APIManager.h" +#import "iTunesSearchResult.h" +#import "CreateJournalEntryViewController.h" +#import "SearchAPITableViewCell.h" // add custom cell +#import "TabBarViewController.h" +#import "WishListTableViewController.h" +#import <Parse/Parse.h> +#import "JournalPost.h" // for parse + +@interface SearchAPIViewController () +< +UITableViewDataSource, +UITableViewDelegate, +UITextFieldDelegate +> +@property (strong, nonatomic) IBOutlet UIButton *wishListButton; +@property (strong, nonatomic) IBOutlet UIButton *journalEntryButton; + +@property (weak, nonatomic) IBOutlet UITextField *searchTextField; +@property (weak, nonatomic) IBOutlet UITableView *tableView; +@property (strong, nonatomic) IBOutlet UIButton *musicButton; +@property (strong, nonatomic) IBOutlet UIButton *moviesButton; +@property (strong, nonatomic) IBOutlet UIButton *booksButton; +@property (strong, nonatomic) IBOutlet UIButton *podcastButton; +@property (strong, nonatomic) IBOutlet UIButton *televisionButton; +@property (nonatomic) NSString *media; +@property (nonatomic) NSMutableArray *searchResults; +@property (nonatomic) NSMutableArray *wishListItems; +@property (nonatomic) iTunesSearchResult *passSearchResult; +@property (nonatomic) JournalPost *journalPost; // for parse +@property (nonatomic) NSString *mediaType; // for parse + +@end + +@implementation SearchAPIViewController + +- (void)viewDidLoad { + + [super viewDidLoad]; + + self.searchTextField.userInteractionEnabled = NO; + self.searchTextField.alpha = .5; + [self disableButtons]; + + self.tableView.delegate = self; + self.tableView.dataSource = self; + self.searchTextField.delegate = self; + + // set up custom cell .xib + UINib *nib = [UINib nibWithNibName:@"SearchAPITableViewCell" bundle:nil]; + [self.tableView registerNib:nib forCellReuseIdentifier:@"SearchAPITableViewCellIdentifier"]; + + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedRowHeight = 35.0; + [self.tableView setSeparatorColor:[UIColor whiteColor]]; +} +- (void) viewDidAppear:(BOOL)animated{ + [self disableButtons]; + self.searchTextField.userInteractionEnabled = NO; + self.searchTextField.alpha =.5; +} + +- (void) disableButtons { + self.wishListButton.userInteractionEnabled = NO; + self.journalEntryButton.userInteractionEnabled = NO; + self.wishListButton.alpha = .5; + self.journalEntryButton.alpha = .5; +} +- (void) enableButtons { + self.wishListButton.userInteractionEnabled = YES; + self.journalEntryButton.userInteractionEnabled = YES; + self.wishListButton.alpha = 1.0; + self.journalEntryButton.alpha = 1.0; +} + +#pragma mark - setup buttons + +- (IBAction)mediaButtonTypeSelected:(id)sender { + + if (self.musicButton.isTouchInside){ + self.media = @"music&entity=album"; + + } else if (self.booksButton.isTouchInside){ + self.media = @"ebook"; + + } else if (self.televisionButton.isTouchInside){ + self.media = @"television"; + + // } else if (self.podcastButton.isTouchInside) { + + } else { + self.media = [sender currentTitle]; + } + + self.searchTextField.userInteractionEnabled = YES; + self.searchTextField.alpha = 1.0; + // NSLog(@"Media button tapped: %@",self.media); +} + +#pragma mark - add to list buttons + +- (IBAction)addToWishListButtonTapped:(id)sender { + + JournalPost *myJournalPost = [[JournalPost alloc] init]; + + myJournalPost[@"title"] = self.passSearchResult.albumOrMovieName; + myJournalPost[@"creator"] = self.passSearchResult.artistName; + myJournalPost[@"dateEntered"] = [NSDate date]; + myJournalPost[@"typeOfMedia"] = self.passSearchResult.mediaType; + myJournalPost[@"imageForMedia"] = self.passSearchResult.artworkURL; + myJournalPost[@"reviewed"] = [NSNumber numberWithBool:NO]; + + [myJournalPost saveEventually]; // save your entry, even if offline + + [self.tabBarController setSelectedIndex:0]; + + // clear search text view and reset tableView once data is passed + self.searchTextField.text = nil; + [self.searchResults removeAllObjects]; + [self.tableView reloadData]; + +} + +// these are the fancy tab bar buttons - need to figure out how to make them vanish on the createJournalViewController + +//- (void)extraLeftItemDidPress { +// NSLog(@"left button tapped"); +// +// JournalPost *myJournalPost = [[JournalPost alloc] init]; +// +// myJournalPost[@"title"] = self.passSearchResult.albumOrMovieName; +// myJournalPost[@"creator"] = self.passSearchResult.artistName; +// myJournalPost[@"dateEntered"] = [NSDate date]; +// myJournalPost[@"typeOfMedia"] = self.passSearchResult.mediaType; +// myJournalPost[@"imageForMedia"] = self.passSearchResult.artworkURL; +// myJournalPost[@"reviewed"] = [NSNumber numberWithBool:NO]; +// +// [myJournalPost saveEventually]; // save your entry, even if offline +// +// [self.tabBarController setSelectedIndex:0]; +//} +// +//- (void)extraRightItemDidPress { +// NSLog(@"right button tapped"); +//} + +#pragma mark - API request + +- (void)makeNewAPIRequestWithSearchTerm:(NSString *)term + inMedia:(NSString *)media { + + self.searchResults = [[NSMutableArray alloc]init]; + + // First API Request - iTunes (music, ebooks, podcast) + + NSString *urlString = [NSString stringWithFormat: + @"https://itunes.apple.com/search?media=%@&term=%@",media,term]; + NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + NSURL *url = [NSURL URLWithString:encodedString]; + + [APIManager GETRequestWithURL:url + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + if (data != nil) { + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + NSArray *results = [json objectForKey:@"results"]; + + for (NSDictionary *result in results) { + + NSString *artistName = [result objectForKey:@"artistName"]; + NSString *albumName = [result objectForKey:@"collectionName"]; + NSString *movieName = [result objectForKey:@"trackName"]; + NSString *artworkURL = [result objectForKey:@"artworkUrl100"]; + + iTunesSearchResult *resultsObject = [[iTunesSearchResult alloc]init]; + + if ([self.media isEqualToString:@"movie"]) { + resultsObject.artistName = artistName; + resultsObject.albumOrMovieName = movieName; + resultsObject.artworkURL = artworkURL; + resultsObject.mediaType = @"movie"; // add media type to iTunesSearchObject so that we can pass it to Parse later + + } else if ([self.media isEqualToString:@"podcast"]) { + resultsObject.artistName = artistName; + resultsObject.albumOrMovieName = movieName; + resultsObject.artworkURL = artworkURL; + resultsObject.mediaType = @"podcast"; + + + } else if ([self.media isEqualToString:@"music&entity=album"]) { + resultsObject.artistName = artistName; + resultsObject.albumOrMovieName = albumName; + resultsObject.artworkURL = artworkURL; + resultsObject.mediaType = @"album"; + + } else if ([self.media isEqualToString:@"ebook"]) { + resultsObject.artistName = artistName; + resultsObject.albumOrMovieName = movieName; + resultsObject.artworkURL = artworkURL; + resultsObject.mediaType = @"book"; + } + + [self.searchResults addObject:resultsObject]; + } + [self.tableView reloadData]; + }}]; + + // Second API Request - for television + + NSString *urlStringTwo = [NSString stringWithFormat:@"http://api.tvmaze.com/search/shows?q=%@",term]; + NSString *encodedStringTwo = [urlStringTwo stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + NSURL *urlTwo = [NSURL URLWithString:encodedStringTwo]; + + [APIManager GETRequestWithURL:urlTwo + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + if (data != nil) { + NSArray *jsonTwo = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + // NSLog(@"TV results: %@",jsonTwo); + + NSDictionary *shows = [jsonTwo valueForKey:@"show"]; + + for (NSDictionary *show in shows) { + + NSString *name = [show valueForKey:@"name"]; + NSArray *image = [show valueForKey:@"image"]; + NSString *imageURL = [image valueForKey:@"medium"]; + NSArray *network = [show valueForKey:@"network"]; + NSString *channel = [network valueForKey:@"name"]; + + if ([self.media isEqualToString:@"television"]) { + + iTunesSearchResult *searchResult = [[iTunesSearchResult alloc]init]; + searchResult.artistName = channel; + searchResult.albumOrMovieName = name; + searchResult.artworkURL = imageURL; + searchResult.mediaType = @"tv"; + + [self.searchResults addObject:searchResult]; + } + } + } + [self.tableView reloadData]; + }]; + + // Third API Request - for movies, including in-theatre + + // https://api.themoviedb.org/3/search/movie?api_key=a958839150c7c7c6333fd335128ea066&query=django + + NSString *urlStringThree = [NSString stringWithFormat:@"https://api.themoviedb.org/3/search/%@?api_key=a958839150c7c7c6333fd335128ea066&query=%@",media,term]; + + NSString *encodedStringThree = [urlStringThree stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + + NSURL *urlThree = [NSURL URLWithString:encodedStringThree]; + + [APIManager GETRequestWithURL:urlThree + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + if (data != nil) { + NSArray *jsonThree = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + NSDictionary *results = [jsonThree valueForKey:@"results"]; + + for (NSDictionary *result in results) { + + NSString *name = [result valueForKey:@"title"]; + NSString *releaseDate = [result valueForKey:@"release_date"]; + NSString *posterPath = [result valueForKey:@"poster_path"]; + + //http://image.tmdb.org/t/p/w500 + + if ([self.media isEqualToString:@"movie"]) { + + iTunesSearchResult *movieResult = [[iTunesSearchResult alloc]init]; + + movieResult.albumOrMovieName = name; + movieResult.artistName = releaseDate; + movieResult.artworkURL = [NSString stringWithFormat:@"http://image.tmdb.org/t/p/w500%@",posterPath]; + movieResult.mediaType = @"movie"; + + [self.searchResults addObject:movieResult]; + } + [self.tableView reloadData]; + } + } + }]; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + + [self.view endEditing:YES]; + [self makeNewAPIRequestWithSearchTerm:textField.text + inMedia:self.media]; + return YES; +} + +#pragma mark - set up table view + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.searchResults.count; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + + SearchAPITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchAPITableViewCellIdentifier" forIndexPath:indexPath]; + + iTunesSearchResult *searchResult = self.searchResults[indexPath.row]; + + cell.titleLabel.text = searchResult.albumOrMovieName; + + if (searchResult.artistName == nil){ + searchResult.artistName =@""; + } + cell.authorArtistDirectorLabel.text = searchResult.artistName; + + NSString *artworkString = searchResult.artworkURL; + NSURL *artworkURL = [NSURL URLWithString:artworkString]; + NSData *artworkData = [NSData dataWithContentsOfURL:artworkURL]; + UIImage *artworkImage = [UIImage imageWithData:artworkData]; + + // NSLog(@"Image String: %@", searchResult.artworkURL); + // NSLog(@"Image URL: %@", artworkURL); + // NSLog(@"Image Data: %@", artworkData); + // NSLog(@"Image: %@", artworkImage); + + cell.artworkImage.image = artworkImage; + + // round corners + cell.imageView.layer.borderWidth = 2.0; + cell.imageView.layer.borderColor = [UIColor blackColor].CGColor; + cell.imageView.layer.cornerRadius = 3.0; + + return cell; +} + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // here is where the data is passed + + iTunesSearchResult *searchResult = self.searchResults[indexPath.row]; + + self.passSearchResult = searchResult; + + [self enableButtons]; +} + +#pragma mark - Navigation + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + + if ([[segue identifier]isEqualToString:@"pushToCreateJournalEntry"]) { + CreateJournalEntryViewController *viewController = segue.destinationViewController; + viewController.postSearchResult = self.passSearchResult; + + // clear text view and reset tableView once data is passed + self.searchTextField.text = nil; + [self.searchResults removeAllObjects]; + [self.tableView reloadData]; + } +} + +//- (void) postAlert { +// +// UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Wait..." +// message:@"Choose something to talk about!" +// preferredStyle:UIAlertControllerStyleAlert]; +// +// UIAlertAction *ok = [UIAlertAction actionWithTitle:@"Oh yeah!" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { +// [alert dismissViewControllerAnimated:YES completion:nil]; +// +// }]; +// +// [alert addAction:ok]; +// [self presentViewController:alert animated:YES completion:nil]; +//} +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SettingsViewController.h b/Unit-2-Journal/Unit-2-Journal/SettingsViewController.h new file mode 100644 index 0000000..148094b --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SettingsViewController.h @@ -0,0 +1,13 @@ +// +// SettingsViewController.h +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/19/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface SettingsViewController : UIViewController + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SettingsViewController.m b/Unit-2-Journal/Unit-2-Journal/SettingsViewController.m new file mode 100644 index 0000000..d814e70 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SettingsViewController.m @@ -0,0 +1,35 @@ +// +// SettingsViewController.m +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/19/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "SettingsViewController.h" +#import <FBSDKCoreKit/FBSDKCoreKit.h> +#import <FBSDKLoginKit/FBSDKLoginKit.h> + +@interface SettingsViewController () + +@end + +@implementation SettingsViewController + +- (void)viewDidLoad { + + [super viewDidLoad]; + + FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc]init]; + loginButton.center = self.view.center; + [self.view addSubview:loginButton]; + +} + +- (void)didReceiveMemoryWarning { + + [super didReceiveMemoryWarning]; +} + + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SignUpViewController.h b/Unit-2-Journal/Unit-2-Journal/SignUpViewController.h new file mode 100644 index 0000000..c10572b --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SignUpViewController.h @@ -0,0 +1,13 @@ +// +// SignUpViewController.h +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface SignUpViewController : UIViewController + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/SignUpViewController.m b/Unit-2-Journal/Unit-2-Journal/SignUpViewController.m new file mode 100644 index 0000000..36a4608 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/SignUpViewController.m @@ -0,0 +1,37 @@ +// +// SignUpViewController.m +// Unit-2-Journal +// +// Created by Brian Blanco on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "SignUpViewController.h" + +@interface SignUpViewController () + +@end + +@implementation SignUpViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/TabBarViewController.h b/Unit-2-Journal/Unit-2-Journal/TabBarViewController.h new file mode 100644 index 0000000..2b2e083 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/TabBarViewController.h @@ -0,0 +1,20 @@ +// +// TabBarViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "YALFoldingTabBar.h" + +@interface TabBarViewController : UITabBarController + +@property (nonatomic, copy) NSArray *leftBarItems; +@property (nonatomic, copy) NSArray *rightBarItems; +@property (nonatomic, strong) UIImage *centerButtonImage; +@property (nonatomic, assign) CGFloat tabBarViewHeight; +@property (nonatomic, strong) YALFoldingTabBar *tabBarView; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/TabBarViewController.m b/Unit-2-Journal/Unit-2-Journal/TabBarViewController.m new file mode 100644 index 0000000..05495f3 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/TabBarViewController.m @@ -0,0 +1,200 @@ +// +// TabBarViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/12/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "TabBarViewController.h" +#import "YALTabBarItem.h" //model +#import "YALTabBarInteracting.h" //protocol +#import "YALAnimatingTabBarConstants.h" + +@interface TabBarViewController () + +<YALTabBarViewDataSource, +YALTabBarViewDelegate> + +@property (nonatomic, assign) YALTabBarState state; + +@end + +@implementation TabBarViewController + +#pragma mark - Initialization + +- (instancetype)init { + + self = [super init]; + if (self) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + + self = [super initWithCoder:aDecoder]; + if (self) { + [self setup]; + } + return self; +} + +- (void)setup { + + self.tabBarViewHeight = YALTabBarViewDefaultHeight; + + [self setupTabBarView]; +} + +#pragma mark - View & LifeCycle + +- (void)viewDidLoad { + + [super viewDidLoad]; + + [self.tabBar setBackgroundImage:[[UIImage alloc] init]]; + [self.tabBar setShadowImage:[[UIImage alloc] init]]; + + self.tabBar.hidden = YES; +} + +- (void)viewWillLayoutSubviews { + + [super viewWillLayoutSubviews]; + + CGRect tabFrame = self.tabBar.frame; + tabFrame.size.height = self.tabBarViewHeight; + tabFrame.origin.y = self.view.frame.size.height - self.tabBarViewHeight; + self.tabBar.frame = tabFrame; +} + +- (void)viewDidLayoutSubviews { + + [super viewDidLayoutSubviews]; + [self updateTabBarViewFrame]; +} + +- (void)setSelectedIndex:(NSUInteger)selectedIndex { + + [super setSelectedIndex:selectedIndex]; + + self.tabBarView.selectedTabBarItemIndex = selectedIndex; + [self.tabBarView setNeedsLayout]; +} + +#pragma mark - Private + +- (void)updateTabBarViewFrame { + + CGFloat tabBarViewOriginX = self.tabBar.frame.origin.x; + CGFloat tabBarViewOriginY = self.tabBar.frame.origin.y; + CGFloat tabBarViewSizeWidth = CGRectGetWidth(self.tabBar.frame); + + self.tabBarView.frame = CGRectMake(tabBarViewOriginX, tabBarViewOriginY, tabBarViewSizeWidth, self.tabBarViewHeight); + [self.tabBarView setNeedsLayout]; +} + +- (void)setupTabBarView { + + self.tabBarView = [[YALFoldingTabBar alloc] initWithFrame:CGRectZero state:self.state]; + + self.tabBarView.dataSource = self; + self.tabBarView.delegate = self; + + [self.view addSubview:self.tabBarView]; +} + +- (id<YALTabBarInteracting>)currentInteractingViewController { + + if ([self.selectedViewController isKindOfClass:[UINavigationController class]]) { + return (id<YALTabBarInteracting>)[(UINavigationController *)self.selectedViewController topViewController]; + } else { + return (id<YALTabBarInteracting>)self.selectedViewController; + } +} + +#pragma mark - YALTabBarViewDataSource + +- (NSArray *)leftTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView { + + return self.leftBarItems; +} + +- (NSArray *)rightTabBarItemsInTabBarView:(YALFoldingTabBar *)tabBarView { + + return self.rightBarItems; +} + +- (UIImage *)centerImageInTabBarView:(YALFoldingTabBar *)tabBarView { + + return self.centerButtonImage; +} + +#pragma mark - YALTabBarViewDelegate + +- (void)tabBarViewWillCollapse:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewWillCollapse)]) { + [viewController tabBarViewWillCollapse]; + } +} + +- (void)tabBarViewDidCollapse:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewDidCollapse)]) { + [viewController tabBarViewDidCollapse]; + } +} + +- (void)tabBarViewWillExpand:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewWillExpand)]) { + [viewController tabBarViewWillExpand]; + } +} + +- (void)tabBarViewDidExpand:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(tabBarViewDidExpand)]) { + [viewController tabBarViewDidExpand]; + } +} + +- (void)extraLeftItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(extraLeftItemDidPress)]) { + [viewController extraLeftItemDidPress]; + } +} + +- (void)extraRightItemDidPressInTabBarView:(YALFoldingTabBar *)tabBarView { + + id<YALTabBarInteracting>viewController = [self currentInteractingViewController]; + if ([viewController respondsToSelector:@selector(extraRightItemDidPress)]) { + [viewController extraRightItemDidPress]; + } +} + +- (void)itemInTabBarViewPressed:(YALFoldingTabBar *)tabBarView atIndex:(NSUInteger)index { + + self.selectedViewController = [self.viewControllers objectAtIndex:index]; +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/.xccurrentversion b/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/.xccurrentversion new file mode 100644 index 0000000..2d436c1 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/.xccurrentversion @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>_XCCurrentVersionName</key> + <string>Unit_2_Journal.xcdatamodel</string> +</dict> +</plist> diff --git a/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/Unit_2_Journal.xcdatamodel/contents b/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/Unit_2_Journal.xcdatamodel/contents new file mode 100644 index 0000000..193f33c --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/Unit_2_Journal.xcdatamodeld/Unit_2_Journal.xcdatamodel/contents @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<model name="Test1.xcdatamodel" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1" systemVersion="11A491" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic"> + <elements/> +</model> \ No newline at end of file diff --git a/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.h b/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.h new file mode 100644 index 0000000..660a6ab --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.h @@ -0,0 +1,16 @@ +// +// ViewCompletedEntryViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "JournalPost.h" + +@interface ViewCompletedEntryViewController : UIViewController + +@property (nonatomic) JournalPost *journalPostDetail; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.m b/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.m new file mode 100644 index 0000000..a17191d --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/ViewCompletedEntryViewController.m @@ -0,0 +1,143 @@ +// +// ViewCompletedEntryViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "ViewCompletedEntryViewController.h" +#import <FBSDKCoreKit/FBSDKCoreKit.h> +#import <FBSDKShareKit/FBSDKShareKit.h> + +@interface ViewCompletedEntryViewController () + +@property (weak, nonatomic) IBOutlet UIImageView *completedImageView; +@property (weak, nonatomic) IBOutlet UILabel *completedTitleLabel; +@property (weak, nonatomic) IBOutlet UILabel *completedCreatorLabel; +@property (weak, nonatomic) IBOutlet UILabel *completedDateLabel; // review written on +@property (weak, nonatomic) IBOutlet UITextView *completedReviewTextView; +@property (strong, nonatomic) IBOutlet UIView *facebookView; + +@property (weak, nonatomic) IBOutlet UIButton *starOne; +@property (weak, nonatomic) IBOutlet UIButton *starTwo; +@property (weak, nonatomic) IBOutlet UIButton *starThree; +@property (weak, nonatomic) IBOutlet UIButton *starFour; +@property (weak, nonatomic) IBOutlet UIButton *starFive; + +@end + +@implementation ViewCompletedEntryViewController + +- (void)viewDidLoad { + + [super viewDidLoad]; + + [self setupFacebookShare]; + + self.completedTitleLabel.text = self.journalPostDetail.title; + self.completedCreatorLabel.text = self.journalPostDetail.creator; + self.completedReviewTextView.text = self.journalPostDetail.postText; + + self.completedReviewTextView.backgroundColor = [UIColor blackColor]; + [self.completedReviewTextView setTextColor:[UIColor whiteColor]]; + [self.completedReviewTextView setFont:[UIFont fontWithName:@"Akkurat" size:25]]; + + NSLog(@"stars: %@", self.journalPostDetail.starRating); + + // convert date to readable format + NSDate *now = self.journalPostDetail.dateEntered; + NSCalendar *calendar = [[NSCalendar alloc] + initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; + NSDateComponents *components = [calendar components:units fromDate:now]; + + self.completedDateLabel.text = [NSString stringWithFormat:@"Entry Date: %ld/%ld/%ld", (long)components.month, (long)components.day, (long)components.year]; // set date text + + NSURL *imageURL = [NSURL URLWithString:self.journalPostDetail.imageForMedia]; + NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; + UIImage *image = [UIImage imageWithData:imageData]; + + self.completedImageView.image = image; + + // round corners + self.completedImageView.clipsToBounds = YES; + self.completedImageView.layer.borderColor = [UIColor blackColor].CGColor; + self.completedImageView.layer.borderWidth = 2.0; + self.completedImageView.layer.cornerRadius = 30.0; + + [self setupStars]; +} + +- (void) setupFacebookShare { + + FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc]init]; + NSString *titleString = [NSString stringWithFormat:@"Check out my review of %@!",self.journalPostDetail.title]; + NSString *descriptionString = [NSString stringWithFormat:@"%@",self.journalPostDetail.postText]; + + content.contentTitle = titleString; + content.contentDescription = [NSString stringWithFormat:@"Review: %@ Rating: %@/5 Stars",descriptionString, self.journalPostDetail.starRating]; + content.imageURL = [NSURL URLWithString:self.journalPostDetail.imageForMedia]; + + FBSDKShareButton *shareButton = [[FBSDKShareButton alloc]initWithFrame:CGRectMake(0, 0, self.facebookView.frame.size.width, self.facebookView.frame.size.height)]; + shareButton.shareContent = content; + //shareButton.center = self.view.center; + + [self.facebookView addSubview:shareButton]; +} + +#pragma mark - stars + +- (void)setupStars { + + if ([self.journalPostDetail.starRating isEqual:@1]) { + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + } + + else if ([self.journalPostDetail.starRating isEqual:@2]) { + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + } + + else if ([self.journalPostDetail.starRating isEqual:@3]) { + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + } + + else if ([self.journalPostDetail.starRating isEqual:@4]) { + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + } + + else if ([self.journalPostDetail.starRating isEqual:@5]) { + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + } +} + +#pragma mark - delete item + +- (IBAction)deleteButtonTapped:(id)sender { + + // delete item from memory and storyboard + + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.h b/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.h new file mode 100644 index 0000000..cfe45c7 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.h @@ -0,0 +1,16 @@ +// +// WatchedWishListViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/20/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "JournalPost.h" + +@interface WatchedWishListViewController : UIViewController + +@property (nonatomic) JournalPost *journalPostDetail; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.m b/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.m new file mode 100644 index 0000000..5ee52d8 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WatchedWishListViewController.m @@ -0,0 +1,228 @@ +// +// WatchedWishListViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/20/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "WatchedWishListViewController.h" +#import "pop/POP.h" +#import "JournalPost.h" +#import <Parse/Parse.h> + +@interface WatchedWishListViewController () <UITextViewDelegate> + +@property (weak, nonatomic) IBOutlet UIImageView *mediaImageView; +@property (weak, nonatomic) IBOutlet UILabel *mediaTitleLabel; +@property (weak, nonatomic) IBOutlet UILabel *mediaCreatorLabel; + +@property (weak, nonatomic) IBOutlet UIButton *starOne; +@property (weak, nonatomic) IBOutlet UIButton *starTwo; +@property (weak, nonatomic) IBOutlet UIButton *starThree; +@property (weak, nonatomic) IBOutlet UIButton *starFour; +@property (weak, nonatomic) IBOutlet UIButton *starFive; +@property (weak, nonatomic) IBOutlet UITextView *textView; +@property (weak, nonatomic) IBOutlet UIButton *doneButton; + +@property (nonatomic) NSMutableArray *journalPostArray; + +@property (strong, nonatomic) NSNumber *rating; // for parse +@property (nonatomic) JournalPost *journalPost; +@property (nonatomic) NSString *mediaType; + + +@end + +@implementation WatchedWishListViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.journalPostArray = [[NSMutableArray alloc] init]; + + self.mediaTitleLabel.text = self.journalPostDetail.title; + self.mediaCreatorLabel.text = self.journalPostDetail.creator; + self.doneButton.hidden = YES; + + NSURL *artworkURL = [NSURL URLWithString:self.journalPostDetail.imageForMedia]; + NSData *artworkData = [NSData dataWithContentsOfURL:artworkURL]; + UIImage *artworkImage = [UIImage imageWithData:artworkData]; + self.mediaImageView.image = artworkImage; + + self.mediaType = self.journalPostDetail.typeOfMedia; + + // NSLog(@"journal post detail: %@", self.journalPostDetail); // test it + + //round image corners + self.mediaImageView.clipsToBounds = YES; + self.mediaImageView.layer.borderColor = [UIColor blackColor].CGColor; + self.mediaImageView.layer.borderWidth = 2.0; + self.mediaImageView.layer.cornerRadius = 25.0; + + //manage textview + self.textView.delegate = self; + self.textView.text = @"Write your thoughts here..."; + self.textView.layer.borderWidth = 1.0f; + self.textView.layer.cornerRadius = 5.0f; + self.textView.layer.borderColor = [UIColor blackColor].CGColor; +} + +- (void) textViewDidBeginEditing:(UITextView *)textView { + + self.textView.text = @""; + self.doneButton.hidden = NO; +} + +#pragma mark - buttons + +- (IBAction)doneButtonTapped:(id)sender { + + self.doneButton.hidden = YES; + [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; +} + +- (IBAction)logToJournalButtonTapped:(id)sender { + + PFQuery *query = [PFQuery queryWithClassName:@"JournalPost"]; + [query whereKey:@"title" equalTo:self.journalPostDetail.title]; + [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) { + + NSLog(@"%@", objects); + + JournalPost *existingPost = [objects firstObject]; + existingPost[@"postText"] = self.textView.text; + existingPost[@"starRating"] = self.rating; + existingPost[@"dateEntered"] = [NSDate date]; + existingPost[@"reviewed"] = [NSNumber numberWithBool:YES]; + + [existingPost saveEventually]; // save entry + }]; + + + +// JournalPost *myJournalPost = [[JournalPost alloc]init]; +// +// myJournalPost[@"postText"] = self.textView.text; +// myJournalPost[@"starRating"] = self.rating; +// myJournalPost[@"title"] = self.journalPostDetail.title; +// myJournalPost[@"creator"] = self.journalPostDetail.creator; +// myJournalPost[@"dateEntered"] = [NSDate date]; +// myJournalPost[@"typeOfMedia"] = self.mediaType; +// myJournalPost[@"imageForMedia"] = self.journalPostDetail.imageForMedia; +// myJournalPost[@"reviewed"] = [NSNumber numberWithBool:YES]; +// +// NSLog(@"my Journal post %@", myJournalPost); +// +// [myJournalPost saveEventually]; // save entry + + [self.navigationController popToRootViewControllerAnimated:YES]; // pop back to root controller + + [self.tabBarController setSelectedIndex:2]; // send to correct tab + + // NOTE: this saves new entry, but does not remove existing wishlist entry... + +} + +#pragma mark - stars + +- (IBAction)starOneTapped:(id)sender { + + [self resetStars]; + [self oneStarRating]; + [self startAnimation]; +} +- (IBAction)starTwoTapped:(id)sender { + + [self resetStars]; + [self twoStarRating]; + [self startAnimation]; +} +- (IBAction)starThreeTapped:(id)sender { + [self resetStars]; + [self threeStarRating]; + [self startAnimation]; +} + +- (IBAction)starFourTapped:(id)sender { + + [self resetStars]; + [self fourStarRating]; + [self startAnimation]; +} + +- (IBAction)starFiveTapped:(id)sender { + + [self resetStars]; + [self fiveStarRating]; + [self startAnimation]; +} + +- (void)oneStarRating { + + self.rating = @1; // assign rating for parse + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)twoStarRating { + + self.rating = @2; // assign rating for parse + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)threeStarRating { + + self.rating = @3; // assign rating for parse + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)fourStarRating { + + self.rating = @4; // assign rating for parse + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)fiveStarRating { + + self.rating = @5; // assign rating for parse + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star_filled2.png"] forState:UIControlStateNormal]; +} + +- (void)resetStars { + + [self.starOne setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starTwo setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starThree setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFour setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; + [self.starFive setBackgroundImage:[UIImage imageNamed:@"rating_star2.png"] forState:UIControlStateNormal]; +} + +#pragma mark - animate + +- (void)startAnimation { + + POPSpringAnimation *spin = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation]; + + spin.fromValue = @(M_PI / 4); + spin.toValue = @(5); + spin.springBounciness = 5; + spin.velocity = @(1); + + [self.starOne.layer pop_addAnimation:spin forKey:nil]; + [self.starTwo.layer pop_addAnimation:spin forKey:nil]; + [self.starThree.layer pop_addAnimation:spin forKey:nil]; + [self.starFour.layer pop_addAnimation:spin forKey:nil]; + [self.starFive.layer pop_addAnimation:spin forKey:nil]; +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.h b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.h new file mode 100644 index 0000000..61049b6 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.h @@ -0,0 +1,17 @@ +// +// WishListTableViewCell.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/21/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface WishListTableViewCell : UITableViewCell + +@property (nonatomic) IBOutlet UILabel *titleLabel; +@property (nonatomic) IBOutlet UILabel *authorArtistDirectorLabel; +@property (nonatomic) IBOutlet UIImageView * artworkImage; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.m b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.m new file mode 100644 index 0000000..af04709 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.m @@ -0,0 +1,52 @@ +// +// WishListTableViewCell.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/21/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "WishListTableViewCell.h" +#import <Pop/POP.h> + +@implementation WishListTableViewCell + +- (void)awakeFromNib { + + // round corners + self.artworkImage.clipsToBounds = YES; + self.artworkImage.layer.borderColor = [UIColor blackColor].CGColor; + self.artworkImage.layer.borderWidth = 2.0; + self.artworkImage.layer.cornerRadius = 25.0; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; +} + +// animate custom cells +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { + + [super setHighlighted:highlighted animated:animated]; + + if (self.highlighted) { + POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewScaleXY]; + scaleAnimation.duration = 0.1; + scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1, 1)]; + [self.titleLabel pop_addAnimation:scaleAnimation forKey:nil]; + [self.authorArtistDirectorLabel pop_addAnimation:scaleAnimation forKey:nil]; + [self.artworkImage pop_addAnimation:scaleAnimation forKey:nil]; + + } else { + POPSpringAnimation *sprintAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY]; + sprintAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)]; + sprintAnimation.velocity = [NSValue valueWithCGPoint:CGPointMake(2, 2)]; + sprintAnimation.springBounciness = 20.f; + [self.titleLabel pop_addAnimation:sprintAnimation forKey:nil]; + [self.authorArtistDirectorLabel pop_addAnimation:sprintAnimation forKey:nil]; + [self.artworkImage pop_addAnimation:sprintAnimation forKey:nil]; + } +} + +@end + diff --git a/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.xib b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.xib new file mode 100644 index 0000000..5914ec0 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WishListTableViewCell.xib @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> + <capability name="Constraints to layout margins" minToolsVersion="6.0"/> + </dependencies> + <customFonts key="customFonts"> + <mutableArray key="Akkurat Bold.otf"> + <string>Akkurat-Bold</string> + </mutableArray> + <mutableArray key="Akkurat Regular.otf"> + <string>Akkurat</string> + </mutableArray> + </customFonts> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="WishListTableViewCellIdentifier" rowHeight="66" id="KGk-i7-Jjw" customClass="WishListTableViewCell"> + <rect key="frame" x="0.0" y="0.0" width="340" height="125"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> + <rect key="frame" x="0.0" y="0.0" width="340" height="124.5"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Vb0-5u-rmQ"> + <rect key="frame" x="18" y="32" width="60" height="60"/> + <animations/> + <constraints> + <constraint firstAttribute="height" constant="60" id="LLD-64-jSM"/> + <constraint firstAttribute="width" constant="60" id="fag-dr-LW7"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TR1-Ae-Cd4"> + <rect key="frame" x="86" y="63" width="238" height="46"/> + <animations/> + <fontDescription key="fontDescription" name="Akkurat" family="Akkurat" pointSize="14"/> + <color key="textColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ywi-Ne-nLf"> + <rect key="frame" x="86" y="16" width="238" height="46.5"/> + <fontDescription key="fontDescription" name="Akkurat-Bold" family="Akkurat" pointSize="17"/> + <color key="textColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <animations/> + <color key="backgroundColor" cocoaTouchSystemColor="darkTextColor"/> + <constraints> + <constraint firstItem="Vb0-5u-rmQ" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="05Q-DJ-JMP"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="leading" secondItem="Vb0-5u-rmQ" secondAttribute="trailing" constant="8" id="4aK-xN-uGi"/> + <constraint firstItem="Vb0-5u-rmQ" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="10" id="C8a-B1-WwL"/> + <constraint firstItem="Vb0-5u-rmQ" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="Ev5-Ck-zXA"/> + <constraint firstAttribute="trailingMargin" secondItem="ywi-Ne-nLf" secondAttribute="trailing" constant="8" id="FFQ-NJ-9ou"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="top" secondItem="ywi-Ne-nLf" secondAttribute="bottom" id="HAv-m5-yWX"/> + <constraint firstAttribute="trailingMargin" secondItem="TR1-Ae-Cd4" secondAttribute="trailing" constant="8" id="Jka-bL-f27"/> + <constraint firstItem="ywi-Ne-nLf" firstAttribute="leading" secondItem="Vb0-5u-rmQ" secondAttribute="trailing" constant="8" id="L74-k4-9jb"/> + <constraint firstItem="ywi-Ne-nLf" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="8" id="Pag-db-ddS"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="leading" secondItem="Vb0-5u-rmQ" secondAttribute="trailing" constant="8" id="Vai-2j-7Lw"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="leading" secondItem="Vb0-5u-rmQ" secondAttribute="trailing" constant="8" id="bGk-BF-l5b"/> + <constraint firstItem="ywi-Ne-nLf" firstAttribute="height" secondItem="TR1-Ae-Cd4" secondAttribute="height" id="bRc-7p-JRM"/> + <constraint firstAttribute="bottomMargin" secondItem="TR1-Ae-Cd4" secondAttribute="bottom" constant="8" id="bUl-jU-Y6L"/> + <constraint firstItem="ywi-Ne-nLf" firstAttribute="top" secondItem="Vb0-5u-rmQ" secondAttribute="top" id="bjp-5S-AIA"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="trailing" secondItem="H2p-sc-9uM" secondAttribute="trailingMargin" id="lt5-VN-osh"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="top" secondItem="ywi-Ne-nLf" secondAttribute="bottom" id="wJo-s4-Ays"/> + <constraint firstItem="TR1-Ae-Cd4" firstAttribute="top" secondItem="ywi-Ne-nLf" secondAttribute="bottom" id="zJ7-QU-glF"/> + </constraints> + <variation key="default"> + <mask key="constraints"> + <exclude reference="Ev5-Ck-zXA"/> + <exclude reference="bjp-5S-AIA"/> + <exclude reference="4aK-xN-uGi"/> + <exclude reference="Vai-2j-7Lw"/> + <exclude reference="lt5-VN-osh"/> + <exclude reference="wJo-s4-Ays"/> + <exclude reference="zJ7-QU-glF"/> + </mask> + </variation> + </tableViewCellContentView> + <animations/> + <connections> + <outlet property="artworkImage" destination="Vb0-5u-rmQ" id="YH4-Ar-buq"/> + <outlet property="authorArtistDirectorLabel" destination="TR1-Ae-Cd4" id="MLM-qU-syZ"/> + <outlet property="titleLabel" destination="ywi-Ne-nLf" id="8lN-ad-NzW"/> + </connections> + <point key="canvasLocation" x="616" y="429.5"/> + </tableViewCell> + </objects> +</document> diff --git a/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.h b/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.h new file mode 100644 index 0000000..0dd46e2 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.h @@ -0,0 +1,17 @@ +// +// WishListTableViewController.h +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "iTunesSearchResult.h" + +@interface WishListTableViewController : UITableViewController + +@property (nonatomic) iTunesSearchResult *searchResult; +@property (nonatomic) NSMutableArray *allJournalPosts; + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.m b/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.m new file mode 100644 index 0000000..4c33f09 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/WishListTableViewController.m @@ -0,0 +1,179 @@ +// +// WishListTableViewController.m +// Unit-2-Journal +// +// Created by Shena Yoshida on 10/10/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "WishListTableViewController.h" +#import "WishListTableViewCell.h" +#import <Parse/Parse.h> +#import "JournalPost.h" +#import "WatchedWishListViewController.h" + +@interface WishListTableViewController () + +@property (nonatomic) NSString *objectID; + +@end + +@implementation WishListTableViewController + +- (void)viewDidLoad { + + [super viewDidLoad]; + + if (self.allJournalPosts == nil) { + self.allJournalPosts = [[NSMutableArray alloc] init]; + } + + // set up custom cell .xib + UINib *nib = [UINib nibWithNibName:@"WishListTableViewCell" bundle:nil]; + [self.tableView registerNib:nib forCellReuseIdentifier:@"WishListTableViewCellIdentifier"]; + + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedRowHeight = 35.0; + [self.tableView setTableFooterView:[UIView new]]; // hide extra lines in empty tableview cells + + [self pullEntriesFromParse]; +} +- (void)viewDidAppear:(BOOL)animated { + + [self pullEntriesFromParse]; +} + +- (void)pullEntriesFromParse { + + PFQuery *query = [PFQuery queryWithClassName:@"JournalPost"]; + + [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) { + + [self.allJournalPosts removeAllObjects]; // clear to prevent doubles + + // create a for loop and iterate through the objects array and push only the posts that are marked with True to "self.allJournalPosts" + for (JournalPost *object in objects) { + if (!object.reviewed) { + + [self.allJournalPosts insertObject:object atIndex:0]; + + //[self.allJournalPosts addObject:object]; + + } + } + // self.allJournalPosts = objects; // pull all images from Parse + + // NSLog(@"info fetched from parse: %@", self.allJournalPosts); // test it! + + [self.tableView reloadData]; // reload tableView + }]; +} + +//#pragma mark - swipe gestures +// +//- (void)setUpSwipeGestures +//{ +// UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(userSwipedLeft:)]; +// swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; +// [self.view addGestureRecognizer:swipeLeft]; +//} +// +//- (void)userSwipedLeft:(UISwipeGestureRecognizer*)swipe +//{ +// if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) { +// +// [self performSegueWithIdentifier:@"pushToHomeList" sender:self]; +// +// //[self dismissViewControllerAnimated:YES completion:nil]; +// } +//} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + return self.allJournalPosts.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + WishListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"WishListTableViewCellIdentifier" forIndexPath:indexPath]; + + JournalPost *thisEntry = self.allJournalPosts[indexPath.row]; + + cell.titleLabel.text = thisEntry.title; + cell.authorArtistDirectorLabel.text = thisEntry.creator; + + NSString *imageString = thisEntry.imageForMedia; + NSURL *imageURL = [NSURL URLWithString:imageString]; + NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; + UIImage *image = [UIImage imageWithData:imageData]; + + cell.artworkImage.image = image; + + // format table view lines + cell.preservesSuperviewLayoutMargins = false; + // cell.separatorInset = UIEdgeInsetsZero; + cell.layoutMargins = UIEdgeInsetsZero; + + return cell; +} + +#pragma mark - didSelectRowAtIndexPath + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + // get the data that we're going to pass + JournalPost *post = self.allJournalPosts[indexPath.row]; + + // declare where we're sending the data + WatchedWishListViewController *detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"WishListJournalEntry"]; + + // pass the data + detailViewController.journalPostDetail = post; + + // present the view controller + [self.navigationController pushViewController:detailViewController animated:YES]; +} + + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + + if (editingStyle == UITableViewCellEditingStyleDelete) { + + // Delete cell from Parse + PFQuery *object = [self.allJournalPosts objectAtIndex:indexPath.row]; + [object delete:nil]; + + // then remove the reference from the table view + [self.allJournalPosts removeObjectAtIndex:indexPath.row]; + // Delete the row from the data source + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + + // reload table view with new data + [self.tableView reloadData]; + + } +} + +#pragma mark - segue + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + + //identifier: moveFromWishToJournalEntry + + if ([[segue identifier] isEqualToString:@"moveFromWishToJournalEntry"]) { + NSIndexPath *selectedIndexPath = [self.tableView indexPathForCell:sender]; + WatchedWishListViewController *viewController = segue.destinationViewController; + JournalPost *thisPost = self.allJournalPosts[selectedIndexPath.row]; + + viewController.journalPostDetail = thisPost; + } +} + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/basictitlefont.ttf b/Unit-2-Journal/Unit-2-Journal/basictitlefont.ttf new file mode 100755 index 0000000..a8db369 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/basictitlefont.ttf differ diff --git a/Unit-2-Journal/Unit-2-Journal/big_nerd_ranch.png b/Unit-2-Journal/Unit-2-Journal/big_nerd_ranch.png new file mode 100644 index 0000000..572d938 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/big_nerd_ranch.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/destroyer.png b/Unit-2-Journal/Unit-2-Journal/destroyer.png new file mode 100644 index 0000000..f4c9295 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/destroyer.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/drake.png b/Unit-2-Journal/Unit-2-Journal/drake.png new file mode 100644 index 0000000..767cf84 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/drake.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.h b/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.h new file mode 100644 index 0000000..610bcd5 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.h @@ -0,0 +1,21 @@ +// +// iTunesSearchResult.h +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/11/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <Parse/PFObject+Subclass.h> +#import "PFObject.h" + +@interface iTunesSearchResult : PFObject <PFSubclassing> + +@property (nonatomic) NSString *artistName; +@property (nonatomic) NSString *albumOrMovieName; +@property (nonatomic) NSString *artworkURL; +@property (nonatomic) NSDate *addedDate; +@property (nonatomic) NSString *mediaType; + + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.m b/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.m new file mode 100644 index 0000000..722ffe0 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/iTunesSearchResult.m @@ -0,0 +1,25 @@ +// +// iTunesSearchResult.m +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/11/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import "iTunesSearchResult.h" + +@implementation iTunesSearchResult + +@dynamic artistName; +@dynamic artworkURL; +@dynamic albumOrMovieName; +@dynamic addedDate; +@dynamic mediaType; + ++(NSString *)parseClassName { + return @"iTunesSearchResult"; +} + + + +@end diff --git a/Unit-2-Journal/Unit-2-Journal/lean_startup.png b/Unit-2-Journal/Unit-2-Journal/lean_startup.png new file mode 100644 index 0000000..35e80ad Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/lean_startup.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/main.m b/Unit-2-Journal/Unit-2-Journal/main.m new file mode 100644 index 0000000..070f920 --- /dev/null +++ b/Unit-2-Journal/Unit-2-Journal/main.m @@ -0,0 +1,16 @@ +// +// main.m +// Unit-2-Journal +// +// Created by Jamaal Sedayao on 10/9/15. +// Copyright © 2015 Jamaal Sedayao. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Unit-2-Journal/Unit-2-Journal/run_the_jewels.png b/Unit-2-Journal/Unit-2-Journal/run_the_jewels.png new file mode 100644 index 0000000..ab94494 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/run_the_jewels.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/sleater_kinney.png b/Unit-2-Journal/Unit-2-Journal/sleater_kinney.png new file mode 100644 index 0000000..6c165ae Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/sleater_kinney.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/talking_heads.png b/Unit-2-Journal/Unit-2-Journal/talking_heads.png new file mode 100644 index 0000000..8feab20 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/talking_heads.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/true_detective.png b/Unit-2-Journal/Unit-2-Journal/true_detective.png new file mode 100644 index 0000000..a750566 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/true_detective.png differ diff --git a/Unit-2-Journal/Unit-2-Journal/x-files.png b/Unit-2-Journal/Unit-2-Journal/x-files.png new file mode 100644 index 0000000..b9e2c03 Binary files /dev/null and b/Unit-2-Journal/Unit-2-Journal/x-files.png differ