diff --git a/.travis.yml b/.travis.yml index 94cccd5..3bbca71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,10 @@ language: objective-c cache: - bundler -osx_image: xcode9 +osx_image: xcode10.1 before_install: - bundle install script: - - bundle exec fastlane run_tests --verbose + - bundle exec fastlane run_unit_tests --verbose diff --git a/CoreDataMigration-Example.xcodeproj/project.pbxproj b/CoreDataMigration-Example.xcodeproj/project.pbxproj index 352b757..47131a5 100644 --- a/CoreDataMigration-Example.xcodeproj/project.pbxproj +++ b/CoreDataMigration-Example.xcodeproj/project.pbxproj @@ -7,21 +7,21 @@ objects = { /* Begin PBXBuildFile section */ + 3D8E52F521E0EF2800FE1D35 /* FileManager+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8E52F421E0EF2800FE1D35 /* FileManager+Helper.swift */; }; + 3D8E52F721E0F98500FE1D35 /* NSManagedObjectContext+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8E52F621E0F98500FE1D35 /* NSManagedObjectContext+Helper.swift */; }; + 3DACAAD221EE9D5D00309A75 /* PostSectionWriterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DACAAD121EE9D5D00309A75 /* PostSectionWriterTableViewCell.swift */; }; + 3DD99ED021F1118700CB4B6E /* Migration2to3ModelMapping.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 3DD99ECF21F1118700CB4B6E /* Migration2to3ModelMapping.xcmappingmodel */; }; + 3DD99ED321F145EC00CB4B6E /* FileManager+ApplicationSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD99ED221F145EC00CB4B6E /* FileManager+ApplicationSupport.swift */; }; + 3DDB26C921EBF87E00388AEE /* PostWriterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDB26C821EBF87E00388AEE /* PostWriterViewController.swift */; }; + 3DDB26CB21EC00FE00388AEE /* PostViewerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DDB26CA21EC00FE00388AEE /* PostViewerViewController.swift */; }; 431DCEAE1F67EC9E00CF6316 /* CoreDataMigration_Example.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEAA1F67EC7100CF6316 /* CoreDataMigration_Example.xcdatamodeld */; }; - 431DCEBE1F67F18100CF6316 /* CoreDataMigrationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEB01F67EE2600CF6316 /* CoreDataMigrationModel.swift */; }; 431DCEBF1F67F18100CF6316 /* CoreDataMigrationStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEB11F67EE2600CF6316 /* CoreDataMigrationStep.swift */; }; 431DCEC01F67F18100CF6316 /* CoreDataMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEB21F67EE2600CF6316 /* CoreDataMigrator.swift */; }; - 431DCEC21F67F1B100CF6316 /* Migration1to2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEC11F67F1B100CF6316 /* Migration1to2.xcmappingmodel */; }; 431DCEC51F67F80B00CF6316 /* AppLoading.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 431DCEC41F67F80B00CF6316 /* AppLoading.storyboard */; }; 431DCECB1F67F93000CF6316 /* AppLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCECA1F67F93000CF6316 /* AppLoadingViewController.swift */; }; 431DCECC1F67FE0500CF6316 /* PostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEC91F67F91C00CF6316 /* PostsViewController.swift */; }; 431DCECD1F67FE0800CF6316 /* PostTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCEC81F67F91C00CF6316 /* PostTableViewCell.swift */; }; 431DCED21F6815A300CF6316 /* Post2ToPost3MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431DCED11F6815A300CF6316 /* Post2ToPost3MigrationPolicy.swift */; }; - 431DCED61F68315900CF6316 /* Migration2to3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 431DCED51F68315400CF6316 /* Migration2to3.xcmappingmodel */; }; - 432EA54D1F6C398E00EFE008 /* TestingAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432EA54C1F6C398E00EFE008 /* TestingAppDelegate.swift */; }; - 432EA54F1F6C39C600EFE008 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432EA54E1F6C39C600EFE008 /* main.swift */; }; - 432EA5501F6C3A9A00EFE008 /* TestingAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432EA54C1F6C398E00EFE008 /* TestingAppDelegate.swift */; }; - 432EA5511F6C3C7D00EFE008 /* CoreDataMigration_Example_1.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 43FBB4331F6C16A80090C536 /* CoreDataMigration_Example_1.sqlite */; }; 432EA5591F6C552800EFE008 /* NSPersistentStoreCoordinator+SQLite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 432EA5581F6C552800EFE008 /* NSPersistentStoreCoordinator+SQLite.swift */; }; 43370DB01F66E7A6006188EC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43370D751F66E74A006188EC /* AppDelegate.swift */; }; 43370DB31F66E830006188EC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43370D781F66E74A006188EC /* LaunchScreen.storyboard */; }; @@ -29,14 +29,16 @@ 43370DBE1F66F0DF006188EC /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43370DBB1F66F0C0006188EC /* CoreDataManager.swift */; }; 4345D4EE1F67E0FE00027D11 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4ED1F67E0FE00027D11 /* UIColor+Hex.swift */; }; 4345D4F01F67E10700027D11 /* UIColor+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4EF1F67E10700027D11 /* UIColor+Random.swift */; }; - 4345D4F51F67E1FC00027D11 /* CGFloat+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4345D4F41F67E1FC00027D11 /* CGFloat+Random.swift */; }; - 43FBB4411F6C16E30090C536 /* CoreDataManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FBB4401F6C16E30090C536 /* CoreDataManagerTests.swift */; }; - 43FBB4431F6C1A8F0090C536 /* CoreDataMigrationModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FBB4301F6C16A80090C536 /* CoreDataMigrationModelTests.swift */; }; - 43FBB4441F6C1A8F0090C536 /* CoreDataMigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FBB4311F6C16A80090C536 /* CoreDataMigratorTests.swift */; }; - 43FBB4461F6C1A950090C536 /* CoreDataMigration_Example_2.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 43FBB4341F6C16A80090C536 /* CoreDataMigration_Example_2.sqlite */; }; - 43FBB4471F6C1A950090C536 /* CoreDataMigration_Example_3.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 43FBB4351F6C16A80090C536 /* CoreDataMigration_Example_3.sqlite */; }; - 43FBB4481F6C1A950090C536 /* CoreDataMigration_Example_WAL.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = 43FBB4361F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite */; }; - 43FBB4491F6C1A950090C536 /* CoreDataMigration_Example_WAL.sqlite-wal in Resources */ = {isa = PBXBuildFile; fileRef = 43FBB4371F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite-wal */; }; + C23BD45A21F08A350039A36B /* PostSectionViewerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BD45921F08A350039A36B /* PostSectionViewerTableViewCell.swift */; }; + C28553DF21DCF5000004C7BA /* CoreDataMigrationVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28553DE21DCF5000004C7BA /* CoreDataMigrationVersion.swift */; }; + C28553E221DD14090004C7BA /* NSManagedObjectModel+Compatible.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28553E121DD14090004C7BA /* NSManagedObjectModel+Compatible.swift */; }; + C28553E421DD1D7B0004C7BA /* NSManagedObjectModel+Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28553E321DD1D7B0004C7BA /* NSManagedObjectModel+Resource.swift */; }; + C28553F821DD21C40004C7BA /* CoreDataManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28553EE21DD21C30004C7BA /* CoreDataManagerTests.swift */; }; + C28553FB21DD21C40004C7BA /* CoreDataMigration_Example_2.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = C28553F321DD21C30004C7BA /* CoreDataMigration_Example_2.sqlite */; }; + C28553FD21DD21C40004C7BA /* CoreDataMigration_Example_1.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = C28553F521DD21C30004C7BA /* CoreDataMigration_Example_1.sqlite */; }; + C28553FE21DD21C40004C7BA /* CoreDataMigration_Example_3.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = C28553F621DD21C30004C7BA /* CoreDataMigration_Example_3.sqlite */; }; + C28553FF21DD21C40004C7BA /* CoreDataMigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28553F721DD21C30004C7BA /* CoreDataMigratorTests.swift */; }; + C285540221DD22040004C7BA /* MockCoreDataMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C285540121DD22040004C7BA /* MockCoreDataMigrator.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,22 +52,24 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 3D8E52F421E0EF2800FE1D35 /* FileManager+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Helper.swift"; sourceTree = ""; }; + 3D8E52F621E0F98500FE1D35 /* NSManagedObjectContext+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Helper.swift"; sourceTree = ""; }; + 3DACAAD121EE9D5D00309A75 /* PostSectionWriterTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostSectionWriterTableViewCell.swift; sourceTree = ""; }; + 3DD99ECF21F1118700CB4B6E /* Migration2to3ModelMapping.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Migration2to3ModelMapping.xcmappingmodel; sourceTree = ""; }; + 3DD99ED221F145EC00CB4B6E /* FileManager+ApplicationSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+ApplicationSupport.swift"; sourceTree = ""; }; + 3DDB26C821EBF87E00388AEE /* PostWriterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostWriterViewController.swift; sourceTree = ""; }; + 3DDB26CA21EC00FE00388AEE /* PostViewerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewerViewController.swift; sourceTree = ""; }; 431DCEAB1F67EC7100CF6316 /* CoreDataMigration_Example 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreDataMigration_Example 2.xcdatamodel"; sourceTree = ""; }; 431DCEAC1F67EC7100CF6316 /* CoreDataMigration_Example 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreDataMigration_Example 3.xcdatamodel"; sourceTree = ""; }; 431DCEAD1F67EC7100CF6316 /* CoreDataMigration_Example.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = CoreDataMigration_Example.xcdatamodel; sourceTree = ""; }; - 431DCEB01F67EE2600CF6316 /* CoreDataMigrationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationModel.swift; sourceTree = ""; }; 431DCEB11F67EE2600CF6316 /* CoreDataMigrationStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationStep.swift; sourceTree = ""; }; 431DCEB21F67EE2600CF6316 /* CoreDataMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrator.swift; sourceTree = ""; }; - 431DCEC11F67F1B100CF6316 /* Migration1to2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Migration1to2.xcmappingmodel; sourceTree = ""; }; 431DCEC41F67F80B00CF6316 /* AppLoading.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AppLoading.storyboard; sourceTree = ""; }; 431DCEC81F67F91C00CF6316 /* PostTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTableViewCell.swift; sourceTree = ""; }; 431DCEC91F67F91C00CF6316 /* PostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsViewController.swift; sourceTree = ""; }; 431DCECA1F67F93000CF6316 /* AppLoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLoadingViewController.swift; sourceTree = ""; }; 431DCED11F6815A300CF6316 /* Post2ToPost3MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post2ToPost3MigrationPolicy.swift; sourceTree = ""; }; - 431DCED51F68315400CF6316 /* Migration2to3.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Migration2to3.xcmappingmodel; sourceTree = ""; }; 431DCED71F68394200CF6316 /* CoreDataMigration_Example 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreDataMigration_Example 4.xcdatamodel"; sourceTree = ""; }; - 432EA54C1F6C398E00EFE008 /* TestingAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingAppDelegate.swift; sourceTree = ""; }; - 432EA54E1F6C39C600EFE008 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 432EA5581F6C552800EFE008 /* NSPersistentStoreCoordinator+SQLite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+SQLite.swift"; sourceTree = ""; }; 43370D731F66E74A006188EC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43370D751F66E74A006188EC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -75,19 +79,19 @@ 43370DBB1F66F0C0006188EC /* CoreDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataManager.swift; sourceTree = ""; }; 4345D4ED1F67E0FE00027D11 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = ""; }; 4345D4EF1F67E10700027D11 /* UIColor+Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Random.swift"; sourceTree = ""; }; - 4345D4F41F67E1FC00027D11 /* CGFloat+Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Random.swift"; sourceTree = ""; }; 43AB8AE51F66E6A5003153B3 /* CoreDataMigration-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CoreDataMigration-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 43AB8AFC1F66E6A5003153B3 /* CoreDataMigration-ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CoreDataMigration-ExampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 43AB8B021F66E6A5003153B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 43FBB4301F6C16A80090C536 /* CoreDataMigrationModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationModelTests.swift; sourceTree = ""; }; - 43FBB4311F6C16A80090C536 /* CoreDataMigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigratorTests.swift; sourceTree = ""; }; - 43FBB4331F6C16A80090C536 /* CoreDataMigration_Example_1.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_1.sqlite; sourceTree = ""; }; - 43FBB4341F6C16A80090C536 /* CoreDataMigration_Example_2.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_2.sqlite; sourceTree = ""; }; - 43FBB4351F6C16A80090C536 /* CoreDataMigration_Example_3.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_3.sqlite; sourceTree = ""; }; - 43FBB4361F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_WAL.sqlite; sourceTree = ""; }; - 43FBB4371F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite-wal */ = {isa = PBXFileReference; lastKnownFileType = file; path = "CoreDataMigration_Example_WAL.sqlite-wal"; sourceTree = ""; }; - 43FBB4401F6C16E30090C536 /* CoreDataManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataManagerTests.swift; sourceTree = ""; }; - 43FBB4421F6C16FB0090C536 /* CoreDataMigration-ExampleTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CoreDataMigration-ExampleTests-Bridging-Header.h"; sourceTree = ""; }; + C23BD45921F08A350039A36B /* PostSectionViewerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostSectionViewerTableViewCell.swift; sourceTree = ""; }; + C28553DE21DCF5000004C7BA /* CoreDataMigrationVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataMigrationVersion.swift; sourceTree = ""; }; + C28553E121DD14090004C7BA /* NSManagedObjectModel+Compatible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Compatible.swift"; sourceTree = ""; }; + C28553E321DD1D7B0004C7BA /* NSManagedObjectModel+Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Resource.swift"; sourceTree = ""; }; + C28553E821DD21950004C7BA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C28553EE21DD21C30004C7BA /* CoreDataManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataManagerTests.swift; sourceTree = ""; }; + C28553F321DD21C30004C7BA /* CoreDataMigration_Example_2.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_2.sqlite; sourceTree = ""; }; + C28553F521DD21C30004C7BA /* CoreDataMigration_Example_1.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_1.sqlite; sourceTree = ""; }; + C28553F621DD21C30004C7BA /* CoreDataMigration_Example_3.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = CoreDataMigration_Example_3.sqlite; sourceTree = ""; }; + C28553F721DD21C30004C7BA /* CoreDataMigratorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataMigratorTests.swift; sourceTree = ""; }; + C285540121DD22040004C7BA /* MockCoreDataMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCoreDataMigrator.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -108,11 +112,46 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3D2C746521DFFE5600514491 /* Helpers */ = { + isa = PBXGroup; + children = ( + 3D8E52F421E0EF2800FE1D35 /* FileManager+Helper.swift */, + 3D8E52F621E0F98500FE1D35 /* NSManagedObjectContext+Helper.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 3DD99ED121F145CF00CB4B6E /* FileManager */ = { + isa = PBXGroup; + children = ( + 3DD99ED221F145EC00CB4B6E /* FileManager+ApplicationSupport.swift */, + ); + path = FileManager; + sourceTree = ""; + }; + 3DDB26C621EBF86300388AEE /* Viewer */ = { + isa = PBXGroup; + children = ( + 3DDB26CA21EC00FE00388AEE /* PostViewerViewController.swift */, + C23BD45921F08A350039A36B /* PostSectionViewerTableViewCell.swift */, + ); + path = Viewer; + sourceTree = ""; + }; + 3DDB26C721EBF86300388AEE /* Writer */ = { + isa = PBXGroup; + children = ( + 3DDB26C821EBF87E00388AEE /* PostWriterViewController.swift */, + 3DACAAD121EE9D5D00309A75 /* PostSectionWriterTableViewCell.swift */, + ); + path = Writer; + sourceTree = ""; + }; 431DCEAF1F67EE2600CF6316 /* Migration */ = { isa = PBXGroup; children = ( - 431DCEB01F67EE2600CF6316 /* CoreDataMigrationModel.swift */, 431DCEB11F67EE2600CF6316 /* CoreDataMigrationStep.swift */, + C28553DE21DCF5000004C7BA /* CoreDataMigrationVersion.swift */, 431DCEB21F67EE2600CF6316 /* CoreDataMigrator.swift */, 431DCEB31F67EE2600CF6316 /* Mappings */, 431DCED01F68156B00CF6316 /* Policies */, @@ -123,8 +162,7 @@ 431DCEB31F67EE2600CF6316 /* Mappings */ = { isa = PBXGroup; children = ( - 431DCEC11F67F1B100CF6316 /* Migration1to2.xcmappingmodel */, - 431DCED51F68315400CF6316 /* Migration2to3.xcmappingmodel */, + 3DD99ECF21F1118700CB4B6E /* Migration2to3ModelMapping.xcmappingmodel */, ); path = Mappings; sourceTree = ""; @@ -175,7 +213,6 @@ children = ( 43370D751F66E74A006188EC /* AppDelegate.swift */, 43370D761F66E74A006188EC /* Info.plist */, - 432EA54E1F6C39C600EFE008 /* main.swift */, ); path = Application; sourceTree = ""; @@ -195,6 +232,8 @@ children = ( 431DCEC61F67F91C00CF6316 /* Loading */, 431DCEC71F67F91C00CF6316 /* Posts */, + 3DDB26C621EBF86300388AEE /* Viewer */, + 3DDB26C721EBF86300388AEE /* Writer */, ); path = ViewControllers; sourceTree = ""; @@ -220,7 +259,8 @@ 4345D4EA1F67E0DD00027D11 /* Extensions */ = { isa = PBXGroup; children = ( - 4345D4F31F67E1FC00027D11 /* CGFloat */, + 3DD99ED121F145CF00CB4B6E /* FileManager */, + C28553E021DD13EF0004C7BA /* NSManagedObjectModel */, 431DCEBC1F67F07100CF6316 /* NSPersistentStoreCoordinator */, 4345D4EC1F67E0DD00027D11 /* UIColor */, ); @@ -236,14 +276,6 @@ path = UIColor; sourceTree = ""; }; - 4345D4F31F67E1FC00027D11 /* CGFloat */ = { - isa = PBXGroup; - children = ( - 4345D4F41F67E1FC00027D11 /* CGFloat+Random.swift */, - ); - path = CGFloat; - sourceTree = ""; - }; 43AB8ADC1F66E6A5003153B3 = { isa = PBXGroup; children = ( @@ -265,9 +297,9 @@ 43AB8AE71F66E6A5003153B3 /* CoreDataMigration-Example */ = { isa = PBXGroup; children = ( - 4345D4EA1F67E0DD00027D11 /* Extensions */, 43370D741F66E74A006188EC /* Application */, 43370D7E1F66E74A006188EC /* CoreData */, + 4345D4EA1F67E0DD00027D11 /* Extensions */, 43370D721F66E74A006188EC /* Resources */, 43370D771F66E74A006188EC /* Storyboards */, 43370D7C1F66E74A006188EC /* ViewControllers */, @@ -278,45 +310,83 @@ 43AB8AFF1F66E6A5003153B3 /* CoreDataMigration-ExampleTests */ = { isa = PBXGroup; children = ( - 43FBB42E1F6C16A80090C536 /* CoreData */, - 43FBB4421F6C16FB0090C536 /* CoreDataMigration-ExampleTests-Bridging-Header.h */, - 43AB8B021F66E6A5003153B3 /* Info.plist */, - 432EA54C1F6C398E00EFE008 /* TestingAppDelegate.swift */, + 3D2C746521DFFE5600514491 /* Helpers */, + C28553E521DD21950004C7BA /* Supporting Files */, + C28553EB21DD21C30004C7BA /* Tests */, ); path = "CoreDataMigration-ExampleTests"; sourceTree = ""; }; - 43FBB42E1F6C16A80090C536 /* CoreData */ = { + C28553E021DD13EF0004C7BA /* NSManagedObjectModel */ = { + isa = PBXGroup; + children = ( + C28553E121DD14090004C7BA /* NSManagedObjectModel+Compatible.swift */, + C28553E321DD1D7B0004C7BA /* NSManagedObjectModel+Resource.swift */, + ); + path = NSManagedObjectModel; + sourceTree = ""; + }; + C28553E521DD21950004C7BA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C28553E821DD21950004C7BA /* Info.plist */, + ); + path = "Supporting Files"; + sourceTree = ""; + }; + C28553EB21DD21C30004C7BA /* Tests */ = { + isa = PBXGroup; + children = ( + C285540021DD21F50004C7BA /* Mocks */, + C28553EC21DD21C30004C7BA /* CoreData */, + ); + path = Tests; + sourceTree = ""; + }; + C28553EC21DD21C30004C7BA /* CoreData */ = { isa = PBXGroup; children = ( - 43FBB42F1F6C16A80090C536 /* Migration */, - 43FBB4401F6C16E30090C536 /* CoreDataManagerTests.swift */, + C28553ED21DD21C30004C7BA /* Manager */, + C28553EF21DD21C30004C7BA /* Migration */, ); path = CoreData; sourceTree = ""; }; - 43FBB42F1F6C16A80090C536 /* Migration */ = { + C28553ED21DD21C30004C7BA /* Manager */ = { isa = PBXGroup; children = ( - 43FBB4301F6C16A80090C536 /* CoreDataMigrationModelTests.swift */, - 43FBB4311F6C16A80090C536 /* CoreDataMigratorTests.swift */, - 43FBB4321F6C16A80090C536 /* Models */, + C28553EE21DD21C30004C7BA /* CoreDataManagerTests.swift */, + ); + path = Manager; + sourceTree = ""; + }; + C28553EF21DD21C30004C7BA /* Migration */ = { + isa = PBXGroup; + children = ( + C28553F721DD21C30004C7BA /* CoreDataMigratorTests.swift */, + C28553F121DD21C30004C7BA /* Models */, ); path = Migration; sourceTree = ""; }; - 43FBB4321F6C16A80090C536 /* Models */ = { + C28553F121DD21C30004C7BA /* Models */ = { isa = PBXGroup; children = ( - 43FBB4331F6C16A80090C536 /* CoreDataMigration_Example_1.sqlite */, - 43FBB4341F6C16A80090C536 /* CoreDataMigration_Example_2.sqlite */, - 43FBB4351F6C16A80090C536 /* CoreDataMigration_Example_3.sqlite */, - 43FBB4361F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite */, - 43FBB4371F6C16A80090C536 /* CoreDataMigration_Example_WAL.sqlite-wal */, + C28553F521DD21C30004C7BA /* CoreDataMigration_Example_1.sqlite */, + C28553F321DD21C30004C7BA /* CoreDataMigration_Example_2.sqlite */, + C28553F621DD21C30004C7BA /* CoreDataMigration_Example_3.sqlite */, ); path = Models; sourceTree = ""; }; + C285540021DD21F50004C7BA /* Mocks */ = { + isa = PBXGroup; + children = ( + C285540121DD22040004C7BA /* MockCoreDataMigrator.swift */, + ); + path = Mocks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -362,16 +432,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0900; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "William Boles"; TargetAttributes = { 43AB8AE41F66E6A5003153B3 = { CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 1010; ProvisioningStyle = Automatic; }; 43AB8AFB1F66E6A5003153B3 = { CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 0900; + LastSwiftMigration = 1010; ProvisioningStyle = Automatic; TestTargetID = 43AB8AE41F66E6A5003153B3; }; @@ -411,11 +482,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 43FBB4471F6C1A950090C536 /* CoreDataMigration_Example_3.sqlite in Resources */, - 43FBB4491F6C1A950090C536 /* CoreDataMigration_Example_WAL.sqlite-wal in Resources */, - 432EA5511F6C3C7D00EFE008 /* CoreDataMigration_Example_1.sqlite in Resources */, - 43FBB4461F6C1A950090C536 /* CoreDataMigration_Example_2.sqlite in Resources */, - 43FBB4481F6C1A950090C536 /* CoreDataMigration_Example_WAL.sqlite in Resources */, + C28553FE21DD21C40004C7BA /* CoreDataMigration_Example_3.sqlite in Resources */, + C28553FB21DD21C40004C7BA /* CoreDataMigration_Example_2.sqlite in Resources */, + C28553FD21DD21C40004C7BA /* CoreDataMigration_Example_1.sqlite in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -426,24 +495,27 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 431DCEBE1F67F18100CF6316 /* CoreDataMigrationModel.swift in Sources */, 43370DB01F66E7A6006188EC /* AppDelegate.swift in Sources */, - 432EA54F1F6C39C600EFE008 /* main.swift in Sources */, 431DCEC01F67F18100CF6316 /* CoreDataMigrator.swift in Sources */, + C28553E421DD1D7B0004C7BA /* NSManagedObjectModel+Resource.swift in Sources */, 431DCECB1F67F93000CF6316 /* AppLoadingViewController.swift in Sources */, - 431DCED61F68315900CF6316 /* Migration2to3.xcmappingmodel in Sources */, - 4345D4F51F67E1FC00027D11 /* CGFloat+Random.swift in Sources */, + 3DDB26CB21EC00FE00388AEE /* PostViewerViewController.swift in Sources */, + 3DD99ED021F1118700CB4B6E /* Migration2to3ModelMapping.xcmappingmodel in Sources */, + C28553E221DD14090004C7BA /* NSManagedObjectModel+Compatible.swift in Sources */, + C28553DF21DCF5000004C7BA /* CoreDataMigrationVersion.swift in Sources */, 432EA5591F6C552800EFE008 /* NSPersistentStoreCoordinator+SQLite.swift in Sources */, + C23BD45A21F08A350039A36B /* PostSectionViewerTableViewCell.swift in Sources */, 4345D4F01F67E10700027D11 /* UIColor+Random.swift in Sources */, 4345D4EE1F67E0FE00027D11 /* UIColor+Hex.swift in Sources */, 431DCED21F6815A300CF6316 /* Post2ToPost3MigrationPolicy.swift in Sources */, 431DCECD1F67FE0800CF6316 /* PostTableViewCell.swift in Sources */, 431DCECC1F67FE0500CF6316 /* PostsViewController.swift in Sources */, 43370DBE1F66F0DF006188EC /* CoreDataManager.swift in Sources */, + 3DD99ED321F145EC00CB4B6E /* FileManager+ApplicationSupport.swift in Sources */, 431DCEBF1F67F18100CF6316 /* CoreDataMigrationStep.swift in Sources */, - 432EA5501F6C3A9A00EFE008 /* TestingAppDelegate.swift in Sources */, 431DCEAE1F67EC9E00CF6316 /* CoreDataMigration_Example.xcdatamodeld in Sources */, - 431DCEC21F67F1B100CF6316 /* Migration1to2.xcmappingmodel in Sources */, + 3DDB26C921EBF87E00388AEE /* PostWriterViewController.swift in Sources */, + 3DACAAD221EE9D5D00309A75 /* PostSectionWriterTableViewCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -451,10 +523,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 43FBB4431F6C1A8F0090C536 /* CoreDataMigrationModelTests.swift in Sources */, - 432EA54D1F6C398E00EFE008 /* TestingAppDelegate.swift in Sources */, - 43FBB4441F6C1A8F0090C536 /* CoreDataMigratorTests.swift in Sources */, - 43FBB4411F6C16E30090C536 /* CoreDataManagerTests.swift in Sources */, + C285540221DD22040004C7BA /* MockCoreDataMigrator.swift in Sources */, + 3D8E52F721E0F98500FE1D35 /* NSManagedObjectContext+Helper.swift in Sources */, + C28553F821DD21C40004C7BA /* CoreDataManagerTests.swift in Sources */, + C28553FF21DD21C40004C7BA /* CoreDataMigratorTests.swift in Sources */, + 3D8E52F521E0EF2800FE1D35 /* FileManager+Helper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -502,6 +575,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -509,6 +583,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -559,6 +634,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -566,6 +642,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -605,7 +682,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.williamboles.CoreDataMigration-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -620,7 +697,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.williamboles.CoreDataMigration-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -632,13 +709,13 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = "CoreDataMigration-ExampleTests/Info.plist"; + INFOPLIST_FILE = "CoreDataMigration-ExampleTests/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.williamboles.CoreDataMigration-ExampleTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "CoreDataMigration-ExampleTests/CoreDataMigration-ExampleTests-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CoreDataMigration-Example.app/CoreDataMigration-Example"; }; @@ -651,12 +728,12 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = "CoreDataMigration-ExampleTests/Info.plist"; + INFOPLIST_FILE = "CoreDataMigration-ExampleTests/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.williamboles.CoreDataMigration-ExampleTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "CoreDataMigration-ExampleTests/CoreDataMigration-ExampleTests-Bridging-Header.h"; - SWIFT_VERSION = 4.0; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CoreDataMigration-Example.app/CoreDataMigration-Example"; }; diff --git a/CoreDataMigration-Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CoreDataMigration-Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/CoreDataMigration-Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/CoreDataMigration-Example.xcodeproj/xcshareddata/xcschemes/CoreDataMigration-Example.xcscheme b/CoreDataMigration-Example.xcodeproj/xcshareddata/xcschemes/CoreDataMigration-Example.xcscheme index c9e4348..a2809d8 100644 --- a/CoreDataMigration-Example.xcodeproj/xcshareddata/xcschemes/CoreDataMigration-Example.xcscheme +++ b/CoreDataMigration-Example.xcodeproj/xcshareddata/xcschemes/CoreDataMigration-Example.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "NO"> @@ -49,6 +48,13 @@ ReferencedContainer = "container:CoreDataMigration-Example.xcodeproj"> + + + + @@ -56,7 +62,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/CoreDataMigration-Example/Application/AppDelegate.swift b/CoreDataMigration-Example/Application/AppDelegate.swift index 01f511e..12e39b3 100644 --- a/CoreDataMigration-Example/Application/AppDelegate.swift +++ b/CoreDataMigration-Example/Application/AppDelegate.swift @@ -9,13 +9,18 @@ import UIKit import CoreData +@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // MARK: - AppLifecycle - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + guard ProcessInfo.processInfo.environment["runningTests"] == nil else { + FileManager.clearApplicationSupportDirectoryContents() + return true + } CoreDataManager.shared.setup { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { // just for example purposes diff --git a/CoreDataMigration-Example/Application/main.swift b/CoreDataMigration-Example/Application/main.swift deleted file mode 100644 index 6568f95..0000000 --- a/CoreDataMigration-Example/Application/main.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// main.swift -// CoreDataMigration-Example -// -// Created by William Boles on 15/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import Foundation -import UIKit - -let isRunningTests = NSClassFromString("XCTestCase") != nil -let appDelegateClass : AnyClass = isRunningTests ? TestingAppDelegate.self : AppDelegate.self -let args = UnsafeMutableRawPointer(CommandLine.unsafeArgv).bindMemory(to: UnsafeMutablePointer.self, capacity: Int(CommandLine.argc)) -UIApplicationMain(CommandLine.argc, args, nil, NSStringFromClass(appDelegateClass)) diff --git a/CoreDataMigration-Example/CoreData/CoreDataManager.swift b/CoreDataMigration-Example/CoreData/CoreDataManager.swift index f7f80c5..2226a17 100644 --- a/CoreDataMigration-Example/CoreData/CoreDataManager.swift +++ b/CoreDataMigration-Example/CoreData/CoreDataManager.swift @@ -11,12 +11,15 @@ import CoreData class CoreDataManager { - let migrator: CoreDataMigrator + let migrator: CoreDataMigratorProtocol + private let storeType: String - lazy var persistentContainer: NSPersistentContainer! = { + lazy var persistentContainer: NSPersistentContainer = { let persistentContainer = NSPersistentContainer(name: "CoreDataMigration_Example") let description = persistentContainer.persistentStoreDescriptions.first description?.shouldInferMappingModelAutomatically = false //inferred mapping will be handled else where + description?.shouldMigrateStoreAutomatically = false + description?.type = storeType return persistentContainer }() @@ -41,7 +44,8 @@ class CoreDataManager { // MARK: - Init - init(migrator: CoreDataMigrator = CoreDataMigrator()) { + init(storeType: String = NSSQLiteStoreType, migrator: CoreDataMigratorProtocol = CoreDataMigrator()) { + self.storeType = storeType self.migrator = migrator } @@ -72,9 +76,9 @@ class CoreDataManager { fatalError("persistentContainer was not set up properly") } - if migrator.requiresMigration(at: storeURL) { + if migrator.requiresMigration(at: storeURL, toVersion: CoreDataMigrationVersion.latest) { DispatchQueue.global(qos: .userInitiated).async { - self.migrator.migrateStore(at: storeURL) + self.migrator.migrateStore(at: storeURL, toVersion: CoreDataMigrationVersion.latest) DispatchQueue.main.async { completion() diff --git a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationModel.swift b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationModel.swift deleted file mode 100644 index be20c19..0000000 --- a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationModel.swift +++ /dev/null @@ -1,207 +0,0 @@ -// -// CoreDataMigrationVersion.swift -// CoreDataMigration-Example -// -// Created by William Boles on 11/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import Foundation -import CoreData - -enum CoreDataVersion: Int { - case version1 = 1 - case version2 - case version3 - case version4 - - // MARK: - Accessors - - var name: String { - if rawValue == 1 { - return "CoreDataMigration_Example" - } else { - return "CoreDataMigration_Example \(rawValue)" - } - } - - static var all: [CoreDataVersion] { - var versions = [CoreDataVersion]() - - for rawVersionValue in 1...1000 { // A bit of a hack here to avoid manual mapping - if let version = CoreDataVersion(rawValue: rawVersionValue) { - versions.append(version) - continue - } - - break - } - - return versions.reversed() - } - - static var latest: CoreDataVersion { - return all.first! - } -} - -class CoreDataMigrationModel { - - let version: CoreDataVersion - - var modelBundle: Bundle { - return Bundle.main - } - - var modelDirectoryName: String { - return "CoreDataMigration_Example.momd" - } - - static var all: [CoreDataMigrationModel] { - var migrationModels = [CoreDataMigrationModel]() - - for version in CoreDataVersion.all { - migrationModels.append(CoreDataMigrationModel(version: version)) - } - - return migrationModels - } - - static var current: CoreDataMigrationModel { - return CoreDataMigrationModel(version: CoreDataVersion.latest) - } - - /** - Determines the next model version from the current model version. - - NB: the next version migration is not always the next actual version. With - this solution we can skip "bad/corrupted" versions. - */ - var successor: CoreDataMigrationModel? { - switch self.version { - case .version1: - return CoreDataMigrationModel(version: .version2) - case .version2: - return CoreDataMigrationModel(version: .version3) - case .version3: - return CoreDataMigrationModel(version: .version4) - case .version4: - return nil - } - } - - // MARK: - Init - - init(version: CoreDataVersion) { - self.version = version - } - - // MARK: - Model - - func managedObjectModel() -> NSManagedObjectModel { - let omoURL = modelBundle.url(forResource: version.name, withExtension: "omo", subdirectory: modelDirectoryName) // optimized model file - let momURL = modelBundle.url(forResource: version.name, withExtension: "mom", subdirectory: modelDirectoryName) - - guard let url = omoURL ?? momURL else { - fatalError("unable to find model in bundle") - } - - guard let model = NSManagedObjectModel(contentsOf: url) else { - fatalError("unable to load model in bundle") - } - - return model - } - - // MARK: - Mapping - - func mappingModelToSuccessor() -> NSMappingModel? { - guard let nextVersion = successor else { - return nil - } - - switch version { - case .version1, .version2: //manual mapped versions - guard let mapping = customMappingModel(to: nextVersion) else { - return nil - } - - return mapping - default: - return inferredMappingModel(to: nextVersion) - } - } - - func inferredMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel { - do { - let sourceModel = managedObjectModel() - let destinationModel = nextVersion.managedObjectModel() - return try NSMappingModel.inferredMappingModel(forSourceModel: sourceModel, destinationModel: destinationModel) - } catch { - fatalError("unable to generate inferred mapping model") - } - } - - func customMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel? { - let sourceModel = managedObjectModel() - let destinationModel = nextVersion.managedObjectModel() - guard let mapping = NSMappingModel(from: [modelBundle], forSourceModel: sourceModel, destinationModel: destinationModel) else { - return nil - } - - return mapping - } - - // MARK: - MigrationSteps - - func migrationSteps(to version: CoreDataMigrationModel) -> [CoreDataMigrationStep] { - guard self.version != version.version else { - return [] - } - - guard let mapping = mappingModelToSuccessor(), let nextVersion = successor else { - return [] - } - - let sourceModel = managedObjectModel() - let destinationModel = nextVersion.managedObjectModel() - - let step = CoreDataMigrationStep(source: sourceModel, destination: destinationModel, mapping: mapping) - let nextStep = nextVersion.migrationSteps(to: version) - - return [step] + nextStep - } - - // MARK: - Metadata - - static func migrationModelCompatibleWithStoreMetadata(_ metadata: [String : Any]) -> CoreDataMigrationModel? { - let compatibleMigrationModel = CoreDataMigrationModel.all.first { - $0.managedObjectModel().isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) - } - - return compatibleMigrationModel - } -} - -// MARK: - Source - -class CoreDataMigrationSourceModel: CoreDataMigrationModel { - - // MARK: - Init - - init?(storeURL: URL) { - guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL) else { - return nil - } - - let migrationVersionModel = CoreDataMigrationModel.all.first { - $0.managedObjectModel().isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) - } - - guard migrationVersionModel != nil else { - return nil - } - - super.init(version: migrationVersionModel!.version) - } -} diff --git a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationStep.swift b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationStep.swift index c00633f..88d559a 100644 --- a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationStep.swift +++ b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationStep.swift @@ -10,7 +10,40 @@ import CoreData struct CoreDataMigrationStep { - let source: NSManagedObjectModel - let destination: NSManagedObjectModel - let mapping: NSMappingModel + let sourceModel: NSManagedObjectModel + let destinationModel: NSManagedObjectModel + let mappingModel: NSMappingModel + + // MARK: Init + + init(sourceVersion: CoreDataMigrationVersion, destinationVersion: CoreDataMigrationVersion) { + let sourceModel = NSManagedObjectModel.managedObjectModel(forResource: sourceVersion.rawValue) + let destinationModel = NSManagedObjectModel.managedObjectModel(forResource: destinationVersion.rawValue) + + guard let mappingModel = CoreDataMigrationStep.mappingModel(fromSourceModel: sourceModel, toDestinationModel: destinationModel) else { + fatalError("Expected modal mapping not present") + } + + self.sourceModel = sourceModel + self.destinationModel = destinationModel + self.mappingModel = mappingModel + } + + // MARK: - Mapping + + private static func mappingModel(fromSourceModel sourceModel: NSManagedObjectModel, toDestinationModel destinationModel: NSManagedObjectModel) -> NSMappingModel? { + guard let customMapping = customMappingModel(fromSourceModel: sourceModel, toDestinationModel: destinationModel) else { + return inferredMappingModel(fromSourceModel:sourceModel, toDestinationModel: destinationModel) + } + + return customMapping + } + + private static func inferredMappingModel(fromSourceModel sourceModel: NSManagedObjectModel, toDestinationModel destinationModel: NSManagedObjectModel) -> NSMappingModel? { + return try? NSMappingModel.inferredMappingModel(forSourceModel: sourceModel, destinationModel: destinationModel) + } + + private static func customMappingModel(fromSourceModel sourceModel: NSManagedObjectModel, toDestinationModel destinationModel: NSManagedObjectModel) -> NSMappingModel? { + return NSMappingModel(from: [Bundle.main], forSourceModel: sourceModel, destinationModel: destinationModel) + } } diff --git a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationVersion.swift b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationVersion.swift new file mode 100644 index 0000000..ff92dbc --- /dev/null +++ b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrationVersion.swift @@ -0,0 +1,42 @@ +// +// CoreDataVersion.swift +// CoreDataMigration-Example +// +// Created by William Boles on 02/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation +import CoreData + +enum CoreDataMigrationVersion: String, CaseIterable { + case version1 = "CoreDataMigration_Example" + case version2 = "CoreDataMigration_Example 2" + case version3 = "CoreDataMigration_Example 3" + case version4 = "CoreDataMigration_Example 4" + + // MARK: - Latest + + static var latest: CoreDataMigrationVersion { + guard let latest = allCases.last else { + fatalError("no model versions found") + } + + return latest + } + + // MARK: - Migration + + func nextVersion() -> CoreDataMigrationVersion? { + switch self { + case .version1: + return .version2 + case .version2: + return .version3 + case .version3: + return .version4 + case .version4: + return nil + } + } +} diff --git a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrator.swift b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrator.swift index 8d27002..9682cd9 100644 --- a/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrator.swift +++ b/CoreDataMigration-Example/CoreData/Migration/CoreDataMigrator.swift @@ -8,6 +8,11 @@ import CoreData +protocol CoreDataMigratorProtocol { + func requiresMigration(at storeURL: URL, toVersion version: CoreDataMigrationVersion) -> Bool + func migrateStore(at storeURL: URL, toVersion version: CoreDataMigrationVersion) +} + /** Responsible for handling Core Data model migrations. @@ -24,45 +29,37 @@ import CoreData Then when we create model version 5, we only need to create one additional mapping 4 to 5. This greatly reduces the work required when adding a new version. */ -class CoreDataMigrator { +class CoreDataMigrator: CoreDataMigratorProtocol { // MARK: - Check - func requiresMigration(at storeURL: URL, currentMigrationModel: CoreDataMigrationModel = CoreDataMigrationModel.current) -> Bool { + func requiresMigration(at storeURL: URL, toVersion version: CoreDataMigrationVersion) -> Bool { guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL) else { return false } - - return !currentMigrationModel.managedObjectModel().isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + + return (CoreDataMigrationVersion.compatibleVersionForStoreMetadata(metadata) != version) } // MARK: - Migration - func migrateStore(at storeURL: URL) { - migrateStore(from: storeURL, to: storeURL, targetVersion: CoreDataMigrationModel.current) - } - - func migrateStore(from sourceURL: URL, to targetURL: URL, targetVersion: CoreDataMigrationModel) { - guard let sourceMigrationModel = CoreDataMigrationSourceModel(storeURL: sourceURL as URL) else { - fatalError("unknown store version at URL \(sourceURL)") - } + func migrateStore(at storeURL: URL, toVersion version: CoreDataMigrationVersion) { + forceWALCheckpointingForStore(at: storeURL) - forceWALCheckpointingForStore(at: sourceURL) + var currentURL = storeURL + let migrationSteps = self.migrationStepsForStore(at: storeURL, toVersion: version) - var currentURL = sourceURL - let migrationSteps = sourceMigrationModel.migrationSteps(to: targetVersion) - - for step in migrationSteps { - let manager = NSMigrationManager(sourceModel: step.source, destinationModel: step.destination) + for migrationStep in migrationSteps { + let manager = NSMigrationManager(sourceModel: migrationStep.sourceModel, destinationModel: migrationStep.destinationModel) let destinationURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(UUID().uuidString) do { - try manager.migrateStore(from: currentURL, sourceType: NSSQLiteStoreType, options: nil, with: step.mapping, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil) + try manager.migrateStore(from: currentURL, sourceType: NSSQLiteStoreType, options: nil, with: migrationStep.mappingModel, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil) } catch let error { - fatalError("failed attempting to migrate from \(step.source) to \(step.destination), error: \(error)") + fatalError("failed attempting to migrate from \(migrationStep.sourceModel) to \(migrationStep.destinationModel), error: \(error)") } - if currentURL != sourceURL { + if currentURL != storeURL { //Destroy intermediate step's store NSPersistentStoreCoordinator.destroyStore(at: currentURL) } @@ -70,23 +67,44 @@ class CoreDataMigrator { currentURL = destinationURL } - NSPersistentStoreCoordinator.replaceStore(at: targetURL, withStoreAt: currentURL) + NSPersistentStoreCoordinator.replaceStore(at: storeURL, withStoreAt: currentURL) - if (currentURL != sourceURL) { + if (currentURL != storeURL) { NSPersistentStoreCoordinator.destroyStore(at: currentURL) } } + private func migrationStepsForStore(at storeURL: URL, toVersion destinationVersion: CoreDataMigrationVersion) -> [CoreDataMigrationStep] { + guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL), let sourceVersion = CoreDataMigrationVersion.compatibleVersionForStoreMetadata(metadata) else { + fatalError("unknown store version at URL \(storeURL)") + } + + return migrationSteps(fromSourceVersion: sourceVersion, toDestinationVersion: destinationVersion) + } + + private func migrationSteps(fromSourceVersion sourceVersion: CoreDataMigrationVersion, toDestinationVersion destinationVersion: CoreDataMigrationVersion) -> [CoreDataMigrationStep] { + var sourceVersion = sourceVersion + var migrationSteps = [CoreDataMigrationStep]() + + while sourceVersion != destinationVersion, let nextVersion = sourceVersion.nextVersion() { + let migrationStep = CoreDataMigrationStep(sourceVersion: sourceVersion, destinationVersion: nextVersion) + migrationSteps.append(migrationStep) + + sourceVersion = nextVersion + } + + return migrationSteps + } + // MARK: - WAL func forceWALCheckpointingForStore(at storeURL: URL) { - guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL), let migrationModel = CoreDataMigrationModel.migrationModelCompatibleWithStoreMetadata(metadata) else { + guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL), let currentModel = NSManagedObjectModel.compatibleModelForStoreMetadata(metadata) else { return } do { - let model = migrationModel.managedObjectModel() - let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: currentModel) let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] let store = persistentStoreCoordinator.addPersistentStore(at: storeURL, options: options) @@ -96,3 +114,18 @@ class CoreDataMigrator { } } } + +private extension CoreDataMigrationVersion { + + // MARK: - Compatible + + static func compatibleVersionForStoreMetadata(_ metadata: [String : Any]) -> CoreDataMigrationVersion? { + let compatibleVersion = CoreDataMigrationVersion.allCases.first { + let model = NSManagedObjectModel.managedObjectModel(forResource: $0.rawValue) + + return model.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + } + + return compatibleVersion + } +} diff --git a/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration1to2.xcmappingmodel/xcmapping.xml b/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration1to2.xcmappingmodel/xcmapping.xml deleted file mode 100644 index 8c02eb9..0000000 --- a/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration1to2.xcmappingmodel/xcmapping.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - 134481920 - 2CB996DF-63DA-4182-BC5B-7CB919C1BB09 - 106 - - - - NSPersistenceFrameworkVersion - 754 - NSStoreModelVersionHashes - - XDDevAttributeMapping - - 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= - - XDDevEntityMapping - - qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= - - XDDevMappingModel - - EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= - - XDDevPropertyMapping - - XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= - - XDDevRelationshipMapping - - akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= - - - NSStoreModelVersionHashesVersion - 3 - NSStoreModelVersionIdentifiers - - - - - - - - - YnBsaXN0MDDUAQIDBAUGODlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKwH -CBMUGRoiJywtMDRVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAtfEBB2YWx1ZUZvcktleVBhdGg60xULDRYXGFpOU1ZhcmlhYmxlgAQQAoAFVnNvdXJjZdIbHB0eWiRjbGFzc25hbWVYJGNsYXNzZXNfEBROU1ZhcmlhYmxlRXhwcmVzc2lvbqMfICFfEBROU1ZhcmlhYmxlRXhwcmVzc2lvblxOU0V4cHJlc3Npb25YTlNPYmplY3TSIw0kJlpOUy5vYmplY3RzoSWAB4AK0w0LKCkqK1lOU0tleVBhdGiACRAKgAhVY29sb3LSGxwuL18QHE5TS2V5UGF0aFNwZWNpZmllckV4cHJlc3Npb26jLiAh0hscMTJeTlNNdXRhYmxlQXJyYXmjMTMhV05TQXJyYXnSGxw1Nl8QE05TS2V5UGF0aEV4cHJlc3Npb26kNTcgIV8QFE5TRnVuY3Rpb25FeHByZXNzaW9uXxAPTlNLZXllZEFyY2hpdmVy0To7VHJvb3SAAQAIABEAGgAjAC0AMgA3AEQASgBVAF8AbgCBAI0AlACWAJgAmgCcAJ4AsQC4AMMAxQDHAMkA0ADVAOAA6QEAAQQBGwEoATEBNgFBAUMBRQFHAU4BWAFaAVwBXgFkAWkBiAGMAZEBoAGkAawBsQHHAcwB4wH1AfgB/QAAAAAAAAIBAAAAAAAAADwAAAAAAAAAAAAAAAAAAAH/ - - hexColor - - - - date - - - - CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGBW4Fb1gkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv -cBIAAYagrxCVAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APgAWAEIARcBGwEfAS4BNAE1AT0BTAFVAV8BYAFhAWIBdwF4AYABgQGCAY4BogGjAaQBpQGmAacBqAGpAaoBuQHIAdcB2wHqAfkB+gIJAhgCJwIzAkUCRgJHAkgCSQJKAksCTAJbAmoCeQKIAokCmAKnArYCvgLTAtQC3ALoAvwDCwMaAykDLQM8A0sDWgNpA3gDhAOWA6UDtAPDA9ID0wPiA/EEAAQVBBYEHgQqBD4ETQRcBGsEbwR+BI0EnASrBLoExgTYBOcE9gUFBRQFIwUyBUEFQgVFBU4FUgVWBVoFYgVlBWkFalUkbnVsbNcACQAKAAsADAANAA4ADwAQABEAEgATABQAEwAWXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgJSAkYAAgJKAAICT3gAYABkAGgAbABwAHQAeAAoAHwAgACEAIgAjACQAJQAmACcAKAAlABMAKwAsAC0ALgAvACUAJQATXxAcWERCdWNrZXRGb3JDbGFzc2Vzd2FzRW5jb2RlZF8QGlhEQnVja2V0Rm9yUGFja2FnZXNzdG9yYWdlXxAcWERCdWNrZXRGb3JJbnRlcmZhY2Vzc3RvcmFnZV8QD194ZF9vd25pbmdNb2RlbF8QHVhEQnVja2V0Rm9yUGFja2FnZXN3YXNFbmNvZGVkVl9vd25lcl8QG1hEQnVja2V0Rm9yRGF0YVR5cGVzc3RvcmFnZVtfdmlzaWJpbGl0eV8QGVhEQnVja2V0Rm9yQ2xhc3Nlc3N0b3JhZ2VVX25hbWVfEB9YREJ1Y2tldEZvckludGVyZmFjZXN3YXNFbmNvZGVkXxAeWERCdWNrZXRGb3JEYXRhVHlwZXN3YXNFbmNvZGVkXxAQX3VuaXF1ZUVsZW1lbnRJRIAEgI+AjYABgASAAICOgJAQAIAFgAOABIAEgABQU1lFU9MANgA3AAoAOAA6ADxXTlMua2V5c1pOUy5vYmplY3RzoQA5gAahADuAB4AlVFBvc3TfEBAAPwBAAEEAQgAdAEMARAAfAEUARgAKACEARwBIACQASQBKAEsAJQAlABAATwBQAC0AJQBKAFMAOQBKAFYAVwBYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAmALIAEgASAAoAKgIqABIAJgIyABoAJgIuACAgSxekjRldvcmRlcmVk0wA2ADcACgBcAF4APKEAXYALoQBfgAyAJV5YRF9QU3RlcmVvdHlwZdkAHQAhAGMACgAkAGQAHwBJAGUAOwBdAEoAaQATACUALQBYAG1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmAK4AAgAQIgA3TADYANwAKAG8AeQA8qQBwAHEAcgBzAHQAdQB2AHcAeIAOgA+AEIARgBKAE4AUgBWAFqkAegB7AHwAfQB+AH8AgACBAIKAF4AbgByAHoAfgCGAI4AmgCqAJV8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZWERfUFNLX2ZldGNoUmVxdWVzdHNBcnJheV8QEVhEX1BTS19pc0Fic3RyYWN0XxAPWERfUFNLX3VzZXJJbmZvXxATWERfUFNLX2NsYXNzTWFwcGluZ18QFlhEX1BTS19lbnRpdHlDbGFzc05hbWXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwCZABMAXwBYAFgAWAAtAFgAoABwAFgAWAATAFhVX3R5cGVYX2RlZmF1bHRcX2Fzc29jaWF0aW9uW19pc1JlYWRPbmx5WV9pc1N0YXRpY1lfaXNVbmlxdWVaX2lzRGVyaXZlZFpfaXNPcmRlcmVkXF9pc0NvbXBvc2l0ZVdfaXNMZWFmgACAGIAAgAwICAgIgBqADggIgAAI0gA3AAoApwCooIAZ0gCqAKsArACtWiRjbGFzc25hbWVYJGNsYXNzZXNeTlNNdXRhYmxlQXJyYXmjAKwArgCvV05TQXJyYXlYTlNPYmplY3TSAKoAqwCxALJfEBBYRFVNTFByb3BlcnR5SW1wpACzALQAtQCvXxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAF8AWABYAFgALQBYAKAAcQBYAFgAEwBYgACAAIAAgAwICAgIgBqADwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAxwATAF8AWABYAFgALQBYAKAAcgBYAFgAEwBYgACAHYAAgAwICAgIgBqAEAgIgAAI0gA3AAoA1QCooIAZ3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAF8AWABYAFgALQBYAKAAcwBYAFgAEwBYgACAAIAAgAwICAgIgBqAEQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA6AATAF8AWABYAFgALQBYAKAAdABYAFgAEwBYgACAIIAAgAwICAgIgBqAEggIgAAI0gA3AAoA9gCooIAZ3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATAF8AWABYAFgALQBYAKAAdQBYAFgAEwBYgACAIoAAgAwICAgIgBqAEwgIgAAICN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAQoAEwBfAFgAWABYAC0AWACgAHYAWABYABMAWIAAgCSAAIAMCAgICIAagBQICIAACNMANgA3AAoBGAEZADygoIAl0gCqAKsBHAEdXxATTlNNdXRhYmxlRGljdGlvbmFyeaMBHAEeAK9cTlNEaWN0aW9uYXJ53xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBIQATAF8AWABYAFgALQBYAKAAdwBYAFgAEwBYgACAJ4AAgAwICAgIgBqAFQgIgAAI1gAhAAoAJABJAB0AHwEvATAAEwBYABMALYAogCmAAAiAAF8QFFhER2VuZXJpY1JlY29yZENsYXNz0gCqAKsBNgE3XVhEVU1MQ2xhc3NJbXCmATgBOQE6ATsBPACvXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAOQATAF8AWABYAFgALQBYAKAAeABYAFgAEwBYgACABoAAgAwICAgIgBqAFggIgAAI0gCqAKsBTQFOXxASWERVTUxTdGVyZW90eXBlSW1wpwFPAVABUQFSAVMBVACvXxASWERVTUxTdGVyZW90eXBlSW1wXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0wA2ADcACgFWAVoAPKMBVwFYAVmALYAugC+jAVsBXAFdgDCAW4BzgCVVY29sb3JUZGF0ZVZwb3N0SUTfEBIAjgCPAJABYwAdAJIAkwFkAB8AkQFlAJQACgAhAJUAlgAkAJcAEwATABMAJQA7AFgAWAFtAC0AWABKAFgBcQFXAFgAWAF1AFhfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAHCAiAMgiACQiAWoAtCAiAMQgSMUBls9MANgA3AAoBeQF8ADyiAXoBe4AzgDSiAX0BfoA1gEmAJV8QElhEX1BQcm9wU3RlcmVvdHlwZV8QElhEX1BBdHRfU3RlcmVvdHlwZdkAHQAhAYMACgAkAYQAHwBJAYUBWwF6AEoAaQATACUALQBYAY1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAMIAzgAmAK4AAgAQIgDbTADYANwAKAY8BmAA8qAGQAZEBkgGTAZQBlQGWAZeAN4A4gDmAOoA7gDyAPYA+qAGZAZoBmwGcAZ0BngGfAaCAP4BAgEGAQ4BEgEaAR4BIgCVfEBtYRF9QUFNLX2lzU3RvcmVkSW5UcnV0aEZpbGVfEBtYRF9QUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBBYRF9QUFNLX3VzZXJJbmZvXxARWERfUFBTS19pc0luZGV4ZWRfEBJYRF9QUFNLX2lzT3B0aW9uYWxfEBpYRF9QUFNLX2lzU3BvdGxpZ2h0SW5kZXhlZF8QEVhEX1BQU0tfZWxlbWVudElEXxATWERfUFBTS19pc1RyYW5zaWVudN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwF9AFgAWABYAC0AWACgAZAAWABYABMAWIAAgCKAAIA1CAgICIAagDcICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwF9AFgAWABYAC0AWACgAZEAWABYABMAWIAAgACAAIA1CAgICIAagDgICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAcoAEwF9AFgAWABYAC0AWACgAZIAWABYABMAWIAAgEKAAIA1CAgICIAagDkICIAACNMANgA3AAoB2AHZADygoIAl3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATAX0AWABYAFgALQBYAKABkwBYAFgAEwBYgACAIoAAgDUICAgIgBqAOggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMB7AATAX0AWABYAFgALQBYAKABlABYAFgAEwBYgACARYAAgDUICAgIgBqAOwgIgAAICd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwF9AFgAWABYAC0AWACgAZUAWABYABMAWIAAgCKAAIA1CAgICIAagDwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwF9AFgAWABYAC0AWACgAZYAWABYABMAWIAAgACAAIA1CAgICIAagD0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwF9AFgAWABYAC0AWACgAZcAWABYABMAWIAAgCKAAIA1CAgICIAagD4ICIAACNkAHQAhAigACgAkAikAHwBJAioBWwF7AEoAaQATACUALQBYAjJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAMIA0gAmAK4AAgAQIgErTADYANwAKAjQCPAA8pwI1AjYCNwI4AjkCOgI7gEuATIBNgE6AT4BQgFGnAj0CPgI/AkACQQJCAkOAUoBTgFSAVYBXgFiAWYAlXxAdWERfUEF0dEtfZGVmYXVsdFZhbHVlQXNTdHJpbmdfEChYRF9QQXR0S19hbGxvd3NFeHRlcm5hbEJpbmFyeURhdGFTdG9yYWdlXxAXWERfUEF0dEtfbWluVmFsdWVTdHJpbmdfEBZYRF9QQXR0S19hdHRyaWJ1dGVUeXBlXxAXWERfUEF0dEtfbWF4VmFsdWVTdHJpbmdfEB1YRF9QQXR0S192YWx1ZVRyYW5zZm9ybWVyTmFtZV8QIFhEX1BBdHRLX3JlZ3VsYXJFeHByZXNzaW9uU3RyaW5n3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAX4AWABYAFgALQBYAKACNQBYAFgAEwBYgACAAIAAgEkICAgIgBqASwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATAX4AWABYAFgALQBYAKACNgBYAFgAEwBYgACAIoAAgEkICAgIgBqATAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAX4AWABYAFgALQBYAKACNwBYAFgAEwBYgACAAIAAgEkICAgIgBqATQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMCewATAX4AWABYAFgALQBYAKACOABYAFgAEwBYgACAVoAAgEkICAgIgBqATggIgAAIEQK83xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAX4AWABYAFgALQBYAKACOQBYAFgAEwBYgACAAIAAgEkICAgIgBqATwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAX4AWABYAFgALQBYAKACOgBYAFgAEwBYgACAAIAAgEkICAgIgBqAUAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAX4AWABYAFgALQBYAKACOwBYAFgAEwBYgACAAIAAgEkICAgIgBqAUQgIgAAI0gCqAKsCtwK4XVhEUE1BdHRyaWJ1dGWmArkCugK7ArwCvQCvXVhEUE1BdHRyaWJ1dGVcWERQTVByb3BlcnR5XxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xASAI4AjwCQAr8AHQCSAJMCwAAfAJECwQCUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgCyQAtAFgASgBYAXEBWABYAFgC0QBYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgF0IgAkIgFqALggIgFwIEr6cmaPTADYANwAKAtUC2AA8ogF6AXuAM4A0ogLZAtqAXoBpgCXZAB0AIQLdAAoAJALeAB8ASQLfAVwBegBKAGkAEwAlAC0AWALnXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgFuAM4AJgCuAAIAECIBf0wA2ADcACgLpAvIAPKgBkAGRAZIBkwGUAZUBlgGXgDeAOIA5gDqAO4A8gD2APqgC8wL0AvUC9gL3AvgC+QL6gGCAYYBigGSAZYBmgGeAaIAl3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATAtkAWABYAFgALQBYAKABkABYAFgAEwBYgACAIoAAgF4ICAgIgBqANwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAtkAWABYAFgALQBYAKABkQBYAFgAEwBYgACAAIAAgF4ICAgIgBqAOAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMDHAATAtkAWABYAFgALQBYAKABkgBYAFgAEwBYgACAY4AAgF4ICAgIgBqAOQgIgAAI0wA2ADcACgMqAysAPKCggCXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMC2QBYAFgAWAAtAFgAoAGTAFgAWAATAFiAAIAigACAXggICAiAGoA6CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwHsABMC2QBYAFgAWAAtAFgAoAGUAFgAWAATAFiAAIBFgACAXggICAiAGoA7CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMC2QBYAFgAWAAtAFgAoAGVAFgAWAATAFiAAIAigACAXggICAiAGoA8CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMC2QBYAFgAWAAtAFgAoAGWAFgAWAATAFiAAIAAgACAXggICAiAGoA9CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMC2QBYAFgAWAAtAFgAoAGXAFgAWAATAFiAAIAigACAXggICAiAGoA+CAiAAAjZAB0AIQN5AAoAJAN6AB8ASQN7AVwBewBKAGkAEwAlAC0AWAODXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgFuANIAJgCuAAIAECIBq0wA2ADcACgOFA40APKcCNQI2AjcCOAI5AjoCO4BLgEyATYBOgE+AUIBRpwOOA48DkAORA5IDkwOUgGuAbIBtgG6AcIBxgHKAJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLaAFgAWABYAC0AWACgAjUAWABYABMAWIAAgACAAIBpCAgICIAagEsICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwLaAFgAWABYAC0AWACgAjYAWABYABMAWIAAgCKAAIBpCAgICIAagEwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLaAFgAWABYAC0AWACgAjcAWABYABMAWIAAgACAAIBpCAgICIAagE0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATA8UAEwLaAFgAWABYAC0AWACgAjgAWABYABMAWIAAgG+AAIBpCAgICIAagE4ICIAACBEDhN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLaAFgAWABYAC0AWACgAjkAWABYABMAWIAAgACAAIBpCAgICIAagE8ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLaAFgAWABYAC0AWACgAjoAWABYABMAWIAAgACAAIBpCAgICIAagFAICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLaAFgAWABYAC0AWACgAjsAWABYABMAWIAAgACAAIBpCAgICIAagFEICIAACN8QEgCOAI8AkAQBAB0AkgCTBAIAHwCRBAMAlAAKACEAlQCWACQAlwATABMAEwAlADsAWABYBAsALQBYAEoAWAFxAVkAWABYBBMAWF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAcICIB1CIAJCIBagC8ICIB0CBJflG6d0wA2ADcACgQXBBoAPKIBegF7gDOANKIEGwQcgHaAgYAl2QAdACEEHwAKACQEIAAfAEkEIQFdAXoASgBpABMAJQAtAFgEKV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYBzgDOACYArgACABAiAd9MANgA3AAoEKwQ0ADyoAZABkQGSAZMBlAGVAZYBl4A3gDiAOYA6gDuAPIA9gD6oBDUENgQ3BDgEOQQ6BDsEPIB4gHmAeoB8gH2AfoB/gICAJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwQbAFgAWABYAC0AWACgAZAAWABYABMAWIAAgCKAAIB2CAgICIAagDcICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwQbAFgAWABYAC0AWACgAZEAWABYABMAWIAAgACAAIB2CAgICIAagDgICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATBF4AEwQbAFgAWABYAC0AWACgAZIAWABYABMAWIAAgHuAAIB2CAgICIAagDkICIAACNMANgA3AAoEbARtADygoIAl3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBBsAWABYAFgALQBYAKABkwBYAFgAEwBYgACAIoAAgHYICAgIgBqAOggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMB7AATBBsAWABYAFgALQBYAKABlABYAFgAEwBYgACARYAAgHYICAgIgBqAOwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBBsAWABYAFgALQBYAKABlQBYAFgAEwBYgACAIoAAgHYICAgIgBqAPAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBBsAWABYAFgALQBYAKABlgBYAFgAEwBYgACAAIAAgHYICAgIgBqAPQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBBsAWABYAFgALQBYAKABlwBYAFgAEwBYgACAIoAAgHYICAgIgBqAPggIgAAI2QAdACEEuwAKACQEvAAfAEkEvQFdAXsASgBpABMAJQAtAFgExV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYBzgDSACYArgACABAiAgtMANgA3AAoExwTPADynAjUCNgI3AjgCOQI6AjuAS4BMgE2AToBPgFCAUacE0ATRBNIE0wTUBNUE1oCDgISAhYCGgIeAiICJgCXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEHABYAFgAWAAtAFgAoAI1AFgAWAATAFiAAIAAgACAgQgICAiAGoBLCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMEHABYAFgAWAAtAFgAoAI2AFgAWAATAFiAAIAigACAgQgICAiAGoBMCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEHABYAFgAWAAtAFgAoAI3AFgAWAATAFiAAIAAgACAgQgICAiAGoBNCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwJ7ABMEHABYAFgAWAAtAFgAoAI4AFgAWAATAFiAAIBWgACAgQgICAiAGoBOCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEHABYAFgAWAAtAFgAoAI5AFgAWAATAFiAAIAAgACAgQgICAiAGoBPCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEHABYAFgAWAAtAFgAoAI6AFgAWAATAFiAAIAAgACAgQgICAiAGoBQCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEHABYAFgAWAAtAFgAoAI7AFgAWAATAFiAAIAAgACAgQgICAiAGoBRCAiAAAhaZHVwbGljYXRlc9IANwAKBUMAqKCAGdIAqgCrBUYFR1pYRFBNRW50aXR5pwVIBUkFSgVLBUwFTQCvWlhEUE1FbnRpdHldWERVTUxDbGFzc0ltcF8QElhEVU1MQ2xhc3NpZmllckltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDTADYANwAKBU8FUAA8oKCAJdMANgA3AAoFUwVUADygoIAl0wA2ADcACgVXBVgAPKCggCXSAKoAqwVbBVxeWERNb2RlbFBhY2thZ2WmBV0FXgVfBWAFYQCvXlhETW9kZWxQYWNrYWdlXxAPWERVTUxQYWNrYWdlSW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNIANwAKBWMAqKCAGdMANgA3AAoFZgVnADygoIAlUNIAqgCrBWsFbFlYRFBNTW9kZWyjBWsFbQCvV1hETW9kZWxfEA9OU0tleWVkQXJjaGl2ZXLRBXAAKFRyb290gAEACAAZACIAKwA1ADoAPwFsAXIBjwGhAagBtQHIAeAB7gIIAgoCDAIOAhACEgIUAhYCTwJuAosCqgK8AtwC4wMBAw0DKQMvA1EDcgOFA4cDiQOLA40DjwORA5MDlQOXA5kDmwOdA58DoQOiA6YDswO7A8YDyQPLA84D0APSA9cEGgQ+BGIEhQSsBMwE8wUaBToFXgWCBY4FkAWSBZQFlgWYBZoFnAWeBaAFogWkBaYFqAWqBasFsAW4BcUFyAXKBc0FzwXRBeAGBQYpBlAGdAZ2BngGegZ8Bn4GgAaBBoMGkAajBqUGpwapBqsGrQavBrEGswa1BsgGygbMBs4G0AbSBtQG1gbYBtoG3AbyBwUHIQc+B1oHbgeAB5YHrwfuB/QH/QgKCBYIIAgqCDUIQAhNCFUIVwhZCFsIXQheCF8IYAhhCGMIZQhmCGcIaQhqCHMIdAh2CH8IigiTCKIIqQixCLoIwwjWCN8I8gkJCRsJWglcCV4JYAliCWMJZAllCWYJaAlqCWsJbAluCW8JrgmwCbIJtAm2CbcJuAm5CboJvAm+Cb8JwAnCCcMJzAnNCc8KDgoQChIKFAoWChcKGAoZChoKHAoeCh8KIAoiCiMKYgpkCmYKaApqCmsKbAptCm4KcApyCnMKdAp2CncKgAqBCoMKwgrECsYKyArKCssKzArNCs4K0ArSCtMK1ArWCtcK2AsXCxkLGwsdCx8LIAshCyILIwslCycLKAspCysLLAs5CzoLOws9C0YLXAtjC3ALrwuxC7MLtQu3C7gLuQu6C7sLvQu/C8ALwQvDC8QL3QvfC+EL4wvkC+YL/QwGDBQMIQwvDEQMWAxvDIEMwAzCDMQMxgzIDMkMygzLDMwMzgzQDNEM0gzUDNUM3gzzDQINFw0lDToNTg1lDXcNhA2LDY0Njw2RDZgNmg2cDZ4NoA2mDasNsg39DiAOQA5gDmIOZA5mDmgOag5rDmwObg5vDnEOcg50DnYOdw54DnoOew6ADo0Okg6UDpYOmw6dDp8OoQ62DssO8A8UDzsPXw9hD2MPZQ9nD2kPaw9sD24Pew+MD44PkA+SD5QPlg+YD5oPnA+tD68PsQ+zD7UPtw+5D7sPvQ+/D90P+xAOECIQNxBUEGgQfhC9EL8QwRDDEMUQxhDHEMgQyRDLEM0QzhDPENEQ0hERERMRFREXERkRGhEbERwRHREfESERIhEjESURJhFlEWcRaRFrEW0RbhFvEXARcRFzEXURdhF3EXkRehGHEYgRiRGLEcoRzBHOEdAR0hHTEdQR1RHWEdgR2hHbEdwR3hHfEh4SIBIiEiQSJhInEigSKRIqEiwSLhIvEjASMhIzEjQScxJ1EncSeRJ7EnwSfRJ+En8SgRKDEoQShRKHEogSxxLJEssSzRLPEtAS0RLSEtMS1RLXEtgS2RLbEtwTGxMdEx8TIRMjEyQTJRMmEycTKRMrEywTLRMvEzATVRN5E6ATxBPGE8gTyhPME84T0BPRE9MT4BPvE/ET8xP1E/cT+RP7E/0UDBQOFBAUEhQUFBYUGBQaFBwUPBRnFIEUmhS0FNQU9xU2FTgVOhU8FT4VPxVAFUEVQhVEFUYVRxVIFUoVSxWKFYwVjhWQFZIVkxWUFZUVlhWYFZoVmxWcFZ4VnxXeFeAV4hXkFeYV5xXoFekV6hXsFe4V7xXwFfIV8xYyFjQWNhY4FjoWOxY8Fj0WPhZAFkIWQxZEFkYWRxZKFokWixaNFo8WkRaSFpMWlBaVFpcWmRaaFpsWnRaeFt0W3xbhFuMW5RbmFucW6BbpFusW7RbuFu8W8RbyFzEXMxc1FzcXORc6FzsXPBc9Fz8XQRdCF0MXRRdGF08XXRdqF3gXhReYF68XwRgMGC8YTxhvGHEYcxh1GHcYeRh6GHsYfRh+GIAYgRiDGIUYhhiHGIkYihiPGJwYoRijGKUYqhisGK4YsBjVGPkZIBlEGUYZSBlKGUwZThlQGVEZUxlgGXEZcxl1GXcZeRl7GX0ZfxmBGZIZlBmWGZgZmhmcGZ4ZoBmiGaQZ4xnlGecZ6RnrGewZ7RnuGe8Z8RnzGfQZ9Rn3GfgaNxo5GjsaPRo/GkAaQRpCGkMaRRpHGkgaSRpLGkwaixqNGo8akRqTGpQalRqWGpcamRqbGpwanRqfGqAarRquGq8asRrwGvIa9Br2Gvga+Rr6Gvsa/Br+GwAbARsCGwQbBRtEG0YbSBtKG0wbTRtOG08bUBtSG1QbVRtWG1gbWRuYG5obnBueG6AboRuiG6MbpBumG6gbqRuqG6wbrRvsG+4b8BvyG/Qb9Rv2G/cb+Bv6G/wb/Rv+HAAcARxAHEIcRBxGHEgcSRxKHEscTBxOHFAcURxSHFQcVRx6HJ4cxRzpHOsc7RzvHPEc8xz1HPYc+B0FHRQdFh0YHRodHB0eHSAdIh0xHTMdNR03HTkdOx09HT8dQR2AHYIdhB2GHYgdiR2KHYsdjB2OHZAdkR2SHZQdlR3UHdYd2B3aHdwd3R3eHd8d4B3iHeQd5R3mHegd6R4oHioeLB4uHjAeMR4yHjMeNB42HjgeOR46HjwePR58Hn4egB6CHoQehR6GHoceiB6KHowejR6OHpAekR6UHtMe1R7XHtke2x7cHt0e3h7fHuEe4x7kHuUe5x7oHycfKR8rHy0fLx8wHzEfMh8zHzUfNx84HzkfOx88H3sffR9/H4Efgx+EH4Ufhh+HH4kfix+MH40fjx+QH9sf/iAeID4gQCBCIEQgRiBIIEkgSiBMIE0gTyBQIFIgVCBVIFYgWCBZIF4gayBwIHIgdCB5IHsgfSB/IKQgyCDvIRMhFSEXIRkhGyEdIR8hICEiIS8hQCFCIUQhRiFIIUohTCFOIVAhYSFjIWUhZyFpIWshbSFvIXEhcyGyIbQhtiG4IbohuyG8Ib0hviHAIcIhwyHEIcYhxyIGIggiCiIMIg4iDyIQIhEiEiIUIhYiFyIYIhoiGyJaIlwiXiJgImIiYyJkImUiZiJoImoiayJsIm4ibyJ8In0ifiKAIr8iwSLDIsUixyLIIskiyiLLIs0izyLQItEi0yLUIxMjFSMXIxkjGyMcIx0jHiMfIyEjIyMkIyUjJyMoI2cjaSNrI20jbyNwI3EjciNzI3UjdyN4I3kjeyN8I7sjvSO/I8EjwyPEI8UjxiPHI8kjyyPMI80jzyPQJA8kESQTJBUkFyQYJBkkGiQbJB0kHyQgJCEkIyQkJEkkbSSUJLgkuiS8JL4kwCTCJMQkxSTHJNQk4yTlJOck6STrJO0k7yTxJQAlAiUEJQYlCCUKJQwlDiUQJU8lUSVTJVUlVyVYJVklWiVbJV0lXyVgJWElYyVkJaMlpSWnJaklqyWsJa0lriWvJbElsyW0JbUltyW4Jfcl+SX7Jf0l/yYAJgEmAiYDJgUmByYIJgkmCyYMJksmTSZPJlEmUyZUJlUmViZXJlkmWyZcJl0mXyZgJp8moSajJqUmpyaoJqkmqiarJq0mryawJrEmsya0JvMm9Sb3Jvkm+yb8Jv0m/ib/JwEnAycEJwUnBycIJ0cnSSdLJ00nTydQJ1EnUidTJ1UnVydYJ1knWydcJ2cncCdxJ3MnfCeHJ5YnoSevJ8Qn2CfvKAEoDigPKBAoEigfKCAoISgjKDAoMSgyKDQoPShMKFkoaCh6KI4opSi3KMAowSjDKNAo0SjSKNQo1SjeKOgo7yj3KQkpDikTAAAAAAAAAgIAAAAAAAAFcgAAAAAAAAAAAAAAAAAAKRU= - - CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGBW4Fb1gkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv -cBIAAYagrxCVAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APgAWAEIARcBGwEfAS4BNAE1AT0BTAFVAV8BYAFhAWIBdwF4AYABgQGCAY4BogGjAaQBpQGmAacBqAGpAaoBuQHIAdcB2wHqAfkB+gIJAhgCJwIzAkUCRgJHAkgCSQJKAksCTAJbAmoCeQKIAokCmAKnArYCvgLTAtQC3ALoAvwDCwMaAykDLQM8A0sDWgNpA3gDhAOWA6UDtAPDA9ID0wPiA/EEAAQVBBYEHgQqBD4ETQRcBGsEbwR+BI0EnASrBLoExgTYBOcE9gUFBRQFIwUyBUEFQgVFBU4FUgVWBVoFYgVlBWkFalUkbnVsbNcACQAKAAsADAANAA4ADwAQABEAEgATABQAEwAWXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgJSAkYAAgJKAAICT3gAYABkAGgAbABwAHQAeAAoAHwAgACEAIgAjACQAJQAmACcAKAAlABMAKwAsAC0ALgAvACUAJQATXxAcWERCdWNrZXRGb3JDbGFzc2Vzd2FzRW5jb2RlZF8QGlhEQnVja2V0Rm9yUGFja2FnZXNzdG9yYWdlXxAcWERCdWNrZXRGb3JJbnRlcmZhY2Vzc3RvcmFnZV8QD194ZF9vd25pbmdNb2RlbF8QHVhEQnVja2V0Rm9yUGFja2FnZXN3YXNFbmNvZGVkVl9vd25lcl8QG1hEQnVja2V0Rm9yRGF0YVR5cGVzc3RvcmFnZVtfdmlzaWJpbGl0eV8QGVhEQnVja2V0Rm9yQ2xhc3Nlc3N0b3JhZ2VVX25hbWVfEB9YREJ1Y2tldEZvckludGVyZmFjZXN3YXNFbmNvZGVkXxAeWERCdWNrZXRGb3JEYXRhVHlwZXN3YXNFbmNvZGVkXxAQX3VuaXF1ZUVsZW1lbnRJRIAEgI+AjYABgASAAICOgJAQAIAFgAOABIAEgABQU1lFU9MANgA3AAoAOAA6ADxXTlMua2V5c1pOUy5vYmplY3RzoQA5gAahADuAB4AlVFBvc3TfEBAAPwBAAEEAQgAdAEMARAAfAEUARgAKACEARwBIACQASQBKAEsAJQAlABAATwBQAC0AJQBKAFMAOQBKAFYAVwBYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAmALIAEgASAAoAKgIqABIAJgIyABoAJgIuACAgS7WAHiVdvcmRlcmVk0wA2ADcACgBcAF4APKEAXYALoQBfgAyAJV5YRF9QU3RlcmVvdHlwZdkAHQAhAGMACgAkAGQAHwBJAGUAOwBdAEoAaQATACUALQBYAG1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmAK4AAgAQIgA3TADYANwAKAG8AeQA8qQBwAHEAcgBzAHQAdQB2AHcAeIAOgA+AEIARgBKAE4AUgBWAFqkAegB7AHwAfQB+AH8AgACBAIKAF4AbgByAHoAfgCGAI4AmgCqAJV8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZ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ohXhFeMV5RXnFekV6hXrFewV7RXvFfEV8hXzFfUV9hY1FjcWORY7Fj0WPhY/FkAWQRZDFkUWRhZHFkkWShZNFowWjhaQFpIWlBaVFpYWlxaYFpoWnBadFp4WoBahFuAW4hbkFuYW6BbpFuoW6xbsFu4W8BbxFvIW9Bb1FzQXNhc4FzoXPBc9Fz4XPxdAF0IXRBdFF0YXSBdJF1IXYBdtF3sXiBebF7IXxBgPGDIYUhhyGHQYdhh4GHoYfBh9GH4YgBiBGIMYhBiGGIgYiRiKGIwYjRiSGJ8YpBimGKgYrRivGLEYsxjYGPwZIxlHGUkZSxlNGU8ZURlTGVQZVhljGXQZdhl4GXoZfBl+GYAZghmEGZUZlxmZGZsZnRmfGaEZoxmlGacZ5hnoGeoZ7BnuGe8Z8BnxGfIZ9Bn2GfcZ+Bn6GfsaOho8Gj4aQBpCGkMaRBpFGkYaSBpKGksaTBpOGk8ajhqQGpIalBqWGpcamBqZGpoanBqeGp8aoBqiGqMasBqxGrIatBrzGvUa9xr5Gvsa/Br9Gv4a/xsBGwMbBBsFGwcbCBtHG0kbSxtNG08bUBtRG1IbUxtVG1cbWBtZG1sbXBubG50bnxuhG6MbpBulG6YbpxupG6sbrButG68bsBvvG/Eb8xv1G/cb+Bv5G/ob+xv9G/8cABwBHAMcBBxDHEUcRxxJHEscTBxNHE4cTxxRHFMcVBxVHFccWBx9HKEcyBzsHO4c8BzyHPQc9hz4HPkc+x0IHRcdGR0bHR0dHx0hHSMdJR00HTYdOB06HTwdPh1AHUIdRB2DHYUdhx2JHYsdjB2NHY4djx2RHZMdlB2VHZcdmB3XHdkd2x3dHd8d4B3hHeId4x3lHecd6B3pHesd7B4rHi0eLx4xHjMeNB41HjYeNx45HjsePB49Hj8eQB5/HoEegx6FHoceiB6JHooeix6NHo8ekB6RHpMelB6XHtYe2B7aHtwe3h7fHuAe4R7iHuQe5h7nHuge6h7rHyofLB8uHzAfMh8zHzQfNR82HzgfOh87HzwfPh8/H34fgB+CH4Qfhh+HH4gfiR+KH4wfjh+PH5Afkh+TH94gASAhIEEgQyBFIEcgSSBLIEwgTSBPIFAgUiBTIFUgVyBYIFkgWyBcIGEgbiBzIHUgdyB8IH4ggCCCIKcgyyDyIRYhGCEaIRwhHiEgISIhIyElITIhQyFFIUchSSFLIU0hTyFRIVMhZCFmIWghaiFsIW4hcCFyIXQhdiG1IbchuSG7Ib0hviG/IcAhwSHDIcUhxiHHIckhyiIJIgsiDSIPIhEiEiITIhQiFSIXIhkiGiIbIh0iHiJdIl8iYSJjImUiZiJnImgiaSJrIm0ibiJvInEiciJ/IoAigSKDIsIixCLGIsgiyiLLIswizSLOItAi0iLTItQi1iLXIxYjGCMaIxwjHiMfIyAjISMiIyQjJiMnIygjKiMrI2ojbCNuI3AjciNzI3QjdSN2I3gjeiN7I3wjfiN/I74jwCPCI8QjxiPHI8gjySPKI8wjziPPI9Aj0iPTJBIkFCQWJBgkGiQbJBwkHSQeJCAkIiQjJCQkJiQnJEwkcCSXJLskvSS/JMEkwyTFJMckyCTKJNck5iToJOok7CTuJPAk8iT0JQMlBSUHJQklCyUNJQ8lESUTJVIlVCVWJVglWiVbJVwlXSVeJWAlYiVjJWQlZiVnJaYlqCWqJawlriWvJbAlsSWyJbQltiW3JbgluiW7Jfol/CX+JgAmAiYDJgQmBSYGJggmCiYLJgwmDiYPJk4mUCZSJlQmViZXJlgmWSZaJlwmXiZfJmAmYiZjJqImpCamJqgmqiarJqwmrSauJrAmsiazJrQmtia3JvYm+Cb6Jvwm/ib/JwAnAScCJwQnBicHJwgnCicLJ0onTCdOJ1AnUidTJ1QnVSdWJ1gnWidbJ1wnXidfJ2oncyd0J3YnfyeKJ5knpCeyJ8cn2yfyKAQoESgSKBMoFSgiKCMoJCgmKDMoNCg1KDcoQChPKFwoayh9KJEoqCi6KMMoxCjGKNMo1CjVKNco2CjhKOso8ij6KQwpESkWAAAAAAAAAgIAAAAAAAAFcgAAAAAAAAAAAAAAAAAAKRg= - - - - - Post - Undefined - 1 - Post - 1 - - - - - - postID - - - \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3.xcmappingmodel/xcmapping.xml b/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3.xcmappingmodel/xcmapping.xml deleted file mode 100644 index c847a4b..0000000 --- a/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3.xcmappingmodel/xcmapping.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - 134481920 - C4FB3D23-093B-455B-8BB2-12E8793A4DFC - 110 - - - - NSPersistenceFrameworkVersion - 754 - NSStoreModelVersionHashes - - XDDevAttributeMapping - - 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= - - XDDevEntityMapping - - qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= - - XDDevMappingModel - - EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= - - XDDevPropertyMapping - - XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= - - XDDevRelationshipMapping - - akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= - - - NSStoreModelVersionHashesVersion - 3 - NSStoreModelVersionIdentifiers - - - - - - - - - Undefined - 1 - Color - 1 - - - - - - 1 - post - - - - CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGBW4Fb1gkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv -cBIAAYagrxCVAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APgAWAEIARcBGwEfAS4BNAE1AT0BTAFVAV8BYAFhAWIBdwF4AYABgQGCAY4BogGjAaQBpQGmAacBqAGpAaoBuQHIAdcB2wHqAfkB+gIJAhgCJwIzAkUCRgJHAkgCSQJKAksCTAJbAmoCeQKIAokCmAKnArYCvgLTAtQC3ALoAvwDCwMaAykDLQM8A0sDWgNpA3gDhAOWA6UDtAPDA9ID0wPiA/EEAAQVBBYEHgQqBD4ETQRcBGsEbwR+BI0EnASrBLoExgTYBOcE9gUFBRQFIwUyBUEFQgVFBU4FUgVWBVoFYgVlBWkFalUkbnVsbNcACQAKAAsADAANAA4ADwAQABEAEgATABQAEwAWXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgJSAkYAAgJKAAICT3gAYABkAGgAbABwAHQAeAAoAHwAgACEAIgAjACQAJQAmACcAKAAlABMAKwAsAC0ALgAvACUAJQATXxAcWERCdWNrZXRGb3JDbGFzc2Vzd2FzRW5jb2RlZF8QGlhEQnVja2V0Rm9yUGFja2FnZXNzdG9yYWdlXxAcWERCdWNrZXRGb3JJbnRlcmZhY2Vzc3RvcmFnZV8QD194ZF9vd25pbmdNb2RlbF8QHVhEQnVja2V0Rm9yUGFja2FnZXN3YXNFbmNvZGVkVl9vd25lcl8QG1hEQnVja2V0Rm9yRGF0YVR5cGVzc3RvcmFnZVtfdmlzaWJpbGl0eV8QGVhEQnVja2V0Rm9yQ2xhc3Nlc3N0b3JhZ2VVX25hbWVfEB9YREJ1Y2tldEZvckludGVyZmFjZXN3YXNFbmNvZGVkXxAeWERCdWNrZXRGb3JEYXRhVHlwZXN3YXNFbmNvZGVkXxAQX3VuaXF1ZUVsZW1lbnRJRIAEgI+AjYABgASAAICOgJAQAIAFgAOABIAEgABQU1lFU9MANgA3AAoAOAA6ADxXTlMua2V5c1pOUy5vYmplY3RzoQA5gAahADuAB4AlVFBvc3TfEBAAPwBAAEEAQgAdAEMARAAfAEUARgAKACEARwBIACQASQBKAEsAJQAlABAATwBQAC0AJQBKAFMAOQBKAFYAVwBYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAmALIAEgASAAoAKgIqABIAJgIyABoAJgIuACAgTAAAAAQqX+5ZXb3JkZXJlZNMANgA3AAoAXABeADyhAF2AC6EAX4AMgCVeWERfUFN0ZXJlb3R5cGXZAB0AIQBjAAoAJABkAB8ASQBlADsAXQBKAGkAEwAlAC0AWABtXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgAeAC4AJgCuAAIAECIAN0wA2ADcACgBvAHkAPKkAcABxAHIAcwB0AHUAdgB3AHiADoAPgBCAEYASgBOAFIAVgBapAHoAewB8AH0AfgB/AIAAgQCCgBeAG4AcgB6AH4AhgCOAJoAqgCVfEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmll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oxWlFaYV5RXnFekV6xXtFe4V7xXwFfEV8xX1FfYV9xX5FfoWORY7Fj0WPxZBFkIWQxZEFkUWRxZJFkoWSxZNFk4WURaQFpIWlBaWFpgWmRaaFpsWnBaeFqAWoRaiFqQWpRbkFuYW6BbqFuwW7RbuFu8W8BbyFvQW9Rb2FvgW+Rc4FzoXPBc+F0AXQRdCF0MXRBdGF0gXSRdKF0wXTRdWF2QXcRd/F4wXnxe2F8gYExg2GFYYdhh4GHoYfBh+GIAYgRiCGIQYhRiHGIgYihiMGI0YjhiQGJEYlhijGKgYqhisGLEYsxi1GLcY3BkAGScZSxlNGU8ZURlTGVUZVxlYGVoZZxl4GXoZfBl+GYAZghmEGYYZiBmZGZsZnRmfGaEZoxmlGacZqRmrGeoZ7BnuGfAZ8hnzGfQZ9Rn2GfgZ+hn7GfwZ/hn/Gj4aQBpCGkQaRhpHGkgaSRpKGkwaThpPGlAaUhpTGpIalBqWGpgamhqbGpwanRqeGqAaohqjGqQaphqnGrQatRq2Grga9xr5Gvsa/Rr/GwAbARsCGwMbBRsHGwgbCRsLGwwbSxtNG08bURtTG1QbVRtWG1cbWRtbG1wbXRtfG2AbnxuhG6MbpRunG6gbqRuqG6sbrRuvG7AbsRuzG7Qb8xv1G/cb+Rv7G/wb/Rv+G/8cARwDHAQcBRwHHAgcRxxJHEscTRxPHFAcURxSHFMcVRxXHFgcWRxbHFwcgRylHMwc8BzyHPQc9hz4HPoc/Bz9HP8dDB0bHR0dHx0hHSMdJR0nHSkdOB06HTwdPh1AHUIdRB1GHUgdhx2JHYsdjR2PHZAdkR2SHZMdlR2XHZgdmR2bHZwd2x3dHd8d4R3jHeQd5R3mHecd6R3rHewd7R3vHfAeLx4xHjMeNR43HjgeOR46HjsePR4/HkAeQR5DHkQegx6FHoceiR6LHowejR6OHo8ekR6THpQelR6XHpgemx7aHtwe3h7gHuIe4x7kHuUe5h7oHuoe6x7sHu4e7x8uHzAfMh80HzYfNx84HzkfOh88Hz4fPx9AH0IfQx+CH4Qfhh+IH4ofix+MH40fjh+QH5Ifkx+UH5Yflx/iIAUgJSBFIEcgSSBLIE0gTyBQIFEgUyBUIFYgVyBZIFsgXCBdIF8gYCBlIHIgdyB5IHsggCCCIIQghiCrIM8g9iEaIRwhHiEgISIhJCEmISchKSE2IUchSSFLIU0hTyFRIVMhVSFXIWghaiFsIW4hcCFyIXQhdiF4IXohuSG7Ib0hvyHBIcIhwyHEIcUhxyHJIcohyyHNIc4iDSIPIhEiEyIVIhYiFyIYIhkiGyIdIh4iHyIhIiIiYSJjImUiZyJpImoiayJsIm0ibyJxInIicyJ1InYigyKEIoUihyLGIsgiyiLMIs4izyLQItEi0iLUItYi1yLYItoi2yMaIxwjHiMgIyIjIyMkIyUjJiMoIyojKyMsIy4jLyNuI3AjciN0I3YjdyN4I3kjeiN8I34jfyOAI4IjgyPCI8QjxiPII8ojyyPMI80jziPQI9Ij0yPUI9Yj1yQWJBgkGiQcJB4kHyQgJCEkIiQkJCYkJyQoJCokKyRQJHQkmyS/JMEkwyTFJMckySTLJMwkziTbJOok7CTuJPAk8iT0JPYk+CUHJQklCyUNJQ8lESUTJRUlFyVWJVglWiVcJV4lXyVgJWElYiVkJWYlZyVoJWolayWqJawlriWwJbIlsyW0JbUltiW4JboluyW8Jb4lvyX+JgAmAiYEJgYmByYIJgkmCiYMJg4mDyYQJhImEyZSJlQmViZYJlomWyZcJl0mXiZgJmImYyZkJmYmZyamJqgmqiasJq4mryawJrEmsia0JrYmtya4Jromuyb6Jvwm/icAJwInAycEJwUnBicIJwonCycMJw4nDydOJ1AnUidUJ1YnVydYJ1knWidcJ14nXydgJ2InYyduJ3cneCd6J4MnjiedJ6gntifLJ98n9igIKBUoFigXKBkoJignKCgoKig3KDgoOSg7KEQoUyhgKG8ogSiVKKwovijHKMgoyijXKNgo2SjbKNwo5SjvKPYo/ikQKRUpGgAAAAAAAAICAAAAAAAABXIAAAAAAAAAAAAAAAAAACkc - - CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel - YnBsaXN0MDDUAAEAAgADAAQABQAGCiwKLVgkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv -cBIAAYagrxD9AAcACAAXADMANAA1AD8AQABBAFwAXQBeAGQAZQBxAIcAiACJAIoAiwCMAI0AjgCPAJAAqQCsALMAuQDIANcA2gDpAPgA+wBbAQsBGgEeASIBMQE3ATgBQAFPAVgBYgFjAWQBZQF6AXsBgwGEAYUBkQGlAaYBpwGoAakBqgGrAawBrQG8AcsB2gHeAe0B/AH9AgwCGwIqAjYCSAJJAkoCSwJMAk0CTgJPAl4CbQJ8AosCjAKbAqoCuQLBAtYC1wLfAusC/wMOAx0DLAMwAz8DTgNdA2wDewOHA5kDqAO3A8YD1QPkA/MEAgQXBBgEIAQhBC0EQQRQBF8EbgRyBIEEkASfBK4EvQTJBNsE3ATdBN4E3wTgBOEE4gAtBPEFAAUBBRAFHwU5BToFQAVMBWIFcQV0BYMFkgWVBaQFswW2BcUF1AXYBecF9gYABgEGAgYDBhgGGQYhBi0GQQZQBl8GbgZyBoEGkAafBq4GvQbJBtsG6gb5BwgHFwcYBycHNgdFB1oHWwdjB28HgweSB6EHsAe0B8MH0gfhB/AH/wgLCB0ILAg7CEoIWQhoCHcIhgiOCKMIpAisCLgIzAjbCOoI+Qj9CQwJGwkqCTkJSAlUCWYJdQmECZMJogmxCcAJzwnQCdMJ3AnrCfoKCQoMChAKFAoYCiAKIwonCihVJG51bGzXAAkACgALAAwADQAOAA8AEAARABIAEwAUABMAFl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoD8gPmAAID6gACA+94AGAAZABoAGwAcAB0AHgAKAB8AIAAhACIAIwAkACUAJgAnACgAJQATACsALAAtAC4ALwAlACUAE18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABID3gPWAAYAEgACA9oD4EACABYADgASABIAAUFNZRVPTADYANwAKADgAOwA+V05TLmtleXNaTlMub2JqZWN0c6IAOQA6gAaAB6IAPAA9gAiAkYAmVUNvbG9yVFBvc3TfEBAAQgBDAEQARQAdAEYARwAfAEgASQAKACEASgBLACQATABNAE4AJQAlABAAUgBTAC0AJQBNAFYAOQBNAFkAWgBbXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAqALYAEgASAAoALgO6ABIAKgPCABoAKgPSACQgTAAAAAQzkolpXb3JkZXJlZNMANgA3AAoAXwBhAD6hAGCADKEAYoANgCZeWERfUFN0ZXJlb3R5cGXZAB0AIQBmAAoAJABnAB8ATABoADwAYABNAGwAEwAlAC0AWwBwXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgAiADIAKgCyAAIAECIAO0wA2ADcACgByAHwAPqkAcwB0AHUAdgB3AHgAeQB6AHuAD4AQgBGAEoATgBSAFYAWgBepAH0AfgB/AIAAgQCCAIMAhACFgBiAHIAdgB+AIIAigCSAJ4ArgCZfEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QGVhEX1BTS19mZXRjaFJlcXVlc3RzQXJyYXlfEBFYRF9QU0tfaXNBYnN0cmFjdF8QD1hEX1BTS191c2VySW5mb18QE1hEX1BTS19jbGFzc01hcHBpbmdfEBZYRF9QU0tfZW50aXR5Q2xhc3NOYW1l3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAnAATAGIAWwBbAFsALQBbAKMAcwBbAFsAEwBbVV90eXBlWF9kZWZhdWx0XF9hc3NvY2lhdGlvbltfaXNSZWFkT25seVlfaXNTdGF0aWNZX2lzVW5pcXVlWl9pc0Rlcml2ZWRaX2lzT3JkZXJlZFxfaXNDb21wb3NpdGVXX2lzTGVhZoAAgBmAAIANCAgICIAbgA8ICIAACNIANwAKAKoAq6CAGtIArQCuAK8AsFokY2xhc3NuYW1lWCRjbGFzc2VzXk5TTXV0YWJsZUFycmF5owCvALEAsldOU0FycmF5WE5TT2JqZWN00gCtAK4AtAC1XxAQWERVTUxQcm9wZXJ0eUltcKQAtgC3ALgAsl8QEFhEVU1MUHJvcGVydHlJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwBiAFsAWwBbAC0AWwCjAHQAWwBbABMAW4AAgACAAIANCAgICIAbgBAICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAMoAEwBiAFsAWwBbAC0AWwCjAHUAWwBbABMAW4AAgB6AAIANCAgICIAbgBEICIAACNIANwAKANgAq6CAGt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwBiAFsAWwBbAC0AWwCjAHYAWwBbABMAW4AAgACAAIANCAgICIAbgBIICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAOsAEwBiAFsAWwBbAC0AWwCjAHcAWwBbABMAW4AAgCGAAIANCAgICIAbgBMICIAACNIANwAKAPkAq6CAGt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwBiAFsAWwBbAC0AWwCjAHgAWwBbABMAW4AAgCOAAIANCAgICIAbgBQICIAACAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwENABMAYgBbAFsAWwAtAFsAowB5AFsAWwATAFuAAIAlgACADQgICAiAG4AVCAiAAAjTADYANwAKARsBHAA+oKCAJtIArQCuAR8BIF8QE05TTXV0YWJsZURpY3Rpb25hcnmjAR8BIQCyXE5TRGljdGlvbmFyed8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATASQAEwBiAFsAWwBbAC0AWwCjAHoAWwBbABMAW4AAgCiAAIANCAgICIAbgBYICIAACNYAIQAKACQATAAdAB8BMgEzABMAWwATAC2AKYAqgAAIgABfEBRYREdlbmVyaWNSZWNvcmRDbGFzc9IArQCuATkBOl1YRFVNTENsYXNzSW1wpgE7ATwBPQE+AT8Asl1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATADkAEwBiAFsAWwBbAC0AWwCjAHsAWwBbABMAW4AAgAaAAIANCAgICIAbgBcICIAACNIArQCuAVABUV8QElhEVU1MU3RlcmVvdHlwZUltcKcBUgFTAVQBVQFWAVcAsl8QElhEVU1MU3RlcmVvdHlwZUltcF1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNMANgA3AAoBWQFdAD6jAVoBWwFcgC6AL4AwowFeAV8BYIAxgFyAc4AmV2NvbG9ySURTaGV4VHBvc3TfEBIAkQCSAJMBZgAdAJUAlgFnAB8AlAFoAJcACgAhAJgAmQAkAJoAEwATABMAJQA8AFsAWwFwAC0AWwBNAFsBdAFaAFsAWwF4AFtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAICAiAMwiACgiAW4AuCAiAMggS8aNsvtMANgA3AAoBfAF/AD6iAX0BfoA0gDWiAYABgYA2gEqAJl8QElhEX1BQcm9wU3RlcmVvdHlwZV8QElhEX1BBdHRfU3RlcmVvdHlwZdkAHQAhAYYACgAkAYcAHwBMAYgBXgF9AE0AbAATACUALQBbAZBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAMYA0gAqALIAAgAQIgDfTADYANwAKAZIBmwA+qAGTAZQBlQGWAZcBmAGZAZqAOIA5gDqAO4A8gD2APoA/qAGcAZ0BngGfAaABoQGiAaOAQIBBgEKARIBFgEeASIBJgCZfEBtYRF9QUFNLX2lzU3RvcmVkSW5UcnV0aEZpbGVfEBtYRF9QUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBBYRF9QUFNLX3VzZXJJbmZvXxARWERfUFBTS19pc0luZGV4ZWRfEBJYRF9QUFNLX2lzT3B0aW9uYWxfEBpYRF9QUFNLX2lzU3BvdGxpZ2h0SW5kZXhlZF8QEVhEX1BQU0tfZWxlbWVudElEXxATWERfUFBTS19pc1RyYW5zaWVudN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwGAAFsAWwBbAC0AWwCjAZMAWwBbABMAW4AAgCOAAIA2CAgICIAbgDgICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwGAAFsAWwBbAC0AWwCjAZQAWwBbABMAW4AAgACAAIA2CAgICIAbgDkICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAc0AEwGAAFsAWwBbAC0AWwCjAZUAWwBbABMAW4AAgEOAAIA2CAgICIAbgDoICIAACNMANgA3AAoB2wHcAD6goIAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATAYAAWwBbAFsALQBbAKMBlgBbAFsAEwBbgACAI4AAgDYICAgIgBuAOwgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMB7wATAYAAWwBbAFsALQBbAKMBlwBbAFsAEwBbgACARoAAgDYICAgIgBuAPAgIgAAICd8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwGAAFsAWwBbAC0AWwCjAZgAWwBbABMAW4AAgCOAAIA2CAgICIAbgD0ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwGAAFsAWwBbAC0AWwCjAZkAWwBbABMAW4AAgACAAIA2CAgICIAbgD4ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwGAAFsAWwBbAC0AWwCjAZoAWwBbABMAW4AAgCOAAIA2CAgICIAbgD8ICIAACNkAHQAhAisACgAkAiwAHwBMAi0BXgF+AE0AbAATACUALQBbAjVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAMYA1gAqALIAAgAQIgEvTADYANwAKAjcCPwA+pwI4AjkCOgI7AjwCPQI+gEyATYBOgE+AUIBRgFKnAkACQQJCAkMCRAJFAkaAU4BUgFWAVoBYgFmAWoAmXxAdWERfUEF0dEtfZGVmYXVsdFZhbHVlQXNTdHJpbmdfEChYRF9QQXR0S19hbGxvd3NFeHRlcm5hbEJpbmFyeURhdGFTdG9yYWdlXxAXWERfUEF0dEtfbWluVmFsdWVTdHJpbmdfEBZYRF9QQXR0S19hdHRyaWJ1dGVUeXBlXxAXWERfUEF0dEtfbWF4VmFsdWVTdHJpbmdfEB1YRF9QQXR0S192YWx1ZVRyYW5zZm9ybWVyTmFtZV8QIFhEX1BBdHRLX3JlZ3VsYXJFeHByZXNzaW9uU3RyaW5n3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAYEAWwBbAFsALQBbAKMCOABbAFsAEwBbgACAAIAAgEoICAgIgBuATAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATAYEAWwBbAFsALQBbAKMCOQBbAFsAEwBbgACAI4AAgEoICAgIgBuATQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAYEAWwBbAFsALQBbAKMCOgBbAFsAEwBbgACAAIAAgEoICAgIgBuATggIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMCfgATAYEAWwBbAFsALQBbAKMCOwBbAFsAEwBbgACAV4AAgEoICAgIgBuATwgIgAAIEQK83xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAYEAWwBbAFsALQBbAKMCPABbAFsAEwBbgACAAIAAgEoICAgIgBuAUAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAYEAWwBbAFsALQBbAKMCPQBbAFsAEwBbgACAAIAAgEoICAgIgBuAUQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAYEAWwBbAFsALQBbAKMCPgBbAFsAEwBbgACAAIAAgEoICAgIgBuAUggIgAAI0gCtAK4CugK7XVhEUE1BdHRyaWJ1dGWmArwCvQK+Ar8CwACyXVhEUE1BdHRyaWJ1dGVcWERQTVByb3BlcnR5XxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xASAJEAkgCTAsIAHQCVAJYCwwAfAJQCxACXAAoAIQCYAJkAJACaABMAEwATACUAPABbAFsCzAAtAFsATQBbAXQBWwBbAFsC1ABbXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASACAgIgF4IgAoIgFuALwgIgF0IEtVpR9zTADYANwAKAtgC2wA+ogF9AX6ANIA1ogLcAt2AX4BqgCbZAB0AIQLgAAoAJALhAB8ATALiAV8BfQBNAGwAEwAlAC0AWwLqXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgFyANIAKgCyAAIAECIBg0wA2ADcACgLsAvUAPqgBkwGUAZUBlgGXAZgBmQGagDiAOYA6gDuAPIA9gD6AP6gC9gL3AvgC+QL6AvsC/AL9gGGAYoBjgGWAZoBngGiAaYAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATAtwAWwBbAFsALQBbAKMBkwBbAFsAEwBbgACAI4AAgF8ICAgIgBuAOAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAtwAWwBbAFsALQBbAKMBlABbAFsAEwBbgACAAIAAgF8ICAgIgBuAOQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMDHwATAtwAWwBbAFsALQBbAKMBlQBbAFsAEwBbgACAZIAAgF8ICAgIgBuAOggIgAAI0wA2ADcACgMtAy4APqCggCbfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMC3ABbAFsAWwAtAFsAowGWAFsAWwATAFuAAIAjgACAXwgICAiAG4A7CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwHvABMC3ABbAFsAWwAtAFsAowGXAFsAWwATAFuAAIBGgACAXwgICAiAG4A8CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMC3ABbAFsAWwAtAFsAowGYAFsAWwATAFuAAIAjgACAXwgICAiAG4A9CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwATABMC3ABbAFsAWwAtAFsAowGZAFsAWwATAFuAAIAAgACAXwgICAiAG4A+CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMC3ABbAFsAWwAtAFsAowGaAFsAWwATAFuAAIAjgACAXwgICAiAG4A/CAiAAAjZAB0AIQN8AAoAJAN9AB8ATAN+AV8BfgBNAGwAEwAlAC0AWwOGXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgFyANYAKgCyAAIAECIBr0wA2ADcACgOIA5AAPqcCOAI5AjoCOwI8Aj0CPoBMgE2AToBPgFCAUYBSpwORA5IDkwOUA5UDlgOXgGyAbYBugG+AcIBxgHKAJt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwLdAFsAWwBbAC0AWwCjAjgAWwBbABMAW4AAgACAAIBqCAgICIAbgEwICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwLdAFsAWwBbAC0AWwCjAjkAWwBbABMAW4AAgCOAAIBqCAgICIAbgE0ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwLdAFsAWwBbAC0AWwCjAjoAWwBbABMAW4AAgACAAIBqCAgICIAbgE4ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAn4AEwLdAFsAWwBbAC0AWwCjAjsAWwBbABMAW4AAgFeAAIBqCAgICIAbgE8ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwLdAFsAWwBbAC0AWwCjAjwAWwBbABMAW4AAgACAAIBqCAgICIAbgFAICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwLdAFsAWwBbAC0AWwCjAj0AWwBbABMAW4AAgACAAIBqCAgICIAbgFEICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwLdAFsAWwBbAC0AWwCjAj4AWwBbABMAW4AAgACAAIBqCAgICIAbgFIICIAACN8QEgCRAJIAkwQDAB0AlQCWBAQAHwCUBAUAlwAKACEAmACZACQAmgATABMAEwAlADwAWwBbBA0ALQBbAE0AWwQRAVwAWwBbBBUAW18QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAgICIB1CIAKCIDWgDAICIB0CBMAAAABDsPpM9MANgA3AAoEGQQcAD6iAX0EG4A0gHaiBB0EHoB3gIKAJl8QEFhEX1BSX1N0ZXJlb3R5cGXZAB0AIQQiAAoAJAQjAB8ATAQkAWABfQBNAGwAEwAlAC0AWwQsXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHOANIAKgCyAAIAECIB40wA2ADcACgQuBDcAPqgBkwGUAZUBlgGXAZgBmQGagDiAOYA6gDuAPIA9gD6AP6gEOAQ5BDoEOwQ8BD0EPgQ/gHmAeoB7gH2AfoB/gICAgYAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATBB0AWwBbAFsALQBbAKMBkwBbAFsAEwBbgACAI4AAgHcICAgIgBuAOAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBB0AWwBbAFsALQBbAKMBlABbAFsAEwBbgACAAIAAgHcICAgIgBuAOQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMEYQATBB0AWwBbAFsALQBbAKMBlQBbAFsAEwBbgACAfIAAgHcICAgIgBuAOggIgAAI0wA2ADcACgRvBHAAPqCggCbfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMEHQBbAFsAWwAtAFsAowGWAFsAWwATAFuAAIAjgACAdwgICAiAG4A7CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwHvABMEHQBbAFsAWwAtAFsAowGXAFsAWwATAFuAAIBGgACAdwgICAiAG4A8CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMEHQBbAFsAWwAtAFsAowGYAFsAWwATAFuAAIAjgACAdwgICAiAG4A9CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwATABMEHQBbAFsAWwAtAFsAowGZAFsAWwATAFuAAIAAgACAdwgICAiAG4A+CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMEHQBbAFsAWwAtAFsAowGaAFsAWwATAFuAAIAjgACAdwgICAiAG4A/CAiAAAjZAB0AIQS+AAoAJAS/AB8ATATAAWAEGwBNAGwAEwAlAC0AWwTIXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHOAdoAKgCyAAIAECICD0wA2ADcACgTKBNIAPqcEywTMBM0EzgTPBNAE0YCEgIWAhoCHgIiAiYCKpwTTBNQE1QTWBNcE2ATZgIuAjYCPgJCA8YDygPOAJl8QD1hEX1BSS19taW5Db3VudF8QEVhEX1BSS19kZWxldGVSdWxlXxAPWERfUFJLX21heENvdW50XxASWERfUFJLX2Rlc3RpbmF0aW9uXxAPWERfUFJLX2lzVG9NYW55XlhEX1BSS19vcmRlcmVkXxAaWERfUFJLX2ludmVyc2VSZWxhdGlvbnNoaXDfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwTkABMEHgBbAFsAWwAtAFsAowTLAFsAWwATAFuAAICMgACAgggICAiAG4CECAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwTzABMEHgBbAFsAWwAtAFsAowTMAFsAWwATAFuAAICOgACAgggICAiAG4CFCAiAAAgQAd8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBPMAEwQeAFsAWwBbAC0AWwCjBM0AWwBbABMAW4AAgI6AAICCCAgICIAbgIYICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAD0AEwQeAFsAWwBbAC0AWwCjBM4AWwBbABMAW4AAgJGAAICCCAgICIAbgIcICIAACN8QEAUgBSEFIgUjAB0FJAUlAB8FJgUnAAoAIQUoBSkAJABMAE0FKwAlACUAEAUvAFMALQAlAE0AVgA6AE0FNgU3AFtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WACoCjgASABIACgJOA7oAEgAqA8IAHgAqA74CSCBI6j6xL0wA2ADcACgU7BT0APqEAYIAMoQU+gJSAJtkAHQAhBUEACgAkBUIAHwBMBUMAPQBgAE0AbAATACUALQBbBUtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAkYAMgAqALIAAgAQIgJXTADYANwAKBU0FVwA+qQBzAHQAdQB2AHcAeAB5AHoAe4APgBCAEYASgBOAFIAVgBaAF6kFWAVZBVoFWwVcBV0FXgVfBWCAloCYgJmAm4CcgJ6An4ChgKKAJt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBWQAEwU+AFsAWwBbAC0AWwCjAHMAWwBbABMAW4AAgJeAAICUCAgICIAbgA8ICIAACNIANwAKBXIAq6CAGt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwU+AFsAWwBbAC0AWwCjAHQAWwBbABMAW4AAgACAAICUCAgICIAbgBAICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBYUAEwU+AFsAWwBbAC0AWwCjAHUAWwBbABMAW4AAgJqAAICUCAgICIAbgBEICIAACNIANwAKBZMAq6CAGt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwU+AFsAWwBbAC0AWwCjAHYAWwBbABMAW4AAgACAAICUCAgICIAbgBIICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBaYAEwU+AFsAWwBbAC0AWwCjAHcAWwBbABMAW4AAgJ2AAICUCAgICIAbgBMICIAACNIANwAKBbQAq6CAGt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwU+AFsAWwBbAC0AWwCjAHgAWwBbABMAW4AAgCOAAICUCAgICIAbgBQICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBccAEwU+AFsAWwBbAC0AWwCjAHkAWwBbABMAW4AAgKCAAICUCAgICIAbgBUICIAACNMANgA3AAoF1QXWAD6goIAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMBJAATBT4AWwBbAFsALQBbAKMAegBbAFsAEwBbgACAKIAAgJQICAgIgBuAFggIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAOgATBT4AWwBbAFsALQBbAKMAewBbAFsAEwBbgACAB4AAgJQICAgIgBuAFwgIgAAI0wA2ADcACgX3BfsAPqMF+AX5BfqApIClgKajBfwF/QX+gKeAv4DXgCZUZGF0ZVVjb2xvclZwb3N0SUTfEBIAkQCSAJMGBAAdAJUAlgYFAB8AlAYGAJcACgAhAJgAmQAkAJoAEwATABMAJQA9AFsAWwYOAC0AWwBNAFsBdAX4AFsAWwYWAFtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABICRCAiAqQiACgiAW4CkCAiAqAgSf/dtxtMANgA3AAoGGgYdAD6iAX0BfoA0gDWiBh4GH4CqgLWAJtkAHQAhBiIACgAkBiMAHwBMBiQF/AF9AE0AbAATACUALQBbBixfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAp4A0gAqALIAAgAQIgKvTADYANwAKBi4GNwA+qAGTAZQBlQGWAZcBmAGZAZqAOIA5gDqAO4A8gD2APoA/qAY4BjkGOgY7BjwGPQY+Bj+ArICtgK6AsICxgLKAs4C0gCbfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMGHgBbAFsAWwAtAFsAowGTAFsAWwATAFuAAIAjgACAqggICAiAG4A4CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwATABMGHgBbAFsAWwAtAFsAowGUAFsAWwATAFuAAIAAgACAqggICAiAG4A5CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwZhABMGHgBbAFsAWwAtAFsAowGVAFsAWwATAFuAAICvgACAqggICAiAG4A6CAiAAAjTADYANwAKBm8GcAA+oKCAJt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwYeAFsAWwBbAC0AWwCjAZYAWwBbABMAW4AAgCOAAICqCAgICIAbgDsICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAe8AEwYeAFsAWwBbAC0AWwCjAZcAWwBbABMAW4AAgEaAAICqCAgICIAbgDwICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwYeAFsAWwBbAC0AWwCjAZgAWwBbABMAW4AAgCOAAICqCAgICIAbgD0ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwYeAFsAWwBbAC0AWwCjAZkAWwBbABMAW4AAgACAAICqCAgICIAbgD4ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwYeAFsAWwBbAC0AWwCjAZoAWwBbABMAW4AAgCOAAICqCAgICIAbgD8ICIAACNkAHQAhBr4ACgAkBr8AHwBMBsAF/AF+AE0AbAATACUALQBbBshfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAp4A1gAqALIAAgAQIgLbTADYANwAKBsoG0gA+pwI4AjkCOgI7AjwCPQI+gEyATYBOgE+AUIBRgFKnBtMG1AbVBtYG1wbYBtmAt4C4gLmAuoC8gL2AvoAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBh8AWwBbAFsALQBbAKMCOABbAFsAEwBbgACAAIAAgLUICAgIgBuATAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATBh8AWwBbAFsALQBbAKMCOQBbAFsAEwBbgACAI4AAgLUICAgIgBuATQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBh8AWwBbAFsALQBbAKMCOgBbAFsAEwBbgACAAIAAgLUICAgIgBuATggIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMHCgATBh8AWwBbAFsALQBbAKMCOwBbAFsAEwBbgACAu4AAgLUICAgIgBuATwgIgAAIEQOE3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBh8AWwBbAFsALQBbAKMCPABbAFsAEwBbgACAAIAAgLUICAgIgBuAUAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBh8AWwBbAFsALQBbAKMCPQBbAFsAEwBbgACAAIAAgLUICAgIgBuAUQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATBh8AWwBbAFsALQBbAKMCPgBbAFsAEwBbgACAAIAAgLUICAgIgBuAUggIgAAI3xASAJEAkgCTB0YAHQCVAJYHRwAfAJQHSACXAAoAIQCYAJkAJACaABMAEwATACUAPQBbAFsHUAAtAFsATQBbBBEF+QBbAFsHWABbXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASAkQgIgMEIgAoIgNaApQgIgMAIEtlpCJ7TADYANwAKB1wHXwA+ogF9BBuANIB2ogdgB2GAwoDNgCbZAB0AIQdkAAoAJAdlAB8ATAdmBf0BfQBNAGwAEwAlAC0AWwduXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgL+ANIAKgCyAAIAECIDD0wA2ADcACgdwB3kAPqgBkwGUAZUBlgGXAZgBmQGagDiAOYA6gDuAPIA9gD6AP6gHegd7B3wHfQd+B38HgAeBgMSAxYDGgMiAyYDKgMuAzIAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATB2AAWwBbAFsALQBbAKMBkwBbAFsAEwBbgACAI4AAgMIICAgIgBuAOAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATB2AAWwBbAFsALQBbAKMBlABbAFsAEwBbgACAAIAAgMIICAgIgBuAOQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMHowATB2AAWwBbAFsALQBbAKMBlQBbAFsAEwBbgACAx4AAgMIICAgIgBuAOggIgAAI0wA2ADcACgexB7IAPqCggCbfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMHYABbAFsAWwAtAFsAowGWAFsAWwATAFuAAIAjgACAwggICAiAG4A7CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMHYABbAFsAWwAtAFsAowGXAFsAWwATAFuAAIAjgACAwggICAiAG4A8CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMHYABbAFsAWwAtAFsAowGYAFsAWwATAFuAAIAjgACAwggICAiAG4A9CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwATABMHYABbAFsAWwAtAFsAowGZAFsAWwATAFuAAIAAgACAwggICAiAG4A+CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMHYABbAFsAWwAtAFsAowGaAFsAWwATAFuAAIAjgACAwggICAiAG4A/CAiAAAjZAB0AIQgAAAoAJAgBAB8ATAgCBf0EGwBNAGwAEwAlAC0AWwgKXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgL+AdoAKgCyAAIAECIDO0wA2ADcACggMCBQAPqcEywTMBM0EzgTPBNAE0YCEgIWAhoCHgIiAiYCKpwgVCBYIFwgYCBkIGggbgM+A0IDRgNKA04DUgNWAJt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBOQAEwdhAFsAWwBbAC0AWwCjBMsAWwBbABMAW4AAgIyAAIDNCAgICIAbgIQICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBPMAEwdhAFsAWwBbAC0AWwCjBMwAWwBbABMAW4AAgI6AAIDNCAgICIAbgIUICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATBPMAEwdhAFsAWwBbAC0AWwCjBM0AWwBbABMAW4AAgI6AAIDNCAgICIAbgIYICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATADwAEwdhAFsAWwBbAC0AWwCjBM4AWwBbABMAW4AAgAiAAIDNCAgICIAbgIcICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwdhAFsAWwBbAC0AWwCjBM8AWwBbABMAW4AAgCOAAIDNCAgICIAbgIgICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwdhAFsAWwBbAC0AWwCjBNAAWwBbABMAW4AAgCOAAIDNCAgICIAbgIkICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAWAAEwdhAFsAWwBbAC0AWwCjBNEAWwBbABMAW4AAgHOAAIDNCAgICIAbgIoICIAACNIArQCuCIcIiF8QEFhEUE1SZWxhdGlvbnNoaXCmCIkIigiLCIwIjQCyXxAQWERQTVJlbGF0aW9uc2hpcFxYRFBNUHJvcGVydHlfEBBYRFVNTFByb3BlcnR5SW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDfEBIAkQCSAJMIjwAdAJUAlgiQAB8AlAiRAJcACgAhAJgAmQAkAJoAEwATABMAJQA9AFsAWwiZAC0AWwBNAFsBdAX6AFsAWwihAFtfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABICRCAiA2QiACgiAW4CmCAiA2AgSrVfTJ9MANgA3AAoIpQioAD6iAX0BfoA0gDWiCKkIqoDagOWAJtkAHQAhCK0ACgAkCK4AHwBMCK8F/gF9AE0AbAATACUALQBbCLdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WA14A0gAqALIAAgAQIgNvTADYANwAKCLkIwgA+qAGTAZQBlQGWAZcBmAGZAZqAOIA5gDqAO4A8gD2APoA/qAjDCMQIxQjGCMcIyAjJCMqA3IDdgN6A4IDhgOKA44DkgCbfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwD9ABMIqQBbAFsAWwAtAFsAowGTAFsAWwATAFuAAIAjgACA2ggICAiAG4A4CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwATABMIqQBbAFsAWwAtAFsAowGUAFsAWwATAFuAAIAAgACA2ggICAiAG4A5CAiAAAjfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwjsABMIqQBbAFsAWwAtAFsAowGVAFsAWwATAFuAAIDfgACA2ggICAiAG4A6CAiAAAjTADYANwAKCPoI+wA+oKCAJt8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwipAFsAWwBbAC0AWwCjAZYAWwBbABMAW4AAgCOAAIDaCAgICIAbgDsICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAe8AEwipAFsAWwBbAC0AWwCjAZcAWwBbABMAW4AAgEaAAIDaCAgICIAbgDwICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwipAFsAWwBbAC0AWwCjAZgAWwBbABMAW4AAgCOAAIDaCAgICIAbgD0ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATABMAEwipAFsAWwBbAC0AWwCjAZkAWwBbABMAW4AAgACAAIDaCAgICIAbgD4ICIAACN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAP0AEwipAFsAWwBbAC0AWwCjAZoAWwBbABMAW4AAgCOAAIDaCAgICIAbgD8ICIAACNkAHQAhCUkACgAkCUoAHwBMCUsF/gF+AE0AbAATACUALQBbCVNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WA14A1gAqALIAAgAQIgObTADYANwAKCVUJXQA+pwI4AjkCOgI7AjwCPQI+gEyATYBOgE+AUIBRgFKnCV4JXwlgCWEJYgljCWSA54DogOmA6oDrgOyA7YAm3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATCKoAWwBbAFsALQBbAKMCOABbAFsAEwBbgACAAIAAgOUICAgIgBuATAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATCKoAWwBbAFsALQBbAKMCOQBbAFsAEwBbgACAI4AAgOUICAgIgBuATQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATCKoAWwBbAFsALQBbAKMCOgBbAFsAEwBbgACAAIAAgOUICAgIgBuATggIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMCfgATCKoAWwBbAFsALQBbAKMCOwBbAFsAEwBbgACAV4AAgOUICAgIgBuATwgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATCKoAWwBbAFsALQBbAKMCPABbAFsAEwBbgACAAIAAgOUICAgIgBuAUAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATCKoAWwBbAFsALQBbAKMCPQBbAFsAEwBbgACAAIAAgOUICAgIgBuAUQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATCKoAWwBbAFsALQBbAKMCPgBbAFsAEwBbgACAAIAAgOUICAgIgBuAUggIgAAIWmR1cGxpY2F0ZXPSADcACgnRAKuggBrSAK0ArgnUCdVaWERQTUVudGl0eacJ1gnXCdgJ2QnaCdsAslpYRFBNRW50aXR5XVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATBB4AWwBbAFsALQBbAKMEzwBbAFsAEwBbgACAI4AAgIIICAgIgBuAiAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATBB4AWwBbAFsALQBbAKME0ABbAFsAEwBbgACAI4AAgIIICAgIgBuAiQgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMF/QATBB4AWwBbAFsALQBbAKME0QBbAFsAEwBbgACAv4AAgIIICAgIgBuAiggIgAAI0gA3AAoKCgCroIAa0wA2ADcACgoNCg4APqCggCbTADYANwAKChEKEgA+oKCAJtMANgA3AAoKFQoWAD6goIAm0gCtAK4KGQoaXlhETW9kZWxQYWNrYWdlpgobChwKHQoeCh8Asl5YRE1vZGVsUGFja2FnZV8QD1hEVU1MUGFja2FnZUltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDSADcACgohAKuggBrTADYANwAKCiQKJQA+oKCAJlDSAK0ArgopCipZWERQTU1vZGVsowopCisAsldYRE1vZGVsXxAPTlNLZXllZEFyY2hpdmVy0QouAChUcm9vdIABAAgAGQAiACsANQA6AD8CPAJCAl8CcQJ4AoUCmAKwAr4C2ALaAtwC3gLgAuIC5ALmAx8DPgNbA3oDjAOsA7MD0QPdA/kD/wQhBEIEVQRXBFkEWwRdBF8EYQRjBGUEZwRpBGsEbQRvBHEEcgR2BIMEiwSWBJsEnQSfBKQEpgSoBKoEsAS1BPgFHAVABWMFigWqBdEF+AYYBjwGYAZsBm4GcAZyBnQGdgZ4BnoGfAZ+BoAGggaEBoYGiAaJBpIGmganBqoGrAavBrEGswbCBucHCwcyB1YHWAdaB1wHXgdgB2IHYwdlB3IHhQeHB4kHiweNB48HkQeTB5UHlweqB6wHrgewB7IHtAe2B7gHuge8B74H1AfnCAMIIAg8CFAIYgh4CJEI0AjWCN8I7Aj4CQIJDAkXCSIJLwk3CTkJOwk9CT8JQAlBCUIJQwlFCUcJSAlJCUsJTAlVCVYJWAlhCWwJdQmECYsJkwmcCaUJuAnBCdQJ6wn9CjwKPgpACkIKRApFCkYKRwpICkoKTApNCk4KUApRCpAKkgqUCpYKmAqZCpoKmwqcCp4KoAqhCqIKpAqlCq4KrwqxCvAK8gr0CvYK+Ar5CvoK+wr8Cv4LAAsBCwILBAsFC0QLRgtIC0oLTAtNC04LTwtQC1ILVAtVC1YLWAtZC2ILYwtlC6QLpguoC6oLrAutC64LrwuwC7ILtAu1C7YLuAu5C7oL+Qv7C/0L/wwBDAIMAwwEDAUMBwwJDAoMCwwNDA4MGwwcDB0MHwwoDD4MRQxSDJEMkwyVDJcMmQyaDJsMnAydDJ8MoQyiDKMMpQymDL8MwQzDDMUMxgzIDN8M6Az2DQMNEQ0mDToNUQ1jDaINpA2mDagNqg2rDawNrQ2uDbANsg2zDbQNtg23DcAN1Q3kDfkOBw4cDjAORw5ZDmYObQ5vDnEOcw56DnwOfg6ADoIOig6ODpMO3g8BDyEPQQ9DD0UPRw9JD0sPTA9ND08PUA9SD1MPVQ9XD1gPWQ9bD1wPYQ9uD3MPdQ93D3wPfg+AD4IPlw+sD9EP9RAcEEAQQhBEEEYQSBBKEEwQTRBPEFwQbRBvEHEQcxB1EHcQeRB7EH0QjhCQEJIQlBCWEJgQmhCcEJ4QoBC+ENwQ7xEDERgRNRFJEV8RnhGgEaIRpBGmEacRqBGpEaoRrBGuEa8RsBGyEbMR8hH0EfYR+BH6EfsR/BH9Ef4SABICEgMSBBIGEgcSRhJIEkoSTBJOEk8SUBJRElISVBJWElcSWBJaElsSaBJpEmoSbBKrEq0SrxKxErMStBK1ErYStxK5ErsSvBK9Er8SwBL/EwETAxMFEwcTCBMJEwoTCxMNEw8TEBMRExMTFBMVE1QTVhNYE1oTXBNdE14TXxNgE2ITZBNlE2YTaBNpE6gTqhOsE64TsBOxE7ITsxO0E7YTuBO5E7oTvBO9E/wT/hQAFAIUBBQFFAYUBxQIFAoUDBQNFA4UEBQRFDYUWhSBFKUUpxSpFKsUrRSvFLEUshS0FMEU0BTSFNQU1hTYFNoU3BTeFO0U7xTxFPMU9RT3FPkU+xT9FR0VSBViFXsVlRW1FdgWFxYZFhsWHRYfFiAWIRYiFiMWJRYnFigWKRYrFiwWaxZtFm8WcRZzFnQWdRZ2FncWeRZ7FnwWfRZ/FoAWvxbBFsMWxRbHFsgWyRbKFssWzRbPFtAW0RbTFtQXExcVFxcXGRcbFxwXHRceFx8XIRcjFyQXJRcnFygXKxdqF2wXbhdwF3IXcxd0F3UXdhd4F3oXexd8F34Xfxe+F8AXwhfEF8YXxxfIF8kXyhfMF84XzxfQF9IX0xgSGBQYFhgYGBoYGxgcGB0YHhggGCIYIxgkGCYYJxgwGD4YSxhZGGYYeRiQGKIY7RkQGTAZUBlSGVQZVhlYGVoZWxlcGV4ZXxlhGWIZZBlmGWcZaBlqGWsZcBl9GYIZhBmGGYsZjRmPGZEZthnaGgEaJRonGikaKxotGi8aMRoyGjQaQRpSGlQaVhpYGloaXBpeGmAaYhpzGnUadxp5GnsafRp/GoEagxqFGsQaxhrIGsoazBrNGs4azxrQGtIa1BrVGtYa2BrZGxgbGhscGx4bIBshGyIbIxskGyYbKBspGyobLBstG2wbbhtwG3IbdBt1G3Ybdxt4G3obfBt9G34bgBuBG44bjxuQG5Ib0RvTG9Ub1xvZG9ob2xvcG90b3xvhG+Ib4xvlG+YcJRwnHCkcKxwtHC4cLxwwHDEcMxw1HDYcNxw5HDoceRx7HH0cfxyBHIIcgxyEHIUchxyJHIocixyNHI4czRzPHNEc0xzVHNYc1xzYHNkc2xzdHN4c3xzhHOIdIR0jHSUdJx0pHSodKx0sHS0dLx0xHTIdMx01HTYdWx1/HaYdyh3MHc4d0B3SHdQd1h3XHdkd5h31Hfcd+R37Hf0d/x4BHgMeEh4UHhYeGB4aHhweHh4gHiIeYR5jHmUeZx5pHmoeax5sHm0ebx5xHnIecx51HnYetR63Hrkeux69Hr4evx7AHsEewx7FHsYexx7JHsofCR8LHw0fDx8RHxIfEx8UHxUfFx8ZHxofGx8dHx4fXR9fH2EfYx9lH2YfZx9oH2kfax9tH24fbx9xH3IfsR+zH7Uftx+5H7ofux+8H70fvx/BH8Ifwx/FH8YgBSAHIAkgCyANIA4gDyAQIBEgEyAVIBYgFyAZIBogWSBbIF0gXyBhIGIgYyBkIGUgZyBpIGogayBtIG4guSDcIPwhHCEeISAhIiEkISYhJyEoISohKyEtIS4hMCEyITMhNCE2ITchQCFNIVIhVCFWIVshXSFf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 - - - - - date - - - - colorID - - - - CoreDataMigration_Example.Post2ToPost3MigrationPolicy - Post - Undefined - 2 - Post - 1 - - - - - - hex - - - - 1 - color - - - - postID - - - \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3ModelMapping.xcmappingmodel/xcmapping.xml b/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3ModelMapping.xcmappingmodel/xcmapping.xml new file mode 100644 index 0000000..3f52f63 --- /dev/null +++ b/CoreDataMigration-Example/CoreData/Migration/Mappings/Migration2to3ModelMapping.xcmappingmodel/xcmapping.xml @@ -0,0 +1,112 @@ + + + + + + 134481920 + 87E9047A-56E0-4CF2-BF13-03049CE47DD8 + 112 + + + + NSPersistenceFrameworkVersion + 866 + NSStoreModelVersionHashes + + XDDevAttributeMapping + + 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= + + XDDevEntityMapping + + qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= + + XDDevMappingModel + + EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= + + XDDevPropertyMapping + + XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= + + XDDevRelationshipMapping + + akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= + + + NSStoreModelVersionHashesVersion + 3 + NSStoreModelVersionIdentifiers + + + + + + + + + 1 + sections + + + + CoreDataMigration_Example.Post2ToPost3MigrationPolicy + Post + Undefined + 2 + Post + 1 + + + + + + hexColor + + + + 1 + post + + + + body + + + + title + + + + date + + + + Undefined + 1 + Section + 1 + + + + + + postID + + + + index + + + + CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGBrMGtFgkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv +cBIAAYagrxCuAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APgAWAEIARcBGwEfAS4BNAE1AT0BTAFVAWEBYgFjAWQBZQF6AXsBgwGEAYUBkQGlAaYBpwGoAakBqgGrAawBrQG8AcsB2gHeAe0B/AH9AgwCGwIcAisCNwJJAkoCSwJMAk0CTgJPAlACXwJuAn0CjAKNApwCqwK6AsIC1wLYAuAC7AMAAw8DHgMtAzEDQANPA14DbQN8A4gDmgOpA7gDxwPWA+UD9AQDBBgEGQQhBC0EQQRQBF8EbgRyBIEEkASfBK4EvQTJBNsE6gT5BQgFFwUmBTUFRAVZBVoFYgVuBYIFkQWgBa8FswXCBdEF4AXvBf4GCgYcBisGOgZJBlgGWQZoBncGhgaHBooGkwaXBpsGnwanBqoGrgavVSRudWxs1wAJAAoACwAMAA0ADgAPABAAEQASABMAFAATABZfEA9feGRfcm9vdFBhY2thZ2VWJGNsYXNzXF94ZF9jb21tZW50c18QEF94ZF9tb2RlbE1hbmFnZXJfEBVfY29uZmlndXJhdGlvbnNCeU5hbWVdX3hkX21vZGVsTmFtZV8QF19tb2RlbFZlcnNpb25JZGVudGlmaWVygAKArYCqgACAq4AAgKzeABgAGQAaABsAHAAdAB4ACgAfACAAIQAiACMAJAAlACYAJwAoACUAEwArACwALQAuAC8AJQAlABNfEBxYREJ1Y2tldEZvckNsYXNzZXN3YXNFbmNvZGVkXxAaWERCdWNrZXRGb3JQYWNrYWdlc3N0b3JhZ2VfEBxYREJ1Y2tldEZvckludGVyZmFjZXNzdG9yYWdlXxAPX3hkX293bmluZ01vZGVsXxAdWERCdWNrZXRGb3JQYWNrYWdlc3dhc0VuY29kZWRWX293bmVyXxAbWERCdWNrZXRGb3JEYXRhVHlwZXNzdG9yYWdlW192aXNpYmlsaXR5XxAZWERCdWNrZXRGb3JDbGFzc2Vzc3RvcmFnZVVfbmFtZV8QH1hEQnVja2V0Rm9ySW50ZXJmYWNlc3dhc0VuY29kZWRfEB5YREJ1Y2tldEZvckRhdGFUeXBlc3dhc0VuY29kZWRfEBBfdW5pcXVlRWxlbWVudElEgASAqICmgAGABIAAgKeAqRAAgAWAA4AEgASAAFBTWUVT0wA2ADcACgA4ADoAPFdOUy5rZXlzWk5TLm9iamVjdHOhADmABqEAO4AHgCVUUG9zdN8QEAA/AEAAQQBCAB0AQwBEAB8ARQBGAAoAIQBHAEgAJABJAEoASwAlACUAEABPAFAALQAlAEoAUwA5AEoAVgBXAFhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SACYAsgASABIACgAqAo4AEgAmApYAGgAmApIAICBJbJfVxV29yZGVyZWTTADYANwAKAFwAXgA8oQBdgAuhAF+ADIAlXlhEX1BTdGVyZW90eXBl2QAdACEAYwAKACQAZAAfAEkAZQA7AF0ASgBpABMAJQAtAFgAbV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYAHgAuACYArgACABAiADdMANgA3AAoAbwB5ADypAHAAcQByAHMAdAB1AHYAdwB4gA6AD4AQgBGAEoATgBSAFYAWqQB6AHsAfAB9AH4AfwCAAIEAgoAXgBuAHIAegB+AIYAjgCaAKoAlXxATWERQTUNvbXBvdW5kSW5kZXhlc18QEFhEX1BTS19lbGVtZW50SURfEBlYRFBNVW5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d3B3dHd8d4B4fHiEeIx4lHiceKB4pHioeKx4tHi8eMB4xHjMeNB5zHnUedx55HnsefB59Hn4efx6BHoMehB6FHoceiB7HHskeyx7NHs8e0B7RHtIe0x7VHtce2B7ZHtse3B8bHx0fHx8hHyMfJB8lHyYfJx8pHysfLB8tHy8fMB9vH3Efcx91H3cfeB95H3ofex99H38fgB+BH4MfhB/DH8Ufxx/JH8sfzB/NH84fzx/RH9Mf1B/VH9cf2CAjIEYgZiCGIIggiiCMII4gkCCRIJIglCCVIJcgmCCaIJwgnSCeIKAgoSCmILMguCC6ILwgwSDDIMUgxyDsIRAhNyFbIV0hXyFhIWMhZSFnIWghaiF3IYghiiGMIY4hkCGSIZQhliGYIakhqyGtIa8hsSGzIbUhtyG5Ibsh+iH8If4iACICIgMiBCIFIgYiCCIKIgsiDCIOIg8iTiJQIlIiVCJWIlciWCJZIloiXCJeIl8iYCJiImMioiKkIqYiqCKqIqsirCKtIq4isCKyIrMitCK2IrcixCLFIsYiyCMHIwkjCyMNIw8jECMRIxIjEyMVIxcjGCMZIxsjHCNbI10jXyNhI2MjZCNlI2YjZyNpI2sjbCNtI28jcCOvI7EjsyO1I7cjuCO5I7ojuyO9I78jwCPBI8MjxCQDJAUkByQJJAskDCQNJA4kDyQRJBMkFCQVJBckGCRXJFkkWyRdJF8kYCRhJGIkYyRlJGckaCRpJGskbCSRJLUk3CUAJQIlBCUGJQglCiUMJQ0lDyUcJSslLSUvJTElMyU1JTclOSVIJUolTCVOJVAlUiVUJVYlWCWXJZklmyWdJZ8loCWhJaIloyWlJaclqCWpJaslrCXrJe0l7yXxJfMl9CX1JfYl9yX5Jfsl/CX9Jf8mACY/JkEmQyZFJkcmSCZJJkomSyZNJk8mUCZRJlMmVCaTJpUmlyaZJpsmnCadJp4mnyahJqMmpCalJqcmqCbnJukm6ybtJu8m8CbxJvIm8yb1Jvcm+Cb5Jvsm/Cc7Jz0nPydBJ0MnRCdFJ0YnRydJJ0snTCdNJ08nUCePJ5EnkyeVJ5cnmCeZJ5onmyedJ58noCehJ6MnpCfvKBIoMihSKFQoVihYKFooXChdKF4oYChhKGMoZChmKGgoaShqKGwobShyKH8ohCiGKIgojSiPKJEokyi4KNwpAyknKSkpKyktKS8pMSkzKTQpNilDKVQpVilYKVopXCleKWApYilkKXUpdyl5KXspfSl/KYEpgymFKYcpxinIKcopzCnOKc8p0CnRKdIp1CnWKdcp2CnaKdsqGiocKh4qICoiKiMqJColKiYqKCoqKisqLCouKi8qbipwKnIqdCp2KncqeCp5KnoqfCp+Kn8qgCqCKoMqkCqRKpIqlCrTKtUq1yrZKtsq3CrdKt4q3yrhKuMq5CrlKucq6CsnKykrKystKy8rMCsxKzIrMys1KzcrOCs5KzsrPCt7K30rfyuBK4MrhCuFK4YrhyuJK4srjCuNK48rkCvPK9Er0yvVK9cr2CvZK9or2yvdK98r4CvhK+Mr5CwjLCUsJywpLCssLCwtLC4sLywxLDMsNCw1LDcsOCxdLIEsqCzMLM4s0CzSLNQs1izYLNks2yzoLPcs+Sz7LP0s/y0BLQMtBS0ULRYtGC0aLRwtHi0gLSItJC1jLWUtZy1pLWstbC1tLW4tby1xLXMtdC11LXcteC23Lbktuy29Lb8twC3BLcItwy3FLcctyC3JLcstzC4LLg0uDy4RLhMuFC4VLhYuFy4ZLhsuHC4dLh8uIC5fLmEuYy5lLmcuaC5pLmouay5tLm8ucC5xLnMudC53LrYuuC66Lrwuvi6/LsAuwS7CLsQuxi7HLsguyi7LLwovDC8OLxAvEi8TLxQvFS8WLxgvGi8bLxwvHi8fL14vYC9iL2QvZi9nL2gvaS9qL2wvbi9vL3Avci9zL34vhy+IL4ovky+eL60vuC/GL9sv7zAGMBgwJTAmMCcwKTA2MDcwODA6MEcwSDBJMEswVDBjMHAwfzCRMKUwvDDOMNcw2DDaMOcw6DDpMOsw7DD1MP8xBjEOMSAxJTEqAAAAAAAAAgIAAAAAAAAGtwAAAAAAAAAAAAAAAAAAMSw= + + CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGDLcMuFgkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv +cBIAAYagrxEBMAAHAAgAFwAzADQANQA/AEAAQQBcAF0AXgBkAGUAcQCHAIgAiQCKAIsAjACNAI4AjwCQAKkArACzALkAyADXANoA6QD4APsAWwELARoBHgEiATEBNwE4AUABTwFYAWQBZQFmAWcBaAF9AX4BhgGHAYgBlAGoAakBqgGrAawBrQGuAa8BsAG/Ac4B3QHhAfAB/wIAAg8CHgItAjkCSwJMAk0CTgJPAlACUQJSAmECcAJ/Ao4CjwKeAq0CvALEAtkC2gLiAuMC7wMDAxIDIQMwAzQDQwNSA2EDcAN/A4sDnQOeA58DoAOhA6IDowOkAC0DswPCA8MD0gPhA/sD/AQCBA4EJAQzBDYERQRUBFcEZgR1BHgEhwSWBJoEqQS4BMQExQTGBMcEyATdBN4E5gTyBQYFFQUkBTMFNwVGBVUFZAVzBYIFjgWgBa8FvgXNBdwF6wX6BgkGHgYfBicGMwZHBlYGZQZ0BngGhwaWBqUGtAbDBs8G4QbwBv8HDgcdBywHOwdKB18HYAdoB3QHiAeXB6YHtQe5B8gH1wfmB/UIBAgQCCIIMQhACEEIUAhfCG4IfQiMCJQIqQiqCLIIvgjSCOEI8Aj/CQMJEgkhCTAJPwlOCVoJbAl7CYoJmQmoCakJuAnHCdYJ1wnaCeMJ8goBChAKJQomCi4KOgpOCl0KbAp7Cn8KjgqdCqwKuwrKCtYK6Ar3CwYLFQskCzMLQgtRC2YLZwtvC3sLjwueC60LvAvAC88L3gvtC/wMCwwXDCkMOAw5DEgMVwxmDGcMdgyFDJQMlwybDJ8MowyrDK4MsgyzVSRudWxs1wAJAAoACwAMAA0ADgAPABAAEQASABMAFAATABZfEA9feGRfcm9vdFBhY2thZ2VWJGNsYXNzXF94ZF9jb21tZW50c18QEF94ZF9tb2RlbE1hbmFnZXJfEBVfY29uZmlndXJhdGlvbnNCeU5hbWVdX3hkX21vZGVsTmFtZV8QF19tb2RlbFZlcnNpb25JZGVudGlmaWVygAKBAS+BASyAAIEBLYAAgQEu3gAYABkAGgAbABwAHQAeAAoAHwAgACEAIgAjACQAJQAmACcAKAAlABMAKwAsAC0ALgAvACUAJQATXxAcWERCdWNrZXRGb3JDbGFzc2Vzd2FzRW5jb2RlZF8QGlhEQnVja2V0Rm9yUGFja2FnZXNzdG9yYWdlXxAcWERCdWNrZXRGb3JJbnRlcmZhY2Vzc3RvcmFnZV8QD194ZF9vd25pbmdNb2RlbF8QHVhEQnVja2V0Rm9yUGFja2FnZXN3YXNFbmNvZGVkVl9vd25lcl8QG1hEQnVja2V0Rm9yRGF0YVR5cGVzc3RvcmFnZVtfdmlzaWJpbGl0eV8QGVhEQnVja2V0Rm9yQ2xhc3Nlc3N0b3JhZ2VVX25hbWVfEB9YREJ1Y2tldEZvckludGVyZmFjZXN3YXNFbmNvZGVkXxAeWERCdWNrZXRGb3JEYXRhVHlwZXN3YXNFbmNvZGVkXxAQX3VuaXF1ZUVsZW1lbnRJRIAEgQEqgQEogAGABIAAgQEpgQErEACABYADgASABIAAUFNZRVPTADYANwAKADgAOwA+V05TLmtleXNaTlMub2JqZWN0c6IAOQA6gAaAB6IAPAA9gAiAe4AmV1NlY3Rpb25UUG9zdN8QEABCAEMARABFAB0ARgBHAB8ASABJAAoAIQBKAEsAJABMAE0ATgAlACUAEABSAFMALQAlAE0AVgA5AE0AWQBaAFtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SACoAtgASABIACgAuA8YAEgAqA84AGgAqBASeACQgSJmOFQVdvcmRlcmVk0wA2ADcACgBfAGEAPqEAYIAMoQBigA2AJl5YRF9QU3RlcmVvdHlwZdkAHQAhAGYACgAkAGcAHwBMAGgAPABgAE0AbAATACUALQBbAHBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WACIAMgAqALIAAgAQIgA7TADYANwAKAHIAfAA+qQBzAHQAdQB2AHcAeAB5AHoAe4APgBCAEYASgBOAFIAVgBaAF6kAfQB+AH8AgACBAIIAgwCEAIWAGIAcgB2AH4AggCKAJIAngCuAJl8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZWERfUFNLX2ZldGNoUmVxdWVzdHNBcnJheV8QEVhEX1BTS19pc0Fic3RyYWN0XxAPWERfUFNLX3VzZXJJbmZvXxATWERfUFNLX2NsYXNzTWFwcGluZ18QFlhEX1BTS19lbnRpdHlDbGFzc05hbWXfEA8AkQCSAJMAHQCUAJUAlgAfAJcACgAhAJgAmQAkAJoAEwCcABMAYgBbAFsAWwAtAFsAowBzAFsAWwATAFtVX3R5cGVYX2RlZmF1bHRcX2Fzc29jaWF0aW9uW19pc1JlYWRPbmx5WV9pc1N0YXRpY1lfaXNVbmlxdWVaX2lzRGVyaXZlZFpfaXNPcmRlcmVkXF9pc0NvbXBvc2l0ZVdfaXNMZWFmgACAGYAAgA0ICAgIgBuADwgIgAAI0gA3AAoAqgCroIAa0gCtAK4ArwCwWiRjbGFzc25hbWVYJGNsYXNzZXNeTlNNdXRhYmxlQXJyYXmjAK8AsQCyV05TQXJyYXlYTlNPYmplY3TSAK0ArgC0ALVfEBBYRFVNTFByb3BlcnR5SW1wpAC2ALcAuACyXxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAGIAWwBbAFsALQBbAKMAdABbAFsAEwBbgACAAIAAgA0ICAgIgBuAEAgIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAygATAGIAWwBbAFsALQBbAKMAdQBbAFsAEwBbgACAHoAAgA0ICAgIgBuAEQgIgAAI0gA3AAoA2ACroIAa3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAEwATAGIAWwBbAFsALQBbAKMAdgBbAFsAEwBbgACAAIAAgA0ICAgIgBuAEggIgAAI3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA6wATAGIAWwBbAFsALQBbAKMAdwBbAFsAEwBbgACAIYAAgA0ICAgIgBuAEwgIgAAI0gA3AAoA+QCroIAa3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMA/QATAGIAWwBbAFsALQBbAKMAeABbAFsAEwBbgACAI4AAgA0ICAgIgBuAFAgIgAAICN8QDwCRAJIAkwAdAJQAlQCWAB8AlwAKACEAmACZACQAmgATAQ0AEwBiAFsAWwBbAC0AWwCjAHkAWwBbABMAW4AAgCWAAIANCAgICIAbgBUICIAACNMANgA3AAoBGwEcAD6goIAm0gCtAK4BHwEgXxATTlNNdXRhYmxlRGljdGlvbmFyeaMBHwEhALJcTlNEaWN0aW9uYXJ53xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMBJAATAGIAWwBbAFsALQBbAKMAegBbAFsAEwBbgACAKIAAgA0ICAgIgBuAFggIgAAI1gAhAAoAJABMAB0AHwEyATMAEwBbABMALYApgCqAAAiAAF8QFFhER2VuZXJpY1JlY29yZENsYXNz0gCtAK4BOQE6XVhEVU1MQ2xhc3NJbXCmATsBPAE9AT4BPwCyXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAJEAkgCTAB0AlACVAJYAHwCXAAoAIQCYAJkAJACaABMAOQATAGIAWwBbAFsALQBbAKMAewBbAFsAEwBbgACABoAAgA0ICAgIgBuAFwgIgAAI0gCtAK4BUAFRXxASWERVTUxTdGVyZW90eXBlSW1wpwFSAVMBVAFVAVYBVwCyXxASWERVTUxTdGVyZW90eXBlSW1wXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0wA2ADcACgFZAV4APqQBWgFbAVwBXYAugC+AMIAxpAFfAWABYQFigDKAXYD3gQEOgCZUYm9keVRwb3N0VXRpdGxlVWluZGV43xASAJEAkgCTAWkAHQCVAJYBagAfAJQBawCXAAoAIQCYAJkAJACaABMAEwATACUAPABbAFsBcwAtAFsATQBbAXcBWgBbAFsBewBbXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASACAgIgDQIgAoIgFyALggIgDMIElnkWAbTADYANwAKAX8BggA+ogGAAYGANYA2ogGDAYSAN4BLgCZfEBJYRF9QUHJvcFN0ZXJlb3R5cGVfEBJYRF9QQXR0X1N0ZXJlb3R5cGXZAB0AIQGJAAoAJAGKAB8ATAGLAV8BgABNAGwAEwAlAC0AWwGTXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgDKANYAKgCyAAIAECIA40wA2ADcACgGVAZ4APqgBlgGXAZgBmQGaAZsBnAGdgDmAOoA7gDyAPYA+gD+AQKgBnwGgAaEBogGjAaQBpQGmgEGAQoBDgEWARoBIgEmASoAmXxAbWERfUFBTS19pc1N0b3JlZEluVHJ1dGhGaWxlXxAbWERfUFBTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAQWERfUFBTS191c2VySW5mb18QEVhEX1BQU0tfaXNJbmRleGVkXxASWERfUFBTS19pc09wdGlvbmFsXxAaWERfUFBTS19pc1Nwb3RsaWdodEluZGV4ZWRfEBFYRF9QUFNLX2VsZW1lbnRJRF8QE1hEX1B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ICIAACNIANwAKDJUAq6CAGtMANgA3AAoMmAyZAD6goIAm0wA2ADcACgycDJ0APqCggCbTADYANwAKDKAMoQA+oKCAJtIArQCuDKQMpV5YRE1vZGVsUGFja2FnZaYMpgynDKgMqQyqALJeWERNb2RlbFBhY2thZ2VfEA9YRFVNTFBhY2thZ2VJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0gA3AAoMrACroIAa0wA2ADcACgyvDLAAPqCggCZQ0gCtAK4MtAy1WVhEUE1Nb2RlbKMMtAy2ALJXWERNb2RlbF8QD05TS2V5ZWRBcmNoaXZlctEMuQAoVHJvb3SAAQAIABkAIgArADUAOgA/AqMCqQLGAtgC3wLsAv8DFwMlAz8DQQNEA0cDSQNMA04DUQOKA6kDxgPlA/cEFwQeBDwESARkBGoEjAStBMAEwgTFBMgEygTMBM4E0QTUBNYE2ATaBNwE3gTgBOEE5QTyBPoFBQUKBQwFDgUTBRUFFwUZBSEFJgVpBY0FsQXUBfsGGwZCBmkGiQatBtEG3QbfBuEG4wblBucG6QbrBu0G7wbxBvMG9Qb4BvoG+wcABwgHFQcYBxoHHQcfByEHMAdVB3kHoAfEB8YHyAfKB8wHzgfQB9EH0wfgB/MH9Qf3B/kH+wf9B/8IAQgDCAUIGAgaCBwIHgggCCIIJAgmCCgIKggsCEIIVQhxCI4Iqgi+CNAI5gj/CT4JRAlNCVoJZglwCXoJhQmQCZ0JpQmnCakJqwmtCa4JrwmwCbEJswm1CbYJtwm5CboJwwnECcYJzwnaCeMJ8gn5CgEKCgoTCiYKLwpCClkKawqqCqwKrgqwCrIKswq0CrUKtgq4CroKuwq8Cr4Kvwr+CwALAgsECwYLBwsICwkLCgsMCw4LDwsQCxILEwscCx0LHwteC2ALYgtkC2YLZwtoC2kLagtsC24LbwtwC3ILcwuyC7QLtgu4C7oLuwu8C70LvgvAC8ILwwvEC8YLxwvQC9EL0wwSDBQMFgwYDBoMGwwcDB0MHgwgDCIMIwwkDCYMJwwoDGcMaQxrDG0MbwxwDHEMcgxzDHUMdwx4DHkMewx8DIkMigyLDI0MlgysDLMMwAz/DQENAw0FDQcNCA0JDQoNCw0NDQ8NEA0RDRMNFA0tDS8NMQ0zDTQNNg1NDVYNZA1xDX8NlA2oDb8N0Q4QDhIOFA4WDhgOGQ4aDhsOHA4eDiAOIQ4iDiQOJQ4uDkMOUg5nDnUOig6eDrUOxw7UDt0O3w7hDuMO5Q7uDvAO8g70DvcO+Q7+DwMPCQ8PD1oPfQ+dD70Pvw/BD8MPxQ/HD8gPyQ/LD8wPzg/PD9EP0w/UD9UP1w/YD90P6g/vD/EP8w/4D/oP/A/+EBMQKBBNEHEQmBC8EL4QwBDCEMQQxhDIEMkQyxDYEOkQ6xDtEO8Q8RDzEPUQ9xD5EQoRDBEOERAREhEUERYRGBEaERwROhFYEWsRfxGUEbERxRHbEhoSHBIeEiASIhIjEiQSJRImEigSKhIrEiwSLhIvEm4ScBJyEnQSdhJ3EngSeRJ6EnwSfhJ/EoASghKDEsISxBLGEsgSyhLLEswSzRLOEtAS0hLTEtQS1hLXEuQS5RLmEugTJxMpEysTLRMvEzATMRMyEzMTNRM3EzgTORM7EzwTexN9E38TgRODE4QThROGE4cTiROLE4wTjROPE5ATkRPQE9IT1BPWE9gT2RPaE9sT3BPeE+AT4RPiE+QT5RQkFCYUKBQqFCwULRQuFC8UMBQyFDQUNRQ2FDgUORR4FHoUfBR+FIAUgRSCFIMUhBSGFIgUiRSKFIwUjRSyFNYU/RUhFSMVJRUnFSkVKxUtFS4VMBU9FUwVThVQFVIVVBVWFVgVWhVpFWsVbRVvFXEVcxV1FXcVeRWZFcQV3hX3FhEWMRZUFpMWlRaXFpkWmxacFp0WnhafFqEWoxakFqUWpxaoFucW6RbrFu0W7xbwFvEW8hbzFvUW9xb4FvkW+xb8FzsXPRc/F0EXQxdEF0UXRhdHF0kXSxdMF00XTxdQF48XkReTF5UXlxeYF5kXmhebF50XnxegF6EXoxekF6cX5hfoF+oX7BfuF+8X8BfxF/IX9Bf2F/cX+Bf6F/sYOhg8GD4YQBhCGEMYRBhFGEYYSBhKGEsYTBhOGE8YjhiQGJIYlBiWGJcYmBiZGJoYnBieGJ8YoBiiGKMYrBi6GMcY1RjiGPUZDBkeGWkZjBmsGcwZzhnQGdIZ1BnWGdcZ2BnaGdsZ3RneGeAZ4hnjGeQZ5hnnGewZ+Rn+GgAaAhoHGgkaCxoNGiAaRRppGpAatBq2Grgauhq8Gr4awBrBGsMa0BrhGuMa5RrnGuka6xrtGu8a8RsCGwQbBhsIGwobDBsOGxAbEhsUG1MbVRtXG1kbWxtcG10bXhtfG2EbYxtkG2UbZxtoG6cbqRurG60brxuwG7EbshuzG7Ubtxu4G7kbuxu8G/sb/Rv/HAEcAxwEHAUcBhwHHAkcCxwMHA0cDxwQHB0cHhwfHCEcYBxiHGQcZhxoHGkcahxrHGwcbhxwHHEcchx0HHUctBy2HLgcuhy8HL0cvhy/HMAcwhzEHMUcxhzIHMkdCB0KHQwdDh0QHREdEh0THRQdFh0YHRkdGh0cHR0dXB1eHWAdYh1kHWUdZh1nHWgdah1sHW0dbh1wHXEdsB2yHbQdth24Hbkduh27Hbwdvh3AHcEdwh3EHcUd6h4OHjUeWR5bHl0eXx5hHmMeZR5mHmgedR6EHoYeiB6KHowejh6QHpIeoR6jHqUepx6pHqserR6vHrEewx7XHuke/h8QHx8fPB97H30ffx+BH4MfhB+FH4Yfhx+JH4sfjB+NH48fkB/PH9Ef0x/VH9cf2B/ZH9of2x/dH98f4B/hH+Mf5B/mICUgJyApICsgLSAuIC8gMCAxIDMgNSA2IDcgOSA6IHkgeyB9IH8ggSCCIIMghCCFIIcgiSCKIIsgjSCOINEg9SEZITwhYyGDIaoh0SHxIhUiOSI7Ij0iPyJBIkMiRSJHIkkiSyJNIk8iUSJTIlUiViJbImgiayJtInAiciJ0IpkivSLkIwgjCiMMIw4jECMSIxQjFSMXIyQjNyM5IzsjPSM/I0EjQyNFI0cjSSNcI14jYCNiI2QjZiNoI2ojbCNuI3AjryOxI7MjtSO3I7gjuSO6I7sjvSO/I8AjwSPDI8QjzSPOI9AkDyQRJBMkFSQXJBgkGSQaJBskHSQfJCAkISQjJCQkYyRlJGckaSRrJGwkbSRuJG8kcSRzJHQkdSR3JHgkgSSCJIQkwyTFJMckySTLJMwkzSTOJM8k0STTJNQk1STXJNglFyUZJRslHSUfJSAlISUiJSMlJSUnJSglKSUrJSwlNSU2JTgldyV5JXslfSV/JYAlgSWCJYMlhSWHJYgliSWLJYwlyyXNJc8l0SXTJdQl1SXWJdcl2SXbJdwl3SXfJeAl7SXuJe8l8SYwJjImNCY2JjgmOSY6JjsmPCY+JkAmQSZCJkQmRSaEJoYmiCaKJowmjSaOJo8mkCa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YUxlTJlMnUyhTKlNpU2tTbVNvU3JTc1N0U3VTdlN4U3pTe1N8U35Tf1O+U8BTwlPEU8dTyFPJU8pTy1PNU89T0FPRU9NT1FQTVBVUF1QZVBxUHVQeVB9UIFQiVCRUJVQmVChUKVRoVGpUbFRuVHFUclRzVHRUdVR3VHlUelR7VH1UflS9VL9UwVTDVMZUx1TIVMlUylTMVM5Uz1TQVNJU01T4VRxVQ1VnVWpVbFVuVXBVclV0VXVVeFWFVZRVllWYVZpVnFWeVaBVolWxVbRVt1W6Vb1VwFXDVcZVyFYHVglWDFYOVhFWElYTVhRWFVYXVhlWGlYbVh1WHlYgVl9WYVZjVmVWaFZpVmpWa1ZsVm5WcFZxVnJWdFZ1VrRWtla4VrpWvVa+Vr9WwFbBVsNWxVbGVsdWyVbKVwlXC1cOVxBXE1cUVxVXFlcXVxlXG1ccVx1XH1cgVyJXYVdjV2VXZ1dqV2tXbFdtV25XcFdyV3NXdFd2V3dXtle4V7pXvFe/V8BXwVfCV8NXxVfHV8hXyVfLV8xYC1gNWA9YEVgUWBVYFlgXWBhYGlgcWB1YHlggWCFYKlgrWC1YOlg7WDxYPlhLWExYTVhPWFxYXVheWGBYaVh4WIVYlFimWLpY0VjjWOxY7VjvWPxY/Vj+WQBZAVkKWRRZG1kjWTVZOlk/AAAAAAAAAgIAAAAAAAAMuwAAAAAAAAAAAAAAAAAAWUE= + + + + \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Migration/Policies/Post2ToPost3MigrationPolicy.swift b/CoreDataMigration-Example/CoreData/Migration/Policies/Post2ToPost3MigrationPolicy.swift index 8a6d640..293d334 100644 --- a/CoreDataMigration-Example/CoreData/Migration/Policies/Post2ToPost3MigrationPolicy.swift +++ b/CoreDataMigration-Example/CoreData/Migration/Policies/Post2ToPost3MigrationPolicy.swift @@ -10,17 +10,25 @@ import CoreData final class Post2ToPost3MigrationPolicy: NSEntityMigrationPolicy { - override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { - try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager) + override func createDestinationInstances(forSource sourceInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { + try super.createDestinationInstances(forSource: sourceInstance, in: mapping, manager: manager) - guard let destinationPost = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else { + guard let destinationPost = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sourceInstance]).first else { fatalError("was expected a post") } - let color = NSEntityDescription.insertNewObject(forEntityName: "Color", into: destinationPost.managedObjectContext!) - color.setValue(UUID().uuidString, forKey: "colorID") - color.setValue(sInstance.value(forKey: "hexColor"), forKey: "hex") + let sourceBody = sourceInstance.value(forKey: "content") as? String + let sourceTitle = sourceBody?.prefix(4).appending("...") - destinationPost.setValue(color, forKey: "color") + let section = NSEntityDescription.insertNewObject(forEntityName: "Section", into: destinationPost.managedObjectContext!) + section.setValue(sourceTitle, forKey: "title") + section.setValue(sourceBody, forKey: "body") + section.setValue(destinationPost, forKey: "post") + section.setValue(0, forKey: "index") + + var sections = Set() + sections.insert(section) + + destinationPost.setValue(sections, forKey: "sections") } } diff --git a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel/contents b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel/contents index bb82c43..0fefc54 100644 --- a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel/contents +++ b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 2.xcdatamodel/contents @@ -1,11 +1,12 @@ - + + - + - + \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel/contents b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel/contents index 13470e1..efe5f33 100644 --- a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel/contents +++ b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 3.xcdatamodel/contents @@ -1,17 +1,19 @@ - - - - - - + + - + + + + + + + - - + + \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 4.xcdatamodel/contents b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 4.xcdatamodel/contents index 4708576..84a8743 100644 --- a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 4.xcdatamodel/contents +++ b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example 4.xcdatamodel/contents @@ -1,18 +1,20 @@ - - - - - - + - + - + + + + + + + + - - + + \ No newline at end of file diff --git a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example.xcdatamodel/contents b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example.xcdatamodel/contents index 41cc583..e103a01 100644 --- a/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example.xcdatamodel/contents +++ b/CoreDataMigration-Example/CoreData/Model/CoreDataMigration_Example.xcdatamodeld/CoreDataMigration_Example.xcdatamodel/contents @@ -1,11 +1,12 @@ - + + - + \ No newline at end of file diff --git a/CoreDataMigration-Example/Extensions/CGFloat/CGFloat+Random.swift b/CoreDataMigration-Example/Extensions/CGFloat/CGFloat+Random.swift deleted file mode 100644 index 34cdbbf..0000000 --- a/CoreDataMigration-Example/Extensions/CGFloat/CGFloat+Random.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// CGFloat+Random.swift -// CoreDataMigration-Example -// -// Created by William Boles on 12/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import Foundation -import UIKit - -extension CGFloat { - - // MARK: - Random - - static func random() -> CGFloat { - return CGFloat(arc4random()) / CGFloat(UInt32.max) - } -} diff --git a/CoreDataMigration-Example/Extensions/FileManager/FileManager+ApplicationSupport.swift b/CoreDataMigration-Example/Extensions/FileManager/FileManager+ApplicationSupport.swift new file mode 100644 index 0000000..4ca8de3 --- /dev/null +++ b/CoreDataMigration-Example/Extensions/FileManager/FileManager+ApplicationSupport.swift @@ -0,0 +1,25 @@ +// +// FileManager+ApplicationSupport.swift +// CoreDataMigration-Example +// +// Created by William Boles on 17/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation + +import Foundation + +extension FileManager { + + // MARK: - ApplicationSupport + + static func clearApplicationSupportDirectoryContents() { + let applicationSupportURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + let applicationSupportDirectoryContents = try! FileManager.default.contentsOfDirectory(atPath: applicationSupportURL.path) + applicationSupportDirectoryContents.forEach { + let fileURL = URL(fileURLWithPath: applicationSupportURL.path, isDirectory: true).appendingPathComponent($0) + try? FileManager.default.removeItem(atPath: fileURL.path) + } + } +} diff --git a/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Compatible.swift b/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Compatible.swift new file mode 100644 index 0000000..38d9ffd --- /dev/null +++ b/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Compatible.swift @@ -0,0 +1,20 @@ +// +// NSManagedObjectModel+Compatible.swift +// CoreDataMigration-Example +// +// Created by William Boles on 02/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation +import CoreData + +extension NSManagedObjectModel { + + // MARK: - Compatible + + static func compatibleModelForStoreMetadata(_ metadata: [String : Any]) -> NSManagedObjectModel? { + let mainBundle = Bundle.main + return NSManagedObjectModel.mergedModel(from: [mainBundle], forStoreMetadata: metadata) + } +} diff --git a/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Resource.swift b/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Resource.swift new file mode 100644 index 0000000..2bf160a --- /dev/null +++ b/CoreDataMigration-Example/Extensions/NSManagedObjectModel/NSManagedObjectModel+Resource.swift @@ -0,0 +1,32 @@ +// +// NSManagedObjectModel+Resource.swift +// CoreDataMigration-Example +// +// Created by William Boles on 02/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation +import CoreData + +extension NSManagedObjectModel { + + // MARK: - Resource + + static func managedObjectModel(forResource resource: String) -> NSManagedObjectModel { + let mainBundle = Bundle.main + let subdirectory = "CoreDataMigration_Example.momd" + let omoURL = mainBundle.url(forResource: resource, withExtension: "omo", subdirectory: subdirectory) // optimized model file + let momURL = mainBundle.url(forResource: resource, withExtension: "mom", subdirectory: subdirectory) + + guard let url = omoURL ?? momURL else { + fatalError("unable to find model in bundle") + } + + guard let model = NSManagedObjectModel(contentsOf: url) else { + fatalError("unable to load model in bundle") + } + + return model + } +} diff --git a/CoreDataMigration-Example/Extensions/UIColor/UIColor+Hex.swift b/CoreDataMigration-Example/Extensions/UIColor/UIColor+Hex.swift index 85c5f6a..511e3ac 100644 --- a/CoreDataMigration-Example/Extensions/UIColor/UIColor+Hex.swift +++ b/CoreDataMigration-Example/Extensions/UIColor/UIColor+Hex.swift @@ -23,29 +23,22 @@ extension UIColor { } static func colorWithHex(hexColor: String) -> UIColor? { - let red: CGFloat - let green: CGFloat - let blue: CGFloat - let alpha: CGFloat + guard hexColor.count == 6 else { + return nil + } - var color: UIColor? = nil + let scanner = Scanner(string: hexColor) + var hexNumber: UInt64 = 0 - if hexColor.characters.count == 6 { - - let scanner = Scanner(string: hexColor) - var hexNumber: UInt64 = 0 - - if scanner.scanHexInt64(&hexNumber) { - - red = CGFloat((hexNumber & 0xff0000) >> 16) / 255 - green = CGFloat((hexNumber & 0x00ff00) >> 8) / 255 - blue = CGFloat(hexNumber & 0x0000ff) / 255 - alpha = 1.0 - - color = UIColor(red: red, green: green, blue: blue, alpha: alpha) - } + guard scanner.scanHexInt64(&hexNumber) else { + return nil } - return color + let red = CGFloat((hexNumber & 0xff0000) >> 16) / 255 + let green = CGFloat((hexNumber & 0x00ff00) >> 8) / 255 + let blue = CGFloat(hexNumber & 0x0000ff) / 255 + let alpha = CGFloat(1) + + return UIColor(red: red, green: green, blue: blue, alpha: alpha) } } diff --git a/CoreDataMigration-Example/Extensions/UIColor/UIColor+Random.swift b/CoreDataMigration-Example/Extensions/UIColor/UIColor+Random.swift index b0d9571..4fe9019 100644 --- a/CoreDataMigration-Example/Extensions/UIColor/UIColor+Random.swift +++ b/CoreDataMigration-Example/Extensions/UIColor/UIColor+Random.swift @@ -12,7 +12,26 @@ extension UIColor { // MARK: - Random - static var random: UIColor { - return UIColor(red: .random(), green: .random(), blue: .random(), alpha: 1.0) + static var randomPastelColor: UIColor { + let mixColor = UIColor.white + + let randomColorGenerator = { ()-> CGFloat in + CGFloat(arc4random() % 256) / 256 + } + + var red: CGFloat = randomColorGenerator() + var green: CGFloat = randomColorGenerator() + var blue: CGFloat = randomColorGenerator() + + var mixRed: CGFloat = 0 + var mixGreen: CGFloat = 0 + var mixBlue: CGFloat = 0 + mixColor.getRed(&mixRed, green: &mixGreen, blue: &mixBlue, alpha: nil) + + red = (red + mixRed) / 2 + green = (green + mixGreen) / 2 + blue = (blue + mixBlue) / 2 + + return UIColor(red: red, green: green, blue: blue, alpha: 1) } } diff --git a/CoreDataMigration-Example/Storyboards/Base.lproj/LaunchScreen.storyboard b/CoreDataMigration-Example/Storyboards/Base.lproj/LaunchScreen.storyboard index f83f6fd..42a6734 100644 --- a/CoreDataMigration-Example/Storyboards/Base.lproj/LaunchScreen.storyboard +++ b/CoreDataMigration-Example/Storyboards/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,11 @@ - - + + + + + - + + diff --git a/CoreDataMigration-Example/Storyboards/Base.lproj/Main.storyboard b/CoreDataMigration-Example/Storyboards/Base.lproj/Main.storyboard index a603707..60406ad 100644 --- a/CoreDataMigration-Example/Storyboards/Base.lproj/Main.storyboard +++ b/CoreDataMigration-Example/Storyboards/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -25,64 +25,43 @@ - - + + - - - - - - - - - - - - - - + + - + + + + + + - - - + + + + - - + + + @@ -94,14 +73,97 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -119,5 +181,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CoreDataMigration-Example/ViewControllers/Posts/PostTableViewCell.swift b/CoreDataMigration-Example/ViewControllers/Posts/PostTableViewCell.swift index aa17356..b357fdc 100644 --- a/CoreDataMigration-Example/ViewControllers/Posts/PostTableViewCell.swift +++ b/CoreDataMigration-Example/ViewControllers/Posts/PostTableViewCell.swift @@ -8,9 +8,24 @@ import UIKit +struct PostTableViewCellViewModel { + + let preview: String + let date: String + let backgroundColor: UIColor +} + class PostTableViewCell: UITableViewCell { - @IBOutlet weak var postIDLabel: UILabel! + @IBOutlet weak var contentLabel: UILabel! @IBOutlet weak var dateLabel: UILabel! + // MARK: - Configure + + func configure(withViewModel viewModel: PostTableViewCellViewModel) { + contentLabel.text = viewModel.preview + dateLabel.text = viewModel.date + contentView.backgroundColor = viewModel.backgroundColor + } + } diff --git a/CoreDataMigration-Example/ViewControllers/Posts/PostsViewController.swift b/CoreDataMigration-Example/ViewControllers/Posts/PostsViewController.swift index c2834c3..8f0b588 100644 --- a/CoreDataMigration-Example/ViewControllers/Posts/PostsViewController.swift +++ b/CoreDataMigration-Example/ViewControllers/Posts/PostsViewController.swift @@ -15,7 +15,8 @@ class PostsViewController: UITableViewController { lazy var dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "dd/MM/yyyy HH:mm" + dateFormatter.dateStyle = .medium + dateFormatter.timeStyle = .medium return dateFormatter }() @@ -26,6 +27,7 @@ class PostsViewController: UITableViewController { super.viewDidLoad() tableView.rowHeight = 80.0 + tableView.separatorColor = UIColor.clear } override func viewWillAppear(_ animated: Bool) { @@ -34,47 +36,28 @@ class PostsViewController: UITableViewController { loadData() } - // MARK: - ButtonActions + // MARK: - Segue - @IBAction func addButtonPressed(_ sender: Any) { - addPost { - self.loadData() - } - } - - // MARK: - Post - - func addPost(completion: @escaping () -> Void) { - DispatchQueue.global(qos: .userInitiated).async { - let context = CoreDataManager.shared.backgroundContext - context.performAndWait { - let post = NSEntityDescription.insertNewObject(forEntityName: "Post", into: context) as! Post - post.postID = UUID().uuidString - post.date = Date() - - let color = NSEntityDescription.insertNewObject(forEntityName: "Color", into: context) as! Color - color.colorID = UUID().uuidString - color.hex = UIColor.random.hexString - - post.color = color - - try! context.save() - - DispatchQueue.main.async { - completion() - } + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "Viewer" { + if let postViewCcontroller = segue.destination as? PostViewerViewController, let tableViewCell = sender as? UITableViewCell, let indexPath = tableView.indexPath(for: tableViewCell) { + let post = posts[indexPath.row] + let viewModel = postViewerViewModel(forPost: post) + postViewCcontroller.configure(withViewModel: viewModel) } } } // MARK: - Load - func loadData() { + private func loadData() { let context = CoreDataManager.shared.mainContext let request = NSFetchRequest.init(entityName: "Post") let dateSort = NSSortDescriptor(key: "date", ascending: false) + let predicate = NSPredicate(format: "softDeleted == NO") request.sortDescriptors = [dateSort] + request.predicate = predicate posts = try! context.fetch(request) tableView.reloadData() @@ -91,10 +74,30 @@ class PostsViewController: UITableViewController { let cell = tableView.dequeueReusableCell(withIdentifier: "PostTableViewCell", for: indexPath) as! PostTableViewCell - cell.postIDLabel.text = post.postID - cell.dateLabel.text = dateFormatter.string(from: post.date!) - cell.contentView.backgroundColor = UIColor.colorWithHex(hexColor: post.color!.hex!) + let viewModel = cellViewModel(forPost: post) + cell.configure(withViewModel: viewModel) return cell } + + // MARK: - ViewModels + + private func cellViewModel(forPost post: Post) -> PostTableViewCellViewModel { + let backgroundColor = UIColor.colorWithHex(hexColor: post.hexColor!) ?? UIColor.white + let formattedDate = dateFormatter.string(from: post.date!) + let typedSections = post.sections as! Set
+ let firstSection = typedSections.sorted { $0.index < $1.index }.first! + let preview = firstSection.title!.count > 0 ? firstSection.title! : firstSection.body! + + return PostTableViewCellViewModel(preview: preview, date: formattedDate, backgroundColor: backgroundColor) + } + + private func postViewerViewModel(forPost post: Post) -> PostViewerViewModel { + let backgroundColor = UIColor.colorWithHex(hexColor: post.hexColor!) ?? UIColor.white + let typedSections = post.sections as! Set
+ + let sections = typedSections.sorted { $0.index < $1.index }.map { PostViewerSectionViewModel(title: $0.title!, body: $0.body!) } + + return PostViewerViewModel(postID: post.postID!, sections: sections, backgroundColor: backgroundColor) + } } diff --git a/CoreDataMigration-Example/ViewControllers/Viewer/PostSectionViewerTableViewCell.swift b/CoreDataMigration-Example/ViewControllers/Viewer/PostSectionViewerTableViewCell.swift new file mode 100644 index 0000000..c74c374 --- /dev/null +++ b/CoreDataMigration-Example/ViewControllers/Viewer/PostSectionViewerTableViewCell.swift @@ -0,0 +1,31 @@ +// +// PostSectionViewerTableViewCell.swift +// CoreDataMigration-Example +// +// Created by Boles, William (Developer) on 17/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import UIKit + +class PostSectionViewerTableViewCell: UITableViewCell { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var bodyLabel: UILabel! + + // MARK: - Reuse + + override func prepareForReuse() { + super.prepareForReuse() + + titleLabel.text = nil + bodyLabel.text = nil + } + + // MARK: - Configure + + func configure(withViewModel viewModel: PostViewerSectionViewModel) { + titleLabel.text = viewModel.title + bodyLabel.text = viewModel.body + } +} diff --git a/CoreDataMigration-Example/ViewControllers/Viewer/PostViewerViewController.swift b/CoreDataMigration-Example/ViewControllers/Viewer/PostViewerViewController.swift new file mode 100644 index 0000000..d2ff9bf --- /dev/null +++ b/CoreDataMigration-Example/ViewControllers/Viewer/PostViewerViewController.swift @@ -0,0 +1,87 @@ +// +// PostViewerViewController.swift +// CoreDataMigration-Example +// +// Created by William Boles on 13/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import UIKit +import CoreData + +struct PostViewerViewModel { + + let postID: String + let sections: [PostViewerSectionViewModel] + let backgroundColor: UIColor +} + +struct PostViewerSectionViewModel { + + let title: String + let body: String +} + +class PostViewerViewController: UITableViewController { + + private var viewModel: PostViewerViewModel! + + // MARK: - ViewLifecycle + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.tableFooterView = UIView() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + tableView.backgroundColor = viewModel.backgroundColor + } + + // MARK: - Configure + + func configure(withViewModel viewModel: PostViewerViewModel) { + self.viewModel = viewModel + + tableView.reloadData() + } + + // MARK: - UITableViewDataSource + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return viewModel.sections.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let contentSectionViewModel = viewModel.sections[indexPath.row] + + let cell = tableView.dequeueReusableCell(withIdentifier: "PostSectionViewerTableViewCell", for: indexPath) as! PostSectionViewerTableViewCell + + cell.configure(withViewModel: contentSectionViewModel) + + return cell + } + + // MARK: - ButtonActions + + @IBAction func deleteButtonPressed(_ sender: Any) { + DispatchQueue.global(qos: .userInitiated).async { + let context = CoreDataManager.shared.backgroundContext + context.performAndWait { + let request = NSFetchRequest.init(entityName: "Post") + request.predicate = NSPredicate(format: "postID == '\(self.viewModel.postID)'") + + let post = try! context.fetch(request).first! + post.softDeleted = true + + try? context.save() + + DispatchQueue.main.async { + self.navigationController?.popViewController(animated: true) + } + } + } + } +} diff --git a/CoreDataMigration-Example/ViewControllers/Writer/PostSectionWriterTableViewCell.swift b/CoreDataMigration-Example/ViewControllers/Writer/PostSectionWriterTableViewCell.swift new file mode 100644 index 0000000..ae1bfde --- /dev/null +++ b/CoreDataMigration-Example/ViewControllers/Writer/PostSectionWriterTableViewCell.swift @@ -0,0 +1,63 @@ +// +// PostSectionTableViewCell.swift +// CoreDataMigration-Example +// +// Created by William Boles on 15/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import UIKit + +struct PostSectionWriterTableViewCellViewModel { + + var title: String + var body: String +} + +protocol PostSectionWriterTableViewCellDelegate: class { + + func didSetTitle(cell: PostSectionWriterTableViewCell, to title: String) + func didSetBody(cell: PostSectionWriterTableViewCell, to body: String) +} + +class PostSectionWriterTableViewCell: UITableViewCell, UITextFieldDelegate, UITextViewDelegate { + + @IBOutlet weak var titleTextField: UITextField! + @IBOutlet weak var bodyTextView: UITextView! + + weak var delegate: PostSectionWriterTableViewCellDelegate? + + // MARK: - Awake + + override func awakeFromNib() { + super.awakeFromNib() + + titleTextField.delegate = self + bodyTextView.delegate = self + } + + // MARK: - Configure + + func configure(withViewModel viewModel: PostSectionWriterTableViewCellViewModel) { + titleTextField.text = viewModel.title + bodyTextView.text = viewModel.body + } + + // MARK: - UITextFieldDelegate + + func textFieldDidEndEditing(_ textField: UITextField) { + delegate?.didSetTitle(cell: self, to: textField.text ?? "") + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + + return true + } + + // MARK: - UITextViewDelegate + + func textViewDidEndEditing(_ textView: UITextView) { + delegate?.didSetBody(cell: self, to: textView.text ?? "") + } +} diff --git a/CoreDataMigration-Example/ViewControllers/Writer/PostWriterViewController.swift b/CoreDataMigration-Example/ViewControllers/Writer/PostWriterViewController.swift new file mode 100644 index 0000000..ec8236b --- /dev/null +++ b/CoreDataMigration-Example/ViewControllers/Writer/PostWriterViewController.swift @@ -0,0 +1,135 @@ +// +// PostWriterViewController.swift +// CoreDataMigration-Example +// +// Created by William Boles on 13/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import UIKit +import CoreData + +class PostWriterViewController: UITableViewController, PostSectionWriterTableViewCellDelegate { + + var contentSectionViewModels = [PostSectionWriterTableViewCellViewModel]() + + // MARK: - ViewLifecycle + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.rowHeight = 220.0 + tableView.tableFooterView = UIView() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + addNewSectionToTableView() + } + + // MARK: - UITableViewDataSource + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return contentSectionViewModels.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let contentSectionViewModel = contentSectionViewModels[indexPath.row] + + let cell = tableView.dequeueReusableCell(withIdentifier: "PostSectionTableViewCell", for: indexPath) as! PostSectionWriterTableViewCell + + cell.configure(withViewModel: contentSectionViewModel) + cell.delegate = self + + return cell + } + + // MARK: - ButtonActions + + @IBAction func saveButtonPressed(_ sender: Any) { + view.endEditing(true) + + DispatchQueue.global(qos: .userInitiated).async { + let context = CoreDataManager.shared.backgroundContext + context.performAndWait { + let post = NSEntityDescription.insertNewObject(forEntityName: "Post", into: context) as! Post + post.postID = UUID().uuidString + post.date = Date() + post.hexColor = UIColor.randomPastelColor.hexString + + for (index, viewModel) in self.contentSectionViewModels.enumerated() { + guard viewModel.title.count > 0 || viewModel.body.count > 0 else { + continue + } + + let section = NSEntityDescription.insertNewObject(forEntityName: "Section", into: context) as! Section + section.title = viewModel.title + section.body = viewModel.body + section.index = Int16(index) + + section.post = post + post.addToSections(section) + } + + if post.sections?.count ?? 0 > 0 { + try? context.save() + } + + DispatchQueue.main.async { + self.dismiss(animated: true, completion: nil) + } + } + } + } + + @IBAction func addSectionButtonPressed(_ sender: Any) { + view.endEditing(true) + addNewSectionToTableView() + scrollToLastSection() + } + + @IBAction func cancelButtonPressed(_ sender: Any) { + dismiss(animated: true, completion: nil) + } + + // MARK: - Section + + func addNewSectionToTableView() { + let viewModel = PostSectionWriterTableViewCellViewModel(title: "", body: "") + contentSectionViewModels.append(viewModel) + + tableView.reloadData() + } + + func scrollToLastSection() { + let lastIndex = (contentSectionViewModels.count - 1) + let lastIndexPath = IndexPath(item: lastIndex, section: 0) + + tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: true) + } + + // MARK: - PostSectionWriterTableViewCellDelegate + + func didSetTitle(cell: PostSectionWriterTableViewCell, to title: String) { + guard let indexPath = tableView.indexPath(for: cell) else { + return + } + + var viewModel = contentSectionViewModels[indexPath.row] + viewModel.title = title + + contentSectionViewModels[indexPath.row] = viewModel + } + + func didSetBody(cell: PostSectionWriterTableViewCell, to body: String) { + guard let indexPath = tableView.indexPath(for: cell) else { + return + } + + var viewModel = contentSectionViewModels[indexPath.row] + viewModel.body = body + + contentSectionViewModels[indexPath.row] = viewModel + } +} diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigrationModelTests.swift b/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigrationModelTests.swift deleted file mode 100644 index 408a077..0000000 --- a/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigrationModelTests.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// CoreDataMigrationModelTests.swift -// CoreDataMigration-ExampleTests -// -// Created by William Boles on 12/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import XCTest -import CoreData - -@testable import CoreDataMigration_Example - -class CoreDataMigrationModelTests: XCTestCase { - - // MARK: - CustomClasses - - class CoreDataMigrationModelSpy: CoreDataMigrationModel { - - var inferredMappingModelWasCalled = false - var customMappingModelWasCalled = false - - override func inferredMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel { - inferredMappingModelWasCalled = true - - return NSMappingModel() - } - - override func customMappingModel(to nextVersion: CoreDataMigrationModel) -> NSMappingModel? { - customMappingModelWasCalled = true - - return NSMappingModel() - } - } - - // MARK: - Source - - func test_sourceInit_validStoreURL() { - let storeURL = Bundle(for: CoreDataMigrationModelTests.self).resourceURL!.appendingPathComponent("CoreDataMigration_Example_2.sqlite") - let coreDataMigrationModel = CoreDataMigrationSourceModel(storeURL: storeURL) - - XCTAssertNotNil(coreDataMigrationModel) - XCTAssertEqual(coreDataMigrationModel!.version.name, "CoreDataMigration_Example 2") - } - - // MARK: - Steps - - func test_migrationSteps_singleStep() { - let version2 = CoreDataMigrationModel(version: .version2) - let version3 = CoreDataMigrationModel(version: .version3) - - let steps = version2.migrationSteps(to: version3) - - let firstStep = steps.first - - let sourceModel = version2.managedObjectModel() - let destinationModel = version3.managedObjectModel() - - XCTAssertEqual(steps.count, 1) - XCTAssertEqual(firstStep?.source, sourceModel) - XCTAssertEqual(firstStep?.destination, destinationModel) - } - - func test_migrationSteps_multipleSteps() { - let version1 = CoreDataMigrationModel(version: .version1) - let version2 = CoreDataMigrationModel(version: .version2) - let version3 = CoreDataMigrationModel(version: .version3) - - let steps = version1.migrationSteps(to: version3) - - let lastStep = steps.last - - let sourceModel = version2.managedObjectModel() - let destinationModel = version3.managedObjectModel() - - XCTAssertEqual(steps.count, 2) - XCTAssertEqual(lastStep?.source, sourceModel) - XCTAssertEqual(lastStep?.destination, destinationModel) - } - - func test_migrationSteps_toCurrent() { - let version1 = CoreDataMigrationModel(version: .version1) - let currentVersion = CoreDataMigrationModel.current - - let steps = version1.migrationSteps(to: currentVersion) - - XCTAssertEqual(steps.count, (CoreDataVersion.all.count - 1)) - } - - func test_migrationSteps_cannotMigrateToSelf() { - let version3 = CoreDataMigrationModel(version: .version3) - - let steps = version3.migrationSteps(to: version3) - - XCTAssertEqual(steps.count, 0) - } - - // MARK: - Model - - func test_retrieveModel_findAndLoad() { - let version3 = CoreDataMigrationModel(version: .version3) - - let managedObjectModel = version3.managedObjectModel() - - XCTAssertNotNil(managedObjectModel) - } - - // MARK: - Successor - - func test_fromVersion1_manualMapping() { - let version = CoreDataMigrationModelSpy(version: .version1) - - let mappingModel = version.mappingModelToSuccessor() - - XCTAssertNotNil(mappingModel) - XCTAssertTrue(version.customMappingModelWasCalled) - } - - func test_fromVersion2_manualMapping() { - let version = CoreDataMigrationModelSpy(version: .version2) - - let mappingModel = version.mappingModelToSuccessor() - - XCTAssertNotNil(mappingModel) - XCTAssertTrue(version.customMappingModelWasCalled) - } - - func test_fromVersion3_inferredMapping() { - let version = CoreDataMigrationModelSpy(version: .version3) - - let mappingModel = version.mappingModelToSuccessor() - - XCTAssertNotNil(mappingModel) - XCTAssertTrue(version.inferredMappingModelWasCalled) - } - - // MARK: - Current - - func test_current() { - let lastVersion = CoreDataVersion.all.first! - - let expectedModel = CoreDataMigrationModel(version: lastVersion) - let currentModel = CoreDataMigrationModel.current - - XCTAssertEqual(expectedModel.version, currentModel.version) - } -} diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigratorTests.swift b/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigratorTests.swift deleted file mode 100644 index 2bd1bba..0000000 --- a/CoreDataMigration-ExampleTests/CoreData/Migration/CoreDataMigratorTests.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// CoreDataMigratorTests.swift -// CoreDataMigration-ExampleTests -// -// Created by William Boles on 12/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import XCTest -import CoreData - -@testable import CoreDataMigration_Example - -class CoreDataMigratorTests: XCTestCase { - - static func clearTmpDirectoryContents() { - let tmpDirectoryContents = try! FileManager.default.contentsOfDirectory(atPath: NSTemporaryDirectory()) - tmpDirectoryContents.forEach { - let fileURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent($0) - try! FileManager.default.removeItem(atPath: fileURL.path) - } - } - - static func moveFileFromBundleToTmpDirectory(fileName: String) -> URL { - let destinationURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(fileName) - let bundleURL = Bundle(for: CoreDataMigratorTests.self).resourceURL!.appendingPathComponent(fileName) - try! FileManager.default.copyItem(at: bundleURL, to: destinationURL) - - return destinationURL - } - - // MARK: - Properties - - var migrator: CoreDataMigrator! - - // MARK: - Setup - - override class func setUp() { - super.setUp() - clearTmpDirectoryContents() - } - - override func setUp() { - super.setUp() - migrator = CoreDataMigrator() - } - - override func tearDown() { - CoreDataMigratorTests.clearTmpDirectoryContents() - super.tearDown() - } - - // MARK: - SingleStepMigrations - - func test_individualStepMigration_1to2() { - let sourceURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_1.sqlite") - let targetURL = sourceURL - - let modifiedDateBeforeMigration = try! FileManager.default.attributesOfItem(atPath: sourceURL.path)[FileAttributeKey.modificationDate] as! Date - - migrator.migrateStore(from: sourceURL, to: targetURL, targetVersion: CoreDataMigrationModel(version: .version2)) - - let modifiedDateAfterMigration = try! FileManager.default.attributesOfItem(atPath: targetURL.path)[FileAttributeKey.modificationDate] as! Date - - XCTAssertTrue(FileManager.default.fileExists(atPath: targetURL.path)) - XCTAssertTrue(modifiedDateAfterMigration.timeIntervalSince(modifiedDateBeforeMigration) > 0) - } - - func test_individualStepMigration_2to3() { - let sourceURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_2.sqlite") - let targetURL = sourceURL - - let modifiedDateBeforeMigration = try! FileManager.default.attributesOfItem(atPath: sourceURL.path)[FileAttributeKey.modificationDate] as! Date - - migrator.migrateStore(from: sourceURL, to: targetURL, targetVersion: CoreDataMigrationModel(version: .version3)) - - let modifiedDateAfterMigration = try! FileManager.default.attributesOfItem(atPath: targetURL.path)[FileAttributeKey.modificationDate] as! Date - - XCTAssertTrue(FileManager.default.fileExists(atPath: targetURL.path)) - XCTAssertTrue(modifiedDateAfterMigration.timeIntervalSince(modifiedDateBeforeMigration) > 0) - } - - func test_individualStepMigration_3to4() { - let sourceURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_3.sqlite") - let targetURL = sourceURL - - let modifiedDateBeforeMigration = try! FileManager.default.attributesOfItem(atPath: sourceURL.path)[FileAttributeKey.modificationDate] as! Date - - migrator.migrateStore(from: sourceURL, to: targetURL, targetVersion: CoreDataMigrationModel(version: .version4)) - - let modifiedDateAfterMigration = try! FileManager.default.attributesOfItem(atPath: targetURL.path)[FileAttributeKey.modificationDate] as! Date - - XCTAssertTrue(FileManager.default.fileExists(atPath: targetURL.path)) - XCTAssertTrue(modifiedDateAfterMigration.timeIntervalSince(modifiedDateBeforeMigration) > 0) - } - - // MARK: - MultipleStepMigrations - - func test_multipleStepMigration_1toCurrent() { - let sourceURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_1.sqlite") - let targetURL = sourceURL - - let modifiedDateBeforeMigration = try! FileManager.default.attributesOfItem(atPath: sourceURL.path)[FileAttributeKey.modificationDate] as! Date - - migrator.migrateStore(from: sourceURL, to: targetURL, targetVersion: CoreDataMigrationModel.current) - - let modifiedDateAfterMigration = try! FileManager.default.attributesOfItem(atPath: targetURL.path)[FileAttributeKey.modificationDate] as! Date - - XCTAssertTrue(FileManager.default.fileExists(atPath: targetURL.path)) - XCTAssertTrue(modifiedDateAfterMigration.timeIntervalSince(modifiedDateBeforeMigration) > 0) - } - - // MARK: - MigrationRequired - - func test_requiresMigration_true() { - let storeURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_1.sqlite") - - let requiresMigration = migrator.requiresMigration(at: storeURL) - - XCTAssertTrue(requiresMigration) - } - - func test_requiresMigration_false() { - let storeURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_3.sqlite") - let migrationModel = CoreDataMigrationModel(version: .version3) - - let requiresMigration = migrator.requiresMigration(at: storeURL, currentMigrationModel: migrationModel) - - XCTAssertFalse(requiresMigration) - } - - // MARK: - CheckPointing - - func test_forceWALTransactions_success() { - let storeURL = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_WAL.sqlite") - let walLocation = CoreDataMigratorTests.moveFileFromBundleToTmpDirectory(fileName: "CoreDataMigration_Example_WAL.sqlite-wal") - - let sizeBeforeCheckPointing = try! FileManager.default.attributesOfItem(atPath: storeURL.path)[FileAttributeKey.size] as! NSNumber - - migrator.forceWALCheckpointingForStore(at: storeURL) - - let sizeAfterCheckPointing = try! FileManager.default.attributesOfItem(atPath: storeURL.path)[FileAttributeKey.size] as! NSNumber - - XCTAssertFalse(FileManager.default.fileExists(atPath: walLocation.path)) - XCTAssertTrue(sizeAfterCheckPointing.doubleValue > sizeBeforeCheckPointing.doubleValue) - } -} diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite b/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite deleted file mode 100644 index fe8be46..0000000 Binary files a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite and /dev/null differ diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite b/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite deleted file mode 100644 index 0bae4b8..0000000 Binary files a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite and /dev/null differ diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite b/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite deleted file mode 100644 index 8b537e4..0000000 Binary files a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite and /dev/null differ diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite b/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite deleted file mode 100644 index 8b17c9b..0000000 Binary files a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite and /dev/null differ diff --git a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite-wal b/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite-wal deleted file mode 100644 index 6c496f8..0000000 Binary files a/CoreDataMigration-ExampleTests/CoreData/Migration/Models/CoreDataMigration_Example_WAL.sqlite-wal and /dev/null differ diff --git a/CoreDataMigration-ExampleTests/CoreDataMigration-ExampleTests-Bridging-Header.h b/CoreDataMigration-ExampleTests/CoreDataMigration-ExampleTests-Bridging-Header.h deleted file mode 100644 index 1b2cb5d..0000000 --- a/CoreDataMigration-ExampleTests/CoreDataMigration-ExampleTests-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/CoreDataMigration-ExampleTests/Helpers/FileManager+Helper.swift b/CoreDataMigration-ExampleTests/Helpers/FileManager+Helper.swift new file mode 100644 index 0000000..728809b --- /dev/null +++ b/CoreDataMigration-ExampleTests/Helpers/FileManager+Helper.swift @@ -0,0 +1,31 @@ +// +// FileManager+Helper.swift +// CoreDataMigration-ExampleTests +// +// Created by William Boles on 05/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation + +extension FileManager { + + // MARK: - Temp + + static func clearTempDirectoryContents() { + let tmpDirectoryContents = try! FileManager.default.contentsOfDirectory(atPath: NSTemporaryDirectory()) + tmpDirectoryContents.forEach { + let fileURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent($0) + try? FileManager.default.removeItem(atPath: fileURL.path) + } + } + + static func moveFileFromBundleToTempDirectory(filename: String) -> URL { + let destinationURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(filename) + try? FileManager.default.removeItem(at: destinationURL) + let bundleURL = Bundle(for: CoreDataMigratorTests.self).resourceURL!.appendingPathComponent(filename) + try? FileManager.default.copyItem(at: bundleURL, to: destinationURL) + + return destinationURL + } +} diff --git a/CoreDataMigration-ExampleTests/Helpers/NSManagedObjectContext+Helper.swift b/CoreDataMigration-ExampleTests/Helpers/NSManagedObjectContext+Helper.swift new file mode 100644 index 0000000..03413d7 --- /dev/null +++ b/CoreDataMigration-ExampleTests/Helpers/NSManagedObjectContext+Helper.swift @@ -0,0 +1,33 @@ +// +// NSManagedObjectContext+Helper.swift +// CoreDataMigration-ExampleTests +// +// Created by William Boles on 05/01/2019. +// Copyright © 2019 William Boles. All rights reserved. +// + +import Foundation +import CoreData + +extension NSManagedObjectContext { + + // MARK: Model + + convenience init(model: NSManagedObjectModel, storeURL: URL) { + let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try! persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil) + + self.init(concurrencyType: .mainQueueConcurrencyType) + + self.persistentStoreCoordinator = persistentStoreCoordinator + } + + // MARK: - Destroy + + func destroyStore() { + persistentStoreCoordinator?.persistentStores.forEach { + try? persistentStoreCoordinator?.remove($0) + try? persistentStoreCoordinator?.destroyPersistentStore(at: $0.url!, ofType: $0.type, options: nil) + } + } +} diff --git a/CoreDataMigration-ExampleTests/Info.plist b/CoreDataMigration-ExampleTests/Supporting Files/Info.plist similarity index 100% rename from CoreDataMigration-ExampleTests/Info.plist rename to CoreDataMigration-ExampleTests/Supporting Files/Info.plist diff --git a/CoreDataMigration-ExampleTests/TestingAppDelegate.swift b/CoreDataMigration-ExampleTests/TestingAppDelegate.swift deleted file mode 100644 index d79fe8b..0000000 --- a/CoreDataMigration-ExampleTests/TestingAppDelegate.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// TestingAppDelegate.swift -// CoreDataMigration-ExampleTests -// -// Created by William Boles on 15/09/2017. -// Copyright © 2017 William Boles. All rights reserved. -// - -import UIKit -import CoreData - -@testable import CoreDataMigration_Example - -class TestingAppDelegate: NSObject, UIApplicationDelegate { - - var window: UIWindow? - - // MARK: - AppLifecycle - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - - //Just some house keeping - if let storeURL = CoreDataManager().persistentContainer.persistentStoreDescriptions.first?.url { - NSPersistentStoreCoordinator.destroyStore(at: storeURL) - } - - return true - } -} diff --git a/CoreDataMigration-ExampleTests/CoreData/CoreDataManagerTests.swift b/CoreDataMigration-ExampleTests/Tests/CoreData/Manager/CoreDataManagerTests.swift similarity index 60% rename from CoreDataMigration-ExampleTests/CoreData/CoreDataManagerTests.swift rename to CoreDataMigration-ExampleTests/Tests/CoreData/Manager/CoreDataManagerTests.swift index 8269a21..1d6dca8 100644 --- a/CoreDataMigration-ExampleTests/CoreData/CoreDataManagerTests.swift +++ b/CoreDataMigration-ExampleTests/Tests/CoreData/Manager/CoreDataManagerTests.swift @@ -13,49 +13,33 @@ import CoreData class CoreDataManagerTests: XCTestCase { - class CoreDataMigratorMock: CoreDataMigrator { - - var requiresMigrationWasCalled = false - var migrateStoreWasCalled = false - - var requiresMigrationToBeReturned = false - - override func requiresMigration(at: URL, currentMigrationModel: CoreDataMigrationModel = CoreDataMigrationModel.current) -> Bool { - requiresMigrationWasCalled = true - - return requiresMigrationToBeReturned - } - - override func migrateStore(at: URL) { - migrateStoreWasCalled = true - } - } - - var migrator: CoreDataMigratorMock! - var manager: CoreDataManager! + var migrator: MockCoreDataMigrator! + var sut: CoreDataManager! - // MARK: - Setup + // MARK: - Lifecycle override func setUp() { super.setUp() - - migrator = CoreDataMigratorMock() - manager = CoreDataManager(migrator: migrator) + + migrator = MockCoreDataMigrator() + sut = CoreDataManager(storeType: NSInMemoryStoreType, migrator: migrator) } override func tearDown() { - let url = manager.persistentContainer.persistentStoreDescriptions.first!.url! - NSPersistentStoreCoordinator.destroyStore(at: url) + migrator = nil + sut = nil super.tearDown() } - // MARK: - Setup + // MARK: - Tests + + // MARK: Setup func test_setup_loadsStore() { let promise = expectation(description: "calls back") - manager.setup { - XCTAssertTrue(self.manager.persistentContainer.persistentStoreCoordinator.persistentStores.count > 0) + sut.setup { + XCTAssertTrue(self.sut.persistentContainer.persistentStoreCoordinator.persistentStores.count > 0) promise.fulfill() } @@ -69,7 +53,7 @@ class CoreDataManagerTests: XCTestCase { func test_setup_checksIfMigrationRequired() { let promise = expectation(description: "calls back") - manager.setup { + sut.setup { XCTAssertTrue(self.migrator.requiresMigrationWasCalled) XCTAssertFalse(self.migrator.migrateStoreWasCalled) @@ -87,7 +71,7 @@ class CoreDataManagerTests: XCTestCase { migrator.requiresMigrationToBeReturned = true let promise = expectation(description: "calls back") - manager.setup { + sut.setup { XCTAssertTrue(self.migrator.migrateStoreWasCalled) promise.fulfill() @@ -99,5 +83,4 @@ class CoreDataManagerTests: XCTestCase { } } } - } diff --git a/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/CoreDataMigratorTests.swift b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/CoreDataMigratorTests.swift new file mode 100644 index 0000000..de2f5ae --- /dev/null +++ b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/CoreDataMigratorTests.swift @@ -0,0 +1,237 @@ +// +// CoreDataMigratorTests.swift +// CoreDataMigration-ExampleTests +// +// Created by William Boles on 12/09/2017. +// Copyright © 2017 William Boles. All rights reserved. +// + +import XCTest +import CoreData + +@testable import CoreDataMigration_Example + +class CoreDataMigratorTests: XCTestCase { + + var sut: CoreDataMigrator! + + // MARK: - Lifecycle + + override class func setUp() { + super.setUp() + + FileManager.clearTempDirectoryContents() + } + + override func setUp() { + super.setUp() + + sut = CoreDataMigrator() + } + + override func tearDown() { + sut = nil + + super.tearDown() + } + + func tearDownCoreDataStack(context: NSManagedObjectContext) { + context.destroyStore() + } + + // MARK: - Tests + + // MARK: SingleStepMigrations + + func test_individualStepMigration_1to2() { + let sourceURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_1.sqlite") + let toVersion = CoreDataMigrationVersion.version2 + + sut.migrateStore(at: sourceURL, toVersion: toVersion) + + XCTAssertTrue(FileManager.default.fileExists(atPath: sourceURL.path)) + + let model = NSManagedObjectModel.managedObjectModel(forResource: toVersion.rawValue) + let context = NSManagedObjectContext(model: model, storeURL: sourceURL) + let request = NSFetchRequest.init(entityName: "Post") + let sort = NSSortDescriptor(key: "postID", ascending: false) + request.sortDescriptors = [sort] + + let migratedPosts = try? context.fetch(request) + + XCTAssertEqual(migratedPosts?.count, 10) + + let firstMigratedPost = migratedPosts?.first + + let migratedDate = firstMigratedPost?.value(forKey: "date") as? Date + let migratedHexColor = firstMigratedPost?.value(forKey: "hexColor") as? String + let migratedPostID = firstMigratedPost?.value(forKey: "postID") as? String + let migratedContent = firstMigratedPost?.value(forKey: "content") as? String + + XCTAssertEqual(migratedDate?.timeIntervalSince1970, 1547494150.058821) + XCTAssertEqual(migratedHexColor, "1BB732") + XCTAssertEqual(migratedPostID, "FFFECB21-6645-4FDD-B8B0-B960D0E61F5A") + XCTAssertEqual(migratedContent, "Test body") + + tearDownCoreDataStack(context: context) + } + + func test_individualStepMigration_2to3() { + let sourceURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_2.sqlite") + let toVersion = CoreDataMigrationVersion.version3 + + sut.migrateStore(at: sourceURL, toVersion: toVersion) + + XCTAssertTrue(FileManager.default.fileExists(atPath: sourceURL.path)) + + let model = NSManagedObjectModel.managedObjectModel(forResource: toVersion.rawValue) + let context = NSManagedObjectContext(model: model, storeURL: sourceURL) + + let postRequest = NSFetchRequest.init(entityName: "Post") + let postSort = NSSortDescriptor(key: "postID", ascending: false) + postRequest.sortDescriptors = [postSort] + + let migratedPosts = try? context.fetch(postRequest) + + XCTAssertEqual(migratedPosts?.count, 10) + + let firstMigratedPost = migratedPosts?.first + + let migratedDate = firstMigratedPost?.value(forKey: "date") as? Date + let migratedPostID = firstMigratedPost?.value(forKey: "postID") as? String + let migratedHexColor = firstMigratedPost?.value(forKey: "hexColor") as? String + let migratedPostSections = firstMigratedPost?.value(forKey: "sections") as? Set + + XCTAssertEqual(migratedDate?.timeIntervalSince1970, 1547494150.058821) + XCTAssertEqual(migratedPostID, "FFFECB21-6645-4FDD-B8B0-B960D0E61F5A") + XCTAssertEqual(migratedHexColor, "1BB732") + XCTAssertEqual(migratedPostSections?.count, 1) + + let migratedSection = migratedPostSections?.first + + let migratedBody = migratedSection?.value(forKey: "body") as? String + let migratedIndex = migratedSection?.value(forKey: "index") as? Int + let migratedTitle = migratedSection?.value(forKey: "title") as? String + let migratedPost = migratedSection?.value(forKey: "post") as? NSManagedObject + + XCTAssertEqual(migratedTitle, "Test...") + XCTAssertEqual(migratedBody, "Test body") + XCTAssertEqual(migratedIndex, 0) + + XCTAssertNotNil(migratedPost) + + let contentRequest = NSFetchRequest.init(entityName: "Section") + + let migratedSections = try? context.fetch(contentRequest) + + XCTAssertEqual(migratedSections?.count, 10) + + tearDownCoreDataStack(context: context) + } + + func test_individualStepMigration_3to4() { + let sourceURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_3.sqlite") + let toVersion = CoreDataMigrationVersion.version4 + + sut.migrateStore(at: sourceURL, toVersion: toVersion) + + XCTAssertTrue(FileManager.default.fileExists(atPath: sourceURL.path)) + + let model = NSManagedObjectModel.managedObjectModel(forResource: toVersion.rawValue) + let context = NSManagedObjectContext(model: model, storeURL: sourceURL) + + let postRequest = NSFetchRequest.init(entityName: "Post") + let postSort = NSSortDescriptor(key: "date", ascending: false) + postRequest.sortDescriptors = [postSort] + + let migratedPosts = try? context.fetch(postRequest) + + XCTAssertEqual(migratedPosts?.count, 12) + + let firstMigratedPost = migratedPosts?.first + + let migratedDate = firstMigratedPost?.value(forKey: "date") as? Date + let migratedPostID = firstMigratedPost?.value(forKey: "postID") as? String + let migratedSoftDeleted = firstMigratedPost?.value(forKey: "softDeleted") as? Bool + let migratedHexColor = firstMigratedPost?.value(forKey: "hexColor") as? String + let migratedPostSections = firstMigratedPost?.value(forKey: "sections") as? Set + + XCTAssertEqual(migratedDate?.timeIntervalSince1970, 1547764015.200076) + XCTAssertEqual(migratedPostID, "7BC43935-3209-404E-836A-06F3C6518CB1") + XCTAssertFalse(migratedSoftDeleted ?? true) + XCTAssertEqual(migratedHexColor, "BAEFB6") + XCTAssertEqual(migratedPostSections?.count, 2) + + let orderedMigratedSections = migratedPostSections?.sorted { + let index1 = $0.value(forKey: "index") as! Int + let index2 = $1.value(forKey: "index") as! Int + return index1 < index2 + } + + let migratedSection = orderedMigratedSections?.first + + let migratedBody = migratedSection?.value(forKey: "body") as? String + let migratedIndex = migratedSection?.value(forKey: "index") as? Int + let migratedTitle = migratedSection?.value(forKey: "title") as? String + let migratedPost = migratedSection?.value(forKey: "post") as? NSManagedObject + + let expectedBody = "Nam sapien nibh, ornare vitae cursus vehicula, pretium id nibh. Nunc nulla enim, mollis sed leo eu, maximus semper mi. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis faucibus, tortor vitae gravida tristique, dolor nibh faucibus lorem, at semper ex mi id felis. Mauris molestie mauris in feugiat aliquet. In quam ipsum, vestibulum ac purus eu, vulputate consectetur justo. Integer facilisis dictum risus, sit amet condimentum quam pulvinar nec. Curabitur blandit est ut libero lobortis malesuada. Morbi gravida arcu at ultrices commodo. Ut enim metus, viverra tincidunt turpis sit amet, consectetur pharetra urna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ex massa, aliquam at leo quis, rhoncus accumsan nisl. Donec id porttitor massa." + + XCTAssertEqual(migratedTitle, "This post will have 2 sections") + XCTAssertEqual(migratedBody, expectedBody) + XCTAssertEqual(migratedIndex, 0) + + XCTAssertNotNil(migratedPost) + + let contentRequest = NSFetchRequest.init(entityName: "Section") + + let migratedSections = try? context.fetch(contentRequest) + + XCTAssertEqual(migratedSections?.count, 14) + + tearDownCoreDataStack(context: context) + } + + // MARK: MultipleStepMigrations + + func test_multipleStepMigration_fromVersion1toVersion4() { + let sourceURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_1.sqlite") + let toVersion = CoreDataMigrationVersion.version4 + + sut.migrateStore(at: sourceURL, toVersion: toVersion) + + XCTAssertTrue(FileManager.default.fileExists(atPath: sourceURL.path)) + + let model = NSManagedObjectModel.managedObjectModel(forResource: toVersion.rawValue) + let context = NSManagedObjectContext(model: model, storeURL: sourceURL) + + let postRequest = NSFetchRequest.init(entityName: "Post") + let sectionRequest = NSFetchRequest.init(entityName: "Section") + + let migratedPosts = try? context.fetch(postRequest) + let migratedSections = try? context.fetch(sectionRequest) + + XCTAssertEqual(migratedPosts?.count, 10) + XCTAssertEqual(migratedSections?.count, 10) + + tearDownCoreDataStack(context: context) + } + + // MARK: MigrationRequired + + func test_requiresMigration_fromVersion1ToCurrent_true() { + let storeURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_1.sqlite") + + let requiresMigration = sut.requiresMigration(at: storeURL, toVersion: CoreDataMigrationVersion.latest) + + XCTAssertTrue(requiresMigration) + } + + func test_requiresMigration_fromVersion2ToVersion2_false() { + let storeURL = FileManager.moveFileFromBundleToTempDirectory(filename: "CoreDataMigration_Example_2.sqlite") + + let requiresMigration = sut.requiresMigration(at: storeURL, toVersion: .version2) + + XCTAssertFalse(requiresMigration) + } +} diff --git a/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite new file mode 100755 index 0000000..1e18ae6 Binary files /dev/null and b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_1.sqlite differ diff --git a/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite new file mode 100755 index 0000000..1f054c5 Binary files /dev/null and b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_2.sqlite differ diff --git a/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite new file mode 100755 index 0000000..cf36008 Binary files /dev/null and b/CoreDataMigration-ExampleTests/Tests/CoreData/Migration/Models/CoreDataMigration_Example_3.sqlite differ diff --git a/CoreDataMigration-ExampleTests/Tests/Mocks/MockCoreDataMigrator.swift b/CoreDataMigration-ExampleTests/Tests/Mocks/MockCoreDataMigrator.swift new file mode 100644 index 0000000..b75aafc --- /dev/null +++ b/CoreDataMigration-ExampleTests/Tests/Mocks/MockCoreDataMigrator.swift @@ -0,0 +1,32 @@ +// +// MockCoreDataMigrator.swift +// CoreDataMigration-ExampleTests +// +// Created by William Boles on 02/01/2019. +// Copyright © 2017 William Boles. All rights reserved. +// + +import Foundation +import CoreData + +@testable import CoreDataMigration_Example + +class MockCoreDataMigrator: CoreDataMigratorProtocol { + + var requiresMigrationWasCalled = false + var migrateStoreWasCalled = false + + var requiresMigrationToBeReturned = false + + // MARK: - CoreDataMigratorProtocol + + func requiresMigration(at: URL, toVersion: CoreDataMigrationVersion) -> Bool { + requiresMigrationWasCalled = true + + return requiresMigrationToBeReturned + } + + func migrateStore(at storeURL: URL, toVersion version: CoreDataMigrationVersion) { + migrateStoreWasCalled = true + } +} diff --git a/Gemfile b/Gemfile index bb72365..b216561 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source "https://rubygems.org" -gem "fastlane", "2.56.0" +gem "fastlane", "2.104.0" diff --git a/Gemfile.lock b/Gemfile.lock index 53b91dc..74ad8df 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,44 +1,47 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (2.3.5) + CFPropertyList (3.0.0) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) + atomos (0.1.3) babosa (1.0.2) claide (1.0.2) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.5) + commander-fastlane (4.4.6) highline (~> 1.7.2) declarative (0.0.10) declarative-option (0.1.0) - domain_name (0.5.20170404) + domain_name (0.5.20180417) unf (>= 0.0.5, < 1.0.0) - dotenv (2.2.1) - excon (0.59.0) - faraday (0.13.1) + dotenv (2.5.0) + emoji_regex (0.1.1) + excon (0.62.0) + faraday (0.15.4) multipart-post (>= 1.2, < 3) faraday-cookie_jar (0.0.6) faraday (>= 0.7.4) http-cookie (~> 1.0.0) faraday_middleware (0.12.2) faraday (>= 0.7.4, < 1.0) - fastimage (2.1.0) - fastlane (2.56.0) - CFPropertyList (>= 2.3, < 3.0.0) + fastimage (2.1.5) + fastlane (2.104.0) + CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.3, < 3.0.0) babosa (>= 1.0.2, < 2.0.0) bundler (>= 1.12.0, < 2.0.0) colored - commander-fastlane (>= 4.4.5, < 5.0.0) + commander-fastlane (>= 4.4.6, < 5.0.0) dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (~> 0.1) excon (>= 0.45.0, < 1.0.0) faraday (~> 0.9) faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 0.9) fastimage (>= 2.1.0, < 3.0.0) - gh_inspector (>= 1.0.1, < 2.0.0) - google-api-client (>= 0.13.1, < 0.14.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-api-client (>= 0.21.2, < 0.24.0) highline (>= 1.7.2, < 2.0.0) json (< 3.0.0) mini_magick (~> 4.5.1) @@ -47,93 +50,99 @@ GEM multipart-post (~> 2.0.0) plist (>= 3.1.0, < 4.0.0) public_suffix (~> 2.0.0) - rubyzip (>= 1.1.0, < 2.0.0) + rubyzip (>= 1.2.2, < 2.0.0) security (= 0.1.3) - slack-notifier (>= 1.3, < 2.0.0) + simctl (~> 1.6.3) + slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 1.6.2, < 2.0.0) terminal-table (>= 1.4.5, < 2.0.0) - tty-screen (~> 0.5.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) - xcodeproj (>= 1.5.0, < 2.0.0) - xcpretty (>= 0.2.4, < 1.0.0) + xcodeproj (>= 1.6.0, < 2.0.0) + xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - gh_inspector (1.0.3) - google-api-client (0.13.6) + gh_inspector (1.1.3) + google-api-client (0.23.9) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.5) + googleauth (>= 0.5, < 0.7.0) httpclient (>= 2.8.1, < 3.0) mime-types (~> 3.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - googleauth (0.5.3) + signet (~> 0.9) + googleauth (0.6.7) faraday (~> 0.12) - jwt (~> 1.4) - logging (~> 2.0) - memoist (~> 0.12) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) multi_json (~> 1.11) - os (~> 0.9) + os (>= 0.9, < 2.0) signet (~> 0.7) - highline (1.7.8) + highline (1.7.10) http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) json (2.1.0) jwt (1.5.6) - little-plugger (1.1.4) - logging (2.2.2) - little-plugger (~> 1.1) - multi_json (~> 1.10) memoist (0.16.0) - mime-types (3.1) + mime-types (3.2.2) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) + mime-types-data (3.2018.0812) mini_magick (4.5.1) - multi_json (1.12.2) + multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) - nanaimo (0.2.3) - os (0.9.6) - plist (3.3.0) + nanaimo (0.2.6) + naturally (2.2.0) + os (1.0.0) + plist (3.5.0) public_suffix (2.0.5) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) uber (< 0.2.0) - retriable (3.1.1) + retriable (3.1.2) rouge (2.0.7) - rubyzip (1.2.1) + rubyzip (1.2.2) security (0.1.3) - signet (0.7.3) + signet (0.11.0) addressable (~> 2.3) faraday (~> 0.9) - jwt (~> 1.5) + jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - slack-notifier (1.5.1) + simctl (1.6.5) + CFPropertyList + naturally + slack-notifier (2.3.2) terminal-notifier (1.8.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - tty-screen (0.5.0) + tty-cursor (0.6.0) + tty-screen (0.6.5) + tty-spinner (0.9.0) + tty-cursor (~> 0.6.0) uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.4) - unicode-display_width (1.3.0) + unf_ext (0.0.7.5) + unicode-display_width (1.4.1) word_wrap (1.0.0) - xcodeproj (1.5.1) - CFPropertyList (~> 2.3.3) + xcodeproj (1.7.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.3) - xcpretty (0.2.8) + nanaimo (~> 0.2.6) + xcpretty (0.3.0) rouge (~> 2.0.7) - xcpretty-travis-formatter (0.0.4) + xcpretty-travis-formatter (1.0.0) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS ruby DEPENDENCIES - fastlane (= 2.56.0) + fastlane (= 2.104.0) BUNDLED WITH - 1.15.4 + 1.16.0 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 92d0de4..16ff883 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -2,14 +2,14 @@ fastlane_version "2.56.0" default_platform :ios platform :ios do - + # Common - lane :run_tests do + lane :run_unit_tests do scan( scheme: 'CoreDataMigration-Example', skip_build: true ) end - -end \ No newline at end of file + +end diff --git a/fastlane/README.md b/fastlane/README.md index 78f644b..dad888a 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -8,31 +8,17 @@ Make sure you have the latest version of the Xcode command line tools installed: xcode-select --install ``` -## Choose your installation method: - - - - - - - - - - - - - - -
Homebrew -Installer Script -Rubygems -
macOSmacOSmacOS or Linux with Ruby 2.0.0 or above
brew cask install fastlaneDownload the zip file. Then double click on the install script (or run it in a terminal window).sudo gem install fastlane -NV
+Install _fastlane_ using +``` +[sudo] gem install fastlane -NV +``` +or alternatively using `brew cask install fastlane` # Available Actions ## iOS -### ios run_tests +### ios run_unit_tests ``` -fastlane ios run_tests +fastlane ios run_unit_tests ```