Pearl & API update.
This commit is contained in:
		
							
								
								
									
										2
									
								
								platform-darwin/External/Pearl
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								platform-darwin/External/Pearl
									
									
									
									
										vendored
									
									
								
							 Submodule platform-darwin/External/Pearl updated: 3d04d775e0...4eb904f9b4
									
								
							@@ -241,6 +241,11 @@
 | 
			
		||||
		DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
 | 
			
		||||
		DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */; };
 | 
			
		||||
		DAA7BC2720C4C27100101DC7 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA7BB8A20C4C10F00101DC7 /* libsodium.a */; };
 | 
			
		||||
		DAAA1D4123CD145000F3DF56 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */; };
 | 
			
		||||
		DAAA1D4423CD161300F3DF56 /* UILayoutGuide+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */; };
 | 
			
		||||
		DAAA1D4523CD161300F3DF56 /* UILayoutGuide+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */; };
 | 
			
		||||
		DAAA1D4823CD164500F3DF56 /* PearlRSAKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */; };
 | 
			
		||||
		DAAA1D4923CD164500F3DF56 /* PearlRSAKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */; };
 | 
			
		||||
		DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
 | 
			
		||||
		DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9B1F7725C500CC6D43 /* aes.c */; };
 | 
			
		||||
		DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */; };
 | 
			
		||||
@@ -415,8 +420,6 @@
 | 
			
		||||
		DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460115039823003ABA7C /* PearlKeyChain.m */; };
 | 
			
		||||
		DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */; };
 | 
			
		||||
		DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460915039823003ABA7C /* Pearl-UIKit.h */; };
 | 
			
		||||
		DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460A15039823003ABA7C /* PearlAlert.h */; };
 | 
			
		||||
		DAFE4A3F15039824003ABA7C /* PearlAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460B15039823003ABA7C /* PearlAlert.m */; };
 | 
			
		||||
		DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460C15039823003ABA7C /* PearlArrayTVC.h */; };
 | 
			
		||||
		DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460D15039823003ABA7C /* PearlArrayTVC.m */; };
 | 
			
		||||
		DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460E15039823003ABA7C /* PearlBoxView.h */; };
 | 
			
		||||
@@ -427,8 +430,6 @@
 | 
			
		||||
		DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461715039823003ABA7C /* PearlMessageView.m */; };
 | 
			
		||||
		DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461815039823003ABA7C /* PearlRootViewController.h */; };
 | 
			
		||||
		DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461915039823003ABA7C /* PearlRootViewController.m */; };
 | 
			
		||||
		DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461A15039823003ABA7C /* PearlSheet.h */; };
 | 
			
		||||
		DAFE4A4F15039824003ABA7C /* PearlSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461B15039823003ABA7C /* PearlSheet.m */; };
 | 
			
		||||
		DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461C15039823003ABA7C /* PearlUIDebug.h */; };
 | 
			
		||||
		DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461D15039823003ABA7C /* PearlUIDebug.m */; };
 | 
			
		||||
		DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461E15039823003ABA7C /* PearlUIUtils.h */; };
 | 
			
		||||
@@ -896,6 +897,11 @@
 | 
			
		||||
		DAA7BBC620C4C10F00101DC7 /* crypto_generichash_blake2b.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_generichash_blake2b.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAA7BBC720C4C10F00101DC7 /* crypto_sign_edwards25519sha512batch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_sign_edwards25519sha512batch.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAA7BBC820C4C10F00101DC7 /* sodium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sodium.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
 | 
			
		||||
		DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILayoutGuide+Pearl.m"; sourceTree = "<group>"; };
 | 
			
		||||
		DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILayoutGuide+Pearl.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRSAKey.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRSAKey.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
 | 
			
		||||
		DAB07C9B1F7725C500CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
 | 
			
		||||
		DAB07C9C1F7725C500CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
 | 
			
		||||
@@ -1640,8 +1646,6 @@
 | 
			
		||||
		DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit-Dependencies.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460915039823003ABA7C /* Pearl-UIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit.h"; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460A15039823003ABA7C /* PearlAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlAlert.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460B15039823003ABA7C /* PearlAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlAlert.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460C15039823003ABA7C /* PearlArrayTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlArrayTVC.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460D15039823003ABA7C /* PearlArrayTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlArrayTVC.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE460E15039823003ABA7C /* PearlBoxView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlBoxView.h; sourceTree = "<group>"; };
 | 
			
		||||
@@ -1652,8 +1656,6 @@
 | 
			
		||||
		DAFE461715039823003ABA7C /* PearlMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlMessageView.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461815039823003ABA7C /* PearlRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRootViewController.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461915039823003ABA7C /* PearlRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRootViewController.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461A15039823003ABA7C /* PearlSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlSheet.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461B15039823003ABA7C /* PearlSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSheet.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461C15039823003ABA7C /* PearlUIDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIDebug.h; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461D15039823003ABA7C /* PearlUIDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIDebug.m; sourceTree = "<group>"; };
 | 
			
		||||
		DAFE461E15039823003ABA7C /* PearlUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIUtils.h; sourceTree = "<group>"; };
 | 
			
		||||
@@ -2940,6 +2942,7 @@
 | 
			
		||||
		DABD3BD71711E2DC00CF925C /* iOS */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */,
 | 
			
		||||
				DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */,
 | 
			
		||||
				DABD3BFC1711E2DC00CF925C /* main.m */,
 | 
			
		||||
				DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */,
 | 
			
		||||
@@ -3166,6 +3169,8 @@
 | 
			
		||||
				DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */,
 | 
			
		||||
				DAFE460015039823003ABA7C /* PearlKeyChain.h */,
 | 
			
		||||
				DAFE460115039823003ABA7C /* PearlKeyChain.m */,
 | 
			
		||||
				DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */,
 | 
			
		||||
				DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */,
 | 
			
		||||
				DAFE460615039823003ABA7C /* README */,
 | 
			
		||||
			);
 | 
			
		||||
			path = "Pearl-Crypto";
 | 
			
		||||
@@ -3179,8 +3184,6 @@
 | 
			
		||||
				DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */,
 | 
			
		||||
				DAFE460915039823003ABA7C /* Pearl-UIKit.h */,
 | 
			
		||||
				DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */,
 | 
			
		||||
				DAFE460A15039823003ABA7C /* PearlAlert.h */,
 | 
			
		||||
				DAFE460B15039823003ABA7C /* PearlAlert.m */,
 | 
			
		||||
				DAFE4A61150399FF003ABA7C /* PearlAppDelegate.h */,
 | 
			
		||||
				DAFE4A60150399FF003ABA7C /* PearlAppDelegate.m */,
 | 
			
		||||
				DAFE460C15039823003ABA7C /* PearlArrayTVC.h */,
 | 
			
		||||
@@ -3205,8 +3208,6 @@
 | 
			
		||||
				93D390FADEB325D8D54A957D /* PearlOverlay.m */,
 | 
			
		||||
				DAFE461815039823003ABA7C /* PearlRootViewController.h */,
 | 
			
		||||
				DAFE461915039823003ABA7C /* PearlRootViewController.m */,
 | 
			
		||||
				DAFE461A15039823003ABA7C /* PearlSheet.h */,
 | 
			
		||||
				DAFE461B15039823003ABA7C /* PearlSheet.m */,
 | 
			
		||||
				93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */,
 | 
			
		||||
				93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */,
 | 
			
		||||
				93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */,
 | 
			
		||||
@@ -3231,6 +3232,8 @@
 | 
			
		||||
				DAFE4A63150399FF003ABA89 /* UIControl+PearlSelect.m */,
 | 
			
		||||
				DAFE4A1115039824003ABA7C /* UIImage+PearlScaling.h */,
 | 
			
		||||
				DAFE4A1215039824003ABA7C /* UIImage+PearlScaling.m */,
 | 
			
		||||
				DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */,
 | 
			
		||||
				DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */,
 | 
			
		||||
				93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */,
 | 
			
		||||
				93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */,
 | 
			
		||||
				93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */,
 | 
			
		||||
@@ -3296,6 +3299,7 @@
 | 
			
		||||
				DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
 | 
			
		||||
				DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
 | 
			
		||||
				DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */,
 | 
			
		||||
				DAAA1D4923CD164500F3DF56 /* PearlRSAKey.h in Headers */,
 | 
			
		||||
				DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
 | 
			
		||||
				DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
 | 
			
		||||
				DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
 | 
			
		||||
@@ -3322,7 +3326,6 @@
 | 
			
		||||
				DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */,
 | 
			
		||||
				DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
 | 
			
		||||
				DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
 | 
			
		||||
				DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
 | 
			
		||||
				DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */,
 | 
			
		||||
				DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
 | 
			
		||||
				DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
 | 
			
		||||
@@ -3332,7 +3335,6 @@
 | 
			
		||||
				DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
 | 
			
		||||
				DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
 | 
			
		||||
				DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */,
 | 
			
		||||
				DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
 | 
			
		||||
				DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
 | 
			
		||||
				DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
 | 
			
		||||
				DAFE4A5415039824003ABA7C /* PearlValidatingTextField.h in Headers */,
 | 
			
		||||
@@ -3368,6 +3370,7 @@
 | 
			
		||||
				93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
 | 
			
		||||
				93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
 | 
			
		||||
				DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */,
 | 
			
		||||
				DAAA1D4523CD161300F3DF56 /* UILayoutGuide+Pearl.h in Headers */,
 | 
			
		||||
				93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
@@ -3874,6 +3877,7 @@
 | 
			
		||||
				DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
 | 
			
		||||
				DAA1764619D8B82B0044227B /* name_new.png in Resources */,
 | 
			
		||||
				DA45224B190628B2008F650A /* icon_gear.png in Resources */,
 | 
			
		||||
				DAAA1D4123CD145000F3DF56 /* Storyboard.storyboard in Resources */,
 | 
			
		||||
				DA8495311A93049300B3053D /* icon_down.png in Resources */,
 | 
			
		||||
				DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
 | 
			
		||||
				DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
 | 
			
		||||
@@ -4059,6 +4063,7 @@
 | 
			
		||||
				DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
 | 
			
		||||
				DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
 | 
			
		||||
				DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
 | 
			
		||||
				DAAA1D4823CD164500F3DF56 /* PearlRSAKey.m in Sources */,
 | 
			
		||||
				DAFE4A1B15039824003ABA7C /* PearlAbstractStrings.m in Sources */,
 | 
			
		||||
				DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
 | 
			
		||||
				DAEFB01E19BCBD9E00525079 /* UIView+LayoutGone.m in Sources */,
 | 
			
		||||
@@ -4073,7 +4078,6 @@
 | 
			
		||||
				DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
 | 
			
		||||
				DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */,
 | 
			
		||||
				DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */,
 | 
			
		||||
				DAFE4A3F15039824003ABA7C /* PearlAlert.m in Sources */,
 | 
			
		||||
				DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */,
 | 
			
		||||
				DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */,
 | 
			
		||||
				DAFE4A4515039824003ABA7C /* PearlGradientView.m in Sources */,
 | 
			
		||||
@@ -4082,7 +4086,6 @@
 | 
			
		||||
				DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */,
 | 
			
		||||
				DACE2F6519BA6A0A0010F92E /* PearlProfiler.m in Sources */,
 | 
			
		||||
				DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */,
 | 
			
		||||
				DAFE4A4F15039824003ABA7C /* PearlSheet.m in Sources */,
 | 
			
		||||
				DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */,
 | 
			
		||||
				DAFE4A5315039824003ABA7C /* PearlUIUtils.m in Sources */,
 | 
			
		||||
				DAFE4A5515039824003ABA7C /* PearlValidatingTextField.m in Sources */,
 | 
			
		||||
@@ -4119,6 +4122,7 @@
 | 
			
		||||
				93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
 | 
			
		||||
				93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
 | 
			
		||||
				DAA141201922FF020032B392 /* PearlTween.m in Sources */,
 | 
			
		||||
				DAAA1D4423CD161300F3DF56 /* UILayoutGuide+Pearl.m in Sources */,
 | 
			
		||||
				DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */,
 | 
			
		||||
				93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
 | 
			
		||||
				DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */,
 | 
			
		||||
@@ -4309,7 +4313,7 @@
 | 
			
		||||
				GCC_WARN_UNUSED_LABEL = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VALUE = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 | 
			
		||||
				MTL_ENABLE_DEBUG_INFO = NO;
 | 
			
		||||
				OTHER_LDFLAGS = "-ObjC";
 | 
			
		||||
				PRODUCT_NAME = "${TARGET_NAME}";
 | 
			
		||||
@@ -4348,7 +4352,6 @@
 | 
			
		||||
					"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
 | 
			
		||||
				);
 | 
			
		||||
				INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 | 
			
		||||
				LIBRARY_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
@@ -4523,7 +4526,7 @@
 | 
			
		||||
				GCC_WARN_UNUSED_LABEL = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VALUE = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 | 
			
		||||
				MTL_ENABLE_DEBUG_INFO = YES;
 | 
			
		||||
				ONLY_ACTIVE_ARCH = YES;
 | 
			
		||||
				OTHER_LDFLAGS = "-ObjC";
 | 
			
		||||
@@ -4628,7 +4631,7 @@
 | 
			
		||||
				GCC_WARN_UNUSED_LABEL = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VALUE = YES;
 | 
			
		||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 | 
			
		||||
				MTL_ENABLE_DEBUG_INFO = NO;
 | 
			
		||||
				OTHER_LDFLAGS = "-ObjC";
 | 
			
		||||
				PRODUCT_NAME = "${TARGET_NAME}";
 | 
			
		||||
@@ -4666,7 +4669,6 @@
 | 
			
		||||
					"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
 | 
			
		||||
				);
 | 
			
		||||
				INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 | 
			
		||||
				LIBRARY_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
@@ -4710,7 +4712,6 @@
 | 
			
		||||
					"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
 | 
			
		||||
				);
 | 
			
		||||
				INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
 | 
			
		||||
				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 | 
			
		||||
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 | 
			
		||||
				LIBRARY_SEARCH_PATHS = (
 | 
			
		||||
					"$(inherited)",
 | 
			
		||||
@@ -4728,7 +4729,6 @@
 | 
			
		||||
				SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
 | 
			
		||||
				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 | 
			
		||||
				SWIFT_VERSION = 4.0;
 | 
			
		||||
				TARGETED_DEVICE_FAMILY = 1;
 | 
			
		||||
			};
 | 
			
		||||
			name = Release;
 | 
			
		||||
		};
 | 
			
		||||
 
 | 
			
		||||
@@ -104,24 +104,19 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IPHONE
 | 
			
		||||
    if (![[MPAppDelegate_Shared get] canMakePayments]) {
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"App Store Not Set Up" message:
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"App Store Not Set Up" message:
 | 
			
		||||
                        @"Make sure your Apple ID is set under Settings -> iTunes & App Store, "
 | 
			
		||||
                                @"you have a payment method added to the account and purchases are"
 | 
			
		||||
                                @"not disabled under General -> Restrictions."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                         if (buttonIndex == alert.cancelButtonIndex)
 | 
			
		||||
                             // Cancel
 | 
			
		||||
                             return;
 | 
			
		||||
                         if (buttonIndex == alert.firstOtherButtonIndex) {
 | 
			
		||||
                             // Settings
 | 
			
		||||
                             [PearlLinks openSettingsStore];
 | 
			
		||||
                             return;
 | 
			
		||||
                         }
 | 
			
		||||
 | 
			
		||||
                         // Try Anyway
 | 
			
		||||
                         [self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
 | 
			
		||||
                     } cancelTitle:@"Cancel" otherTitles:@"Settings", @"Try Anyway", nil];
 | 
			
		||||
                        @"you have a payment method added to the account and purchases are"
 | 
			
		||||
                        @"not disabled under General -> Restrictions."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            [PearlLinks openSettingsStore];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Try Anyway" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            [self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -163,11 +158,12 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
 | 
			
		||||
    MPError( error, @"StoreKit request (%@) failed.", request );
 | 
			
		||||
 | 
			
		||||
#if TARGET_OS_IPHONE
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Purchase Failed" message:
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
 | 
			
		||||
                    strf( @"%@\n\n%@", error.localizedDescription,
 | 
			
		||||
                            @"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
 | 
			
		||||
                       cancelTitle:@"OK" otherTitles:nil];
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
#else
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -256,17 +256,19 @@
 | 
			
		||||
 | 
			
		||||
#ifdef PEARL_UIKIT
 | 
			
		||||
                masterPassword = PearlAwait( ^(void (^setResult)(id)) {
 | 
			
		||||
                    [PearlAlert showAlertWithTitle:@"Enter Old Master Password"
 | 
			
		||||
                                           message:PearlString(
 | 
			
		||||
                                                           @"Your old master password is required to migrate the stored password for %@",
 | 
			
		||||
                                                           site.name )
 | 
			
		||||
                                         viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                         initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                                if (buttonIndex_ == [alert_ cancelButtonIndex])
 | 
			
		||||
                                    setResult( nil );
 | 
			
		||||
                                else
 | 
			
		||||
                                    setResult( [alert_ textFieldAtIndex:0].text );
 | 
			
		||||
                            }          cancelTitle:@"Don't Migrate" otherTitles:@"Migrate", nil];
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
 | 
			
		||||
                                    PearlString( @"Your old master password is required to migrate the stored password for %@", site.name )
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addTextFieldWithConfigurationHandler:nil];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
 | 
			
		||||
                            ^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
                            }]];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Don't Migrate" style:UIAlertActionStyleCancel handler:
 | 
			
		||||
                            ^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                                setResult( nil );
 | 
			
		||||
                            }]];
 | 
			
		||||
                    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                } );
 | 
			
		||||
#endif
 | 
			
		||||
                if (!masterPassword)
 | 
			
		||||
 
 | 
			
		||||
@@ -51,17 +51,21 @@
 | 
			
		||||
 | 
			
		||||
#define mpw_log(level, format, ...) \
 | 
			
		||||
    do { \
 | 
			
		||||
        void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
 | 
			
		||||
        char *_msg = NULL; \
 | 
			
		||||
        asprintf( &_msg, format, ##__VA_ARGS__ ); \
 | 
			
		||||
        CFStringRef fileStr = CFStringCreateWithCString( NULL, basename( (char *)__FILE__ ), kCFStringEncodingUTF8 ); \
 | 
			
		||||
        CFStringRef funcStr = CFStringCreateWithCString( NULL, __FUNCTION__, kCFStringEncodingUTF8 ); \
 | 
			
		||||
        CFStringRef msgStr = CFStringCreateWithCString( NULL, _msg, kCFStringEncodingUTF8 ); \
 | 
			
		||||
        _sendMsg( objc_msgSend( (id)objc_getClass( "PearlLogger" ), sel_getUid( "get" ) ), \
 | 
			
		||||
                sel_getUid( "inFile:atLine:fromFunction:withLevel:text:" ), fileStr, __LINE__, funcStr, level, msgStr ); \
 | 
			
		||||
        CFRelease( fileStr ); \
 | 
			
		||||
        CFRelease( funcStr ); \
 | 
			
		||||
        CFRelease( msgStr ); \
 | 
			
		||||
        if (_msg) { \
 | 
			
		||||
            CFStringRef fileStr = CFStringCreateWithCString( NULL, basename( (char *)__FILE__ ), kCFStringEncodingUTF8 ); \
 | 
			
		||||
            CFStringRef funcStr = CFStringCreateWithCString( NULL, __FUNCTION__, kCFStringEncodingUTF8 ); \
 | 
			
		||||
            CFStringRef msgStr = CFStringCreateWithCString( NULL, _msg, kCFStringEncodingUTF8 ); \
 | 
			
		||||
            id (*_getLogger)(id, SEL) = (void *)objc_msgSend; \
 | 
			
		||||
            void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
 | 
			
		||||
            _sendMsg( _getLogger( (id)objc_getClass( "PearlLogger" ), sel_getUid( "get" ) ), \
 | 
			
		||||
                    sel_getUid( "inFile:atLine:fromFunction:withLevel:text:" ), fileStr, __LINE__, funcStr, level, msgStr ); \
 | 
			
		||||
            if (fileStr) { CFRelease( fileStr ); } \
 | 
			
		||||
            if (funcStr) { CFRelease( funcStr ); } \
 | 
			
		||||
            if (msgStr) { CFRelease( msgStr ); } \
 | 
			
		||||
            free(_msg); \
 | 
			
		||||
        } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );
 | 
			
		||||
 
 | 
			
		||||
@@ -172,23 +172,24 @@
 | 
			
		||||
            if (![site.questions count])
 | 
			
		||||
                [self setMultiple:NO animated:YES];
 | 
			
		||||
 | 
			
		||||
            else
 | 
			
		||||
                [PearlAlert showAlertWithTitle:@"Remove Site Questions?" message:
 | 
			
		||||
            else {
 | 
			
		||||
                UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Remove Site Questions?" message:
 | 
			
		||||
                                @"Do you want to remove the questions you have configured for this site?"
 | 
			
		||||
                                     viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                             tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                                 if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                                     return;
 | 
			
		||||
 | 
			
		||||
                                 [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                                     MPSiteEntity *site_ = [self siteInContext:context];
 | 
			
		||||
                                     NSOrderedSet *questions = [site_.questions copy];
 | 
			
		||||
                                     for (MPSiteQuestionEntity *question in questions)
 | 
			
		||||
                                         [context deleteObject:question];
 | 
			
		||||
                                     [context saveToStore];
 | 
			
		||||
                                     [self setMultiple:NO animated:YES];
 | 
			
		||||
                                 }];
 | 
			
		||||
                             } cancelTitle:@"Cancel" otherTitles:@"Remove Questions", nil];
 | 
			
		||||
                                                                             preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                [controller addAction:[UIAlertAction actionWithTitle:@"Remove Questions" style:UIAlertActionStyleDestructive handler:
 | 
			
		||||
                        ^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                            [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                                MPSiteEntity *site_ = [self siteInContext:context];
 | 
			
		||||
                                NSOrderedSet *questions = [site_.questions copy];
 | 
			
		||||
                                for (MPSiteQuestionEntity *question in questions)
 | 
			
		||||
                                    [context deleteObject:question];
 | 
			
		||||
                                [context saveToStore];
 | 
			
		||||
                                [self setMultiple:NO animated:YES];
 | 
			
		||||
                            }];
 | 
			
		||||
                        }]];
 | 
			
		||||
                [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -197,9 +198,9 @@
 | 
			
		||||
        if (!self.multiple) {
 | 
			
		||||
            NSObject *answer = [site resolveSiteAnswerUsingKey:[MPiOSAppDelegate get].key];
 | 
			
		||||
            body = strf( @"Master Password generated the following security answer for your site: %@\n\n"
 | 
			
		||||
                    @"%@\n"
 | 
			
		||||
                    @"\n\nYou should use this as the answer to each security question the site asks you.\n"
 | 
			
		||||
                    @"Do not share this answer with others!", site.name, answer );
 | 
			
		||||
                         @"%@\n"
 | 
			
		||||
                         @"\n\nYou should use this as the answer to each security question the site asks you.\n"
 | 
			
		||||
                         @"Do not share this answer with others!", site.name, answer );
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            NSMutableString *bodyBuilder = [NSMutableString string];
 | 
			
		||||
@@ -209,7 +210,7 @@
 | 
			
		||||
                [bodyBuilder appendFormat:@"For question: '%@', use answer: %@\n", question.keyword, answer];
 | 
			
		||||
            }
 | 
			
		||||
            [bodyBuilder appendFormat:@"\n\nUse the answer for the matching security question.\n"
 | 
			
		||||
                    @"Do not share this answer with others!"];
 | 
			
		||||
                                      @"Do not share this answer with others!"];
 | 
			
		||||
            body = bodyBuilder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -225,7 +226,7 @@
 | 
			
		||||
- (void)copyAnswer:(NSString *)answer {
 | 
			
		||||
 | 
			
		||||
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
 | 
			
		||||
    if (@available(iOS 10.0, *)) {
 | 
			
		||||
    if (@available( iOS 10.0, * )) {
 | 
			
		||||
        [pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
 | 
			
		||||
                     options:@{
 | 
			
		||||
                             UIPasteboardOptionLocalOnly     : @NO,
 | 
			
		||||
 
 | 
			
		||||
@@ -228,9 +228,9 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                             case MPAvatarModeLowered: {
 | 
			
		||||
                                 [self.avatarSizeConstraint updateConstant:
 | 
			
		||||
                                         self.avatarImageView.image.size.height * (self.visibility * 0.3f + 0.7f)];
 | 
			
		||||
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 self.nameContainer.visible = YES;
 | 
			
		||||
                                 self.nameContainer.backgroundColor = [UIColor clearColor];
 | 
			
		||||
                                 self.avatarImageView.visible = YES;
 | 
			
		||||
@@ -239,9 +239,9 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                             case MPAvatarModeRaisedButInactive: {
 | 
			
		||||
                                 [self.avatarSizeConstraint updateConstant:
 | 
			
		||||
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
 | 
			
		||||
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 self.nameContainer.visible = YES;
 | 
			
		||||
                                 self.nameContainer.backgroundColor = [UIColor clearColor];
 | 
			
		||||
                                 self.avatarImageView.visible = NO;
 | 
			
		||||
@@ -250,9 +250,9 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                             case MPAvatarModeRaisedAndActive: {
 | 
			
		||||
                                 [self.avatarSizeConstraint updateConstant:
 | 
			
		||||
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
 | 
			
		||||
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 self.nameContainer.visible = YES;
 | 
			
		||||
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                                 self.avatarImageView.visible = YES;
 | 
			
		||||
@@ -261,9 +261,9 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                             case MPAvatarModeRaisedAndHidden: {
 | 
			
		||||
                                 [self.avatarSizeConstraint updateConstant:
 | 
			
		||||
                                         self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
 | 
			
		||||
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 self.nameContainer.visible = NO;
 | 
			
		||||
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                                 self.avatarImageView.visible = NO;
 | 
			
		||||
@@ -271,9 +271,9 @@ const long MPAvatarAdd = 10000;
 | 
			
		||||
                             }
 | 
			
		||||
                             case MPAvatarModeRaisedAndMinimized: {
 | 
			
		||||
                                 [self.avatarSizeConstraint updateConstant:36];
 | 
			
		||||
                                 [self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2];
 | 
			
		||||
                                 [self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultLow];
 | 
			
		||||
                                 [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultHigh + 2];
 | 
			
		||||
                                 [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
 | 
			
		||||
                                 self.nameContainer.visible = NO;
 | 
			
		||||
                                 self.nameContainer.backgroundColor = [UIColor blackColor];
 | 
			
		||||
                                 self.avatarImageView.visible = YES;
 | 
			
		||||
 
 | 
			
		||||
@@ -56,16 +56,15 @@
 | 
			
		||||
 | 
			
		||||
    BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
 | 
			
		||||
    if (traceEnabled) {
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message:
 | 
			
		||||
                        @"Trace mode will log the internal operation of the application.\n"
 | 
			
		||||
                                @"Unless you're looking for the cause of a problem, you should leave this off to save memory."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                         if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                             return;
 | 
			
		||||
 | 
			
		||||
                         [MPiOSConfig get].traceMode = @YES;
 | 
			
		||||
                     } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Enable Trace", nil];
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enable Trace Mode?" message:
 | 
			
		||||
                                         @"Trace mode will log the internal operation of the application.\n"
 | 
			
		||||
                                         @"Unless you're looking for the cause of a problem, you should leave this off to save memory."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Enable Trace" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            [MPiOSConfig get].traceMode = @YES;
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        [MPiOSConfig get].traceMode = @NO;
 | 
			
		||||
@@ -79,13 +78,14 @@
 | 
			
		||||
- (IBAction)mail:(UIBarButtonItem *)sender {
 | 
			
		||||
 | 
			
		||||
    if ([[MPiOSConfig get].traceMode boolValue]) {
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message:
 | 
			
		||||
                        @"Trace-level log messages will not be mailed. "
 | 
			
		||||
                                @"These messages contain sensitive and personal information."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                         [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
 | 
			
		||||
                     } cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Hiding Trace Messages" message:
 | 
			
		||||
                                         @"Trace-level log messages will not be mailed. "
 | 
			
		||||
                                         @"These messages contain sensitive and personal information."
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
 | 
			
		||||
        }]];
 | 
			
		||||
        [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
 | 
			
		||||
        [UIView animateWithDuration:0.6f delay:0 usingSpringWithDamping:0.75f initialSpringVelocity:1
 | 
			
		||||
                            options:UIViewAnimationOptionCurveEaseOut animations:^{
 | 
			
		||||
                    [[passwordsVC.popdownToTopConstraint updatePriority:1] layoutIfNeeded];
 | 
			
		||||
                    [[passwordsVC.popdownToTopConstraint withPriority:1] layoutIfNeeded];
 | 
			
		||||
                }        completion:^(BOOL finished) {
 | 
			
		||||
                    [popdownVC didMoveToParentViewController:passwordsVC];
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +63,7 @@
 | 
			
		||||
        [popdownVC willMoveToParentViewController:nil];
 | 
			
		||||
        [UIView animateWithDuration:0.4f delay:0 options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionOverrideInheritedDuration
 | 
			
		||||
                         animations:^{
 | 
			
		||||
                             [[passwordsVC.popdownToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded];
 | 
			
		||||
                             [[passwordsVC.popdownToTopConstraint withPriority:UILayoutPriorityDefaultHigh] layoutIfNeeded];
 | 
			
		||||
                         } completion:^(BOOL finished) {
 | 
			
		||||
                    [popdownVC.view removeFromSuperview];
 | 
			
		||||
                    [popdownVC removeFromParentViewController];
 | 
			
		||||
 
 | 
			
		||||
@@ -114,11 +114,13 @@
 | 
			
		||||
 | 
			
		||||
    if (cell == self.checkInconsistencies)
 | 
			
		||||
        [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
            if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems)
 | 
			
		||||
                [PearlAlert showAlertWithTitle:@"No Inconsistencies" message:
 | 
			
		||||
            if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) {
 | 
			
		||||
                UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message:
 | 
			
		||||
                                @"No inconsistencies were detected in your sites."
 | 
			
		||||
                                     viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                             tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
                                                                             preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:nil]];
 | 
			
		||||
                [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
 | 
			
		||||
 
 | 
			
		||||
@@ -261,19 +261,20 @@
 | 
			
		||||
    if (!site)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    [PearlSheet showSheetWithTitle:strf( @"Delete %@?", site.name ) viewStyle:UIActionSheetStyleAutomatic
 | 
			
		||||
                         initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
 | 
			
		||||
                if (buttonIndex == [sheet cancelButtonIndex])
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                    MPSiteEntity *site_ = [self siteInContext:context];
 | 
			
		||||
                    if (site_) {
 | 
			
		||||
                        [context deleteObject:site_];
 | 
			
		||||
                        [context saveToStore];
 | 
			
		||||
                    }
 | 
			
		||||
                }];
 | 
			
		||||
            }          cancelTitle:@"Cancel" destructiveTitle:@"Delete Site" otherTitles:nil];
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Delete %@?", site.name ) message:nil
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Delete Site" style:UIAlertActionStyleDestructive
 | 
			
		||||
                                                 handler:^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                                                     [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                                                         MPSiteEntity *site_ = [self siteInContext:context];
 | 
			
		||||
                                                         if (site_) {
 | 
			
		||||
                                                             [context deleteObject:site_];
 | 
			
		||||
                                                             [context saveToStore];
 | 
			
		||||
                                                         }
 | 
			
		||||
                                                     }];
 | 
			
		||||
                                                 }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)doChangeType:(UIButton *)sender {
 | 
			
		||||
@@ -281,29 +282,24 @@
 | 
			
		||||
    [self setMode:MPPasswordCellModePassword animated:YES];
 | 
			
		||||
 | 
			
		||||
    MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
 | 
			
		||||
    [PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
 | 
			
		||||
                         initSheet:^(UIActionSheet *sheet) {
 | 
			
		||||
                             for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
 | 
			
		||||
                                 MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
 | 
			
		||||
                                 NSString *typeName = [mainSite.algorithm nameOfType:type];
 | 
			
		||||
                                 if (type == mainSite.type)
 | 
			
		||||
                                     [sheet addButtonWithTitle:strf( @"● %@", typeName )];
 | 
			
		||||
                                 else
 | 
			
		||||
                                     [sheet addButtonWithTitle:typeName];
 | 
			
		||||
                             }
 | 
			
		||||
                         } tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
 | 
			
		||||
                if (buttonIndex == [sheet cancelButtonIndex])
 | 
			
		||||
                    return;
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Change Password Type" message:nil
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
    for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
 | 
			
		||||
        MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
 | 
			
		||||
        NSString *typeName = [mainSite.algorithm nameOfType:type];
 | 
			
		||||
        NSString *title = type == mainSite.type? strf( @"● %@", typeName ): typeName;
 | 
			
		||||
 | 
			
		||||
                MPResultType type = (MPResultType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
 | 
			
		||||
                                  mainSite.user.defaultType?: mainSite.algorithm.defaultType;
 | 
			
		||||
 | 
			
		||||
                [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                    MPSiteEntity *site = [self siteInContext:context];
 | 
			
		||||
                    site = [[MPiOSAppDelegate get] changeSite:site saveInContext:context toType:type];
 | 
			
		||||
                    [self setSite:site animated:YES];
 | 
			
		||||
                }];
 | 
			
		||||
            }          cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:
 | 
			
		||||
                ^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                    [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                        MPSiteEntity *site = [self siteInContext:context];
 | 
			
		||||
                        site = [[MPiOSAppDelegate get] changeSite:site saveInContext:context toType:type];
 | 
			
		||||
                        [self setSite:site animated:YES];
 | 
			
		||||
                    }];
 | 
			
		||||
                }]];
 | 
			
		||||
    }
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)doEdit:(UIButton *)sender {
 | 
			
		||||
@@ -370,24 +366,23 @@
 | 
			
		||||
 | 
			
		||||
    [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
 | 
			
		||||
        MPSiteEntity *mainSite = [self siteInContext:mainContext];
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Login Page" message:nil
 | 
			
		||||
                             viewStyle:UIAlertViewStylePlainTextInput
 | 
			
		||||
                             initAlert:^(UIAlertView *alert, UITextField *firstField) {
 | 
			
		||||
                                 firstField.placeholder = strf( @"Login URL for %@", mainSite.name );
 | 
			
		||||
                                 firstField.text = mainSite.url;
 | 
			
		||||
                             }
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                         if (buttonIndex == alert.cancelButtonIndex)
 | 
			
		||||
                             return;
 | 
			
		||||
 | 
			
		||||
                         [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                             MPSiteEntity *site = [self siteInContext:context];
 | 
			
		||||
                             NSURL *url = [NSURL URLWithString:[alert textFieldAtIndex:0].text];
 | 
			
		||||
                             site.url = [url.host? url: nil absoluteString];
 | 
			
		||||
                             [context saveToStore];
 | 
			
		||||
                         }];
 | 
			
		||||
                     }
 | 
			
		||||
                           cancelTitle:@"Cancel" otherTitles:@"Save", nil];
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Login Page" message:nil
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
        [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
            textField.placeholder = strf( @"Login URL for %@", mainSite.name );
 | 
			
		||||
            textField.text = mainSite.url;
 | 
			
		||||
        }];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Save" style:UIAlertActionStyleDefault
 | 
			
		||||
                                                     handler:^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                                                         [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
 | 
			
		||||
                                                             MPSiteEntity *site = [self siteInContext:context];
 | 
			
		||||
                                                             NSURL *url = [NSURL URLWithString:controller.textFields.firstObject.text];
 | 
			
		||||
                                                             site.url = [url.host? url: nil absoluteString];
 | 
			
		||||
                                                             [context saveToStore];
 | 
			
		||||
                                                         }];
 | 
			
		||||
                                                     }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -446,15 +441,11 @@
 | 
			
		||||
 | 
			
		||||
    if (self.transientSite) {
 | 
			
		||||
        [[UIResponder findFirstResponder] resignFirstResponder];
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Create Site"
 | 
			
		||||
                               message:strf( @"Remember site named:\n%@", self.transientSite )
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                             initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                    if (buttonIndex == [alert cancelButtonIndex]) {
 | 
			
		||||
                        self.contentButton.selected = NO;
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Create Site" message:
 | 
			
		||||
                        strf( @"Remember site named:\n%@", self.transientSite )
 | 
			
		||||
                                                                     preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:
 | 
			
		||||
                ^(UIAlertAction *_Nonnull action) {
 | 
			
		||||
                    [[MPiOSAppDelegate get]
 | 
			
		||||
                            addSiteNamed:self.transientSite completion:^(MPSiteEntity *site, NSManagedObjectContext *context) {
 | 
			
		||||
                        [self copyContentOfSite:site saveInContext:context];
 | 
			
		||||
@@ -465,7 +456,11 @@
 | 
			
		||||
                            }];
 | 
			
		||||
                        } );
 | 
			
		||||
                    }];
 | 
			
		||||
                }          cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
 | 
			
		||||
                }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
            self.contentButton.selected = NO;
 | 
			
		||||
        }]];
 | 
			
		||||
        [UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -677,7 +672,7 @@
 | 
			
		||||
        [self.window endEditing:YES];
 | 
			
		||||
 | 
			
		||||
        UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
 | 
			
		||||
        if (@available(iOS 10.0, *)) {
 | 
			
		||||
        if (@available( iOS 10.0, * )) {
 | 
			
		||||
            [pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: password } ]
 | 
			
		||||
                         options:@{
 | 
			
		||||
                                 UIPasteboardOptionLocalOnly     : @NO,
 | 
			
		||||
 
 | 
			
		||||
@@ -447,8 +447,8 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
 | 
			
		||||
    _active = active;
 | 
			
		||||
 | 
			
		||||
    [UIView animateWithDuration:animated? 0.4f: 0 animations:^{
 | 
			
		||||
        [self.navigationBarToTopConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
        [self.sitesToBottomConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
        [self.navigationBarToTopConstraint withPriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
        [self.sitesToBottomConstraint withPriority:active? 1: UILayoutPriorityDefaultHigh];
 | 
			
		||||
        [self.view layoutIfNeeded];
 | 
			
		||||
    }                completion:completion];
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -146,15 +146,14 @@ PearlEnum( MPDevelopmentFuelConsumption,
 | 
			
		||||
 | 
			
		||||
- (IBAction)restorePurchases:(id)sender {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"Restore Previous Purchases" message:
 | 
			
		||||
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Restore Previous Purchases" message:
 | 
			
		||||
                    @"This will check with Apple to find and activate any purchases you made from other devices."
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                 tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                     if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                         return;
 | 
			
		||||
 | 
			
		||||
                     [[MPAppDelegate_Shared get] restoreCompletedTransactions];
 | 
			
		||||
                 } cancelTitle:@"Cancel" otherTitles:@"Find Purchases", nil];
 | 
			
		||||
                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Find Purchases" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
        [[MPAppDelegate_Shared get] restoreCompletedTransactions];
 | 
			
		||||
    }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (IBAction)sendThanks:(id)sender {
 | 
			
		||||
 
 | 
			
		||||
@@ -432,33 +432,27 @@ referenceSizeForFooterInSection:(NSInteger)section {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        NSManagedObjectID *userID = user.permanentObjectID;
 | 
			
		||||
        [PearlSheet showSheetWithTitle:user.name
 | 
			
		||||
                             viewStyle:UIActionSheetStyleBlackTranslucent
 | 
			
		||||
                             initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
 | 
			
		||||
                    if (buttonIndex == [sheet cancelButtonIndex])
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (buttonIndex == [sheet destructiveButtonIndex]) {
 | 
			
		||||
                        // Delete User
 | 
			
		||||
                        [PearlAlert showParentalGateWithTitle:@"Deleting User" message:
 | 
			
		||||
                                        @"The user and its sites will be deleted.\nPlease confirm by solving:"
 | 
			
		||||
                                                   completion:^(BOOL continuing) {
 | 
			
		||||
                                                       if (continuing)
 | 
			
		||||
                                                           [self deleteUser:userID];
 | 
			
		||||
                                                   }];
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (buttonIndex == [sheet firstOtherButtonIndex])
 | 
			
		||||
                        // Reset Password
 | 
			
		||||
                        [PearlAlert showParentalGateWithTitle:@"Resetting User" message:
 | 
			
		||||
                                        @"The user's master password will be reset.\nPlease confirm by solving:"
 | 
			
		||||
                                                   completion:^(BOOL continuing) {
 | 
			
		||||
                                                       if (continuing)
 | 
			
		||||
                                                           [self resetUser:userID avatar:avatarCell];
 | 
			
		||||
                                                   }];
 | 
			
		||||
                }          cancelTitle:[PearlStrings get].commonButtonCancel
 | 
			
		||||
                      destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil];
 | 
			
		||||
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
 | 
			
		||||
                                             @"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
                [self deleteUser:userID];
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Reset Password" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Resetting User" message:
 | 
			
		||||
                                             @"The user's master password will be reset." preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
 | 
			
		||||
                [self resetUser:userID avatar:avatarCell];
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
        [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -110,20 +110,24 @@
 | 
			
		||||
 | 
			
		||||
                case MPFixableResultNoProblems:
 | 
			
		||||
                    break;
 | 
			
		||||
                case MPFixableResultProblemsFixed:
 | 
			
		||||
                    [PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message:
 | 
			
		||||
                case MPFixableResultProblemsFixed: {
 | 
			
		||||
                    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Inconsistencies Fixed" message:
 | 
			
		||||
                                    @"Some inconsistencies were detected in your sites.\n"
 | 
			
		||||
                                            @"All issues were fixed."
 | 
			
		||||
                                         viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                                 tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
                                    @"All issues were fixed."
 | 
			
		||||
                                                                                 preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
                    [self presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
                    break;
 | 
			
		||||
                case MPFixableResultProblemsNotFixed:
 | 
			
		||||
                    [PearlAlert showAlertWithTitle:@"Inconsistencies Found" message:
 | 
			
		||||
                }
 | 
			
		||||
                case MPFixableResultProblemsNotFixed: {
 | 
			
		||||
                    UIAlertController *controller = [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."
 | 
			
		||||
                                         viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                                 tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
 | 
			
		||||
                                    @"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];
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } );
 | 
			
		||||
 | 
			
		||||
@@ -133,12 +137,14 @@
 | 
			
		||||
        } );
 | 
			
		||||
 | 
			
		||||
        NSString *latestFeatures = [MPStoreViewController latestStoreFeatures];
 | 
			
		||||
        if (latestFeatures)
 | 
			
		||||
            [PearlAlert showAlertWithTitle:@"New Features" message:
 | 
			
		||||
        if (latestFeatures) {
 | 
			
		||||
            UIAlertController *controller = [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 )
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil
 | 
			
		||||
                               cancelTitle:@"Thanks" otherTitles:nil];
 | 
			
		||||
                                  @"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];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @catch (id exception) {
 | 
			
		||||
        err( @"During Post-Startup: %@", exception );
 | 
			
		||||
@@ -161,14 +167,22 @@
 | 
			
		||||
                    MPError( error, @"While reading imported sites from %@.", url );
 | 
			
		||||
 | 
			
		||||
                if (!importedSitesData) {
 | 
			
		||||
                    [PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@",
 | 
			
		||||
                            [error localizedDescription]?: error )];
 | 
			
		||||
                    UIAlertController *controller = [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];
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
 | 
			
		||||
                if (!importedSitesString) {
 | 
			
		||||
                    [PearlAlert showError:@"Master Password couldn't understand the import file."];
 | 
			
		||||
                    UIAlertController *controller = [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];
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -190,33 +204,45 @@
 | 
			
		||||
    PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
 | 
			
		||||
    [self importSites:importData askImportPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( ^(void (^setResult)(id)) {
 | 
			
		||||
            [PearlAlert showAlertWithTitle:strf( @"Importing Sites For\n%@", userName )
 | 
			
		||||
                                   message:@"Enter the master password used to create this export file."
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                 initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                        if (buttonIndex_ == [alert_ cancelButtonIndex])
 | 
			
		||||
                            setResult( nil );
 | 
			
		||||
                        else
 | 
			
		||||
                            setResult( [alert_ textFieldAtIndex:0].text );
 | 
			
		||||
                    }          cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
 | 
			
		||||
            UIAlertController *controller = [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) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    } askUserPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( (id)^(void (^setResult)(id)) {
 | 
			
		||||
            [PearlAlert showAlertWithTitle:strf( @"Master Password For\n%@", userName )
 | 
			
		||||
                                   message:@"Enter the current master password for this user."
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                 initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                        if (buttonIndex_ == [alert_ cancelButtonIndex])
 | 
			
		||||
                            setResult( nil );
 | 
			
		||||
                        else
 | 
			
		||||
                            setResult( [alert_ textFieldAtIndex:0].text );
 | 
			
		||||
                    }          cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
 | 
			
		||||
                            @"Enter the current master password for this user."
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    }          result:^(NSError *error) {
 | 
			
		||||
        [activityOverlay cancelOverlayAnimated:YES];
 | 
			
		||||
 | 
			
		||||
        if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError))
 | 
			
		||||
            [PearlAlert showError:error.localizedDescription];
 | 
			
		||||
        if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
 | 
			
		||||
                                                                         preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        }
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -237,17 +263,17 @@
 | 
			
		||||
    PearlNotMainQueue( ^{
 | 
			
		||||
        NSString *importData = [UIPasteboard generalPasteboard].string;
 | 
			
		||||
        MPMarshalInfo *importInfo = mpw_marshal_read_info( importData.UTF8String );
 | 
			
		||||
        if (importInfo->format != MPMarshalFormatNone)
 | 
			
		||||
            [PearlAlert showAlertWithTitle:@"Import Sites?" message:
 | 
			
		||||
        if (importInfo->format != MPMarshalFormatNone) {
 | 
			
		||||
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
 | 
			
		||||
                            @"We've detected Master Password import sites on your pasteboard, would you like to import them?"
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                         tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                             if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                                 return;
 | 
			
		||||
 | 
			
		||||
                             [self importSites:importData];
 | 
			
		||||
                             [UIPasteboard generalPasteboard].string = @"";
 | 
			
		||||
                         } cancelTitle:@"No" otherTitles:@"Import Sites", nil];
 | 
			
		||||
                                                                         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];
 | 
			
		||||
        }
 | 
			
		||||
        mpw_marshal_info_free( &importInfo );
 | 
			
		||||
    } );
 | 
			
		||||
 | 
			
		||||
@@ -314,26 +340,29 @@
 | 
			
		||||
 | 
			
		||||
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    if (![PearlEMail canSendMail])
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"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"
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                             initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
 | 
			
		||||
                           otherTitles:nil];
 | 
			
		||||
 | 
			
		||||
    else if (logs)
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"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."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                             initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                    [self openFeedbackWithLogs:(buttonIndex_ == [alert_ firstOtherButtonIndex]) forVC:viewController];
 | 
			
		||||
                }          cancelTitle:nil otherTitles:@"Include Logs", @"No Logs", nil];
 | 
			
		||||
    if (![PearlEMail canSendMail]) {
 | 
			
		||||
        UIAlertController *controller = [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];
 | 
			
		||||
    }
 | 
			
		||||
    else if (logs) {
 | 
			
		||||
        UIAlertController *controller = [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) {
 | 
			
		||||
            [self openFeedbackWithLogs:YES forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            [self openFeedbackWithLogs:NO forVC:viewController];
 | 
			
		||||
        }]];
 | 
			
		||||
        [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        [self openFeedbackWithLogs:NO forVC:viewController];
 | 
			
		||||
}
 | 
			
		||||
@@ -349,9 +378,9 @@
 | 
			
		||||
                                subject:strf( @"Feedback for Master Password [%@]",
 | 
			
		||||
                                        [[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] )
 | 
			
		||||
                                   body:strf( @"\n\n\n"
 | 
			
		||||
                                                   @"--\n"
 | 
			
		||||
                                                   @"%@"
 | 
			
		||||
                                                   @"Master Password %@, build %@",
 | 
			
		||||
                                              @"--\n"
 | 
			
		||||
                                              @"%@"
 | 
			
		||||
                                              @"Master Password %@, build %@",
 | 
			
		||||
                                           userName? ([userName stringByAppendingString:@"\n"]): @"",
 | 
			
		||||
                                           [PearlInfoPlist get].CFBundleShortVersionString,
 | 
			
		||||
                                           [PearlInfoPlist get].CFBundleVersion )
 | 
			
		||||
@@ -372,173 +401,163 @@
 | 
			
		||||
 | 
			
		||||
    static dispatch_once_t once = 0;
 | 
			
		||||
    dispatch_once( &once, ^{
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"Failed To Load Sites" message:
 | 
			
		||||
        UIAlertController *controller = [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."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                         if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                             return;
 | 
			
		||||
                         if (buttonIndex == [alert firstOtherButtonIndex])
 | 
			
		||||
                             [self openFeedbackWithLogs:YES forVC:nil];
 | 
			
		||||
                         if (buttonIndex == [alert firstOtherButtonIndex] + 1)
 | 
			
		||||
                             [self deleteAndResetStore];
 | 
			
		||||
                     } cancelTitle:@"Ignore" otherTitles:@"E-Mail Logs", @"Reset", nil];
 | 
			
		||||
                        @"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];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller 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];
 | 
			
		||||
    } );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showExportForVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"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."
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                 tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                     if (buttonIndex != [alert cancelButtonIndex])
 | 
			
		||||
                         [PearlAlert showAlertWithTitle:@"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."
 | 
			
		||||
                                              viewStyle:UIAlertViewStyleDefault initAlert:nil
 | 
			
		||||
                                      tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                                          if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0)
 | 
			
		||||
                                              // Safe Export
 | 
			
		||||
                                              [self showExportRevealPasswords:NO forVC:viewController];
 | 
			
		||||
                                          if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
 | 
			
		||||
                                              // Show Passwords
 | 
			
		||||
                                              [self showExportRevealPasswords:YES forVC:viewController];
 | 
			
		||||
                                      } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords",
 | 
			
		||||
                                                                                          nil];
 | 
			
		||||
                 } cancelTitle:@"Cancel" otherTitles:@"Export Sites", nil];
 | 
			
		||||
    UIAlertController *controller = [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:
 | 
			
		||||
                        @"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];
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller_ 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];
 | 
			
		||||
    }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
 | 
			
		||||
 | 
			
		||||
    if (![PearlEMail canSendMail]) {
 | 
			
		||||
        [PearlAlert showAlertWithTitle:@"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."
 | 
			
		||||
                             viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                             initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
 | 
			
		||||
                           otherTitles:nil];
 | 
			
		||||
        UIAlertController *controller = [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];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
 | 
			
		||||
        return PearlAwait( ^(void (^setResult)(id)) {
 | 
			
		||||
            [PearlAlert showAlertWithTitle:strf( @"Master Password For:\n%@", userName )
 | 
			
		||||
                                   message:@"Enter the user's master password to create an export file."
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleSecureTextInput
 | 
			
		||||
                                 initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
 | 
			
		||||
                        if (buttonIndex_ == [alert_ cancelButtonIndex])
 | 
			
		||||
                            setResult( nil );
 | 
			
		||||
                        else
 | 
			
		||||
                            setResult( [alert_ textFieldAtIndex:0].text );
 | 
			
		||||
                    }          cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Export", nil];
 | 
			
		||||
            UIAlertController *controller = [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) {
 | 
			
		||||
                textField.secureTextEntry = YES;
 | 
			
		||||
            }];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( controller.textFields.firstObject.text );
 | 
			
		||||
            }]];
 | 
			
		||||
            [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 | 
			
		||||
                setResult( nil );
 | 
			
		||||
            }]];
 | 
			
		||||
            [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
        } );
 | 
			
		||||
    }                         result:^(NSString *mpsites, NSError *error) {
 | 
			
		||||
        if (!mpsites || error) {
 | 
			
		||||
            MPError( error, @"Failed to export mpsites." );
 | 
			
		||||
            [PearlAlert showAlertWithTitle:@"Export Error"
 | 
			
		||||
                                   message:error.localizedDescription
 | 
			
		||||
                                 viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                                 initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
 | 
			
		||||
                               otherTitles:nil];
 | 
			
		||||
            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];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
 | 
			
		||||
                     tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
 | 
			
		||||
                         if (buttonIndex == [sheet cancelButtonIndex])
 | 
			
		||||
                             return;
 | 
			
		||||
        NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
 | 
			
		||||
        [exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
 | 
			
		||||
        NSString *exportFileName = strf( @"%@ (%@).mpsites",
 | 
			
		||||
                [self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
 | 
			
		||||
 | 
			
		||||
                         NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
 | 
			
		||||
                         [exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
 | 
			
		||||
                         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) {
 | 
			
		||||
            NSString *message;
 | 
			
		||||
            if (revealPasswords)
 | 
			
		||||
                message = strf( @"Export of Master Password sites with passwords included.\n\n"
 | 
			
		||||
                                @"REMINDER: Make sure nobody else sees this file!  Passwords are visible!\n\n\n"
 | 
			
		||||
                                @"--\n"
 | 
			
		||||
                                @"%@\n"
 | 
			
		||||
                                @"Master Password %@, build %@",
 | 
			
		||||
                        [self activeUserForMainThread].name,
 | 
			
		||||
                        [PearlInfoPlist get].CFBundleShortVersionString,
 | 
			
		||||
                        [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
            else
 | 
			
		||||
                message = strf( @"Backup of Master Password sites.\n\n\n"
 | 
			
		||||
                                @"--\n"
 | 
			
		||||
                                @"%@\n"
 | 
			
		||||
                                @"Master Password %@, build %@",
 | 
			
		||||
                        [self activeUserForMainThread].name,
 | 
			
		||||
                        [PearlInfoPlist get].CFBundleShortVersionString,
 | 
			
		||||
                        [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
 | 
			
		||||
                         if (buttonIndex == [sheet firstOtherButtonIndex]) {
 | 
			
		||||
                             NSString *message;
 | 
			
		||||
                             if (revealPasswords)
 | 
			
		||||
                                 message = strf( @"Export of Master Password sites with passwords included.\n\n"
 | 
			
		||||
                                                 @"REMINDER: Make sure nobody else sees this file!  Passwords are visible!\n\n\n"
 | 
			
		||||
                                                 @"--\n"
 | 
			
		||||
                                                 @"%@\n"
 | 
			
		||||
                                                 @"Master Password %@, build %@",
 | 
			
		||||
                                         [self activeUserForMainThread].name,
 | 
			
		||||
                                         [PearlInfoPlist get].CFBundleShortVersionString,
 | 
			
		||||
                                         [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
                             else
 | 
			
		||||
                                 message = strf( @"Backup of Master Password sites.\n\n\n"
 | 
			
		||||
                                                 @"--\n"
 | 
			
		||||
                                                 @"%@\n"
 | 
			
		||||
                                                 @"Master Password %@, build %@",
 | 
			
		||||
                                         [self activeUserForMainThread].name,
 | 
			
		||||
                                         [PearlInfoPlist get].CFBundleShortVersionString,
 | 
			
		||||
                                         [PearlInfoPlist get].CFBundleVersion );
 | 
			
		||||
 | 
			
		||||
                             [PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
 | 
			
		||||
                                         attachments:[[PearlEMailAttachment alloc]
 | 
			
		||||
                                                             initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
 | 
			
		||||
                                                                    mimeType:@"text/plain" fileName:exportFileName],
 | 
			
		||||
                                                     nil];
 | 
			
		||||
                             return;
 | 
			
		||||
                         }
 | 
			
		||||
 | 
			
		||||
                         NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
 | 
			
		||||
                                                                                                inDomains:NSUserDomainMask] lastObject];
 | 
			
		||||
                         NSURL *exportURL = [[applicationSupportURL
 | 
			
		||||
                                 URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
 | 
			
		||||
                                 URLByAppendingPathComponent:exportFileName isDirectory:NO];
 | 
			
		||||
                         NSError *writeError = nil;
 | 
			
		||||
                         if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
 | 
			
		||||
                                 writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
 | 
			
		||||
                             MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
 | 
			
		||||
                         else {
 | 
			
		||||
                             self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
 | 
			
		||||
                             self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
 | 
			
		||||
                             self.interactionController.delegate = self;
 | 
			
		||||
                             [self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
 | 
			
		||||
                         }
 | 
			
		||||
                     } cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
 | 
			
		||||
            [PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
 | 
			
		||||
                        attachments:[[PearlEMailAttachment alloc]
 | 
			
		||||
                                            initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
 | 
			
		||||
                                                   mimeType:@"text/plain" fileName:exportFileName],
 | 
			
		||||
                                    nil];
 | 
			
		||||
            return;
 | 
			
		||||
        }]];
 | 
			
		||||
        [controller addAction:[UIAlertAction actionWithTitle:@"Share / Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
 | 
			
		||||
            NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
 | 
			
		||||
                                                                                   inDomains:NSUserDomainMask] lastObject];
 | 
			
		||||
            NSURL *exportURL = [[applicationSupportURL
 | 
			
		||||
                    URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
 | 
			
		||||
                    URLByAppendingPathComponent:exportFileName isDirectory:NO];
 | 
			
		||||
            NSError *writeError = nil;
 | 
			
		||||
            if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
 | 
			
		||||
                    writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
 | 
			
		||||
                MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
 | 
			
		||||
            else {
 | 
			
		||||
                self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
 | 
			
		||||
                self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
 | 
			
		||||
                self.interactionController.delegate = self;
 | 
			
		||||
                [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];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
 | 
			
		||||
 | 
			
		||||
    [PearlAlert showAlertWithTitle:@"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."
 | 
			
		||||
                         viewStyle:UIAlertViewStyleDefault
 | 
			
		||||
                         initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
 | 
			
		||||
                if (buttonIndex == [alert cancelButtonIndex])
 | 
			
		||||
                    return;
 | 
			
		||||
    UIAlertController *controller = [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) {
 | 
			
		||||
        [moc performBlockAndWait:^{
 | 
			
		||||
            inf( @"Clearing keyID for user: %@.", user.userID );
 | 
			
		||||
            user.keyID = nil;
 | 
			
		||||
            [self forgetSavedKeyFor:user];
 | 
			
		||||
            [moc saveToStore];
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
                [moc performBlockAndWait:^{
 | 
			
		||||
                    inf( @"Clearing keyID for user: %@.", user.userID );
 | 
			
		||||
                    user.keyID = nil;
 | 
			
		||||
                    [self forgetSavedKeyFor:user];
 | 
			
		||||
                    [moc saveToStore];
 | 
			
		||||
                }];
 | 
			
		||||
 | 
			
		||||
                [self signOutAnimated:YES];
 | 
			
		||||
                if (didReset)
 | 
			
		||||
                    didReset();
 | 
			
		||||
            }
 | 
			
		||||
                       cancelTitle:[PearlStrings get].commonButtonAbort
 | 
			
		||||
                       otherTitles:[PearlStrings get].commonButtonContinue, nil];
 | 
			
		||||
        [self signOutAnimated:YES];
 | 
			
		||||
        if (didReset)
 | 
			
		||||
            didReset();
 | 
			
		||||
    }]];
 | 
			
		||||
    [controller addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
 | 
			
		||||
    [self.navigationController presentViewController:controller animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - UIDocumentInteractionControllerDelegate
 | 
			
		||||
 
 | 
			
		||||
@@ -1,133 +1,135 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
			
		||||
<plist version="1.0">
 | 
			
		||||
    <dict>
 | 
			
		||||
        <key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
        <string>$(DEVELOPMENT_LANGUAGE)</string>
 | 
			
		||||
        <key>CFBundleDisplayName</key>
 | 
			
		||||
        <string>M. Password</string>
 | 
			
		||||
        <key>CFBundleDocumentTypes</key>
 | 
			
		||||
        <array>
 | 
			
		||||
            <dict>
 | 
			
		||||
                <key>CFBundleTypeExtensions</key>
 | 
			
		||||
                <array>
 | 
			
		||||
                    <string>mpsites</string>
 | 
			
		||||
                </array>
 | 
			
		||||
                <key>CFBundleTypeIconFiles</key>
 | 
			
		||||
                <array>
 | 
			
		||||
                    <string>Icon-Small</string>
 | 
			
		||||
                </array>
 | 
			
		||||
                <key>CFBundleTypeName</key>
 | 
			
		||||
                <string>Master Password sites</string>
 | 
			
		||||
                <key>LSHandlerRank</key>
 | 
			
		||||
                <string>Owner</string>
 | 
			
		||||
                <key>LSItemContentTypes</key>
 | 
			
		||||
                <array>
 | 
			
		||||
                    <string>com.lyndir.masterpassword.sites</string>
 | 
			
		||||
                </array>
 | 
			
		||||
            </dict>
 | 
			
		||||
        </array>
 | 
			
		||||
        <key>CFBundleExecutable</key>
 | 
			
		||||
        <string>$(EXECUTABLE_NAME)</string>
 | 
			
		||||
        <key>CFBundleIdentifier</key>
 | 
			
		||||
        <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
 | 
			
		||||
        <key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
        <string>6.0</string>
 | 
			
		||||
        <key>CFBundleName</key>
 | 
			
		||||
        <string>$(PRODUCT_NAME)</string>
 | 
			
		||||
        <key>CFBundlePackageType</key>
 | 
			
		||||
        <string>APPL</string>
 | 
			
		||||
        <key>CFBundleShortVersionString</key>
 | 
			
		||||
        <string>[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>
 | 
			
		||||
        <string>© 2011-2018</string>
 | 
			
		||||
        <key>UIAppFonts</key>
 | 
			
		||||
        <array>
 | 
			
		||||
            <string>Exo2.0-Bold.otf</string>
 | 
			
		||||
            <string>Exo2.0-ExtraBold.otf</string>
 | 
			
		||||
            <string>Exo2.0-Regular.otf</string>
 | 
			
		||||
            <string>Exo2.0-Thin.otf</string>
 | 
			
		||||
            <string>SourceCodePro-Black.otf</string>
 | 
			
		||||
            <string>SourceCodePro-Regular.otf</string>
 | 
			
		||||
            <string>SourceCodePro-ExtraLight.otf</string>
 | 
			
		||||
        </array>
 | 
			
		||||
        <key>UIStatusBarHidden</key>
 | 
			
		||||
        <true/>
 | 
			
		||||
        <key>UIStatusBarStyle</key>
 | 
			
		||||
        <string>UIStatusBarStyleDefault</string>
 | 
			
		||||
        <key>UIStatusBarTintParameters</key>
 | 
			
		||||
        <dict>
 | 
			
		||||
            <key>UINavigationBar</key>
 | 
			
		||||
            <dict>
 | 
			
		||||
                <key>Style</key>
 | 
			
		||||
                <string>UIBarStyleDefault</string>
 | 
			
		||||
                <key>TintColor</key>
 | 
			
		||||
                <dict>
 | 
			
		||||
                    <key>Blue</key>
 | 
			
		||||
                    <real>0.42745098039215684</real>
 | 
			
		||||
                    <key>Green</key>
 | 
			
		||||
                    <real>0.39215686274509803</real>
 | 
			
		||||
                    <key>Red</key>
 | 
			
		||||
                    <real>0.37254901960784315</real>
 | 
			
		||||
                </dict>
 | 
			
		||||
                <key>Translucent</key>
 | 
			
		||||
                <false/>
 | 
			
		||||
            </dict>
 | 
			
		||||
        </dict>
 | 
			
		||||
        <key>UISupportedInterfaceOrientations</key>
 | 
			
		||||
        <array>
 | 
			
		||||
            <string>UIInterfaceOrientationPortrait</string>
 | 
			
		||||
            <string>UIInterfaceOrientationLandscapeLeft</string>
 | 
			
		||||
            <string>UIInterfaceOrientationLandscapeRight</string>
 | 
			
		||||
        </array>
 | 
			
		||||
        <key>UISupportedInterfaceOrientations~ipad</key>
 | 
			
		||||
        <array>
 | 
			
		||||
            <string>UIInterfaceOrientationPortrait</string>
 | 
			
		||||
            <string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
			
		||||
            <string>UIInterfaceOrientationLandscapeLeft</string>
 | 
			
		||||
            <string>UIInterfaceOrientationLandscapeRight</string>
 | 
			
		||||
        </array>
 | 
			
		||||
        <key>UTExportedTypeDeclarations</key>
 | 
			
		||||
        <array>
 | 
			
		||||
            <dict>
 | 
			
		||||
                <key>UTTypeConformsTo</key>
 | 
			
		||||
                <array>
 | 
			
		||||
                    <string>public.utf8-plain-text</string>
 | 
			
		||||
                </array>
 | 
			
		||||
                <key>UTTypeDescription</key>
 | 
			
		||||
                <string>Master Password sites</string>
 | 
			
		||||
                <key>UTTypeIdentifier</key>
 | 
			
		||||
                <string>com.lyndir.masterpassword.sites</string>
 | 
			
		||||
                <key>UTTypeSize320IconFile</key>
 | 
			
		||||
                <string>Icon-320.png</string>
 | 
			
		||||
                <key>UTTypeSize64IconFile</key>
 | 
			
		||||
                <string>Icon-64.png</string>
 | 
			
		||||
                <key>UTTypeTagSpecification</key>
 | 
			
		||||
                <dict>
 | 
			
		||||
                    <key>public.filename-extension</key>
 | 
			
		||||
                    <array>
 | 
			
		||||
                        <string>mpsites</string>
 | 
			
		||||
                    </array>
 | 
			
		||||
                </dict>
 | 
			
		||||
            </dict>
 | 
			
		||||
        </array>
 | 
			
		||||
    </dict>
 | 
			
		||||
<dict>
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>$(DEVELOPMENT_LANGUAGE)</string>
 | 
			
		||||
	<key>CFBundleDisplayName</key>
 | 
			
		||||
	<string>M. Password</string>
 | 
			
		||||
	<key>CFBundleDocumentTypes</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>CFBundleTypeExtensions</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>mpsites</string>
 | 
			
		||||
			</array>
 | 
			
		||||
			<key>CFBundleTypeIconFiles</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>Icon-Small</string>
 | 
			
		||||
			</array>
 | 
			
		||||
			<key>CFBundleTypeName</key>
 | 
			
		||||
			<string>Master Password sites</string>
 | 
			
		||||
			<key>LSHandlerRank</key>
 | 
			
		||||
			<string>Owner</string>
 | 
			
		||||
			<key>LSItemContentTypes</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>com.lyndir.masterpassword.sites</string>
 | 
			
		||||
			</array>
 | 
			
		||||
		</dict>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>$(EXECUTABLE_NAME)</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
 | 
			
		||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
			
		||||
	<string>6.0</string>
 | 
			
		||||
	<key>CFBundleName</key>
 | 
			
		||||
	<string>$(PRODUCT_NAME)</string>
 | 
			
		||||
	<key>CFBundlePackageType</key>
 | 
			
		||||
	<string>APPL</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>[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>
 | 
			
		||||
	<string>© 2011-2018</string>
 | 
			
		||||
	<key>UIAppFonts</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>Exo2.0-Bold.otf</string>
 | 
			
		||||
		<string>Exo2.0-ExtraBold.otf</string>
 | 
			
		||||
		<string>Exo2.0-Regular.otf</string>
 | 
			
		||||
		<string>Exo2.0-Thin.otf</string>
 | 
			
		||||
		<string>SourceCodePro-Black.otf</string>
 | 
			
		||||
		<string>SourceCodePro-Regular.otf</string>
 | 
			
		||||
		<string>SourceCodePro-ExtraLight.otf</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>UIMainStoryboardFile</key>
 | 
			
		||||
	<string>Storyboard</string>
 | 
			
		||||
	<key>UIStatusBarHidden</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>UIStatusBarStyle</key>
 | 
			
		||||
	<string>UIStatusBarStyleDefault</string>
 | 
			
		||||
	<key>UIStatusBarTintParameters</key>
 | 
			
		||||
	<dict>
 | 
			
		||||
		<key>UINavigationBar</key>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>Style</key>
 | 
			
		||||
			<string>UIBarStyleDefault</string>
 | 
			
		||||
			<key>TintColor</key>
 | 
			
		||||
			<dict>
 | 
			
		||||
				<key>Blue</key>
 | 
			
		||||
				<real>0.42745098039215684</real>
 | 
			
		||||
				<key>Green</key>
 | 
			
		||||
				<real>0.39215686274509803</real>
 | 
			
		||||
				<key>Red</key>
 | 
			
		||||
				<real>0.37254901960784315</real>
 | 
			
		||||
			</dict>
 | 
			
		||||
			<key>Translucent</key>
 | 
			
		||||
			<false/>
 | 
			
		||||
		</dict>
 | 
			
		||||
	</dict>
 | 
			
		||||
	<key>UISupportedInterfaceOrientations</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>UIInterfaceOrientationPortrait</string>
 | 
			
		||||
		<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
			
		||||
		<string>UIInterfaceOrientationLandscapeRight</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>UISupportedInterfaceOrientations~ipad</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<string>UIInterfaceOrientationPortrait</string>
 | 
			
		||||
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 | 
			
		||||
		<string>UIInterfaceOrientationLandscapeLeft</string>
 | 
			
		||||
		<string>UIInterfaceOrientationLandscapeRight</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>UTExportedTypeDeclarations</key>
 | 
			
		||||
	<array>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>UTTypeConformsTo</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>public.utf8-plain-text</string>
 | 
			
		||||
			</array>
 | 
			
		||||
			<key>UTTypeDescription</key>
 | 
			
		||||
			<string>Master Password sites</string>
 | 
			
		||||
			<key>UTTypeIdentifier</key>
 | 
			
		||||
			<string>com.lyndir.masterpassword.sites</string>
 | 
			
		||||
			<key>UTTypeSize320IconFile</key>
 | 
			
		||||
			<string>Icon-320.png</string>
 | 
			
		||||
			<key>UTTypeSize64IconFile</key>
 | 
			
		||||
			<string>Icon-64.png</string>
 | 
			
		||||
			<key>UTTypeTagSpecification</key>
 | 
			
		||||
			<dict>
 | 
			
		||||
				<key>public.filename-extension</key>
 | 
			
		||||
				<array>
 | 
			
		||||
					<string>mpsites</string>
 | 
			
		||||
				</array>
 | 
			
		||||
			</dict>
 | 
			
		||||
		</dict>
 | 
			
		||||
	</array>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user