Replace Crashlytics/Fabric with Countly & Sentry.
This commit is contained in:
		@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Crashlytics
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Headers
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Modules
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Resources
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,31 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  ANSCompatibility.h
 | 
			
		||||
//  AnswersKit
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#if !__has_feature(nullability)
 | 
			
		||||
#define nonnull
 | 
			
		||||
#define nullable
 | 
			
		||||
#define _Nullable
 | 
			
		||||
#define _Nonnull
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
#define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_feature(objc_generics)
 | 
			
		||||
#define ANS_GENERIC_NSARRAY(type) NSArray<type>
 | 
			
		||||
#define ANS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary<key_type, object_key>
 | 
			
		||||
#else
 | 
			
		||||
#define ANS_GENERIC_NSARRAY(type) NSArray
 | 
			
		||||
#define ANS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,210 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Answers.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "ANSCompatibility.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This class exposes the Answers Events API, allowing you to track key 
 | 
			
		||||
 *  user user actions and metrics in your app.
 | 
			
		||||
 */
 | 
			
		||||
@interface Answers : NSObject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Sign Up event to see users signing up for your app in real-time, understand how
 | 
			
		||||
 *  many users are signing up with different methods and their success rate signing up.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param signUpMethodOrNil     The method by which a user logged in, e.g. Twitter or Digits.
 | 
			
		||||
 *  @param signUpSucceededOrNil  The ultimate success or failure of the login
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logSignUpWithMethod:(nullable NSString *)signUpMethodOrNil
 | 
			
		||||
                    success:(nullable NSNumber *)signUpSucceededOrNil
 | 
			
		||||
           customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Log In event to see users logging into your app in real-time, understand how many
 | 
			
		||||
 *  users are logging in with different methods and their success rate logging into your app.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param loginMethodOrNil      The method by which a user logged in, e.g. email, Twitter or Digits.
 | 
			
		||||
 *  @param loginSucceededOrNil   The ultimate success or failure of the login
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLoginWithMethod:(nullable NSString *)loginMethodOrNil
 | 
			
		||||
                   success:(nullable NSNumber *)loginSucceededOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Share event to see users sharing from your app in real-time, letting you
 | 
			
		||||
 *  understand what content they're sharing from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param shareMethodOrNil      The method by which a user shared, e.g. email, Twitter, SMS.
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logShareWithMethod:(nullable NSString *)shareMethodOrNil
 | 
			
		||||
               contentName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
               contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
                 contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Invite Event to track how users are inviting other users into
 | 
			
		||||
 *  your application.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param inviteMethodOrNil     The method of invitation, e.g. GameCenter, Twitter, email.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logInviteWithMethod:(nullable NSString *)inviteMethodOrNil
 | 
			
		||||
           customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Purchase event to see your revenue in real-time, understand how many users are making purchases, see which
 | 
			
		||||
 *  items are most popular, and track plenty of other important purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param itemPriceOrNil         The purchased item's price.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param purchaseSucceededOrNil Was the purchase succesful or unsuccesful
 | 
			
		||||
 *  @param itemNameOrNil          The human-readable form of the item's name. Example:
 | 
			
		||||
 *  @param itemTypeOrNil          The type, or genre of the item. Example: Song
 | 
			
		||||
 *  @param itemIdOrNil            The machine-readable, unique item identifier Example: SKU
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this purchase.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logPurchaseWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
 | 
			
		||||
                    currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                     success:(nullable NSNumber *)purchaseSucceededOrNil
 | 
			
		||||
                    itemName:(nullable NSString *)itemNameOrNil
 | 
			
		||||
                    itemType:(nullable NSString *)itemTypeOrNil
 | 
			
		||||
                      itemId:(nullable NSString *)itemIdOrNil
 | 
			
		||||
            customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Level Start Event to track where users are in your game.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param levelNameOrNil        The level name
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this level start event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLevelStart:(nullable NSString *)levelNameOrNil
 | 
			
		||||
     customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Level End event to track how users are completing levels in your game.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param levelNameOrNil                 The name of the level completed, E.G. "1" or "Training"
 | 
			
		||||
 *  @param scoreOrNil                     The score the user completed the level with.
 | 
			
		||||
 *  @param levelCompletedSuccesfullyOrNil A boolean representing whether or not the level was completed succesfully.
 | 
			
		||||
 *  @param customAttributesOrNil          A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLevelEnd:(nullable NSString *)levelNameOrNil
 | 
			
		||||
              score:(nullable NSNumber *)scoreOrNil
 | 
			
		||||
            success:(nullable NSNumber *)levelCompletedSuccesfullyOrNil
 | 
			
		||||
   customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Add to Cart event to see users adding items to a shopping cart in real-time, understand how
 | 
			
		||||
 *  many users start the purchase flow, see which items are most popular, and track plenty of other important
 | 
			
		||||
 *  purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param itemPriceOrNil         The purchased item's price.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param itemNameOrNil          The human-readable form of the item's name. Example:
 | 
			
		||||
 *  @param itemTypeOrNil          The type, or genre of the item. Example: Song
 | 
			
		||||
 *  @param itemIdOrNil            The machine-readable, unique item identifier Example: SKU
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logAddToCartWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
 | 
			
		||||
                     currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                     itemName:(nullable NSString *)itemNameOrNil
 | 
			
		||||
                     itemType:(nullable NSString *)itemTypeOrNil
 | 
			
		||||
                       itemId:(nullable NSString *)itemIdOrNil
 | 
			
		||||
             customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Start Checkout event to see users moving through the purchase funnel in real-time, understand how many
 | 
			
		||||
 *  users are doing this and how much they're spending per checkout, and see how it related to other important
 | 
			
		||||
 *  purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param totalPriceOrNil        The total price of the cart.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param itemCountOrNil         The number of items in the cart.
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logStartCheckoutWithPrice:(nullable NSDecimalNumber *)totalPriceOrNil
 | 
			
		||||
                         currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                        itemCount:(nullable NSNumber *)itemCountOrNil
 | 
			
		||||
                 customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Rating event to see users rating content within your app in real-time and understand what
 | 
			
		||||
 *  content is most engaging, from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param ratingOrNil           The integer rating given by the user.
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logRating:(nullable NSNumber *)ratingOrNil
 | 
			
		||||
      contentName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
      contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
        contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
 customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Content View event to see users viewing content within your app in real-time and
 | 
			
		||||
 *  understand what content is most engaging, from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logContentViewWithName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
                   contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
                     contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
              customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Search event allows you to see users searching within your app in real-time and understand
 | 
			
		||||
 *  exactly what they're searching for.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param queryOrNil            The user's query.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logSearchWithQuery:(nullable NSString *)queryOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Custom Event to see user actions that are uniquely important for your app in real-time, to see how often
 | 
			
		||||
 *  they're performing these actions with breakdowns by different categories you add. Use a human-readable name for
 | 
			
		||||
 *  the name of the event, since this is how the event will appear in Answers.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param eventName             The human-readable name for the event.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event. Attribute keys
 | 
			
		||||
 *                               must be <code>NSString</code> and and values must be <code>NSNumber</code> or <code>NSString</code>.
 | 
			
		||||
 *  @discussion                  How we treat <code>NSNumbers</code>:
 | 
			
		||||
 *                               We will provide information about the distribution of values over time.
 | 
			
		||||
 *
 | 
			
		||||
 *                               How we treat <code>NSStrings</code>:
 | 
			
		||||
 *                               NSStrings are used as categorical data, allowing comparison across different category values.
 | 
			
		||||
 *                               Strings are limited to a maximum length of 100 characters, attributes over this length will be
 | 
			
		||||
 *                               truncated.
 | 
			
		||||
 *
 | 
			
		||||
 *                               When tracking the Tweet views to better understand user engagement, sending the tweet's length
 | 
			
		||||
 *                               and the type of media present in the tweet allows you to track how tweet length and the type of media influence
 | 
			
		||||
 *                               engagement.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logCustomEventWithName:(NSString *)eventName
 | 
			
		||||
              customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSAttributes.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define CLS_DEPRECATED(x)  __attribute__ ((deprecated(x)))
 | 
			
		||||
 | 
			
		||||
#if !__has_feature(nullability)
 | 
			
		||||
    #define nonnull
 | 
			
		||||
    #define nullable
 | 
			
		||||
    #define _Nullable
 | 
			
		||||
    #define _Nonnull
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
    #define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
    #define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_feature(objc_generics)
 | 
			
		||||
    #define CLS_GENERIC_NSARRAY(type) NSArray<type>
 | 
			
		||||
    #define CLS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary<key_type, object_key>
 | 
			
		||||
#else
 | 
			
		||||
    #define CLS_GENERIC_NSARRAY(type) NSArray
 | 
			
		||||
    #define CLS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,64 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSLogging.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The CLS_LOG macro provides as easy way to gather more information in your log messages that are
 | 
			
		||||
 * sent with your crash data. CLS_LOG prepends your custom log message with the function name and
 | 
			
		||||
 * line number where the macro was used. If your app was built with the DEBUG preprocessor macro
 | 
			
		||||
 * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
 | 
			
		||||
 * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
 | 
			
		||||
 *
 | 
			
		||||
 * Example output:
 | 
			
		||||
 * -[AppDelegate login:] line 134 $ login start
 | 
			
		||||
 *
 | 
			
		||||
 * If you would like to change this macro, create a new header file, unset our define and then define
 | 
			
		||||
 * your own version. Make sure this new header file is imported after the Crashlytics header file.
 | 
			
		||||
 *
 | 
			
		||||
 * #undef CLS_LOG
 | 
			
		||||
 * #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * Add logging that will be sent with your crash data. This logging will not show up in the system.log
 | 
			
		||||
 * and will only be visible in your Crashlytics dashboard.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
 | 
			
		||||
OBJC_EXTERN void CLSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * Add logging that will be sent with your crash data. This logging will show up in the system.log
 | 
			
		||||
 * and your Crashlytics dashboard. It is not recommended for Release builds.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
 | 
			
		||||
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSReport.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The CLSCrashReport protocol is deprecated. See the CLSReport class and the CrashyticsDelegate changes for details.
 | 
			
		||||
 **/
 | 
			
		||||
@protocol CLSCrashReport <NSObject>
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *identifier;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleVersion;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDate *crashedOnDate;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSVersion;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The CLSReport exposes an interface to the phsyical report that Crashlytics has created. You can
 | 
			
		||||
 * use this class to get information about the event, and can also set some values after the
 | 
			
		||||
 * event has occured.
 | 
			
		||||
 **/
 | 
			
		||||
@interface CLSReport : NSObject <CLSCrashReport>
 | 
			
		||||
 | 
			
		||||
- (instancetype)init NS_UNAVAILABLE;
 | 
			
		||||
+ (instancetype)new NS_UNAVAILABLE;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the session identifier for the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *identifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the custom key value data for the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the CFBundleVersion of the application that generated the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the CFBundleShortVersionString of the application that generated the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the date that the report was created.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDate *dateCreated;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the os version that the application crashed on.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the os build version that the application crashed on.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns YES if the report contains any crash information, otherwise returns NO.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, assign, readonly) BOOL isCrash;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * You can use this method to set, after the event, additional custom keys. The rules
 | 
			
		||||
 * and semantics for this method are the same as those documented in Crashlytics.h. Be aware
 | 
			
		||||
 * that the maximum size and count of custom keys is still enforced, and you can overwrite keys
 | 
			
		||||
 * and/or cause excess keys to be deleted by using this method.
 | 
			
		||||
 **/
 | 
			
		||||
- (void)setObjectValue:(nullable id)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record an application-specific user identifier. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userIdentifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record a user name. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userName;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record a user email. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userEmail;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSStackFrame.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * This class is used in conjunction with -[Crashlytics recordCustomExceptionName:reason:frameArray:] to
 | 
			
		||||
 * record information about non-ObjC/C++ exceptions. All information included here will be displayed 
 | 
			
		||||
 * in the Crashlytics UI, and can influence crash grouping. Be particularly careful with the use of the 
 | 
			
		||||
 * address property. If set, Crashlytics will attempt symbolication and could overwrite other properities 
 | 
			
		||||
 * in the process.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
@interface CLSStackFrame : NSObject
 | 
			
		||||
 | 
			
		||||
+ (instancetype)stackFrame;
 | 
			
		||||
+ (instancetype)stackFrameWithAddress:(NSUInteger)address;
 | 
			
		||||
+ (instancetype)stackFrameWithSymbol:(NSString *)symbol;
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *symbol;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *rawSymbol;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *library;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *fileName;
 | 
			
		||||
@property (nonatomic, assign) uint32_t lineNumber;
 | 
			
		||||
@property (nonatomic, assign) uint64_t offset;
 | 
			
		||||
@property (nonatomic, assign) uint64_t address;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,266 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Crashlytics.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
#import "CLSLogging.h"
 | 
			
		||||
#import "CLSReport.h"
 | 
			
		||||
#import "CLSStackFrame.h"
 | 
			
		||||
#import "Answers.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@protocol CrashlyticsDelegate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Crashlytics. Handles configuration and initialization of Crashlytics.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: The Crashlytics class cannot be subclassed. If this is causing you pain for
 | 
			
		||||
 * testing, we suggest using either a wrapper class or a protocol extension.
 | 
			
		||||
 */
 | 
			
		||||
@interface Crashlytics : NSObject
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, readonly, copy) NSString *APIKey;
 | 
			
		||||
@property (nonatomic, readonly, copy) NSString *version;
 | 
			
		||||
@property (nonatomic, assign)         BOOL      debugMode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The delegate can be used to influence decisions on reporting and behavior, as well as reacting
 | 
			
		||||
 * to previous crashes.
 | 
			
		||||
 *
 | 
			
		||||
 * Make certain that the delegate is setup before starting Crashlytics with startWithAPIKey:... or
 | 
			
		||||
 * via +[Fabric with:...]. Failure to do will result in missing any delegate callbacks that occur
 | 
			
		||||
 * synchronously during start.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, assign, nullable) id <CrashlyticsDelegate> delegate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The recommended way to install Crashlytics into your application is to place a call to +startWithAPIKey: 
 | 
			
		||||
 *  in your -application:didFinishLaunchingWithOptions: or -applicationDidFinishLaunching:
 | 
			
		||||
 *  method.
 | 
			
		||||
 *
 | 
			
		||||
 *  Note: Starting with 3.0, the submission process has been significantly improved. The delay parameter
 | 
			
		||||
 *  is no longer required to throttle submissions on launch, performance will be great without it.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param apiKey The Crashlytics API Key for this app
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter.  Please use +startWithAPIKey: instead.");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
 | 
			
		||||
 *  these convenience methods to activate the framework and set the delegate in one call.
 | 
			
		||||
 *  
 | 
			
		||||
 *  @param apiKey   The Crashlytics API Key for this app
 | 
			
		||||
 *  @param delegate A delegate object which conforms to CrashlyticsDelegate.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(nullable id<CrashlyticsDelegate>)delegate;
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(nullable id<CrashlyticsDelegate>)delegate afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter.  Please use +startWithAPIKey:delegate: instead.");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Access the singleton Crashlytics instance.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)sharedInstance;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The easiest way to cause a crash - great for testing!
 | 
			
		||||
 */
 | 
			
		||||
- (void)crash;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The easiest way to cause a crash with an exception - great for testing.
 | 
			
		||||
 */
 | 
			
		||||
- (void)throwException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user identifier which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  Many of our customers have requested the ability to tie crashes to specific end-users of their
 | 
			
		||||
 *  application in order to facilitate responses to support requests or permit the ability to reach
 | 
			
		||||
 *  out for more information. We allow you to specify up to three separate values for display within
 | 
			
		||||
 *  the Crashlytics UI - but please be mindful of your end-user's privacy.
 | 
			
		||||
 *
 | 
			
		||||
 *  We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
 | 
			
		||||
 *  in your system. This could be a database id, hash, or other value that is meaningless to a
 | 
			
		||||
 *  third-party observer but can be indexed and queried by you.
 | 
			
		||||
 *
 | 
			
		||||
 *  Optionally, you may also specify the end-user's name or username, as well as email address if you
 | 
			
		||||
 *  do not have a system that works well with obscured identifiers.
 | 
			
		||||
 *
 | 
			
		||||
 *  Pursuant to our EULA, this data is transferred securely throughout our system and we will not
 | 
			
		||||
 *  disseminate end-user data unless required to by law. That said, if you choose to provide end-user
 | 
			
		||||
 *  contact information, we strongly recommend that you disclose this in your application's privacy
 | 
			
		||||
 *  policy. Data privacy is of our utmost concern.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param identifier An arbitrary user identifier string which ties an end-user to a record in your system.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserIdentifier:(nullable NSString *)identifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user name which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  Please be mindful of your end-user's privacy and see if setUserIdentifier: can fulfil your needs.
 | 
			
		||||
 *  @see setUserIdentifier:
 | 
			
		||||
 *
 | 
			
		||||
 *  @param name An end user's name.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserName:(nullable NSString *)name;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user email which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  Please be mindful of your end-user's privacy and see if setUserIdentifier: can fulfil your needs.
 | 
			
		||||
 *  
 | 
			
		||||
 *  @see setUserIdentifier:
 | 
			
		||||
 *
 | 
			
		||||
 *  @param email An end user's email address.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserEmail:(nullable NSString *)email;
 | 
			
		||||
 | 
			
		||||
+ (void)setUserIdentifier:(nullable NSString *)identifier CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setUserName:(nullable NSString *)name CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setUserEmail:(nullable NSString *)email CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set a value for a for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  When setting an object value, the object is converted to a string. This is typically done by calling 
 | 
			
		||||
 *  -[NSObject description].
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The object to be associated with the key
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setObjectValue:(nullable id)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an int value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The integer value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setIntValue:(int)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an BOOL value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The BOOL value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an float value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The float value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setFloatValue:(float)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
+ (void)setObjectValue:(nullable id)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setIntValue:(int)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setFloatValue:(float)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This method can be used to record a single exception structure in a report. This is particularly useful
 | 
			
		||||
 *  when your code interacts with non-native languages like Lua, C#, or Javascript. This call can be
 | 
			
		||||
 *  expensive and should only be used shortly before process termination. This API is not intended be to used
 | 
			
		||||
 *  to log NSException objects. All safely-reportable NSExceptions are automatically captured by
 | 
			
		||||
 *  Crashlytics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param name       The name of the custom exception
 | 
			
		||||
 *  @param reason     The reason this exception occured
 | 
			
		||||
 *  @param frameArray An array of CLSStackFrame objects
 | 
			
		||||
 */
 | 
			
		||||
- (void)recordCustomExceptionName:(NSString *)name reason:(nullable NSString *)reason frameArray:(CLS_GENERIC_NSARRAY(CLSStackFrame *) *)frameArray;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * This allows you to record a non-fatal event, described by an NSError object. These events will be grouped and
 | 
			
		||||
 * displayed similarly to crashes. Keep in mind that this method can be expensive. Also, the total number of
 | 
			
		||||
 * NSErrors that can be recorded during your app's life-cycle is limited by a fixed-size circular buffer. If the
 | 
			
		||||
 * buffer is overrun, the oldest data is dropped. Errors are relayed to Crashlytics on a subsequent launch
 | 
			
		||||
 * of your application.
 | 
			
		||||
 *
 | 
			
		||||
 * You can also use the -recordError:withAdditionalUserInfo: to include additional context not represented
 | 
			
		||||
 * by the NSError instance itself.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
- (void)recordError:(NSError *)error;
 | 
			
		||||
- (void)recordError:(NSError *)error withAdditionalUserInfo:(nullable CLS_GENERIC_NSDICTIONARY(NSString *, id) *)userInfo;
 | 
			
		||||
 | 
			
		||||
- (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
- (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
+ (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
+ (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The CrashlyticsDelegate protocol provides a mechanism for your application to take
 | 
			
		||||
 * action on events that occur in the Crashlytics crash reporting system.  You can make
 | 
			
		||||
 * use of these calls by assigning an object to the Crashlytics' delegate property directly,
 | 
			
		||||
 * or through the convenience +startWithAPIKey:delegate: method.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
@protocol CrashlyticsDelegate <NSObject>
 | 
			
		||||
@optional
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
 | 
			
		||||
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  Called when a Crashlytics instance has determined that the last execution of the
 | 
			
		||||
 *  application ended in a crash.  This is called synchronously on Crashlytics
 | 
			
		||||
 *  initialization. Your delegate must invoke the completionHandler, but does not need to do so
 | 
			
		||||
 *  synchronously, or even on the main thread. Invoking completionHandler with NO will cause the
 | 
			
		||||
 *  detected report to be deleted and not submitted to Crashlytics. This is useful for
 | 
			
		||||
 *  implementing permission prompts, or other more-complex forms of logic around submitting crashes.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Failure to invoke the completionHandler will prevent submissions from being reported. Watch out.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Just implementing this delegate method will disable all forms of synchronous report submission. This can
 | 
			
		||||
 *           impact the reliability of reporting crashes very early in application launch.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param report            The CLSReport object representing the last detected crash
 | 
			
		||||
 *  @param completionHandler The completion handler to call when your logic has completed.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  If your app is running on an OS that supports it (OS X 10.9+, iOS 7.0+), Crashlytics will submit
 | 
			
		||||
 *  most reports using out-of-process background networking operations. This results in a significant
 | 
			
		||||
 *  improvement in reliability of reporting, as well as power and performance wins for your users.
 | 
			
		||||
 *  If you don't want this functionality, you can disable by returning NO from this method.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Background submission is not supported for extensions on iOS or OS X.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param crashlytics The Crashlytics singleton instance
 | 
			
		||||
 *
 | 
			
		||||
 *  @return Return NO if you don't want out-of-process background network operations.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
- (BOOL)crashlyticsCanUseBackgroundSessions:(Crashlytics *)crashlytics;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, use Crashlytics.sharedInstance()
 | 
			
		||||
 */
 | 
			
		||||
#define CrashlyticsKit [Crashlytics sharedInstance]
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
framework module Crashlytics {
 | 
			
		||||
    header "Crashlytics.h"
 | 
			
		||||
    header "Answers.h"
 | 
			
		||||
    header "ANSCompatibility.h"
 | 
			
		||||
    header "CLSLogging.h"
 | 
			
		||||
    header "CLSReport.h"
 | 
			
		||||
    header "CLSStackFrame.h"
 | 
			
		||||
    header "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
    export *
 | 
			
		||||
 | 
			
		||||
    link "z"
 | 
			
		||||
    link "c++"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
<?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>BuildMachineOSBuild</key>
 | 
			
		||||
	<string>15F34</string>
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>English</string>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>Crashlytics</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
	<string>com.twitter.crashlytics.mac</string>
 | 
			
		||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>CFBundleName</key>
 | 
			
		||||
	<string>Crashlytics</string>
 | 
			
		||||
	<key>CFBundlePackageType</key>
 | 
			
		||||
	<string>FMWK</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>3.7.2</string>
 | 
			
		||||
	<key>CFBundleSignature</key>
 | 
			
		||||
	<string>????</string>
 | 
			
		||||
	<key>CFBundleSupportedPlatforms</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>MacOSX</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>112</string>
 | 
			
		||||
	<key>DTCompiler</key>
 | 
			
		||||
	<string>com.apple.compilers.llvm.clang.1_0</string>
 | 
			
		||||
	<key>DTPlatformBuild</key>
 | 
			
		||||
	<string>7D175</string>
 | 
			
		||||
	<key>DTPlatformVersion</key>
 | 
			
		||||
	<string>GM</string>
 | 
			
		||||
	<key>DTSDKBuild</key>
 | 
			
		||||
	<string>15E60</string>
 | 
			
		||||
	<key>DTSDKName</key>
 | 
			
		||||
	<string>macosx10.11</string>
 | 
			
		||||
	<key>DTXcode</key>
 | 
			
		||||
	<string>0730</string>
 | 
			
		||||
	<key>DTXcodeBuild</key>
 | 
			
		||||
	<string>7D175</string>
 | 
			
		||||
	<key>NSHumanReadableCopyright</key>
 | 
			
		||||
	<string>Copyright © 2016 Crashlytics, Inc. All rights reserved.</string>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<integer>3</integer>
 | 
			
		||||
		<integer>2</integer>
 | 
			
		||||
		<integer>1</integer>
 | 
			
		||||
		<integer>4</integer>
 | 
			
		||||
	</array>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
A
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
#  run
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2015 Crashlytics. All rights reserved.
 | 
			
		||||
 | 
			
		||||
#  Figure out where we're being called from
 | 
			
		||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
 | 
			
		||||
 | 
			
		||||
#  Quote path in case of spaces or special chars
 | 
			
		||||
DIR="\"${DIR}"
 | 
			
		||||
 | 
			
		||||
PATH_SEP="/"
 | 
			
		||||
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
 | 
			
		||||
UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
 | 
			
		||||
 | 
			
		||||
#  Ensure params are as expected, run in sync mode to validate
 | 
			
		||||
eval $DIR$PATH_SEP$VALIDATE_COMMAND
 | 
			
		||||
return_code=$?
 | 
			
		||||
 | 
			
		||||
if [[ $return_code != 0 ]]; then
 | 
			
		||||
  exit $return_code
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#  Verification passed, upload dSYM in background to prevent Xcode from waiting
 | 
			
		||||
#  Note: Validation is performed again before upload.
 | 
			
		||||
#  Output can still be found in Console.app
 | 
			
		||||
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 &
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Fabric
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Headers
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Modules
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
Versions/Current/Resources
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,60 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  FABAttributes.h
 | 
			
		||||
//  Fabric
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (C) 2015 Twitter, Inc.
 | 
			
		||||
//
 | 
			
		||||
//  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
//  you may not use this file except in compliance with the License.
 | 
			
		||||
//  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
//  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
//  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
//  See the License for the specific language governing permissions and
 | 
			
		||||
//  limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define FAB_UNAVAILABLE(x) __attribute__((unavailable(x)))
 | 
			
		||||
 | 
			
		||||
#if __has_feature(nullability)
 | 
			
		||||
    #define fab_nullable           nullable
 | 
			
		||||
    #define fab_nonnull            nonnull
 | 
			
		||||
    #define fab_null_unspecified   null_unspecified
 | 
			
		||||
    #define fab_null_resettable    null_resettable
 | 
			
		||||
    #define __fab_nullable         __nullable
 | 
			
		||||
    #define __fab_nonnull          __nonnull
 | 
			
		||||
    #define __fab_null_unspecified __null_unspecified
 | 
			
		||||
#else
 | 
			
		||||
    #define fab_nullable
 | 
			
		||||
    #define fab_nonnull
 | 
			
		||||
    #define fab_null_unspecified
 | 
			
		||||
    #define fab_null_resettable
 | 
			
		||||
    #define __fab_nullable
 | 
			
		||||
    #define __fab_nonnull
 | 
			
		||||
    #define __fab_null_unspecified
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
    #define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
    #define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The following macros are defined here to provide
 | 
			
		||||
 * backwards compatability. If you are still using
 | 
			
		||||
 * them you should migrate to the new versions that
 | 
			
		||||
 * are defined above.
 | 
			
		||||
 */
 | 
			
		||||
#define FAB_NONNULL       __fab_nonnull
 | 
			
		||||
#define FAB_NULLABLE      __fab_nullable
 | 
			
		||||
#define FAB_START_NONNULL NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#define FAB_END_NONNULL   NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Fabric.h
 | 
			
		||||
//  Fabric
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (C) 2015 Twitter, Inc.
 | 
			
		||||
//
 | 
			
		||||
//  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
//  you may not use this file except in compliance with the License.
 | 
			
		||||
//  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
//  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
//  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
//  See the License for the specific language governing permissions and
 | 
			
		||||
//  limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "FABAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IPHONE
 | 
			
		||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
 | 
			
		||||
    #error "Fabric's minimum iOS version is 6.0"
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
 | 
			
		||||
    #error "Fabric's minimum OS X version is 10.7"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Fabric Base. Coordinates configuration and starts all provided kits.
 | 
			
		||||
 */
 | 
			
		||||
@interface Fabric : NSObject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize Fabric and all provided kits. Call this method within your App Delegate's `application:didFinishLaunchingWithOptions:` and provide the kits you wish to use.
 | 
			
		||||
 *
 | 
			
		||||
 * For example, in Objective-C:
 | 
			
		||||
 *
 | 
			
		||||
 *      `[Fabric with:@[[Crashlytics class], [Twitter class], [Digits class], [MoPub class]]];`
 | 
			
		||||
 *
 | 
			
		||||
 * Swift:
 | 
			
		||||
 *
 | 
			
		||||
 *      `Fabric.with([Crashlytics.self(), Twitter.self(), Digits.self(), MoPub.self()])`
 | 
			
		||||
 *
 | 
			
		||||
 * Only the first call to this method is honored. Subsequent calls are no-ops.
 | 
			
		||||
 *
 | 
			
		||||
 * @param kitClasses An array of kit Class objects
 | 
			
		||||
 *
 | 
			
		||||
 * @return Returns the shared Fabric instance. In most cases this can be ignored.
 | 
			
		||||
 */
 | 
			
		||||
+ (instancetype)with:(NSArray *)kitClasses;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Returns the Fabric singleton object.
 | 
			
		||||
 */
 | 
			
		||||
+ (instancetype)sharedSDK;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This BOOL enables or disables debug logging, such as kit version information. The default value is NO.
 | 
			
		||||
 */
 | 
			
		||||
@property (nonatomic, assign) BOOL debug;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Unavailable. Use `+sharedSDK` to retrieve the shared Fabric instance.
 | 
			
		||||
 */
 | 
			
		||||
- (id)init FAB_UNAVAILABLE("Use +sharedSDK to retrieve the shared Fabric instance.");
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
framework module Fabric {
 | 
			
		||||
    umbrella header "Fabric.h"
 | 
			
		||||
 | 
			
		||||
    export *
 | 
			
		||||
    module * { export * }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
<?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>BuildMachineOSBuild</key>
 | 
			
		||||
	<string>14F1021</string>
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>en</string>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>Fabric</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
	<string>io.fabric.sdk.mac</string>
 | 
			
		||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>CFBundleName</key>
 | 
			
		||||
	<string>Fabric</string>
 | 
			
		||||
	<key>CFBundlePackageType</key>
 | 
			
		||||
	<string>FMWK</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>1.6.7</string>
 | 
			
		||||
	<key>CFBundleSignature</key>
 | 
			
		||||
	<string>????</string>
 | 
			
		||||
	<key>CFBundleSupportedPlatforms</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>MacOSX</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>53</string>
 | 
			
		||||
	<key>DTCompiler</key>
 | 
			
		||||
	<string>com.apple.compilers.llvm.clang.1_0</string>
 | 
			
		||||
	<key>DTPlatformBuild</key>
 | 
			
		||||
	<string>7C1002</string>
 | 
			
		||||
	<key>DTPlatformVersion</key>
 | 
			
		||||
	<string>GM</string>
 | 
			
		||||
	<key>DTSDKBuild</key>
 | 
			
		||||
	<string>15C43</string>
 | 
			
		||||
	<key>DTSDKName</key>
 | 
			
		||||
	<string>macosx10.11</string>
 | 
			
		||||
	<key>DTXcode</key>
 | 
			
		||||
	<string>0721</string>
 | 
			
		||||
	<key>DTXcodeBuild</key>
 | 
			
		||||
	<string>7C1002</string>
 | 
			
		||||
	<key>NSHumanReadableCopyright</key>
 | 
			
		||||
	<string>Copyright © 2015 Twitter. All rights reserved.</string>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<integer>3</integer>
 | 
			
		||||
		<integer>2</integer>
 | 
			
		||||
		<integer>1</integer>
 | 
			
		||||
		<integer>4</integer>
 | 
			
		||||
	</array>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
A
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
#  run
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2015 Crashlytics. All rights reserved.
 | 
			
		||||
 | 
			
		||||
#  Figure out where we're being called from
 | 
			
		||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
 | 
			
		||||
 | 
			
		||||
#  Quote path in case of spaces or special chars
 | 
			
		||||
DIR="\"${DIR}"
 | 
			
		||||
 | 
			
		||||
PATH_SEP="/"
 | 
			
		||||
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
 | 
			
		||||
UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
 | 
			
		||||
 | 
			
		||||
#  Ensure params are as expected, run in sync mode to validate
 | 
			
		||||
eval $DIR$PATH_SEP$VALIDATE_COMMAND
 | 
			
		||||
return_code=$?
 | 
			
		||||
 | 
			
		||||
if [[ $return_code != 0 ]]; then
 | 
			
		||||
  exit $return_code
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#  Verification passed, upload dSYM in background to prevent Xcode from waiting
 | 
			
		||||
#  Note: Validation is performed again before upload.
 | 
			
		||||
#  Output can still be found in Console.app
 | 
			
		||||
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 &
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1,31 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  ANSCompatibility.h
 | 
			
		||||
//  AnswersKit
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#if !__has_feature(nullability)
 | 
			
		||||
#define nonnull
 | 
			
		||||
#define nullable
 | 
			
		||||
#define _Nullable
 | 
			
		||||
#define _Nonnull
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
#define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_feature(objc_generics)
 | 
			
		||||
#define ANS_GENERIC_NSARRAY(type) NSArray<type>
 | 
			
		||||
#define ANS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary<key_type, object_key>
 | 
			
		||||
#else
 | 
			
		||||
#define ANS_GENERIC_NSARRAY(type) NSArray
 | 
			
		||||
#define ANS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,210 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Answers.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "ANSCompatibility.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This class exposes the Answers Events API, allowing you to track key 
 | 
			
		||||
 *  user user actions and metrics in your app.
 | 
			
		||||
 */
 | 
			
		||||
@interface Answers : NSObject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Sign Up event to see users signing up for your app in real-time, understand how
 | 
			
		||||
 *  many users are signing up with different methods and their success rate signing up.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param signUpMethodOrNil     The method by which a user logged in, e.g. Twitter or Digits.
 | 
			
		||||
 *  @param signUpSucceededOrNil  The ultimate success or failure of the login
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logSignUpWithMethod:(nullable NSString *)signUpMethodOrNil
 | 
			
		||||
                    success:(nullable NSNumber *)signUpSucceededOrNil
 | 
			
		||||
           customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Log In event to see users logging into your app in real-time, understand how many
 | 
			
		||||
 *  users are logging in with different methods and their success rate logging into your app.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param loginMethodOrNil      The method by which a user logged in, e.g. email, Twitter or Digits.
 | 
			
		||||
 *  @param loginSucceededOrNil   The ultimate success or failure of the login
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLoginWithMethod:(nullable NSString *)loginMethodOrNil
 | 
			
		||||
                   success:(nullable NSNumber *)loginSucceededOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Share event to see users sharing from your app in real-time, letting you
 | 
			
		||||
 *  understand what content they're sharing from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param shareMethodOrNil      The method by which a user shared, e.g. email, Twitter, SMS.
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logShareWithMethod:(nullable NSString *)shareMethodOrNil
 | 
			
		||||
               contentName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
               contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
                 contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Invite Event to track how users are inviting other users into
 | 
			
		||||
 *  your application.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param inviteMethodOrNil     The method of invitation, e.g. GameCenter, Twitter, email.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logInviteWithMethod:(nullable NSString *)inviteMethodOrNil
 | 
			
		||||
           customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Purchase event to see your revenue in real-time, understand how many users are making purchases, see which
 | 
			
		||||
 *  items are most popular, and track plenty of other important purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param itemPriceOrNil         The purchased item's price.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param purchaseSucceededOrNil Was the purchase succesful or unsuccesful
 | 
			
		||||
 *  @param itemNameOrNil          The human-readable form of the item's name. Example:
 | 
			
		||||
 *  @param itemTypeOrNil          The type, or genre of the item. Example: Song
 | 
			
		||||
 *  @param itemIdOrNil            The machine-readable, unique item identifier Example: SKU
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this purchase.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logPurchaseWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
 | 
			
		||||
                    currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                     success:(nullable NSNumber *)purchaseSucceededOrNil
 | 
			
		||||
                    itemName:(nullable NSString *)itemNameOrNil
 | 
			
		||||
                    itemType:(nullable NSString *)itemTypeOrNil
 | 
			
		||||
                      itemId:(nullable NSString *)itemIdOrNil
 | 
			
		||||
            customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Level Start Event to track where users are in your game.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param levelNameOrNil        The level name
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this level start event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLevelStart:(nullable NSString *)levelNameOrNil
 | 
			
		||||
     customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Level End event to track how users are completing levels in your game.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param levelNameOrNil                 The name of the level completed, E.G. "1" or "Training"
 | 
			
		||||
 *  @param scoreOrNil                     The score the user completed the level with.
 | 
			
		||||
 *  @param levelCompletedSuccesfullyOrNil A boolean representing whether or not the level was completed succesfully.
 | 
			
		||||
 *  @param customAttributesOrNil          A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logLevelEnd:(nullable NSString *)levelNameOrNil
 | 
			
		||||
              score:(nullable NSNumber *)scoreOrNil
 | 
			
		||||
            success:(nullable NSNumber *)levelCompletedSuccesfullyOrNil
 | 
			
		||||
   customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log an Add to Cart event to see users adding items to a shopping cart in real-time, understand how
 | 
			
		||||
 *  many users start the purchase flow, see which items are most popular, and track plenty of other important
 | 
			
		||||
 *  purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param itemPriceOrNil         The purchased item's price.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param itemNameOrNil          The human-readable form of the item's name. Example:
 | 
			
		||||
 *  @param itemTypeOrNil          The type, or genre of the item. Example: Song
 | 
			
		||||
 *  @param itemIdOrNil            The machine-readable, unique item identifier Example: SKU
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logAddToCartWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
 | 
			
		||||
                     currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                     itemName:(nullable NSString *)itemNameOrNil
 | 
			
		||||
                     itemType:(nullable NSString *)itemTypeOrNil
 | 
			
		||||
                       itemId:(nullable NSString *)itemIdOrNil
 | 
			
		||||
             customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Start Checkout event to see users moving through the purchase funnel in real-time, understand how many
 | 
			
		||||
 *  users are doing this and how much they're spending per checkout, and see how it related to other important
 | 
			
		||||
 *  purchase-related metrics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param totalPriceOrNil        The total price of the cart.
 | 
			
		||||
 *  @param currencyOrNil          The ISO4217 currency code. Example: USD
 | 
			
		||||
 *  @param itemCountOrNil         The number of items in the cart.
 | 
			
		||||
 *  @param customAttributesOrNil  A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logStartCheckoutWithPrice:(nullable NSDecimalNumber *)totalPriceOrNil
 | 
			
		||||
                         currency:(nullable NSString *)currencyOrNil
 | 
			
		||||
                        itemCount:(nullable NSNumber *)itemCountOrNil
 | 
			
		||||
                 customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Rating event to see users rating content within your app in real-time and understand what
 | 
			
		||||
 *  content is most engaging, from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param ratingOrNil           The integer rating given by the user.
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logRating:(nullable NSNumber *)ratingOrNil
 | 
			
		||||
      contentName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
      contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
        contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
 customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Content View event to see users viewing content within your app in real-time and
 | 
			
		||||
 *  understand what content is most engaging, from the type or genre down to the specific id.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param contentNameOrNil      The human readable name for this piece of content.
 | 
			
		||||
 *  @param contentTypeOrNil      The type of content shared.
 | 
			
		||||
 *  @param contentIdOrNil        The unique identifier for this piece of content. Useful for finding the top shared item.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logContentViewWithName:(nullable NSString *)contentNameOrNil
 | 
			
		||||
                   contentType:(nullable NSString *)contentTypeOrNil
 | 
			
		||||
                     contentId:(nullable NSString *)contentIdOrNil
 | 
			
		||||
              customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Search event allows you to see users searching within your app in real-time and understand
 | 
			
		||||
 *  exactly what they're searching for.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param queryOrNil            The user's query.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logSearchWithQuery:(nullable NSString *)queryOrNil
 | 
			
		||||
          customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Log a Custom Event to see user actions that are uniquely important for your app in real-time, to see how often
 | 
			
		||||
 *  they're performing these actions with breakdowns by different categories you add. Use a human-readable name for
 | 
			
		||||
 *  the name of the event, since this is how the event will appear in Answers.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param eventName             The human-readable name for the event.
 | 
			
		||||
 *  @param customAttributesOrNil A dictionary of custom attributes to associate with this event. Attribute keys
 | 
			
		||||
 *                               must be <code>NSString</code> and and values must be <code>NSNumber</code> or <code>NSString</code>.
 | 
			
		||||
 *  @discussion                  How we treat <code>NSNumbers</code>:
 | 
			
		||||
 *                               We will provide information about the distribution of values over time.
 | 
			
		||||
 *
 | 
			
		||||
 *                               How we treat <code>NSStrings</code>:
 | 
			
		||||
 *                               NSStrings are used as categorical data, allowing comparison across different category values.
 | 
			
		||||
 *                               Strings are limited to a maximum length of 100 characters, attributes over this length will be
 | 
			
		||||
 *                               truncated.
 | 
			
		||||
 *
 | 
			
		||||
 *                               When tracking the Tweet views to better understand user engagement, sending the tweet's length
 | 
			
		||||
 *                               and the type of media present in the tweet allows you to track how tweet length and the type of media influence
 | 
			
		||||
 *                               engagement.
 | 
			
		||||
 */
 | 
			
		||||
+ (void)logCustomEventWithName:(NSString *)eventName
 | 
			
		||||
              customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSAttributes.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define CLS_DEPRECATED(x)  __attribute__ ((deprecated(x)))
 | 
			
		||||
 | 
			
		||||
#if !__has_feature(nullability)
 | 
			
		||||
    #define nonnull
 | 
			
		||||
    #define nullable
 | 
			
		||||
    #define _Nullable
 | 
			
		||||
    #define _Nonnull
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
    #define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
    #define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_feature(objc_generics)
 | 
			
		||||
    #define CLS_GENERIC_NSARRAY(type) NSArray<type>
 | 
			
		||||
    #define CLS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary<key_type, object_key>
 | 
			
		||||
#else
 | 
			
		||||
    #define CLS_GENERIC_NSARRAY(type) NSArray
 | 
			
		||||
    #define CLS_GENERIC_NSDICTIONARY(key_type,object_key) NSDictionary
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,64 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSLogging.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The CLS_LOG macro provides as easy way to gather more information in your log messages that are
 | 
			
		||||
 * sent with your crash data. CLS_LOG prepends your custom log message with the function name and
 | 
			
		||||
 * line number where the macro was used. If your app was built with the DEBUG preprocessor macro
 | 
			
		||||
 * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
 | 
			
		||||
 * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
 | 
			
		||||
 *
 | 
			
		||||
 * Example output:
 | 
			
		||||
 * -[AppDelegate login:] line 134 $ login start
 | 
			
		||||
 *
 | 
			
		||||
 * If you would like to change this macro, create a new header file, unset our define and then define
 | 
			
		||||
 * your own version. Make sure this new header file is imported after the Crashlytics header file.
 | 
			
		||||
 *
 | 
			
		||||
 * #undef CLS_LOG
 | 
			
		||||
 * #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * Add logging that will be sent with your crash data. This logging will not show up in the system.log
 | 
			
		||||
 * and will only be visible in your Crashlytics dashboard.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
 | 
			
		||||
OBJC_EXTERN void CLSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * Add logging that will be sent with your crash data. This logging will show up in the system.log
 | 
			
		||||
 * and your Crashlytics dashboard. It is not recommended for Release builds.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
 | 
			
		||||
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSReport.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The CLSCrashReport protocol is deprecated. See the CLSReport class and the CrashyticsDelegate changes for details.
 | 
			
		||||
 **/
 | 
			
		||||
@protocol CLSCrashReport <NSObject>
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *identifier;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleVersion;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDate *crashedOnDate;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSVersion;
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The CLSReport exposes an interface to the phsyical report that Crashlytics has created. You can
 | 
			
		||||
 * use this class to get information about the event, and can also set some values after the
 | 
			
		||||
 * event has occured.
 | 
			
		||||
 **/
 | 
			
		||||
@interface CLSReport : NSObject <CLSCrashReport>
 | 
			
		||||
 | 
			
		||||
- (instancetype)init NS_UNAVAILABLE;
 | 
			
		||||
+ (instancetype)new NS_UNAVAILABLE;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the session identifier for the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *identifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the custom key value data for the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the CFBundleVersion of the application that generated the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the CFBundleShortVersionString of the application that generated the report.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the date that the report was created.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSDate *dateCreated;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the os version that the application crashed on.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the os build version that the application crashed on.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns YES if the report contains any crash information, otherwise returns NO.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, assign, readonly) BOOL isCrash;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * You can use this method to set, after the event, additional custom keys. The rules
 | 
			
		||||
 * and semantics for this method are the same as those documented in Crashlytics.h. Be aware
 | 
			
		||||
 * that the maximum size and count of custom keys is still enforced, and you can overwrite keys
 | 
			
		||||
 * and/or cause excess keys to be deleted by using this method.
 | 
			
		||||
 **/
 | 
			
		||||
- (void)setObjectValue:(nullable id)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record an application-specific user identifier. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userIdentifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record a user name. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userName;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Record a user email. See Crashlytics.h for details.
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString * userEmail;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  CLSStackFrame.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * This class is used in conjunction with -[Crashlytics recordCustomExceptionName:reason:frameArray:] to
 | 
			
		||||
 * record information about non-ObjC/C++ exceptions. All information included here will be displayed 
 | 
			
		||||
 * in the Crashlytics UI, and can influence crash grouping. Be particularly careful with the use of the 
 | 
			
		||||
 * address property. If set, Crashlytics will attempt symbolication and could overwrite other properities 
 | 
			
		||||
 * in the process.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
@interface CLSStackFrame : NSObject
 | 
			
		||||
 | 
			
		||||
+ (instancetype)stackFrame;
 | 
			
		||||
+ (instancetype)stackFrameWithAddress:(NSUInteger)address;
 | 
			
		||||
+ (instancetype)stackFrameWithSymbol:(NSString *)symbol;
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *symbol;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *rawSymbol;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *library;
 | 
			
		||||
@property (nonatomic, copy, nullable) NSString *fileName;
 | 
			
		||||
@property (nonatomic, assign) uint32_t lineNumber;
 | 
			
		||||
@property (nonatomic, assign) uint64_t offset;
 | 
			
		||||
@property (nonatomic, assign) uint64_t address;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,266 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Crashlytics.h
 | 
			
		||||
//  Crashlytics
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
#import "CLSAttributes.h"
 | 
			
		||||
#import "CLSLogging.h"
 | 
			
		||||
#import "CLSReport.h"
 | 
			
		||||
#import "CLSStackFrame.h"
 | 
			
		||||
#import "Answers.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@protocol CrashlyticsDelegate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Crashlytics. Handles configuration and initialization of Crashlytics.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: The Crashlytics class cannot be subclassed. If this is causing you pain for
 | 
			
		||||
 * testing, we suggest using either a wrapper class or a protocol extension.
 | 
			
		||||
 */
 | 
			
		||||
@interface Crashlytics : NSObject
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, readonly, copy) NSString *APIKey;
 | 
			
		||||
@property (nonatomic, readonly, copy) NSString *version;
 | 
			
		||||
@property (nonatomic, assign)         BOOL      debugMode;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The delegate can be used to influence decisions on reporting and behavior, as well as reacting
 | 
			
		||||
 * to previous crashes.
 | 
			
		||||
 *
 | 
			
		||||
 * Make certain that the delegate is setup before starting Crashlytics with startWithAPIKey:... or
 | 
			
		||||
 * via +[Fabric with:...]. Failure to do will result in missing any delegate callbacks that occur
 | 
			
		||||
 * synchronously during start.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
@property (nonatomic, assign, nullable) id <CrashlyticsDelegate> delegate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The recommended way to install Crashlytics into your application is to place a call to +startWithAPIKey: 
 | 
			
		||||
 *  in your -application:didFinishLaunchingWithOptions: or -applicationDidFinishLaunching:
 | 
			
		||||
 *  method.
 | 
			
		||||
 *
 | 
			
		||||
 *  Note: Starting with 3.0, the submission process has been significantly improved. The delay parameter
 | 
			
		||||
 *  is no longer required to throttle submissions on launch, performance will be great without it.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param apiKey The Crashlytics API Key for this app
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter.  Please use +startWithAPIKey: instead.");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
 | 
			
		||||
 *  these convenience methods to activate the framework and set the delegate in one call.
 | 
			
		||||
 *  
 | 
			
		||||
 *  @param apiKey   The Crashlytics API Key for this app
 | 
			
		||||
 *  @param delegate A delegate object which conforms to CrashlyticsDelegate.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(nullable id<CrashlyticsDelegate>)delegate;
 | 
			
		||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(nullable id<CrashlyticsDelegate>)delegate afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter.  Please use +startWithAPIKey:delegate: instead.");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Access the singleton Crashlytics instance.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return The singleton Crashlytics instance
 | 
			
		||||
 */
 | 
			
		||||
+ (Crashlytics *)sharedInstance;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The easiest way to cause a crash - great for testing!
 | 
			
		||||
 */
 | 
			
		||||
- (void)crash;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  The easiest way to cause a crash with an exception - great for testing.
 | 
			
		||||
 */
 | 
			
		||||
- (void)throwException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user identifier which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  Many of our customers have requested the ability to tie crashes to specific end-users of their
 | 
			
		||||
 *  application in order to facilitate responses to support requests or permit the ability to reach
 | 
			
		||||
 *  out for more information. We allow you to specify up to three separate values for display within
 | 
			
		||||
 *  the Crashlytics UI - but please be mindful of your end-user's privacy.
 | 
			
		||||
 *
 | 
			
		||||
 *  We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
 | 
			
		||||
 *  in your system. This could be a database id, hash, or other value that is meaningless to a
 | 
			
		||||
 *  third-party observer but can be indexed and queried by you.
 | 
			
		||||
 *
 | 
			
		||||
 *  Optionally, you may also specify the end-user's name or username, as well as email address if you
 | 
			
		||||
 *  do not have a system that works well with obscured identifiers.
 | 
			
		||||
 *
 | 
			
		||||
 *  Pursuant to our EULA, this data is transferred securely throughout our system and we will not
 | 
			
		||||
 *  disseminate end-user data unless required to by law. That said, if you choose to provide end-user
 | 
			
		||||
 *  contact information, we strongly recommend that you disclose this in your application's privacy
 | 
			
		||||
 *  policy. Data privacy is of our utmost concern.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param identifier An arbitrary user identifier string which ties an end-user to a record in your system.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserIdentifier:(nullable NSString *)identifier;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user name which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  Please be mindful of your end-user's privacy and see if setUserIdentifier: can fulfil your needs.
 | 
			
		||||
 *  @see setUserIdentifier:
 | 
			
		||||
 *
 | 
			
		||||
 *  @param name An end user's name.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserName:(nullable NSString *)name;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Specify a user email which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  Please be mindful of your end-user's privacy and see if setUserIdentifier: can fulfil your needs.
 | 
			
		||||
 *  
 | 
			
		||||
 *  @see setUserIdentifier:
 | 
			
		||||
 *
 | 
			
		||||
 *  @param email An end user's email address.
 | 
			
		||||
 */
 | 
			
		||||
- (void)setUserEmail:(nullable NSString *)email;
 | 
			
		||||
 | 
			
		||||
+ (void)setUserIdentifier:(nullable NSString *)identifier CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setUserName:(nullable NSString *)name CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setUserEmail:(nullable NSString *)email CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set a value for a for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *  When setting an object value, the object is converted to a string. This is typically done by calling 
 | 
			
		||||
 *  -[NSObject description].
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The object to be associated with the key
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setObjectValue:(nullable id)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an int value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The integer value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setIntValue:(int)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an BOOL value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The BOOL value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Set an float value for a key to be associated with your crash data which will be visible in the Crashlytics UI.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param value The float value to be set
 | 
			
		||||
 *  @param key   The key with which to associate the value
 | 
			
		||||
 */
 | 
			
		||||
- (void)setFloatValue:(float)value forKey:(NSString *)key;
 | 
			
		||||
 | 
			
		||||
+ (void)setObjectValue:(nullable id)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setIntValue:(int)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
+ (void)setFloatValue:(float)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This method can be used to record a single exception structure in a report. This is particularly useful
 | 
			
		||||
 *  when your code interacts with non-native languages like Lua, C#, or Javascript. This call can be
 | 
			
		||||
 *  expensive and should only be used shortly before process termination. This API is not intended be to used
 | 
			
		||||
 *  to log NSException objects. All safely-reportable NSExceptions are automatically captured by
 | 
			
		||||
 *  Crashlytics.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param name       The name of the custom exception
 | 
			
		||||
 *  @param reason     The reason this exception occured
 | 
			
		||||
 *  @param frameArray An array of CLSStackFrame objects
 | 
			
		||||
 */
 | 
			
		||||
- (void)recordCustomExceptionName:(NSString *)name reason:(nullable NSString *)reason frameArray:(CLS_GENERIC_NSARRAY(CLSStackFrame *) *)frameArray;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * This allows you to record a non-fatal event, described by an NSError object. These events will be grouped and
 | 
			
		||||
 * displayed similarly to crashes. Keep in mind that this method can be expensive. Also, the total number of
 | 
			
		||||
 * NSErrors that can be recorded during your app's life-cycle is limited by a fixed-size circular buffer. If the
 | 
			
		||||
 * buffer is overrun, the oldest data is dropped. Errors are relayed to Crashlytics on a subsequent launch
 | 
			
		||||
 * of your application.
 | 
			
		||||
 *
 | 
			
		||||
 * You can also use the -recordError:withAdditionalUserInfo: to include additional context not represented
 | 
			
		||||
 * by the NSError instance itself.
 | 
			
		||||
 *
 | 
			
		||||
 **/
 | 
			
		||||
- (void)recordError:(NSError *)error;
 | 
			
		||||
- (void)recordError:(NSError *)error withAdditionalUserInfo:(nullable CLS_GENERIC_NSDICTIONARY(NSString *, id) *)userInfo;
 | 
			
		||||
 | 
			
		||||
- (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
- (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
+ (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
+ (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * The CrashlyticsDelegate protocol provides a mechanism for your application to take
 | 
			
		||||
 * action on events that occur in the Crashlytics crash reporting system.  You can make
 | 
			
		||||
 * use of these calls by assigning an object to the Crashlytics' delegate property directly,
 | 
			
		||||
 * or through the convenience +startWithAPIKey:delegate: method.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
@protocol CrashlyticsDelegate <NSObject>
 | 
			
		||||
@optional
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
 | 
			
		||||
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 *  Called when a Crashlytics instance has determined that the last execution of the
 | 
			
		||||
 *  application ended in a crash.  This is called synchronously on Crashlytics
 | 
			
		||||
 *  initialization. Your delegate must invoke the completionHandler, but does not need to do so
 | 
			
		||||
 *  synchronously, or even on the main thread. Invoking completionHandler with NO will cause the
 | 
			
		||||
 *  detected report to be deleted and not submitted to Crashlytics. This is useful for
 | 
			
		||||
 *  implementing permission prompts, or other more-complex forms of logic around submitting crashes.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Failure to invoke the completionHandler will prevent submissions from being reported. Watch out.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Just implementing this delegate method will disable all forms of synchronous report submission. This can
 | 
			
		||||
 *           impact the reliability of reporting crashes very early in application launch.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param report            The CLSReport object representing the last detected crash
 | 
			
		||||
 *  @param completionHandler The completion handler to call when your logic has completed.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  If your app is running on an OS that supports it (OS X 10.9+, iOS 7.0+), Crashlytics will submit
 | 
			
		||||
 *  most reports using out-of-process background networking operations. This results in a significant
 | 
			
		||||
 *  improvement in reliability of reporting, as well as power and performance wins for your users.
 | 
			
		||||
 *  If you don't want this functionality, you can disable by returning NO from this method.
 | 
			
		||||
 *
 | 
			
		||||
 *  @warning Background submission is not supported for extensions on iOS or OS X.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param crashlytics The Crashlytics singleton instance
 | 
			
		||||
 *
 | 
			
		||||
 *  @return Return NO if you don't want out-of-process background network operations.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
- (BOOL)crashlyticsCanUseBackgroundSessions:(Crashlytics *)crashlytics;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, use Crashlytics.sharedInstance()
 | 
			
		||||
 */
 | 
			
		||||
#define CrashlyticsKit [Crashlytics sharedInstance]
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,14 +0,0 @@
 | 
			
		||||
framework module Crashlytics {
 | 
			
		||||
    header "Crashlytics.h"
 | 
			
		||||
    header "Answers.h"
 | 
			
		||||
    header "ANSCompatibility.h"
 | 
			
		||||
    header "CLSLogging.h"
 | 
			
		||||
    header "CLSReport.h"
 | 
			
		||||
    header "CLSStackFrame.h"
 | 
			
		||||
    header "CLSAttributes.h"
 | 
			
		||||
 | 
			
		||||
    export *
 | 
			
		||||
 | 
			
		||||
    link "z"
 | 
			
		||||
    link "c++"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
#  run
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2015 Crashlytics. All rights reserved.
 | 
			
		||||
 | 
			
		||||
#  Figure out where we're being called from
 | 
			
		||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
 | 
			
		||||
 | 
			
		||||
#  Quote path in case of spaces or special chars
 | 
			
		||||
DIR="\"${DIR}"
 | 
			
		||||
 | 
			
		||||
PATH_SEP="/"
 | 
			
		||||
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
 | 
			
		||||
UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
 | 
			
		||||
 | 
			
		||||
#  Ensure params are as expected, run in sync mode to validate
 | 
			
		||||
eval $DIR$PATH_SEP$VALIDATE_COMMAND
 | 
			
		||||
return_code=$?
 | 
			
		||||
 | 
			
		||||
if [[ $return_code != 0 ]]; then
 | 
			
		||||
  exit $return_code
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#  Verification passed, upload dSYM in background to prevent Xcode from waiting
 | 
			
		||||
#  Note: Validation is performed again before upload.
 | 
			
		||||
#  Output can still be found in Console.app
 | 
			
		||||
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 &
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								platform-darwin/External/iOS/Fabric.framework/Fabric
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								platform-darwin/External/iOS/Fabric.framework/Fabric
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1,60 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  FABAttributes.h
 | 
			
		||||
//  Fabric
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (C) 2015 Twitter, Inc.
 | 
			
		||||
//
 | 
			
		||||
//  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
//  you may not use this file except in compliance with the License.
 | 
			
		||||
//  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
//  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
//  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
//  See the License for the specific language governing permissions and
 | 
			
		||||
//  limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define FAB_UNAVAILABLE(x) __attribute__((unavailable(x)))
 | 
			
		||||
 | 
			
		||||
#if __has_feature(nullability)
 | 
			
		||||
    #define fab_nullable           nullable
 | 
			
		||||
    #define fab_nonnull            nonnull
 | 
			
		||||
    #define fab_null_unspecified   null_unspecified
 | 
			
		||||
    #define fab_null_resettable    null_resettable
 | 
			
		||||
    #define __fab_nullable         __nullable
 | 
			
		||||
    #define __fab_nonnull          __nonnull
 | 
			
		||||
    #define __fab_null_unspecified __null_unspecified
 | 
			
		||||
#else
 | 
			
		||||
    #define fab_nullable
 | 
			
		||||
    #define fab_nonnull
 | 
			
		||||
    #define fab_null_unspecified
 | 
			
		||||
    #define fab_null_resettable
 | 
			
		||||
    #define __fab_nullable
 | 
			
		||||
    #define __fab_nonnull
 | 
			
		||||
    #define __fab_null_unspecified
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
    #define NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NS_ASSUME_NONNULL_END
 | 
			
		||||
    #define NS_ASSUME_NONNULL_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The following macros are defined here to provide
 | 
			
		||||
 * backwards compatability. If you are still using
 | 
			
		||||
 * them you should migrate to the new versions that
 | 
			
		||||
 * are defined above.
 | 
			
		||||
 */
 | 
			
		||||
#define FAB_NONNULL       __fab_nonnull
 | 
			
		||||
#define FAB_NULLABLE      __fab_nullable
 | 
			
		||||
#define FAB_START_NONNULL NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
#define FAB_END_NONNULL   NS_ASSUME_NONNULL_END
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Fabric.h
 | 
			
		||||
//  Fabric
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (C) 2015 Twitter, Inc.
 | 
			
		||||
//
 | 
			
		||||
//  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
//  you may not use this file except in compliance with the License.
 | 
			
		||||
//  You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//  http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
//  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
//  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
//  See the License for the specific language governing permissions and
 | 
			
		||||
//  limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
#import "FABAttributes.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IPHONE
 | 
			
		||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000
 | 
			
		||||
    #error "Fabric's minimum iOS version is 6.0"
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
 | 
			
		||||
    #error "Fabric's minimum OS X version is 10.7"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Fabric Base. Coordinates configuration and starts all provided kits.
 | 
			
		||||
 */
 | 
			
		||||
@interface Fabric : NSObject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize Fabric and all provided kits. Call this method within your App Delegate's `application:didFinishLaunchingWithOptions:` and provide the kits you wish to use.
 | 
			
		||||
 *
 | 
			
		||||
 * For example, in Objective-C:
 | 
			
		||||
 *
 | 
			
		||||
 *      `[Fabric with:@[[Crashlytics class], [Twitter class], [Digits class], [MoPub class]]];`
 | 
			
		||||
 *
 | 
			
		||||
 * Swift:
 | 
			
		||||
 *
 | 
			
		||||
 *      `Fabric.with([Crashlytics.self(), Twitter.self(), Digits.self(), MoPub.self()])`
 | 
			
		||||
 *
 | 
			
		||||
 * Only the first call to this method is honored. Subsequent calls are no-ops.
 | 
			
		||||
 *
 | 
			
		||||
 * @param kitClasses An array of kit Class objects
 | 
			
		||||
 *
 | 
			
		||||
 * @return Returns the shared Fabric instance. In most cases this can be ignored.
 | 
			
		||||
 */
 | 
			
		||||
+ (instancetype)with:(NSArray *)kitClasses;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Returns the Fabric singleton object.
 | 
			
		||||
 */
 | 
			
		||||
+ (instancetype)sharedSDK;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  This BOOL enables or disables debug logging, such as kit version information. The default value is NO.
 | 
			
		||||
 */
 | 
			
		||||
@property (nonatomic, assign) BOOL debug;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Unavailable. Use `+sharedSDK` to retrieve the shared Fabric instance.
 | 
			
		||||
 */
 | 
			
		||||
- (id)init FAB_UNAVAILABLE("Use +sharedSDK to retrieve the shared Fabric instance.");
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
<?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>BuildMachineOSBuild</key>
 | 
			
		||||
	<string>14F1021</string>
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>en</string>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>Fabric</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
	<string>io.fabric.sdk.ios</string>
 | 
			
		||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>CFBundleName</key>
 | 
			
		||||
	<string>Fabric</string>
 | 
			
		||||
	<key>CFBundlePackageType</key>
 | 
			
		||||
	<string>FMWK</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>1.6.7</string>
 | 
			
		||||
	<key>CFBundleSignature</key>
 | 
			
		||||
	<string>????</string>
 | 
			
		||||
	<key>CFBundleSupportedPlatforms</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>iPhoneOS</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>53</string>
 | 
			
		||||
	<key>DTCompiler</key>
 | 
			
		||||
	<string>com.apple.compilers.llvm.clang.1_0</string>
 | 
			
		||||
	<key>DTPlatformBuild</key>
 | 
			
		||||
	<string>13C75</string>
 | 
			
		||||
	<key>DTPlatformName</key>
 | 
			
		||||
	<string>iphoneos</string>
 | 
			
		||||
	<key>DTPlatformVersion</key>
 | 
			
		||||
	<string>9.2</string>
 | 
			
		||||
	<key>DTSDKBuild</key>
 | 
			
		||||
	<string>13C75</string>
 | 
			
		||||
	<key>DTSDKName</key>
 | 
			
		||||
	<string>iphoneos9.2</string>
 | 
			
		||||
	<key>DTXcode</key>
 | 
			
		||||
	<string>0721</string>
 | 
			
		||||
	<key>DTXcodeBuild</key>
 | 
			
		||||
	<string>7C1002</string>
 | 
			
		||||
	<key>MinimumOSVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>NSHumanReadableCopyright</key>
 | 
			
		||||
	<string>Copyright © 2015 Twitter. All rights reserved.</string>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<integer>3</integer>
 | 
			
		||||
		<integer>2</integer>
 | 
			
		||||
		<integer>1</integer>
 | 
			
		||||
		<integer>4</integer>
 | 
			
		||||
	</array>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
framework module Fabric {
 | 
			
		||||
    umbrella header "Fabric.h"
 | 
			
		||||
 | 
			
		||||
    export *
 | 
			
		||||
    module * { export * }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
#  run
 | 
			
		||||
#
 | 
			
		||||
#  Copyright (c) 2015 Crashlytics. All rights reserved.
 | 
			
		||||
 | 
			
		||||
#  Figure out where we're being called from
 | 
			
		||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
 | 
			
		||||
 | 
			
		||||
#  Quote path in case of spaces or special chars
 | 
			
		||||
DIR="\"${DIR}"
 | 
			
		||||
 | 
			
		||||
PATH_SEP="/"
 | 
			
		||||
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
 | 
			
		||||
UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
 | 
			
		||||
 | 
			
		||||
#  Ensure params are as expected, run in sync mode to validate
 | 
			
		||||
eval $DIR$PATH_SEP$VALIDATE_COMMAND
 | 
			
		||||
return_code=$?
 | 
			
		||||
 | 
			
		||||
if [[ $return_code != 0 ]]; then
 | 
			
		||||
  exit $return_code
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
#  Verification passed, upload dSYM in background to prevent Xcode from waiting
 | 
			
		||||
#  Note: Validation is performed again before upload.
 | 
			
		||||
#  Output can still be found in Console.app
 | 
			
		||||
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 &
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -65,6 +65,7 @@
 | 
			
		||||
		93D39E5F7F6D7F5C0FAD090F /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D72239990DDAC2D75B0 /* MPTypes.m */; };
 | 
			
		||||
		93D39EAA4D064193074D3021 /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A813CA9D7E192261ED2 /* MPFixable.m */; };
 | 
			
		||||
		93D39F8A9254177891F38705 /* MPSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A28369954D147E239BA /* MPSetupViewController.m */; };
 | 
			
		||||
		94CD3CD602014A9DC121FDA8 /* Pods_MasterPassword.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D74842A13757EDC1F047D9B4 /* Pods_MasterPassword.framework */; };
 | 
			
		||||
		DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
 | 
			
		||||
		DA071BF3190187FE00179766 /* empty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF1190187FE00179766 /* empty@2x.png */; };
 | 
			
		||||
		DA071BF4190187FE00179766 /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF2190187FE00179766 /* empty.png */; };
 | 
			
		||||
@@ -85,9 +86,6 @@
 | 
			
		||||
		DA0CC5361EAB99BA009A8ED9 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5241EAB99BA009A8ED9 /* IASKTextField.m */; };
 | 
			
		||||
		DA0CC5371EAB99BA009A8ED9 /* IASKTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */; };
 | 
			
		||||
		DA0CC5381EAB99BA009A8ED9 /* IASKTextViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */; };
 | 
			
		||||
		DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */; };
 | 
			
		||||
		DA0CC5411EB57BD4009A8ED9 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */; };
 | 
			
		||||
		DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA141191922FED80032B392 /* Crashlytics.framework */; };
 | 
			
		||||
		DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5441EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld */; };
 | 
			
		||||
		DA0CC58C1EB6B030009A8ED9 /* MPGeneratedSiteEntity+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5791EB6B030009A8ED9 /* MPGeneratedSiteEntity+CoreDataClass.m */; };
 | 
			
		||||
		DA0CC58D1EB6B030009A8ED9 /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC57B1EB6B030009A8ED9 /* MPGeneratedSiteEntity+CoreDataProperties.m */; };
 | 
			
		||||
@@ -171,6 +169,7 @@
 | 
			
		||||
		DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
 | 
			
		||||
		DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
 | 
			
		||||
		DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
 | 
			
		||||
		DA46021D23D5E30B00398FF4 /* MPSecrets.m in Sources */ = {isa = PBXBuildFile; fileRef = DA46021C23D5E30B00398FF4 /* MPSecrets.m */; };
 | 
			
		||||
		DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
 | 
			
		||||
		DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
 | 
			
		||||
		DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
 | 
			
		||||
@@ -496,6 +495,7 @@
 | 
			
		||||
/* End PBXCopyFilesBuildPhase section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
		5C616FA365D7A5C31689B2FF /* Pods-MasterPassword.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.test.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.test.xcconfig"; sourceTree = "<group>"; };
 | 
			
		||||
		93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
 | 
			
		||||
		93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionView+PearlReloadItems.m"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -589,6 +589,7 @@
 | 
			
		||||
		93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
 | 
			
		||||
		93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
 | 
			
		||||
		93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
 | 
			
		||||
		D74842A13757EDC1F047D9B4 /* Pods_MasterPassword.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MasterPassword.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
 | 
			
		||||
		DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; };
 | 
			
		||||
@@ -640,8 +641,6 @@
 | 
			
		||||
		DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextView.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC5271EAB99BA009A8ED9 /* IASKTextViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextViewCell.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextViewCell.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Fabric.plist; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC5451EB6AD0E009A8ED9 /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC5461EB6AD0E009A8ED9 /* MasterPassword 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 2.xcdatamodel"; sourceTree = "<group>"; };
 | 
			
		||||
		DA0CC5471EB6AD0E009A8ED9 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -704,7 +703,6 @@
 | 
			
		||||
		DA29992D19C86F5700AF7DF1 /* thumb_generated_login@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_login@2x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA29992E19C86F5700AF7DF1 /* thumb_generated_login.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_generated_login.png; sourceTree = "<group>"; };
 | 
			
		||||
		DA29993119C9132F00AF7DF1 /* thumb_generated_login@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_login@3x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA2C3D601BD95EEE001137B3 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Fabric.framework; path = ../../../External/iOS/Fabric.framework; sourceTree = "<group>"; };
 | 
			
		||||
		DA2C3D621BD96126001137B3 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
 | 
			
		||||
		DA2C3D641BD9612F001137B3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
 | 
			
		||||
		DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -735,7 +733,6 @@
 | 
			
		||||
		DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; };
 | 
			
		||||
		DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA3B844D190FC5DF00246EEA /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = ../../../External/iOS/Crashlytics.framework; sourceTree = "<group>"; };
 | 
			
		||||
		DA351486233EF8FE00BCF504 /* mpw-algorithm_v2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm_v2.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DA351487233EF8FE00BCF504 /* mpw-algorithm_v1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm_v1.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DA351488233EF8FE00BCF504 /* mpw-algorithm_v3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm_v3.h"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -743,6 +740,8 @@
 | 
			
		||||
		DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Regular.otf"; sourceTree = "<group>"; };
 | 
			
		||||
		DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA45711C1F572F1E00D54152 /* PearlCryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlCryptUtils.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA46021B23D5E30B00398FF4 /* MPSecrets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSecrets.h; sourceTree = "<group>"; };
 | 
			
		||||
		DA46021C23D5E30B00398FF4 /* MPSecrets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSecrets.m; sourceTree = "<group>"; };
 | 
			
		||||
		DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
 | 
			
		||||
		DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
 | 
			
		||||
		DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; };
 | 
			
		||||
@@ -773,7 +772,6 @@
 | 
			
		||||
		DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableSet+Pearl.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableSet+Pearl.m"; sourceTree = "<group>"; };
 | 
			
		||||
		DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };
 | 
			
		||||
		DAA141191922FED80032B392 /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
 | 
			
		||||
		DAA1411C1922FF020032B392 /* PearlTween.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlTween.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAA1411D1922FF020032B392 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAA1411F1922FF020032B392 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
 | 
			
		||||
@@ -1685,6 +1683,8 @@
 | 
			
		||||
		DAFE4A63150399FF003ABA8F /* UIScrollView+PearlFlashingIndicators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+PearlFlashingIndicators.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDateFormatter+RFC3339.m"; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDateFormatter+RFC3339.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DC2D4B0016EB0A535147BA13 /* Pods-MasterPassword.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.release.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.release.xcconfig"; sourceTree = "<group>"; };
 | 
			
		||||
		FE662C1B92299C911450537C /* Pods-MasterPassword.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MasterPassword.debug.xcconfig"; path = "Target Support Files/Pods-MasterPassword/Pods-MasterPassword.debug.xcconfig"; sourceTree = "<group>"; };
 | 
			
		||||
/* End PBXFileReference section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFrameworksBuildPhase section */
 | 
			
		||||
@@ -1705,7 +1705,6 @@
 | 
			
		||||
				DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
 | 
			
		||||
				DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
 | 
			
		||||
				DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
 | 
			
		||||
				DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
 | 
			
		||||
				DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
 | 
			
		||||
				DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */,
 | 
			
		||||
				DAE2725A19C93B8E007C5262 /* StoreKit.framework in Frameworks */,
 | 
			
		||||
@@ -1722,7 +1721,7 @@
 | 
			
		||||
				DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */,
 | 
			
		||||
				DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */,
 | 
			
		||||
				DA5BFA4F147E415C00F98B1E /* CoreData.framework in Frameworks */,
 | 
			
		||||
				DA0CC5411EB57BD4009A8ED9 /* Fabric.framework in Frameworks */,
 | 
			
		||||
				94CD3CD602014A9DC121FDA8 /* Pods_MasterPassword.framework in Frameworks */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
@@ -1770,6 +1769,16 @@
 | 
			
		||||
/* End PBXFrameworksBuildPhase section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXGroup section */
 | 
			
		||||
		6B6983E746CC7BE4292982AE /* Pods */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				FE662C1B92299C911450537C /* Pods-MasterPassword.debug.xcconfig */,
 | 
			
		||||
				DC2D4B0016EB0A535147BA13 /* Pods-MasterPassword.release.xcconfig */,
 | 
			
		||||
				5C616FA365D7A5C31689B2FF /* Pods-MasterPassword.test.xcconfig */,
 | 
			
		||||
			);
 | 
			
		||||
			path = Pods;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		93D39A2239FFFE6BEC83E191 /* core */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
@@ -1862,14 +1871,6 @@
 | 
			
		||||
			path = Views;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		DA0CC5391EB57B5C009A8ED9 /* Fabric */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DA0CC53A1EB57B5C009A8ED9 /* Fabric.plist */,
 | 
			
		||||
			);
 | 
			
		||||
			path = Fabric;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		DA24EBB019DAD4D000FF010B /* ios */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
@@ -1966,6 +1967,7 @@
 | 
			
		||||
				DA5BFA45147E415C00F98B1E /* Products */,
 | 
			
		||||
				DACA23B41705DF7D002C6C22 /* Resources */,
 | 
			
		||||
				DABD3B9F1711E2DB00CF925C /* Source */,
 | 
			
		||||
				6B6983E746CC7BE4292982AE /* Pods */,
 | 
			
		||||
			);
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
@@ -1992,8 +1994,6 @@
 | 
			
		||||
				DA5BFA4E147E415C00F98B1E /* CoreData.framework */,
 | 
			
		||||
				DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */,
 | 
			
		||||
				DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */,
 | 
			
		||||
				DA3B844D190FC5DF00246EEA /* Crashlytics.framework */,
 | 
			
		||||
				DA2C3D601BD95EEE001137B3 /* Fabric.framework */,
 | 
			
		||||
				DA5BFA4A147E415C00F98B1E /* Foundation.framework */,
 | 
			
		||||
				DA2C3D621BD96126001137B3 /* libc++.tbd */,
 | 
			
		||||
				DA2C3D641BD9612F001137B3 /* libz.tbd */,
 | 
			
		||||
@@ -2007,6 +2007,7 @@
 | 
			
		||||
				DABB981515100B4000B05417 /* SystemConfiguration.framework */,
 | 
			
		||||
				93D394077F8FAB8167647187 /* Twitter.framework */,
 | 
			
		||||
				DA5BFA48147E415C00F98B1E /* UIKit.framework */,
 | 
			
		||||
				D74842A13757EDC1F047D9B4 /* Pods_MasterPassword.framework */,
 | 
			
		||||
			);
 | 
			
		||||
			name = Frameworks;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
@@ -2014,8 +2015,6 @@
 | 
			
		||||
		DAA141181922FED80032B392 /* iOS */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DA0CC53F1EB57B91009A8ED9 /* Fabric.framework */,
 | 
			
		||||
				DAA141191922FED80032B392 /* Crashlytics.framework */,
 | 
			
		||||
			);
 | 
			
		||||
			path = iOS;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
@@ -2954,7 +2953,6 @@
 | 
			
		||||
		DABD3BD71711E2DC00CF925C /* iOS */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */,
 | 
			
		||||
				DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */,
 | 
			
		||||
				DABD3BFC1711E2DC00CF925C /* main.m */,
 | 
			
		||||
				DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */,
 | 
			
		||||
@@ -2987,20 +2985,22 @@
 | 
			
		||||
				93D39CC01630D0421205C4C4 /* MPNavigationController.m */,
 | 
			
		||||
				93D39B455A71EC98C749E623 /* MPOverlayViewController.h */,
 | 
			
		||||
				93D395105935859D71679931 /* MPOverlayViewController.m */,
 | 
			
		||||
				93D39975CE5AEC99E3F086C7 /* MPSiteCell.h */,
 | 
			
		||||
				93D39DEA995041A13DC9CAF7 /* MPSiteCell.m */,
 | 
			
		||||
				93D39C44361BE57AF0B3071F /* MPSitesSegue.h */,
 | 
			
		||||
				93D39E7A12CC352B2825AA66 /* MPSitesSegue.m */,
 | 
			
		||||
				93D3914D7597F9A28DB9D85E /* MPSitesViewController.h */,
 | 
			
		||||
				93D3924EE15017F8A12CB436 /* MPSitesViewController.m */,
 | 
			
		||||
				93D392876BE5C011DE73B43F /* MPPopdownSegue.h */,
 | 
			
		||||
				93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */,
 | 
			
		||||
				DABD3BEA1711E2DC00CF925C /* MPPreferencesViewController.h */,
 | 
			
		||||
				DABD3BEB1711E2DC00CF925C /* MPPreferencesViewController.m */,
 | 
			
		||||
				93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */,
 | 
			
		||||
				93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */,
 | 
			
		||||
				DA46021B23D5E30B00398FF4 /* MPSecrets.h */,
 | 
			
		||||
				DA46021C23D5E30B00398FF4 /* MPSecrets.m */,
 | 
			
		||||
				93D39730673227EFF6DEFF19 /* MPSetupViewController.h */,
 | 
			
		||||
				93D39A28369954D147E239BA /* MPSetupViewController.m */,
 | 
			
		||||
				93D39975CE5AEC99E3F086C7 /* MPSiteCell.h */,
 | 
			
		||||
				93D39DEA995041A13DC9CAF7 /* MPSiteCell.m */,
 | 
			
		||||
				93D39C44361BE57AF0B3071F /* MPSitesSegue.h */,
 | 
			
		||||
				93D39E7A12CC352B2825AA66 /* MPSitesSegue.m */,
 | 
			
		||||
				93D3914D7597F9A28DB9D85E /* MPSitesViewController.h */,
 | 
			
		||||
				93D3924EE15017F8A12CB436 /* MPSitesViewController.m */,
 | 
			
		||||
				93D39149A5F1F9B174D6D061 /* MPStoreViewController.h */,
 | 
			
		||||
				93D3957D76F71A652716EECC /* MPStoreViewController.m */,
 | 
			
		||||
				DABD3BEC1711E2DC00CF925C /* MPTypeViewController.h */,
 | 
			
		||||
@@ -3010,6 +3010,7 @@
 | 
			
		||||
				93D39F556F2F142740A65E59 /* MPWebViewController.h */,
 | 
			
		||||
				93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
 | 
			
		||||
				DABD3BF91711E2DC00CF925C /* Settings.bundle */,
 | 
			
		||||
				DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */,
 | 
			
		||||
			);
 | 
			
		||||
			path = iOS;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
@@ -3044,7 +3045,6 @@
 | 
			
		||||
		DACA23B41705DF7D002C6C22 /* Resources */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DA0CC5391EB57B5C009A8ED9 /* Fabric */,
 | 
			
		||||
				DACA29701705E1A8002C6C22 /* Data */,
 | 
			
		||||
				DAE1EF2417E942DE00BC0086 /* Localizable.strings */,
 | 
			
		||||
				DABD360D1711E29400CF925C /* Media */,
 | 
			
		||||
@@ -3442,12 +3442,13 @@
 | 
			
		||||
			isa = PBXNativeTarget;
 | 
			
		||||
			buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
 | 
			
		||||
			buildPhases = (
 | 
			
		||||
				B8D66904C16DDB94975E6ABD /* [CP] Check Pods Manifest.lock */,
 | 
			
		||||
				DA8D88E019DA412A00B189D0 /* Run Script: genassets */,
 | 
			
		||||
				DA5BFA40147E415C00F98B1E /* Sources */,
 | 
			
		||||
				DA5BFA41147E415C00F98B1E /* Frameworks */,
 | 
			
		||||
				DA5BFA42147E415C00F98B1E /* Resources */,
 | 
			
		||||
				DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */,
 | 
			
		||||
				DAD3125D155288AA00A3F9ED /* Run Script: Fabric */,
 | 
			
		||||
				4A87858EE3659604089E2F9F /* [CP] Embed Pods Frameworks */,
 | 
			
		||||
			);
 | 
			
		||||
			buildRules = (
 | 
			
		||||
			);
 | 
			
		||||
@@ -3722,7 +3723,6 @@
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
				DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
 | 
			
		||||
				DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
 | 
			
		||||
				DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
 | 
			
		||||
				DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
 | 
			
		||||
				DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
 | 
			
		||||
@@ -3906,6 +3906,48 @@
 | 
			
		||||
/* End PBXResourcesBuildPhase section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXShellScriptBuildPhase section */
 | 
			
		||||
		4A87858EE3659604089E2F9F /* [CP] Embed Pods Frameworks */ = {
 | 
			
		||||
			isa = PBXShellScriptBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
			);
 | 
			
		||||
			inputPaths = (
 | 
			
		||||
				"${PODS_ROOT}/Target Support Files/Pods-MasterPassword/Pods-MasterPassword-frameworks.sh",
 | 
			
		||||
				"${BUILT_PRODUCTS_DIR}/Countly/Countly.framework",
 | 
			
		||||
				"${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework",
 | 
			
		||||
			);
 | 
			
		||||
			name = "[CP] Embed Pods Frameworks";
 | 
			
		||||
			outputPaths = (
 | 
			
		||||
				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Countly.framework",
 | 
			
		||||
				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
			shellPath = /bin/sh;
 | 
			
		||||
			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MasterPassword/Pods-MasterPassword-frameworks.sh\"\n";
 | 
			
		||||
			showEnvVarsInLog = 0;
 | 
			
		||||
		};
 | 
			
		||||
		B8D66904C16DDB94975E6ABD /* [CP] Check Pods Manifest.lock */ = {
 | 
			
		||||
			isa = PBXShellScriptBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
			);
 | 
			
		||||
			inputFileListPaths = (
 | 
			
		||||
			);
 | 
			
		||||
			inputPaths = (
 | 
			
		||||
				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
 | 
			
		||||
				"${PODS_ROOT}/Manifest.lock",
 | 
			
		||||
			);
 | 
			
		||||
			name = "[CP] Check Pods Manifest.lock";
 | 
			
		||||
			outputFileListPaths = (
 | 
			
		||||
			);
 | 
			
		||||
			outputPaths = (
 | 
			
		||||
				"$(DERIVED_FILE_DIR)/Pods-MasterPassword-checkManifestLockResult.txt",
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
			shellPath = /bin/sh;
 | 
			
		||||
			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 | 
			
		||||
			showEnvVarsInLog = 0;
 | 
			
		||||
		};
 | 
			
		||||
		DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */ = {
 | 
			
		||||
			isa = PBXShellScriptBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
@@ -3918,7 +3960,7 @@
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
			shellPath = "/bin/sh -e";
 | 
			
		||||
			shellScript = "exec Scripts/updatePlist\n";
 | 
			
		||||
			shellScript = "exec Scripts/updatePlist";
 | 
			
		||||
			showEnvVarsInLog = 0;
 | 
			
		||||
		};
 | 
			
		||||
		DA8D88E019DA412A00B189D0 /* Run Script: genassets */ = {
 | 
			
		||||
@@ -3949,21 +3991,6 @@
 | 
			
		||||
			shellPath = /bin/sh;
 | 
			
		||||
			shellScript = "";
 | 
			
		||||
		};
 | 
			
		||||
		DAD3125D155288AA00A3F9ED /* Run Script: Fabric */ = {
 | 
			
		||||
			isa = PBXShellScriptBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
			);
 | 
			
		||||
			inputPaths = (
 | 
			
		||||
			);
 | 
			
		||||
			name = "Run Script: Fabric";
 | 
			
		||||
			outputPaths = (
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
			shellPath = "/bin/bash -e";
 | 
			
		||||
			shellScript = "[[ $DEPLOYMENT_LOCATION != YES ]] && exit\n\napiKey=$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" Resources/Fabric/Fabric.plist)\n[[ $apiKey ]] && External/iOS/Fabric.framework/run \"$apiKey\"";
 | 
			
		||||
			showEnvVarsInLog = 0;
 | 
			
		||||
		};
 | 
			
		||||
/* End PBXShellScriptBuildPhase section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXSourcesBuildPhase section */
 | 
			
		||||
@@ -4028,6 +4055,7 @@
 | 
			
		||||
				93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
 | 
			
		||||
				93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
 | 
			
		||||
				93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
 | 
			
		||||
				DA46021D23D5E30B00398FF4 /* MPSecrets.m in Sources */,
 | 
			
		||||
				93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
 | 
			
		||||
				93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
 | 
			
		||||
				93D392FD5E2052F7D7DB3774 /* NSString+MPMarkDown.m in Sources */,
 | 
			
		||||
@@ -4294,9 +4322,7 @@
 | 
			
		||||
				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 | 
			
		||||
				GCC_PREPROCESSOR_DEFINITIONS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"NDEBUG=1",
 | 
			
		||||
					"NS_BLOCK_ASSERTIONS=1",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_UIKIT,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
@@ -4347,6 +4373,7 @@
 | 
			
		||||
		};
 | 
			
		||||
		DA09744A1E95703B00F0BFE8 /* Test */ = {
 | 
			
		||||
			isa = XCBuildConfiguration;
 | 
			
		||||
			baseConfigurationReference = 5C616FA365D7A5C31689B2FF /* Pods-MasterPassword.test.xcconfig */;
 | 
			
		||||
			buildSettings = {
 | 
			
		||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
			
		||||
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 | 
			
		||||
@@ -4508,7 +4535,6 @@
 | 
			
		||||
				GCC_PREPROCESSOR_DEFINITIONS = (
 | 
			
		||||
					"DEBUG=1",
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_UIKIT,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
@@ -4612,9 +4638,8 @@
 | 
			
		||||
				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 | 
			
		||||
				GCC_PREPROCESSOR_DEFINITIONS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"NDEBUG=1",
 | 
			
		||||
					"PUBLIC=1",
 | 
			
		||||
					"NS_BLOCK_ASSERTIONS=1",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_UIKIT,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
@@ -4665,6 +4690,7 @@
 | 
			
		||||
		};
 | 
			
		||||
		DA5BFA6E147E415C00F98B1E /* Debug */ = {
 | 
			
		||||
			isa = XCBuildConfiguration;
 | 
			
		||||
			baseConfigurationReference = FE662C1B92299C911450537C /* Pods-MasterPassword.debug.xcconfig */;
 | 
			
		||||
			buildSettings = {
 | 
			
		||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
			
		||||
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 | 
			
		||||
@@ -4707,6 +4733,7 @@
 | 
			
		||||
		};
 | 
			
		||||
		DA5BFA6F147E415C00F98B1E /* Release */ = {
 | 
			
		||||
			isa = XCBuildConfiguration;
 | 
			
		||||
			baseConfigurationReference = DC2D4B0016EB0A535147BA13 /* Pods-MasterPassword.release.xcconfig */;
 | 
			
		||||
			buildSettings = {
 | 
			
		||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
			
		||||
				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 | 
			
		||||
 
 | 
			
		||||
@@ -2999,7 +2999,6 @@
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"NDEBUG=1",
 | 
			
		||||
					"NS_BLOCK_ASSERTIONS=1",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_COCOA,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
@@ -3388,7 +3387,6 @@
 | 
			
		||||
				GCC_PREPROCESSOR_DEFINITIONS = (
 | 
			
		||||
					"DEBUG=1",
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_COCOA,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
@@ -3489,7 +3487,6 @@
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
					"NDEBUG=1",
 | 
			
		||||
					"NS_BLOCK_ASSERTIONS=1",
 | 
			
		||||
					"CRASHLYTICS=1",
 | 
			
		||||
					PEARL,
 | 
			
		||||
					PEARL_COCOA,
 | 
			
		||||
					PEARL_CRYPTO,
 | 
			
		||||
 
 | 
			
		||||
@@ -10,4 +10,7 @@
 | 
			
		||||
   <FileRef
 | 
			
		||||
      location = "group:MasterPassword-macOS.xcodeproj">
 | 
			
		||||
   </FileRef>
 | 
			
		||||
   <FileRef
 | 
			
		||||
      location = "group:Pods/Pods.xcodeproj">
 | 
			
		||||
   </FileRef>
 | 
			
		||||
</Workspace>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								platform-darwin/Podfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								platform-darwin/Podfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
workspace 'MasterPassword'
 | 
			
		||||
project 'MasterPassword-iOS'
 | 
			
		||||
 | 
			
		||||
platform :ios, '9.3'
 | 
			
		||||
 | 
			
		||||
target 'MasterPassword' do
 | 
			
		||||
  use_modular_headers!
 | 
			
		||||
  use_frameworks!
 | 
			
		||||
 | 
			
		||||
  pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git'
 | 
			
		||||
  pod 'Countly'
 | 
			
		||||
end
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
<?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>API Key</key>
 | 
			
		||||
	<string></string>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
@@ -54,17 +54,3 @@ setPlistWithKey CFBundleShortVersionString "$version"
 | 
			
		||||
setSettingWithTitle "Build" "$commit"
 | 
			
		||||
setSettingWithTitle "Version" "$version"
 | 
			
		||||
setSettingWithTitle "Copyright" "$(getPlistWithKey NSHumanReadableCopyright)"
 | 
			
		||||
 | 
			
		||||
if [[ $DEPLOYMENT_LOCATION = YES ]]; then
 | 
			
		||||
    # This build is a release.  Do some release checks.
 | 
			
		||||
    fabricPlist="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/Fabric.plist"
 | 
			
		||||
    passed=1
 | 
			
		||||
    [[ $description != *-dirty ]] || \
 | 
			
		||||
        { passed=0; err 'ERROR: Cannot release a dirty version, first commit any changes.'; }
 | 
			
		||||
    [[ $build == 0 ]] || \
 | 
			
		||||
        { passed=0; err 'ERROR: Commit is not tagged for release, first tag accordingly.'; }
 | 
			
		||||
    [[ -r "$fabricPlist" && $(PlistBuddy -c "Print :'API Key'" "$fabricPlist" 2>/dev/null) ]] || \
 | 
			
		||||
        { passed=0; err 'ERROR: Cannot release: Fabric API key is missing.'; }
 | 
			
		||||
    (( passed )) || \
 | 
			
		||||
        { ftl "Failed to pass release checks.  Fix the above errors and re-try.  Aborting."; exit 1; }
 | 
			
		||||
fi
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import "MPAppDelegate_InApp.h"
 | 
			
		||||
#import <Countly/Countly.h>
 | 
			
		||||
 | 
			
		||||
@interface MPAppDelegate_Shared(InApp_Private)<SKProductsRequestDelegate, SKPaymentTransactionObserver>
 | 
			
		||||
@end
 | 
			
		||||
@@ -204,13 +205,16 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
 | 
			
		||||
                [queue finishTransaction:transaction];
 | 
			
		||||
 | 
			
		||||
                if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
                    SKProduct *product = self.products[transaction.payment.productIdentifier];
 | 
			
		||||
                    for (int q = 0; q < transaction.payment.quantity; ++q)
 | 
			
		||||
                        [Answers logPurchaseWithPrice:product.price currency:[product.priceLocale objectForKey:NSLocaleCurrencyCode]
 | 
			
		||||
                                              success:@YES itemName:product.localizedTitle itemType:@"InApp"
 | 
			
		||||
                                               itemId:product.productIdentifier customAttributes:attributes];
 | 
			
		||||
#endif
 | 
			
		||||
                    [attributes addEntriesFromDictionary:@{
 | 
			
		||||
                            @"id": product.productIdentifier,
 | 
			
		||||
                            @"name": product.localizedTitle,
 | 
			
		||||
                            @"price": product.price.description,
 | 
			
		||||
                            @"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
 | 
			
		||||
                            @"state"   : @"success",
 | 
			
		||||
                            @"quantity": @(transaction.payment.quantity).description,
 | 
			
		||||
                    }];
 | 
			
		||||
                    [Countly.sharedInstance recordEvent:@"purchase" segmentation:attributes];
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
@@ -229,16 +233,16 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
 | 
			
		||||
                [queue finishTransaction:transaction];
 | 
			
		||||
 | 
			
		||||
                if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
                    SKProduct *product = self.products[transaction.payment.productIdentifier];
 | 
			
		||||
                    [Answers logPurchaseWithPrice:product.price currency:[product.priceLocale objectForKey:NSLocaleCurrencyCode]
 | 
			
		||||
                                          success:@NO itemName:product.localizedTitle itemType:@"InApp" itemId:product.productIdentifier
 | 
			
		||||
                                 customAttributes:@{
 | 
			
		||||
                                         @"state"   : @"Failed",
 | 
			
		||||
                                         @"quantity": @(transaction.payment.quantity),
 | 
			
		||||
                                         @"reason"  : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
 | 
			
		||||
                                 }];
 | 
			
		||||
#endif
 | 
			
		||||
                    [Countly.sharedInstance recordEvent:@"purchase" segmentation:@{
 | 
			
		||||
                            @"id": product.productIdentifier,
 | 
			
		||||
                            @"name": product.localizedTitle,
 | 
			
		||||
                            @"price": product.price.description,
 | 
			
		||||
                            @"currency": [product.priceLocale objectForKey:NSLocaleCurrencyCode],
 | 
			
		||||
                            @"state"   : @"failed",
 | 
			
		||||
                            @"quantity": @(transaction.payment.quantity).description,
 | 
			
		||||
                            @"reason"  : [transaction.error localizedFailureReason]?: [transaction.error localizedDescription],
 | 
			
		||||
                    }];
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,8 @@
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import <Crashlytics/Answers.h>
 | 
			
		||||
#import <Countly/Countly.h>
 | 
			
		||||
 | 
			
		||||
#import "MPAppDelegate_Key.h"
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
 | 
			
		||||
@@ -122,6 +123,10 @@
 | 
			
		||||
    if (self.key)
 | 
			
		||||
        self.key = nil;
 | 
			
		||||
 | 
			
		||||
    if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
        [Countly.sharedInstance userLoggedOut];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    self.activeUser = nil;
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] postNotificationName:MPSignedOutNotification object:self userInfo:@{ @"animated": @(animated) }];
 | 
			
		||||
}
 | 
			
		||||
@@ -180,11 +185,11 @@
 | 
			
		||||
            dbg( @"Automatic login failed for user: %@", user.userID );
 | 
			
		||||
 | 
			
		||||
        if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
            [Answers logLoginWithMethod:password? @"Password": @"Automatic" success:@NO customAttributes:@{
 | 
			
		||||
                    @"algorithm": @(user.algorithm.version),
 | 
			
		||||
            [Countly.sharedInstance recordEvent:@"login" segmentation:@{
 | 
			
		||||
                    @"method"   : password? @"Password": @"Automatic",
 | 
			
		||||
                    @"state"  : @"failed",
 | 
			
		||||
                    @"algorithm": @(user.algorithm.version).description,
 | 
			
		||||
            }];
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return NO;
 | 
			
		||||
@@ -207,13 +212,13 @@
 | 
			
		||||
 | 
			
		||||
    @try {
 | 
			
		||||
        if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
            [[Crashlytics sharedInstance] setUserName:user.userID];
 | 
			
		||||
            [Countly.sharedInstance userLoggedIn:user.userID];
 | 
			
		||||
 | 
			
		||||
            [Answers logLoginWithMethod:password? @"Password": @"Automatic" success:@YES customAttributes:@{
 | 
			
		||||
                    @"algorithm": @(user.algorithm.version),
 | 
			
		||||
            [Countly.sharedInstance recordEvent:@"login" segmentation:@{
 | 
			
		||||
                    @"method"   : password? @"Password": @"Automatic",
 | 
			
		||||
                    @"state"  : @"success",
 | 
			
		||||
                    @"algorithm": @(user.algorithm.version).description,
 | 
			
		||||
            }];
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @catch (id exception) {
 | 
			
		||||
 
 | 
			
		||||
@@ -216,7 +216,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
 | 
			
		||||
        self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
 | 
			
		||||
        self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
 | 
			
		||||
        if (@available(iOS 10.0, macOS 10.12, *))
 | 
			
		||||
        if (@available( iOS 10.0, macOS 10.12, * ))
 | 
			
		||||
            self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
 | 
			
		||||
        else
 | 
			
		||||
            // When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
 | 
			
		||||
@@ -565,38 +565,51 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
           saveInContext:(NSManagedObjectContext *)context {
 | 
			
		||||
 | 
			
		||||
    // Read metadata for the import file.
 | 
			
		||||
    MPMarshalledInfo *info = mpw_marshal_read( importData.UTF8String );
 | 
			
		||||
    if (info->format == MPMarshalFormatNone)
 | 
			
		||||
    MPMarshalledFile *file = mpw_marshal_read( NULL, importData.UTF8String );
 | 
			
		||||
    if (!file)
 | 
			
		||||
        return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
 | 
			
		||||
                @"type"                  : @(MPMarshalErrorInternal),
 | 
			
		||||
                NSLocalizedDescriptionKey: @"Could not process Master Password import data.",
 | 
			
		||||
        }]), @"While importing sites." );
 | 
			
		||||
    if (file->error.type != MPMarshalSuccess) {
 | 
			
		||||
        MPMarshalErrorType type = file->error.type;
 | 
			
		||||
        mpw_marshal_file_free( &file );
 | 
			
		||||
        return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
 | 
			
		||||
                @"type"                  : @(type),
 | 
			
		||||
                NSLocalizedDescriptionKey: @"Could not parse Master Password import data.",
 | 
			
		||||
        }]), @"While importing sites." );
 | 
			
		||||
    }
 | 
			
		||||
    if (file->info->format == MPMarshalFormatNone) {
 | 
			
		||||
        mpw_marshal_file_free( &file );
 | 
			
		||||
        return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
 | 
			
		||||
                @"type"                  : @(MPMarshalErrorFormat),
 | 
			
		||||
                NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
 | 
			
		||||
        }]), @"While importing sites." );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get master password for import file.
 | 
			
		||||
    MPKey *importKey;
 | 
			
		||||
    NSString *importMasterPassword;
 | 
			
		||||
    do {
 | 
			
		||||
        importMasterPassword = askImportPassword( @(info->fullName) );
 | 
			
		||||
        importMasterPassword = askImportPassword( @(file->info->fullName) );
 | 
			
		||||
        if (!importMasterPassword) {
 | 
			
		||||
            inf( @"Import cancelled." );
 | 
			
		||||
            mpw_marshal_info_free( &info );
 | 
			
		||||
            mpw_marshal_file_free( &file );
 | 
			
		||||
            return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        importKey = [[MPKey alloc] initForFullName:@(info->fullName) withMasterPassword:importMasterPassword];
 | 
			
		||||
    } while ([[[importKey keyIDForAlgorithm:MPAlgorithmForVersion( info->algorithm )] encodeHex]
 | 
			
		||||
                            caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
 | 
			
		||||
        importKey = [[MPKey alloc] initForFullName:@(file->info->fullName) withMasterPassword:importMasterPassword];
 | 
			
		||||
    } while ([[[importKey keyIDForAlgorithm:MPAlgorithmForVersion( file->info->algorithm )] encodeHex]
 | 
			
		||||
                     caseInsensitiveCompare:@(file->info->keyID)] != NSOrderedSame);
 | 
			
		||||
 | 
			
		||||
    // Parse import data.
 | 
			
		||||
    MPMarshalError importError = { .type = MPMarshalSuccess };
 | 
			
		||||
    MPMarshalledUser *importUser = mpw_marshal_auth( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
 | 
			
		||||
    mpw_marshal_info_free( &info );
 | 
			
		||||
    MPMarshalledUser *importUser = mpw_marshal_auth( file, mpw_masterKeyProvider_str( importMasterPassword.UTF8String ) );
 | 
			
		||||
 | 
			
		||||
    @try {
 | 
			
		||||
        if (!importUser || importError.type != MPMarshalSuccess)
 | 
			
		||||
        if (!importUser || file->error.type != MPMarshalSuccess)
 | 
			
		||||
            return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
 | 
			
		||||
                    @"type"                  : @(importError.type),
 | 
			
		||||
                    NSLocalizedDescriptionKey: @(importError.description),
 | 
			
		||||
                    @"type"                  : @(file->error.type),
 | 
			
		||||
                    NSLocalizedDescriptionKey: @(file->error.message),
 | 
			
		||||
            }]), @"While importing sites." );
 | 
			
		||||
 | 
			
		||||
        // Find an existing user to update.
 | 
			
		||||
@@ -654,9 +667,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
            else {
 | 
			
		||||
                // Create new site.
 | 
			
		||||
                id<MPAlgorithm> algorithm = MPAlgorithmForVersion( importSite->algorithm );
 | 
			
		||||
                Class entityType = [algorithm classOfType:importSite->type];
 | 
			
		||||
                Class entityType = [algorithm classOfType:importSite->resultType];
 | 
			
		||||
                if (!entityType)
 | 
			
		||||
                    return MPMakeError( @"Invalid site type in import file: %@ has type %lu", @(importSite->siteName), (long)importSite->type );
 | 
			
		||||
                    return MPMakeError( @"Invalid site type in import file: %@ has type %lu", @(importSite->siteName),
 | 
			
		||||
                            (long)importSite->resultType );
 | 
			
		||||
 | 
			
		||||
                MPSiteEntity *site = (MPSiteEntity *)[entityType insertNewObjectInContext:context];
 | 
			
		||||
                site.user = user;
 | 
			
		||||
@@ -676,7 +690,9 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
        return nil;
 | 
			
		||||
    }
 | 
			
		||||
    @finally {
 | 
			
		||||
        mpw_marshal_file_free( &importUser );
 | 
			
		||||
        mpw_marshal_file_free( &file );
 | 
			
		||||
        mpw_marshal_user_free( &importUser );
 | 
			
		||||
        mpw_masterKeyProvider_free();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -684,13 +700,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
          usingKey:(MPKey *)userKey {
 | 
			
		||||
 | 
			
		||||
    site.name = @(importSite->siteName);
 | 
			
		||||
    if (importSite->content)
 | 
			
		||||
        [site.algorithm importPassword:@(importSite->content) protectedByKey:importKey intoSite:site usingKey:userKey];
 | 
			
		||||
    site.type = importSite->type;
 | 
			
		||||
    if (importSite->resultState)
 | 
			
		||||
        [site.algorithm importPassword:@(importSite->resultState) protectedByKey:importKey intoSite:site usingKey:userKey];
 | 
			
		||||
    site.type = importSite->resultType;
 | 
			
		||||
    if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
 | 
			
		||||
        ((MPGeneratedSiteEntity *)site).counter = importSite->counter;
 | 
			
		||||
    site.algorithm = MPAlgorithmForVersion( importSite->algorithm );
 | 
			
		||||
    site.loginName = importSite->loginContent? @(importSite->loginContent): nil;
 | 
			
		||||
    site.loginName = importSite->loginState? @(importSite->loginState): nil;
 | 
			
		||||
    site.loginGenerated = importSite->loginType & MPResultTypeClassTemplate;
 | 
			
		||||
    site.url = importSite->url? @(importSite->url): nil;
 | 
			
		||||
    site.uses = importSite->uses;
 | 
			
		||||
@@ -703,10 +719,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
 | 
			
		||||
    [MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
        MPUserEntity *user = [self activeUserInContext:context];
 | 
			
		||||
        NSString *masterPassword = askImportPassword( user.name );
 | 
			
		||||
 | 
			
		||||
        inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
 | 
			
		||||
        MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String, masterPassword.UTF8String, user.algorithm.version );
 | 
			
		||||
        MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String,
 | 
			
		||||
                mpw_masterKeyProvider_str( askImportPassword( user.name ).UTF8String ), user.algorithm.version );
 | 
			
		||||
        exportUser->redacted = !revealPasswords;
 | 
			
		||||
        exportUser->avatar = (unsigned int)user.avatar;
 | 
			
		||||
        exportUser->defaultType = user.defaultType;
 | 
			
		||||
@@ -722,8 +738,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
 | 
			
		||||
            MPMarshalledSite *exportSite = mpw_marshal_site( exportUser,
 | 
			
		||||
                    site.name.UTF8String, site.type, counter, site.algorithm.version );
 | 
			
		||||
            exportSite->content = content.UTF8String;
 | 
			
		||||
            exportSite->loginContent = site.loginName.UTF8String;
 | 
			
		||||
            exportSite->resultState = content.UTF8String;
 | 
			
		||||
            exportSite->loginState = site.loginName.UTF8String;
 | 
			
		||||
            exportSite->loginType = site.loginGenerated? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
 | 
			
		||||
            exportSite->url = site.url.UTF8String;
 | 
			
		||||
            exportSite->uses = (unsigned int)site.uses;
 | 
			
		||||
@@ -733,19 +749,21 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
 | 
			
		||||
                mpw_marshal_question( exportSite, siteQuestion.keyword.UTF8String );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        char *export = NULL;
 | 
			
		||||
        MPMarshalError exportError = (MPMarshalError){ .type= MPMarshalSuccess };
 | 
			
		||||
        mpw_marshal_write( &export, MPMarshalFormatFlat, exportUser, &exportError );
 | 
			
		||||
        MPMarshalledFile *exportFile = NULL;
 | 
			
		||||
        const char *export = mpw_marshal_write( MPMarshalFormatFlat, &exportFile, exportUser );
 | 
			
		||||
        NSString *mpsites = nil;
 | 
			
		||||
        if (export && exportError.type == MPMarshalSuccess)
 | 
			
		||||
        if (export && exportFile && exportFile->error.type == MPMarshalSuccess)
 | 
			
		||||
            mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
 | 
			
		||||
        mpw_free_string( &export );
 | 
			
		||||
 | 
			
		||||
        resultBlock( mpsites, exportError.type == MPMarshalSuccess? nil:
 | 
			
		||||
        resultBlock( mpsites, exportFile && exportFile->error.type == MPMarshalSuccess? nil:
 | 
			
		||||
                              [NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
 | 
			
		||||
                                      @"type"                  : @(exportError.type),
 | 
			
		||||
                                      NSLocalizedDescriptionKey: @(exportError.description),
 | 
			
		||||
                                      @"type"                  : @(exportFile? exportFile->error.type: MPMarshalErrorInternal),
 | 
			
		||||
                                      NSLocalizedDescriptionKey: @(exportFile? exportFile->error.message: nil),
 | 
			
		||||
                              }] );
 | 
			
		||||
        mpw_marshal_file_free( &exportFile );
 | 
			
		||||
        mpw_marshal_user_free( &exportUser );
 | 
			
		||||
        mpw_masterKeyProvider_free();
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import "MPConfig.h"
 | 
			
		||||
#import "MPAppDelegate_Shared.h"
 | 
			
		||||
 | 
			
		||||
@implementation MPConfig
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,7 @@
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import <Crashlytics/Crashlytics.h>
 | 
			
		||||
#import <Crashlytics/Answers.h>
 | 
			
		||||
#import <Sentry/Sentry.h>
 | 
			
		||||
 | 
			
		||||
__BEGIN_DECLS
 | 
			
		||||
extern NSString *const MPErrorDomain;
 | 
			
		||||
@@ -34,28 +33,21 @@ extern NSString *const MPFoundInconsistenciesNotification;
 | 
			
		||||
 | 
			
		||||
extern NSString *const MPSitesImportedNotificationUserKey;
 | 
			
		||||
extern NSString *const MPInconsistenciesFixResultUserKey;
 | 
			
		||||
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
#define MPError(error_, message, ...) ({ \
 | 
			
		||||
#define MPError(error_, message_, ...) ({ \
 | 
			
		||||
    NSError *__error = error_; \
 | 
			
		||||
    err( message @"%@%@", ##__VA_ARGS__, __error && [message length]? @"\n": @"", [__error fullDescription]?: @"" ); \
 | 
			
		||||
    err( message_ @"%@%@", ##__VA_ARGS__, __error && [message_ length]? @"\n": @"", [__error fullDescription]?: @"" ); \
 | 
			
		||||
    \
 | 
			
		||||
    if (__error && [[MPConfig get].sendInfo boolValue]) { \
 | 
			
		||||
        [[Crashlytics sharedInstance] recordError:__error withAdditionalUserInfo:@{ \
 | 
			
		||||
                @"location": strf( @"%@:%d %@", @(basename((char *)__FILE__)), __LINE__, NSStringFromSelector(_cmd) ), \
 | 
			
		||||
        }]; \
 | 
			
		||||
        SentryEvent *event = [[SentryEvent alloc] initWithLevel:kSentrySeverityError]; \
 | 
			
		||||
        event.message = strf(@"%@: %@", message_, [__error localizedDescription]); \
 | 
			
		||||
        event.logger = @"MPError"; \
 | 
			
		||||
        [SentryClient.sharedClient appendStacktraceToEvent:event]; \
 | 
			
		||||
        [SentryClient.sharedClient sendEvent:event withCompletionHandler:nil]; \
 | 
			
		||||
    } \
 | 
			
		||||
    __error; \
 | 
			
		||||
})
 | 
			
		||||
#else
 | 
			
		||||
#define MPError(error_, message, ...) ({ \
 | 
			
		||||
    NSError *__error = error_; \
 | 
			
		||||
    err( message @"%@%@", ##__VA_ARGS__, __error? @"\n": @"", [__error fullDescription]?: @"" ); \
 | 
			
		||||
    __error; \
 | 
			
		||||
})
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MPMakeError(message, ...) ({ \
 | 
			
		||||
     MPError( [NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ \
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
 | 
			
		||||
 | 
			
		||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 | 
			
		||||
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
    NSString *crashlyticsAPIKey = [self crashlyticsAPIKey];
 | 
			
		||||
    if ([crashlyticsAPIKey length]) {
 | 
			
		||||
        inf(@"Initializing Crashlytics");
 | 
			
		||||
@@ -92,7 +91,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
 | 
			
		||||
        CLSLog( @"Crashlytics (%@) initialized for: %@ v%@.", //
 | 
			
		||||
                [Crashlytics sharedInstance].version, [PearlInfoPlist get].CFBundleName, [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Setup delegates and listeners.
 | 
			
		||||
    [MPConfig get].delegate = self;
 | 
			
		||||
@@ -650,25 +648,4 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:NSStringFromSelector( configKey )];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Crashlytics
 | 
			
		||||
 | 
			
		||||
- (NSDictionary *)crashlyticsInfo {
 | 
			
		||||
 | 
			
		||||
    static NSDictionary *crashlyticsInfo = nil;
 | 
			
		||||
    if (crashlyticsInfo == nil)
 | 
			
		||||
        crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
 | 
			
		||||
                [[NSBundle mainBundle] URLForResource:@"Crashlytics" withExtension:@"plist"]];
 | 
			
		||||
 | 
			
		||||
    return crashlyticsInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)crashlyticsAPIKey {
 | 
			
		||||
 | 
			
		||||
    NSString *crashlyticsAPIKey = NSNullToNil( [[self crashlyticsInfo] valueForKeyPath:@"API Key"] );
 | 
			
		||||
    if (![crashlyticsAPIKey length])
 | 
			
		||||
        wrn( @"Crashlytics API key not set.  Crash logs won't be recorded." );
 | 
			
		||||
 | 
			
		||||
    return crashlyticsAPIKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 
 | 
			
		||||
@@ -53,20 +53,6 @@
 | 
			
		||||
        <string>????</string>
 | 
			
		||||
        <key>CFBundleVersion</key>
 | 
			
		||||
        <string>[auto]</string>
 | 
			
		||||
        <key>Fabric</key>
 | 
			
		||||
        <dict>
 | 
			
		||||
            <key>APIKey</key>
 | 
			
		||||
            <string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string>
 | 
			
		||||
            <key>Kits</key>
 | 
			
		||||
            <array>
 | 
			
		||||
                <dict>
 | 
			
		||||
                    <key>KitInfo</key>
 | 
			
		||||
                    <dict/>
 | 
			
		||||
                    <key>KitName</key>
 | 
			
		||||
                    <string>Crashlytics</string>
 | 
			
		||||
                </dict>
 | 
			
		||||
            </array>
 | 
			
		||||
        </dict>
 | 
			
		||||
        <key>LSApplicationCategoryType</key>
 | 
			
		||||
        <string>public.app-category.productivity</string>
 | 
			
		||||
        <key>LSMinimumSystemVersion</key>
 | 
			
		||||
 
 | 
			
		||||
@@ -58,18 +58,24 @@ MP_LIBS_END
 | 
			
		||||
        mpw_log_sink( level, file, line, function, format, ##__VA_ARGS__ ); \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#define MPW_LOG mpw_log_os
 | 
			
		||||
 | 
			
		||||
#include "mpw-util.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __OBJC__
 | 
			
		||||
 | 
			
		||||
#import "Pearl-Prefix.pch"
 | 
			
		||||
 | 
			
		||||
#define MPW_LOG(level, file, line, function, format, ...) mpw_log_os(level, file, line, function, strf(format, ##__VA_ARGS__))
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IOS
 | 
			
		||||
#import <UIKit/UIKit.h>
 | 
			
		||||
#import "MPTypes.h"
 | 
			
		||||
#import "MPiOSConfig.h"
 | 
			
		||||
#elif TARGET_OS_OSX
 | 
			
		||||
#import <Cocoa/Cocoa.h>
 | 
			
		||||
#import "MPTypes.h"
 | 
			
		||||
#import "MPMacConfig.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define MPW_LOG mpw_log_os
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "mpw-util.h"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								platform-darwin/Source/iOS/MPSecrets.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								platform-darwin/Source/iOS/MPSecrets.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
//==============================================================================
 | 
			
		||||
// This file is part of Master Password.
 | 
			
		||||
// Copyright (c) 2011-2017, Maarten Billemont.
 | 
			
		||||
//
 | 
			
		||||
// Master Password is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
//
 | 
			
		||||
// Master Password is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You can find a copy of the GNU General Public License in the
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import <Foundation/Foundation.h>
 | 
			
		||||
 | 
			
		||||
extern NSString *appSecret;
 | 
			
		||||
extern NSString *appSalt;
 | 
			
		||||
extern NSString *sentryDSN;
 | 
			
		||||
extern NSString *countlyKey;
 | 
			
		||||
extern NSString *countlySalt;
 | 
			
		||||
 | 
			
		||||
NSString *decrypt(NSString *appSecret);
 | 
			
		||||
NSString *digest(NSString *value);
 | 
			
		||||
							
								
								
									
										75
									
								
								platform-darwin/Source/iOS/MPSecrets.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								platform-darwin/Source/iOS/MPSecrets.m
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
//==============================================================================
 | 
			
		||||
// This file is part of Master Password.
 | 
			
		||||
// Copyright (c) 2011-2017, Maarten Billemont.
 | 
			
		||||
//
 | 
			
		||||
// Master Password is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
//
 | 
			
		||||
// Master Password is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You can find a copy of the GNU General Public License in the
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import "MPSecrets.h"
 | 
			
		||||
#import "base64.h"
 | 
			
		||||
 | 
			
		||||
// printf <secret> | openssl enc -[ed] -aes-128-cbc -a -A -K <appSecret> -iv 0
 | 
			
		||||
NSString *appSecret    = @"";
 | 
			
		||||
NSString *appSalt      = @"";
 | 
			
		||||
NSString *sentryDSN    = @"";
 | 
			
		||||
NSString *countlyKey   = @"";
 | 
			
		||||
NSString *countlySalt  = @"";
 | 
			
		||||
 | 
			
		||||
NSString *decrypt(NSString *secret) {
 | 
			
		||||
 | 
			
		||||
    if (!secret)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    const char *secretString = [secret cStringUsingEncoding:NSUTF8StringEncoding];
 | 
			
		||||
    size_t length = mpw_base64_decode_max( secretString );
 | 
			
		||||
    if (!length)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    size_t keyLength;
 | 
			
		||||
    const uint8_t *key = mpw_unhex( [appSecret cStringUsingEncoding:NSUTF8StringEncoding], &keyLength );
 | 
			
		||||
    if (!key)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    uint8_t *base64 = calloc( length, sizeof( uint8_t ) );
 | 
			
		||||
    length = mpw_base64_decode( base64, secretString );
 | 
			
		||||
 | 
			
		||||
    const void *plain = mpw_aes_decrypt( key, keyLength, base64, &length );
 | 
			
		||||
    mpw_free( &key, keyLength );
 | 
			
		||||
    @try {
 | 
			
		||||
        return [[NSString alloc] initWithBytes:plain length:length encoding:NSUTF8StringEncoding];
 | 
			
		||||
    }
 | 
			
		||||
    @finally {
 | 
			
		||||
        mpw_free( &plain, length );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NSString *digest(NSString *value) {
 | 
			
		||||
 | 
			
		||||
    if (!value)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    size_t appSaltLength, valueLength;
 | 
			
		||||
    const void *appSaltString = [decrypt( appSalt ) cStringUsingEncoding:NSUTF8StringEncoding length:&appSaltLength];
 | 
			
		||||
    const void *valueString = [value cStringUsingEncoding:NSUTF8StringEncoding length:&valueLength];
 | 
			
		||||
    const uint8_t *digest = mpw_hash_hmac_sha256( appSaltString, appSaltLength, valueString, valueLength );
 | 
			
		||||
    if (!digest)
 | 
			
		||||
        return nil;
 | 
			
		||||
 | 
			
		||||
    @try {
 | 
			
		||||
        return [[NSString alloc] initWithBytes:mpw_hex( digest, 32 ) length:16 encoding:NSUTF8StringEncoding];
 | 
			
		||||
    }
 | 
			
		||||
    @finally {
 | 
			
		||||
        mpw_free( &digest, 32 );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -57,6 +57,8 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
 | 
			
		||||
    self.dataSource = [NSMutableArray new];
 | 
			
		||||
 | 
			
		||||
    self.view.backgroundColor = [UIColor clearColor];
 | 
			
		||||
    if (@available( iOS 11, * ))
 | 
			
		||||
        self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
 | 
			
		||||
    [self.collectionView automaticallyAdjustInsetsForKeyboard];
 | 
			
		||||
    self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
 | 
			
		||||
    if ([self.searchBar respondsToSelector:@selector( keyboardAppearance )])
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,8 @@
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import <Crashlytics/Answers.h>
 | 
			
		||||
#import <Countly/Countly.h>
 | 
			
		||||
 | 
			
		||||
#import "MPUsersViewController.h"
 | 
			
		||||
#import "MPEntities.h"
 | 
			
		||||
#import "MPAvatarCell.h"
 | 
			
		||||
@@ -228,14 +229,10 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
 | 
			
		||||
                        user.name = newUserName;
 | 
			
		||||
 | 
			
		||||
                        if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
                            [Answers logSignUpWithMethod:@"Manual"
 | 
			
		||||
                                                 success:@YES
 | 
			
		||||
                                        customAttributes:@{
 | 
			
		||||
                                                @"algorithm": @(user.algorithm.version),
 | 
			
		||||
                                                @"avatar"   : @(user.avatar),
 | 
			
		||||
                                        }];
 | 
			
		||||
#endif
 | 
			
		||||
                            [Countly.sharedInstance recordEvent:@"new-user" segmentation:@{
 | 
			
		||||
                                    @"algorithm": @(user.algorithm.version).description,
 | 
			
		||||
                                    @"avatar"   : @(user.avatar).description,
 | 
			
		||||
                            }];
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@@ -666,7 +663,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
 | 
			
		||||
    [self removeObservers];
 | 
			
		||||
    [self observeKeyPath:@"avatarCollectionView.contentOffset" withBlock:
 | 
			
		||||
            ^(id from, id to, NSKeyValueChange cause, MPUsersViewController *self) {
 | 
			
		||||
                [self updateAvatarVisibility];
 | 
			
		||||
                PearlMainQueue( ^{ [self updateAvatarVisibility]; } );
 | 
			
		||||
            }];
 | 
			
		||||
 | 
			
		||||
    PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue],
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,10 @@
 | 
			
		||||
#import "MPAppDelegate_Store.h"
 | 
			
		||||
#import "MPStoreViewController.h"
 | 
			
		||||
#import "mpw-marshal.h"
 | 
			
		||||
#import "MPSecrets.h"
 | 
			
		||||
 | 
			
		||||
#import <Sentry/Sentry.h>
 | 
			
		||||
#import <Countly/Countly.h>
 | 
			
		||||
 | 
			
		||||
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
 | 
			
		||||
 | 
			
		||||
@@ -35,11 +39,10 @@
 | 
			
		||||
 | 
			
		||||
    static dispatch_once_t once = 0;
 | 
			
		||||
    dispatch_once( &once, ^{
 | 
			
		||||
        [PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
 | 
			
		||||
        [PearlLogger get].historyLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelTrace: PearlLogLevelInfo;
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
        [PearlLogger get].printLevel = PearlLogLevelTrace;
 | 
			
		||||
#else
 | 
			
		||||
        [PearlLogger get].printLevel = [[MPiOSConfig get].traceMode boolValue]? PearlLogLevelDebug: PearlLogLevelInfo;
 | 
			
		||||
        //[PearlLogger get].printLevel = PearlLogLevelTrace;
 | 
			
		||||
#endif
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
@@ -47,34 +50,73 @@
 | 
			
		||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 | 
			
		||||
 | 
			
		||||
    @try {
 | 
			
		||||
//        [[NSBundle mainBundle] mutableInfoDictionary][@"CFBundleDisplayName"] = @"Master Password";
 | 
			
		||||
//        [[NSBundle mainBundle] mutableLocalizedInfoDictionary][@"CFBundleDisplayName"] = @"Master Password";
 | 
			
		||||
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
        NSString *crashlyticsAPIKey = [self crashlyticsAPIKey];
 | 
			
		||||
        if ([crashlyticsAPIKey length]) {
 | 
			
		||||
            inf( @"Initializing Crashlytics" );
 | 
			
		||||
#if DEBUG
 | 
			
		||||
            [Crashlytics sharedInstance].debugMode = YES;
 | 
			
		||||
        // Sentry
 | 
			
		||||
        SentryClient.sharedClient = [[SentryClient alloc] initWithDsn:decrypt( sentryDSN ) didFailWithError:nil];
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
        SentryClient.sharedClient.environment = @"Development";
 | 
			
		||||
#elif PUBLIC
 | 
			
		||||
        SentryClient.sharedClient.environment = @"Public";
 | 
			
		||||
#else
 | 
			
		||||
        SentryClient.sharedClient.environment = @"Private";
 | 
			
		||||
#endif
 | 
			
		||||
            [[Crashlytics sharedInstance] setUserIdentifier:[PearlKeyChain deviceIdentifier]];
 | 
			
		||||
            [[Crashlytics sharedInstance] setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
 | 
			
		||||
            [[Crashlytics sharedInstance] setUserName:@"Anonymous"];
 | 
			
		||||
            [Crashlytics startWithAPIKey:crashlyticsAPIKey];
 | 
			
		||||
            [[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
 | 
			
		||||
                PearlLogLevel level = PearlLogLevelWarn;
 | 
			
		||||
                if ([[MPConfig get].sendInfo boolValue])
 | 
			
		||||
                    level = PearlLogLevelDebug;
 | 
			
		||||
        SentryClient.sharedClient.enabled = [MPiOSConfig get].sendInfo;
 | 
			
		||||
        [SentryClient.sharedClient enableAutomaticBreadcrumbTracking];
 | 
			
		||||
        [SentryClient.sharedClient startCrashHandlerWithError:nil];
 | 
			
		||||
        [[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
 | 
			
		||||
            PearlLogLevel level = PearlLogLevelWarn;
 | 
			
		||||
            if ([[MPConfig get].sendInfo boolValue])
 | 
			
		||||
                level = PearlLogLevelDebug;
 | 
			
		||||
 | 
			
		||||
                if (message.level >= level)
 | 
			
		||||
                    CLSLog( @"%@", [message messageDescription] );
 | 
			
		||||
            if (message.level >= level) {
 | 
			
		||||
                SentrySeverity sentryLevel = kSentrySeverityInfo;
 | 
			
		||||
                switch (message.level) {
 | 
			
		||||
                    case PearlLogLevelTrace:
 | 
			
		||||
                        sentryLevel = kSentrySeverityDebug;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PearlLogLevelDebug:
 | 
			
		||||
                        sentryLevel = kSentrySeverityDebug;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PearlLogLevelInfo:
 | 
			
		||||
                        sentryLevel = kSentrySeverityInfo;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PearlLogLevelWarn:
 | 
			
		||||
                        sentryLevel = kSentrySeverityWarning;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PearlLogLevelError:
 | 
			
		||||
                        sentryLevel = kSentrySeverityError;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case PearlLogLevelFatal:
 | 
			
		||||
                        sentryLevel = kSentrySeverityFatal;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
                SentryBreadcrumb *breadcrumb = [[SentryBreadcrumb alloc] initWithLevel:sentryLevel category:@"Pearl"];
 | 
			
		||||
                breadcrumb.type = @"log";
 | 
			
		||||
                breadcrumb.message = message.message;
 | 
			
		||||
                breadcrumb.timestamp = message.occurrence;
 | 
			
		||||
                breadcrumb.data = @{ @"file": message.fileName, @"line": @(message.lineNumber), @"function": message.function };
 | 
			
		||||
                [SentryClient.sharedClient.breadcrumbs addBreadcrumb:breadcrumb];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                return YES;
 | 
			
		||||
            }];
 | 
			
		||||
            CLSLog( @"Crashlytics (%@) initialized for: %@ v%@.", //
 | 
			
		||||
                    [Crashlytics sharedInstance].version, [PearlInfoPlist get].CFBundleName, [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
        }
 | 
			
		||||
            return YES;
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
        // Countly
 | 
			
		||||
        CountlyConfig *countlyConfig = [CountlyConfig new];
 | 
			
		||||
        countlyConfig.host = @"https://countly.lyndir.app";
 | 
			
		||||
        countlyConfig.appKey = decrypt( countlyKey );
 | 
			
		||||
        countlyConfig.features = @[ CLYPushNotifications ];
 | 
			
		||||
        countlyConfig.requiresConsent = true;
 | 
			
		||||
#if PUBLIC
 | 
			
		||||
        countlyConfig.pushTestMode = nil;
 | 
			
		||||
#elif DEBUG
 | 
			
		||||
        countlyConfig.pushTestMode = CLYPushTestModeDevelopment;
 | 
			
		||||
#else
 | 
			
		||||
        countlyConfig.pushTestMode = CLYPushTestModeTestFlightOrAdHoc;
 | 
			
		||||
#endif
 | 
			
		||||
        countlyConfig.alwaysUsePOST = true;
 | 
			
		||||
        countlyConfig.deviceID = [PearlKeyChain deviceIdentifier];
 | 
			
		||||
        countlyConfig.secretSalt = decrypt( countlySalt );
 | 
			
		||||
        [Countly.sharedInstance startWithConfig:countlyConfig];
 | 
			
		||||
 | 
			
		||||
        [self.hangDetector = [[PearlHangDetector alloc] initWithHangAction:^(NSTimeInterval hangTime) {
 | 
			
		||||
            MPError( [NSError errorWithDomain:MPErrorDomain code:MPErrorHangCode userInfo:@{
 | 
			
		||||
@@ -111,21 +153,21 @@
 | 
			
		||||
                case MPFixableResultNoProblems:
 | 
			
		||||
                    break;
 | 
			
		||||
                case MPFixableResultProblemsFixed: {
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Inconsistencies Fixed" message:
 | 
			
		||||
                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Inconsistencies Fixed" message:
 | 
			
		||||
                                    @"Some inconsistencies were detected in your sites.\n"
 | 
			
		||||
                                    @"All issues were fixed."
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case MPFixableResultProblemsNotFixed: {
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Inconsistencies Found" message:
 | 
			
		||||
                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Inconsistencies Found" message:
 | 
			
		||||
                                    @"Some inconsistencies were detected in your sites.\n"
 | 
			
		||||
                                    @"Not all issues could be fixed.  Try signing in to each user or checking the logs."
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -138,12 +180,12 @@
 | 
			
		||||
 | 
			
		||||
        NSString *latestFeatures = [MPStoreViewController latestStoreFeatures];
 | 
			
		||||
        if (latestFeatures) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"New Features" message:
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"New Features" message:
 | 
			
		||||
                            strf( @"The following features are now available in the store:\n\n%@•••\n\n"
 | 
			
		||||
                                  @"Find the store from the user pull‑down after logging in.", latestFeatures )
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @catch (id exception) {
 | 
			
		||||
@@ -167,22 +209,22 @@
 | 
			
		||||
                    MPError( error, @"While reading imported sites from %@.", url );
 | 
			
		||||
 | 
			
		||||
                if (!importedSitesData) {
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:
 | 
			
		||||
                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
 | 
			
		||||
                                    strf( @"Master Password couldn't read the import sites.\n\n%@",
 | 
			
		||||
                                            (id)[error localizedDescription]?: error )
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
 | 
			
		||||
                if (!importedSitesString) {
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:
 | 
			
		||||
                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
 | 
			
		||||
                                    @"Master Password couldn't understand the import file."
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -204,35 +246,35 @@
 | 
			
		||||
    PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
 | 
			
		||||
    [self importSites:importData askImportPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( ^(void (^setResult)(id)) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
 | 
			
		||||
                            @"Enter the master password used to create this export file."
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( alert.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    } askUserPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( (id)^(void (^setResult)(id)) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
 | 
			
		||||
                            @"Enter the current master password for this user."
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( alert.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    }          result:^(NSError *error) {
 | 
			
		||||
        [activityOverlay cancelOverlayAnimated:YES];
 | 
			
		||||
@@ -262,19 +304,20 @@
 | 
			
		||||
 | 
			
		||||
    PearlNotMainQueue( ^{
 | 
			
		||||
        NSString *importData = [UIPasteboard generalPasteboard].string;
 | 
			
		||||
        MPMarshalInfo *importInfo = mpw_marshal_read_info( importData.UTF8String );
 | 
			
		||||
        if (importInfo->format != MPMarshalFormatNone) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
 | 
			
		||||
        MPMarshalledFile *importFile = mpw_marshal_read( NULL, importData.UTF8String );
 | 
			
		||||
        if (importFile && importFile->error.type == MPMarshalSuccess && importFile->info->format != MPMarshalFormatNone) {
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
 | 
			
		||||
                            @"We've detected Master Password import sites on your pasteboard, would you like to import them?"
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Import Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
                [self importSites:importData];
 | 
			
		||||
                [UIPasteboard generalPasteboard].string = @"";
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Import Sites" style:UIAlertActionStyleDefault handler:
 | 
			
		||||
                    ^(UIAlertAction *action) {
 | 
			
		||||
                        [self importSites:importData];
 | 
			
		||||
                        [UIPasteboard generalPasteboard].string = @"";
 | 
			
		||||
                    }]];
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        }
 | 
			
		||||
        mpw_marshal_info_free( &importInfo );
 | 
			
		||||
        mpw_marshal_file_free( &importFile );
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
    [super applicationDidBecomeActive:application];
 | 
			
		||||
@@ -341,27 +384,27 @@
 | 
			
		||||
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    if (![PearlEMail canSendMail]) {
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Feedback" message:
 | 
			
		||||
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
 | 
			
		||||
                        @"Have a question, comment, issue or just saying thanks?\n\n"
 | 
			
		||||
                        @"We'd love to hear what you think!\n"
 | 
			
		||||
                        @"masterpassword@lyndir.com"
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
    else if (logs) {
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Feedback" message:
 | 
			
		||||
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
 | 
			
		||||
                        @"Have a question, comment, issue or just saying thanks?\n\n"
 | 
			
		||||
                        @"If you're having trouble, it may help us if you can first reproduce the problem "
 | 
			
		||||
                        @"and then include log files in your message."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Include Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Include Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self openFeedbackWithLogs:YES forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self openFeedbackWithLogs:NO forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        [self openFeedbackWithLogs:NO forVC:viewController];
 | 
			
		||||
@@ -401,83 +444,83 @@
 | 
			
		||||
 | 
			
		||||
    static dispatch_once_t once = 0;
 | 
			
		||||
    dispatch_once( &once, ^{
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Failed To Load Sites" message:
 | 
			
		||||
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Failed To Load Sites" message:
 | 
			
		||||
                        @"Master Password was unable to open your sites history.\n"
 | 
			
		||||
                        @"This may be due to corruption.  You can either reset Master Password and "
 | 
			
		||||
                        @"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                [self openFeedbackWithLogs:YES forVC:nil];
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self openFeedbackWithLogs:YES forVC:nil];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                [self deleteAndResetStore];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self deleteAndResetStore];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showExportForVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Exporting Your Sites" message:
 | 
			
		||||
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Exporting Your Sites" message:
 | 
			
		||||
                    @"An export is great for keeping a backup list of your accounts.\n\n"
 | 
			
		||||
                    @"When the file is ready, you will be able to mail it to yourself.\n"
 | 
			
		||||
                    @"You can open it with a text editor or with Master Password if you need to restore your list of sites."
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Export Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Show Passwords?" message:
 | 
			
		||||
                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [alert addAction:[UIAlertAction actionWithTitle:@"Export Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        UIAlertController *sheet = [UIAlertController alertControllerWithTitle:@"Show Passwords?" message:
 | 
			
		||||
                        @"Would you like to make all your passwords visible in the export file?\n\n"
 | 
			
		||||
                        @"A safe export will include all sites but make their passwords invisible.\n"
 | 
			
		||||
                        @"It is great as a backup and remains safe when fallen in the wrong hands."
 | 
			
		||||
                                                                      preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller_ addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                                 [self showExportRevealPasswords:NO forVC:viewController];
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
        [sheet addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self showExportRevealPasswords:NO forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller_ addAction:[UIAlertAction actionWithTitle:@"Show Passwords" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                                 [self showExportRevealPasswords:YES forVC:viewController];
 | 
			
		||||
        [sheet addAction:[UIAlertAction actionWithTitle:@"Show Passwords" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self showExportRevealPasswords:YES forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller_ animated:YES completion:nil];
 | 
			
		||||
        [sheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:sheet animated:YES completion:nil];
 | 
			
		||||
    }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    if (![PearlEMail canSendMail]) {
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Cannot Send Mail" message:
 | 
			
		||||
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Cannot Send Mail" message:
 | 
			
		||||
                        @"Your device is not yet set up for sending mail.\n"
 | 
			
		||||
                        @"Close Master Password, go into Settings and add a Mail account."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( ^(void (^setResult)(id)) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName ) message:
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName ) message:
 | 
			
		||||
                            @"Enter the user's master password to create an export file."
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( alert.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    }                         result:^(NSString *mpsites, NSError *error) {
 | 
			
		||||
        if (!mpsites || error) {
 | 
			
		||||
            MPError( error, @"Failed to export mpsites." );
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
 | 
			
		||||
                                                                    preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -486,9 +529,9 @@
 | 
			
		||||
        NSString *exportFileName = strf( @"%@ (%@).mpsites",
 | 
			
		||||
                [self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
 | 
			
		||||
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
 | 
			
		||||
                                                                preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            NSString *message;
 | 
			
		||||
            if (revealPasswords)
 | 
			
		||||
                message = strf( @"Export of Master Password sites with passwords included.\n\n"
 | 
			
		||||
@@ -511,11 +554,12 @@
 | 
			
		||||
            [PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
 | 
			
		||||
                        attachments:[[PearlEMailAttachment alloc]
 | 
			
		||||
                                            initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
 | 
			
		||||
                                                   mimeType:@"text/plain" fileName:exportFileName],
 | 
			
		||||
                                                   mimeType:@"text/plain"
 | 
			
		||||
                                                   fileName:exportFileName],
 | 
			
		||||
                                    nil];
 | 
			
		||||
            return;
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Share / Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Share / Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
 | 
			
		||||
                                                                                   inDomains:NSUserDomainMask] lastObject];
 | 
			
		||||
            NSURL *exportURL = [[applicationSupportURL
 | 
			
		||||
@@ -532,19 +576,19 @@
 | 
			
		||||
                [self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
 | 
			
		||||
            }
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        [alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
 | 
			
		||||
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message:
 | 
			
		||||
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message:
 | 
			
		||||
                    @"If you continue, you'll be able to set a new master password.\n\n"
 | 
			
		||||
                    @"Changing your master password will cause all your generated passwords to change!\n"
 | 
			
		||||
                    @"Changing the master password back to the old one will cause your passwords to revert as well."
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                                                            preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
        [moc performBlockAndWait:^{
 | 
			
		||||
            inf( @"Clearing keyID for user: %@.", user.userID );
 | 
			
		||||
            user.keyID = nil;
 | 
			
		||||
@@ -556,8 +600,8 @@
 | 
			
		||||
        if (didReset)
 | 
			
		||||
            didReset();
 | 
			
		||||
    }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    [alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:alert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - UIDocumentInteractionControllerDelegate
 | 
			
		||||
@@ -581,51 +625,41 @@
 | 
			
		||||
 | 
			
		||||
    // Send info
 | 
			
		||||
    if ([[MPConfig get].sendInfo boolValue]) {
 | 
			
		||||
        [Countly.sharedInstance giveConsentForAllFeatures];
 | 
			
		||||
 | 
			
		||||
        if ([PearlLogger get].printLevel > PearlLogLevelInfo)
 | 
			
		||||
            [PearlLogger get].printLevel = PearlLogLevelInfo;
 | 
			
		||||
 | 
			
		||||
#ifdef CRASHLYTICS
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].rememberLogin boolValue] forKey:@"rememberLogin"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[MPConfig get].sendInfo boolValue] forKey:@"sendInfo"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].helpHidden boolValue] forKey:@"helpHidden"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[MPiOSConfig get].showSetup boolValue] forKey:@"showQuickStart"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].firstRun boolValue] forKey:@"firstRun"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].launchCount intValue] forKey:@"launchCount"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[[PearlConfig get].askForReviews boolValue] forKey:@"askForReviews"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setIntValue:[[PearlConfig get].reviewAfterLaunches intValue] forKey:@"reviewAfterLaunches"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isSimulator] forKey:@"simulator"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isAppEncrypted] forKey:@"encrypted"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isJailbroken] forKey:@"jailbroken"];
 | 
			
		||||
        [[Crashlytics sharedInstance] setObjectValue:[PearlDeviceUtils platform] forKey:@"platform"];
 | 
			
		||||
        NSMutableDictionary *prefs = [NSMutableDictionary new];
 | 
			
		||||
        prefs[@"rememberLogin"] = [MPConfig get].rememberLogin;
 | 
			
		||||
        prefs[@"sendInfo"] = [MPConfig get].sendInfo;
 | 
			
		||||
        prefs[@"helpHidden"] = [MPiOSConfig get].helpHidden;
 | 
			
		||||
        prefs[@"showQuickStart"] = [MPiOSConfig get].showSetup;
 | 
			
		||||
        prefs[@"firstRun"] = [PearlConfig get].firstRun;
 | 
			
		||||
        prefs[@"launchCount"] = [PearlConfig get].launchCount;
 | 
			
		||||
        prefs[@"askForReviews"] = [PearlConfig get].askForReviews;
 | 
			
		||||
        prefs[@"reviewAfterLaunches"] = [PearlConfig get].reviewAfterLaunches;
 | 
			
		||||
        prefs[@"reviewedVersion"] = [PearlConfig get].reviewedVersion;
 | 
			
		||||
        prefs[@"simulator"] = @([PearlDeviceUtils isSimulator]);
 | 
			
		||||
        prefs[@"encrypted"] = @([PearlDeviceUtils isAppEncrypted]);
 | 
			
		||||
        prefs[@"jailbroken"] = @([PearlDeviceUtils isJailbroken]);
 | 
			
		||||
        prefs[@"platform"] = [PearlDeviceUtils platform];
 | 
			
		||||
#ifdef APPSTORE
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:[PearlDeviceUtils isAppEncrypted] forKey:@"reviewedVersion"];
 | 
			
		||||
        prefs[@"reviewedVersion"] = @([PearlDeviceUtils isAppEncrypted]);
 | 
			
		||||
#else
 | 
			
		||||
        [[Crashlytics sharedInstance] setBoolValue:YES forKey:@"reviewedVersion"];
 | 
			
		||||
#endif
 | 
			
		||||
        prefs[@"reviewedVersion"] = @(YES);
 | 
			
		||||
#endif
 | 
			
		||||
        PearlMainQueueOperation( ^{
 | 
			
		||||
            if (![[SentryClient.sharedClient.extra dictionaryWithValuesForKeys:prefs.allKeys] isEqualToDictionary:prefs]) {
 | 
			
		||||
                NSMutableDictionary *extra = [SentryClient.sharedClient.extra mutableCopy]?: [NSMutableDictionary dictionary];
 | 
			
		||||
                [extra addEntriesFromDictionary:prefs];
 | 
			
		||||
                SentryClient.sharedClient.extra = extra;
 | 
			
		||||
            }
 | 
			
		||||
        } );
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        [Countly.sharedInstance cancelConsentForAllFeatures];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Crashlytics
 | 
			
		||||
 | 
			
		||||
- (NSDictionary *)crashlyticsInfo {
 | 
			
		||||
 | 
			
		||||
    static NSDictionary *crashlyticsInfo = nil;
 | 
			
		||||
    if (crashlyticsInfo == nil)
 | 
			
		||||
        crashlyticsInfo = [[NSDictionary alloc] initWithContentsOfURL:
 | 
			
		||||
                [[NSBundle mainBundle] URLForResource:@"Fabric" withExtension:@"plist"]];
 | 
			
		||||
 | 
			
		||||
    return crashlyticsInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)crashlyticsAPIKey {
 | 
			
		||||
 | 
			
		||||
    NSString *crashlyticsAPIKey = NSNullToNil( [[self crashlyticsInfo] valueForKeyPath:@"API Key"] );
 | 
			
		||||
    if (![crashlyticsAPIKey length])
 | 
			
		||||
        wrn( @"Crashlytics API key not set.  Crash logs won't be recorded." );
 | 
			
		||||
 | 
			
		||||
    return crashlyticsAPIKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@
 | 
			
		||||
// LICENSE file.  Alternatively, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#import "MPiOSConfig.h"
 | 
			
		||||
 | 
			
		||||
@implementation MPiOSConfig
 | 
			
		||||
 | 
			
		||||
@dynamic helpHidden, siteInfoHidden, showSetup, actionsTipShown, typeTipShown, loginNameTipShown, traceMode, dictationSearch, allowDowngrade;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,20 +41,6 @@
 | 
			
		||||
	<string>[auto]</string>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>[auto]</string>
 | 
			
		||||
	<key>Fabric</key>
 | 
			
		||||
	<dict>
 | 
			
		||||
		<key>APIKey</key>
 | 
			
		||||
		<string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string>
 | 
			
		||||
		<key>Kits</key>
 | 
			
		||||
		<array>
 | 
			
		||||
			<dict>
 | 
			
		||||
				<key>KitInfo</key>
 | 
			
		||||
				<dict/>
 | 
			
		||||
				<key>KitName</key>
 | 
			
		||||
				<string>Crashlytics</string>
 | 
			
		||||
			</dict>
 | 
			
		||||
		</array>
 | 
			
		||||
	</dict>
 | 
			
		||||
	<key>LSRequiresIPhoneOS</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>NSHumanReadableCopyright</key>
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -185,7 +185,6 @@ void cli_mpw(Arguments *args, Operation *operation);
 | 
			
		||||
void cli_save(Arguments *args, Operation *operation);
 | 
			
		||||
 | 
			
		||||
MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation);
 | 
			
		||||
MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword);
 | 
			
		||||
void cli_masterKeyProvider_free(void);
 | 
			
		||||
 | 
			
		||||
/** ========================================================================
 | 
			
		||||
@@ -825,7 +824,7 @@ void cli_save(Arguments *args, Operation *operation) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const char *buf = mpw_marshal_write( operation->sitesFormat, operation->file, operation->user );
 | 
			
		||||
    const char *buf = mpw_marshal_write( operation->sitesFormat, &operation->file, operation->user );
 | 
			
		||||
    if (!buf || operation->file->error.type != MPMarshalSuccess)
 | 
			
		||||
        wrn( "Couldn't encode updated configuration file:\n  %s: %s", operation->sitesPath, operation->file->error.message );
 | 
			
		||||
 | 
			
		||||
@@ -836,47 +835,25 @@ void cli_save(Arguments *args, Operation *operation) {
 | 
			
		||||
    fclose( sitesFile );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MPMasterKey __cli_masterKeyProvider_currentKey = NULL;
 | 
			
		||||
static MPAlgorithmVersion __cli_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1;
 | 
			
		||||
static const char *__cli_masterKeyProvider_currentPassword = NULL;
 | 
			
		||||
static Operation *__cli_masterKeyProvider_currentOperation = NULL;
 | 
			
		||||
 | 
			
		||||
static MPMasterKey __cli_masterKeyProvider_op(MPAlgorithmVersion algorithm, const char *fullName) {
 | 
			
		||||
static bool __cli_masterKeyProvider_op(MPMasterKey *currentKey, MPAlgorithmVersion *currentAlgorithm,
 | 
			
		||||
        MPAlgorithmVersion algorithm, const char *fullName) {
 | 
			
		||||
 | 
			
		||||
    if (mpw_update_master_key( &__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm,
 | 
			
		||||
            algorithm, fullName, __cli_masterKeyProvider_currentOperation->masterPassword ))
 | 
			
		||||
        return mpw_memdup( __cli_masterKeyProvider_currentKey, MPMasterKeySize );
 | 
			
		||||
    if (!currentKey)
 | 
			
		||||
        __cli_masterKeyProvider_currentOperation = NULL;
 | 
			
		||||
    if (!__cli_masterKeyProvider_currentOperation)
 | 
			
		||||
        return false;
 | 
			
		||||
    if (!mpw_update_master_key( currentKey, currentAlgorithm, algorithm, fullName,
 | 
			
		||||
            __cli_masterKeyProvider_currentOperation->masterPassword ))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MPMasterKey __cli_masterKeyProvider_str(MPAlgorithmVersion algorithm, const char *fullName) {
 | 
			
		||||
 | 
			
		||||
    if (mpw_update_master_key( &__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm,
 | 
			
		||||
            algorithm, fullName, __cli_masterKeyProvider_currentPassword ))
 | 
			
		||||
        return mpw_memdup( __cli_masterKeyProvider_currentKey, MPMasterKeySize );
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation) {
 | 
			
		||||
 | 
			
		||||
    mpw_free_string( &__cli_masterKeyProvider_currentPassword );
 | 
			
		||||
    mpw_masterKeyProvider_free();
 | 
			
		||||
    __cli_masterKeyProvider_currentOperation = operation;
 | 
			
		||||
    return __cli_masterKeyProvider_op;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    mpw_free_string( &__cli_masterKeyProvider_currentPassword );
 | 
			
		||||
    __cli_masterKeyProvider_currentPassword = mpw_strdup( masterPassword );
 | 
			
		||||
    return __cli_masterKeyProvider_str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cli_masterKeyProvider_free() {
 | 
			
		||||
 | 
			
		||||
    mpw_free( &__cli_masterKeyProvider_currentKey, MPMasterKeySize );
 | 
			
		||||
    __cli_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1;
 | 
			
		||||
    mpw_free_string( &__cli_masterKeyProvider_currentPassword );
 | 
			
		||||
    __cli_masterKeyProvider_currentOperation = NULL;
 | 
			
		||||
    return mpw_masterKeyProvider_proxy( __cli_masterKeyProvider_op );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,55 @@ MP_LIBS_BEGIN
 | 
			
		||||
#include <math.h>
 | 
			
		||||
MP_LIBS_END
 | 
			
		||||
 | 
			
		||||
static MPMasterKey __mpw_masterKeyProvider_currentKey = NULL;
 | 
			
		||||
static MPAlgorithmVersion __mpw_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1;
 | 
			
		||||
static MPMasterKeyProviderProxy __mpw_masterKeyProvider_currentProxy = NULL;
 | 
			
		||||
static const char *__mpw_masterKeyProvider_currentPassword = NULL;
 | 
			
		||||
 | 
			
		||||
static bool __mpw_masterKeyProvider_str(MPMasterKey *currentKey, MPAlgorithmVersion *currentAlgorithm,
 | 
			
		||||
        MPAlgorithmVersion algorithm, const char *fullName) {
 | 
			
		||||
 | 
			
		||||
    if (!currentKey)
 | 
			
		||||
        return mpw_free_string( &__mpw_masterKeyProvider_currentPassword );
 | 
			
		||||
 | 
			
		||||
    return mpw_update_master_key( currentKey, currentAlgorithm, algorithm, fullName, __mpw_masterKeyProvider_currentPassword );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MPMasterKey __mpw_masterKeyProvider_proxy(MPAlgorithmVersion algorithm, const char *fullName) {
 | 
			
		||||
 | 
			
		||||
    if (!__mpw_masterKeyProvider_currentProxy)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    if (!__mpw_masterKeyProvider_currentProxy(
 | 
			
		||||
            &__mpw_masterKeyProvider_currentKey, &__mpw_masterKeyProvider_currentAlgorithm, algorithm, fullName ))
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    return mpw_memdup( __mpw_masterKeyProvider_currentKey, MPMasterKeySize );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_str(const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    mpw_masterKeyProvider_free();
 | 
			
		||||
    __mpw_masterKeyProvider_currentPassword = mpw_strdup( masterPassword );
 | 
			
		||||
    return mpw_masterKeyProvider_proxy( __mpw_masterKeyProvider_str );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_proxy(const MPMasterKeyProviderProxy proxy) {
 | 
			
		||||
 | 
			
		||||
    mpw_masterKeyProvider_free();
 | 
			
		||||
    __mpw_masterKeyProvider_currentProxy = proxy;
 | 
			
		||||
    return __mpw_masterKeyProvider_proxy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mpw_masterKeyProvider_free() {
 | 
			
		||||
 | 
			
		||||
    mpw_free( &__mpw_masterKeyProvider_currentKey, MPMasterKeySize );
 | 
			
		||||
    __mpw_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1;
 | 
			
		||||
    if (__mpw_masterKeyProvider_currentProxy) {
 | 
			
		||||
        __mpw_masterKeyProvider_currentProxy( NULL, NULL, MPAlgorithmVersionCurrent, NULL );
 | 
			
		||||
        __mpw_masterKeyProvider_currentProxy = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MPMarshalledUser *mpw_marshal_user(
 | 
			
		||||
        const char *fullName, MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
 | 
			
		||||
@@ -612,6 +661,7 @@ static const char *mpw_marshal_write_json(
 | 
			
		||||
 | 
			
		||||
static bool mpw_marshal_data_keep_site_exists(
 | 
			
		||||
        MPMarshalledData *child, void *args) {
 | 
			
		||||
 | 
			
		||||
    MPMarshalledUser *user = args;
 | 
			
		||||
 | 
			
		||||
    for (size_t s = 0; s < user->sites_count; ++s) {
 | 
			
		||||
@@ -624,6 +674,7 @@ static bool mpw_marshal_data_keep_site_exists(
 | 
			
		||||
 | 
			
		||||
static bool mpw_marshal_data_keep_question_exists(
 | 
			
		||||
        MPMarshalledData *child, void *args) {
 | 
			
		||||
 | 
			
		||||
    MPMarshalledSite *site = args;
 | 
			
		||||
 | 
			
		||||
    for (size_t s = 0; s < site->questions_count; ++s) {
 | 
			
		||||
@@ -635,16 +686,15 @@ static bool mpw_marshal_data_keep_question_exists(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *mpw_marshal_write(
 | 
			
		||||
        const MPMarshalFormat outFormat, MPMarshalledFile *file, MPMarshalledUser *user) {
 | 
			
		||||
        const MPMarshalFormat outFormat, MPMarshalledFile **file_, MPMarshalledUser *user) {
 | 
			
		||||
 | 
			
		||||
    MPMarshalledFile *file = file_? *file_: NULL;
 | 
			
		||||
    file = mpw_marshal_file( file, NULL, file && file->data? file->data: mpw_marshal_data_new() );
 | 
			
		||||
    if (file_)
 | 
			
		||||
        *file_ = file;
 | 
			
		||||
    if (!file)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    MPMarshalledData *data = file->data? file->data: mpw_marshal_data_new();
 | 
			
		||||
    mpw_marshal_file( file, NULL, data );
 | 
			
		||||
 | 
			
		||||
    file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
 | 
			
		||||
    if (!data) {
 | 
			
		||||
    if (!file->data) {
 | 
			
		||||
        file->error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate data." };
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
@@ -652,12 +702,14 @@ const char *mpw_marshal_write(
 | 
			
		||||
        file->error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    file->error = (MPMarshalError){ MPMarshalSuccess, NULL };
 | 
			
		||||
 | 
			
		||||
    MPMasterKey masterKey = NULL;
 | 
			
		||||
    if (user->masterKeyProvider)
 | 
			
		||||
        masterKey = user->masterKeyProvider( user->algorithm, user->fullName );
 | 
			
		||||
 | 
			
		||||
    // Section: "export"
 | 
			
		||||
    MPMarshalledData *data_export = mpw_marshal_data_get( data, "export", NULL );
 | 
			
		||||
    MPMarshalledData *data_export = mpw_marshal_data_get( file->data, "export", NULL );
 | 
			
		||||
    char dateString[21];
 | 
			
		||||
    time_t now = time( NULL );
 | 
			
		||||
    if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) ))
 | 
			
		||||
@@ -665,7 +717,7 @@ const char *mpw_marshal_write(
 | 
			
		||||
    mpw_marshal_data_set_bool( user->redacted, data_export, "redacted", NULL );
 | 
			
		||||
 | 
			
		||||
    // Section: "user"
 | 
			
		||||
    MPMarshalledData *data_user = mpw_marshal_data_get( data, "user", NULL );
 | 
			
		||||
    MPMarshalledData *data_user = mpw_marshal_data_get( file->data, "user", NULL );
 | 
			
		||||
    mpw_marshal_data_set_num( user->avatar, data_user, "avatar", NULL );
 | 
			
		||||
    mpw_marshal_data_set_str( user->fullName, data_user, "full_name", NULL );
 | 
			
		||||
    mpw_marshal_data_set_str( mpw_identicon_encode( user->identicon ), data_user, "identicon", NULL );
 | 
			
		||||
@@ -676,7 +728,7 @@ const char *mpw_marshal_write(
 | 
			
		||||
        mpw_marshal_data_set_str( dateString, data_user, "last_used", NULL );
 | 
			
		||||
 | 
			
		||||
    // Section "sites"
 | 
			
		||||
    MPMarshalledData *data_sites = mpw_marshal_data_get( data, "sites", NULL );
 | 
			
		||||
    MPMarshalledData *data_sites = mpw_marshal_data_get( file->data, "sites", NULL );
 | 
			
		||||
    mpw_marshal_data_keep( data_sites, mpw_marshal_data_keep_site_exists, user );
 | 
			
		||||
    for (size_t s = 0; s < user->sites_count; ++s) {
 | 
			
		||||
        MPMarshalledSite *site = &user->sites[s];
 | 
			
		||||
@@ -715,7 +767,7 @@ const char *mpw_marshal_write(
 | 
			
		||||
        if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
 | 
			
		||||
            mpw_marshal_data_set_str( dateString, data_sites, site->siteName, "last_used", NULL );
 | 
			
		||||
 | 
			
		||||
        MPMarshalledData *data_questions = mpw_marshal_data_get( data, "sites", site->siteName, "questions", NULL );
 | 
			
		||||
        MPMarshalledData *data_questions = mpw_marshal_data_get( file->data, "sites", site->siteName, "questions", NULL );
 | 
			
		||||
        mpw_marshal_data_keep( data_questions, mpw_marshal_data_keep_question_exists, site );
 | 
			
		||||
        for (size_t q = 0; q < site->questions_count; ++q) {
 | 
			
		||||
            MPMarshalledQuestion *question = &site->questions[q];
 | 
			
		||||
@@ -761,7 +813,11 @@ const char *mpw_marshal_write(
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    if (out && file->error.type == MPMarshalSuccess)
 | 
			
		||||
        mpw_marshal_read( file, out );
 | 
			
		||||
        file = mpw_marshal_read( file, out );
 | 
			
		||||
    if (file_)
 | 
			
		||||
        *file_ = file;
 | 
			
		||||
    else
 | 
			
		||||
        mpw_marshal_file_free( &file );
 | 
			
		||||
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@ MP_LIBS_END
 | 
			
		||||
 | 
			
		||||
//// Types.
 | 
			
		||||
 | 
			
		||||
#define mpw_default( __default, __value ) ({ __typeof__ (__default) _v = (__typeof__ (__default))(__value); _v = _v? _v: __default; })
 | 
			
		||||
#define mpw_default_n( __default, __num ) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: __default; })
 | 
			
		||||
#define mpw_default(__default, __value) ({ __typeof__ (__default) _v = (__typeof__ (__default))(__value); _v = _v? _v: __default; })
 | 
			
		||||
#define mpw_default_n(__default, __num) ({ __typeof__ (__num) _n = (__num); !isnan( _n )? (__typeof__ (__default))_n: __default; })
 | 
			
		||||
 | 
			
		||||
typedef mpw_enum( unsigned int, MPMarshalFormat ) {
 | 
			
		||||
    /** Do not marshal. */
 | 
			
		||||
@@ -66,6 +66,15 @@ typedef mpw_enum( unsigned int, MPMarshalErrorType ) {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef MPMasterKey (*MPMasterKeyProvider)(MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
typedef bool (*MPMasterKeyProviderProxy)(MPMasterKey *, MPAlgorithmVersion *, MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
 | 
			
		||||
/** Create a key provider which handles key generation by proxying the given function.
 | 
			
		||||
 * The proxy function receives the currently cached key and its algorithm.  If those are NULL, the proxy function should clean up its state. */
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_proxy(const MPMasterKeyProviderProxy proxy);
 | 
			
		||||
/** Create a key provider that computes a master key for the given master password. */
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_str(const char *masterPassword);
 | 
			
		||||
/** Free the cached keys and proxy state. */
 | 
			
		||||
void mpw_masterKeyProvider_free(void);
 | 
			
		||||
 | 
			
		||||
typedef struct MPMarshalError {
 | 
			
		||||
    MPMarshalErrorType type;
 | 
			
		||||
@@ -148,9 +157,11 @@ typedef struct MPMarshalledFile {
 | 
			
		||||
//// Marshalling.
 | 
			
		||||
 | 
			
		||||
/** Write the user and all associated data out using the given marshalling format.
 | 
			
		||||
 * @param file A pointer to the original file object to update with the user's data or to NULL to make a new.
 | 
			
		||||
 *             File object will be updated with state or new (allocated).  May be NULL if not interested in a file object.
 | 
			
		||||
 * @return A string (allocated), or NULL if the file is missing, format is unrecognized, does not support marshalling or a format error occurred. */
 | 
			
		||||
const char *mpw_marshal_write(
 | 
			
		||||
        const MPMarshalFormat outFormat, MPMarshalledFile *file, MPMarshalledUser *user);
 | 
			
		||||
        const MPMarshalFormat outFormat, MPMarshalledFile **file, MPMarshalledUser *user);
 | 
			
		||||
/** Parse the user configuration in the input buffer.  Fields that could not be parsed remain at their type's initial value.
 | 
			
		||||
 * @return The updated file object or a new one (allocated) if none was provided; NULL if a file object could not be allocated. */
 | 
			
		||||
MPMarshalledFile *mpw_marshal_read(
 | 
			
		||||
 
 | 
			
		||||
@@ -579,20 +579,23 @@ const char *mpw_hex_l(const uint32_t number) {
 | 
			
		||||
    return mpw_hex( &buf, sizeof( buf ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uint8_t *mpw_unhex(const char *hex) {
 | 
			
		||||
const uint8_t *mpw_unhex(const char *hex, size_t *length) {
 | 
			
		||||
 | 
			
		||||
    if (!hex)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    size_t length = strlen( hex );
 | 
			
		||||
    if (length == 0 || length % 2 != 0)
 | 
			
		||||
    size_t hexLength = strlen( hex );
 | 
			
		||||
    if (hexLength == 0 || hexLength % 2 != 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    size_t bytes = length / 2;
 | 
			
		||||
    uint8_t *buf = malloc( bytes );
 | 
			
		||||
    for (size_t b = 0; b < bytes; ++b)
 | 
			
		||||
    size_t bufLength = hexLength / 2;
 | 
			
		||||
    if (length)
 | 
			
		||||
        *length = bufLength;
 | 
			
		||||
 | 
			
		||||
    uint8_t *buf = malloc( bufLength );
 | 
			
		||||
    for (size_t b = 0; b < bufLength; ++b)
 | 
			
		||||
        if (sscanf( hex + b * 2, "%02hhX", &buf[b] ) != 1) {
 | 
			
		||||
            mpw_free( &buf, bytes );
 | 
			
		||||
            mpw_free( &buf, bufLength );
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -230,13 +230,13 @@ const char *mpw_hotp(
 | 
			
		||||
 * @return A string (shared); or NULL if the format is missing or the result could not be allocated or formatted. */
 | 
			
		||||
const char *mpw_str(const char *format, ...);
 | 
			
		||||
const char *mpw_vstr(const char *format, va_list args);
 | 
			
		||||
/** Encode a buffer as a string of hexadecimal characters.
 | 
			
		||||
/** Encode length-bytes from a buffer as a string of hexadecimal characters.
 | 
			
		||||
 * @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */
 | 
			
		||||
const char *mpw_hex(const void *buf, const size_t length);
 | 
			
		||||
const char *mpw_hex_l(const uint32_t number);
 | 
			
		||||
/** Decode a string of hexadecimal characters into a buffer.
 | 
			
		||||
 * @return A buffer (allocated, strlen(hex) / 2); or NULL if hex is NULL, empty, or not an even-length hexadecimal string. */
 | 
			
		||||
const uint8_t *mpw_unhex(const char *hex);
 | 
			
		||||
/** Decode a string of hexadecimal characters into a buffer of length-bytes.
 | 
			
		||||
 * @return A buffer (allocated, *length); or NULL if hex is NULL, empty, or not an even-length hexadecimal string. */
 | 
			
		||||
const uint8_t *mpw_unhex(const char *hex, size_t *length);
 | 
			
		||||
/** Encode a fingerprint for a buffer.
 | 
			
		||||
 * @return A string (shared); or NULL if the buffer is missing or the result could not be allocated. */
 | 
			
		||||
const MPKeyID mpw_id_buf(const void *buf, const size_t length);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user