From 493b3783f05c9a0447b6a34da3803cfc378972be Mon Sep 17 00:00:00 2001 From: Joe Mattiello Date: Wed, 1 Mar 2023 00:48:36 -0500 Subject: [PATCH] Create swift package --- .codecov.yml | 21 + .editorconfig | 44 +- .gitmodules | 13 +- .jazzy.yaml | 28 + .swiftformat | 42 + .swiftlint.yml | 76 + AltStore-SPM.xcodeproj/project.pbxproj | 720 ++++ .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/swiftpm/Package.resolved | 31 +- AltStore.xcodeproj/project.pbxproj | 3435 ----------------- .../xcshareddata/xcschemes/AltDaemon.xcscheme | 111 - .../xcshareddata/xcschemes/AltPlugin.xcscheme | 67 - .../xcshareddata/xcschemes/AltServer.xcscheme | 91 - .../xcschemes/AltStore - Release.xcscheme | 84 - .../xcshareddata/xcschemes/AltStore.xcscheme | 84 - .../xcshareddata/xcschemes/AltXPC.xcscheme | 77 - AltStore/AltStore-Bridging-Header.h | 8 - AltStore/App Detail/AppViewController.swift | 570 --- .../AuthenticationViewController.swift | 171 - .../InstructionsViewController.swift | 54 - .../Browse/ScreenshotCollectionViewCell.swift | 44 - AltStore/Components/AppBannerView.swift | 144 - AltStore/Components/AppIconImageView.swift | 43 - AltStore/Components/CollapsingTextView.swift | 119 - AltStore/Components/PillButton.swift | 192 - .../InstalledAppsCollectionHeaderView.swift | 44 - .../My Apps/UpdateCollectionViewCell.swift | 108 - AltStore/News/NewsCollectionViewCell.swift | 30 - AltStore/Operations/Operation.swift | 93 - .../Patch App/PatchViewController.swift | 499 --- .../Settings/InsetGroupTableViewCell.swift | 132 - .../Settings/LicensesViewController.swift | 53 - AltStore/Settings/PatreonComponents.swift | 96 - .../Settings/SettingsHeaderFooterView.swift | 36 - AltStoreCore/AltStoreCore.h | 25 - AltStoreCore/Model/InstalledExtension.swift | 75 - AltStoreCore/Patreon/Benefit.swift | 27 - AltStoreCore/Patreon/Tier.swift | 50 - AltStoreCore/Types/ALTAppPermission.h | 28 - AltStoreCore/Types/ALTAppPermission.m | 27 - AltStoreCore/Types/ALTPatreonBenefitType.h | 13 - AltStoreCore/Types/ALTPatreonBenefitType.m | 12 - AltStoreCore/Types/ALTSourceUserInfoKey.h | 12 - AltStoreCore/Types/ALTSourceUserInfoKey.m | 11 - Configurations/Archive.xcconfig | 1 + Configurations/Debug.xcconfig | 1 + Configurations/Release.xcconfig | 1 + Configurations/Shared.xcconfig | 1 + Dependencies/MarkdownAttributedString | 1 - Dependencies/em_proxy | 1 + .../em_proxy.xcodeproj/project.pbxproj | 343 -- Dependencies/em_proxy/.gitkeep | 1 - Dependencies/fetch-prebuilt.sh | 52 - Dependencies/libcurl/libcurl.a | Bin 2796140 -> 0 bytes Dependencies/libimobiledevice | 2 +- Dependencies/libplist | 2 +- Dependencies/libusbmuxd | 2 +- Dependencies/minimuxer | 1 + .../minimuxer.xcodeproj/project.pbxproj | 283 -- Dependencies/minimuxer/.gitkeep | 1 - Package.resolved | 104 + Package.swift | 289 ++ Plugins/CargoPlugin-Generate/Plugin.swift | 70 + Plugins/CargoPlugin/Plugin.swift | 70 + Shared/ALTConstants.h | 11 - Shared/ALTConstants.m | 11 - .../Categories/CFNotificationName+AltStore.h | 17 - .../Categories/CFNotificationName+AltStore.m | 13 - Shared/Extensions/NSError+AltStore.swift | 143 - Shared/XPC/AltXPCProtocol.h | 18 - Sources/AltBackup/ViewController.swift | 206 - .../AltPatcher}/ALTAppPatcher.h | 0 .../AltPatcher}/ALTAppPatcher.m | 0 .../include/ALTAppPatcher/ALTAppPatcher.h | 19 + .../include/ALTAppPatcher/_ALTAppPatcher.h | 1 + Sources/Cargo/Commands/Build.swift | 61 + Sources/Cargo/Commands/Cargo.swift | 22 + ....ExcludingOptions+RulesFilterOptions.swift | 20 + .../Commands/Common/RulesFilterOptions.swift | 20 + Sources/Cargo/Commands/Version.swift | 23 + .../Cargo/swiftlint/Commands/Analyze.swift | 61 + ....ExcludingOptions+RulesFilterOptions.swift | 20 + .../Commands/Common/RulesFilterOptions.swift | 20 + Sources/Cargo/swiftlint/Commands/Docs.swift | 43 + .../swiftlint/Commands/GenerateDocs.swift | 28 + Sources/Cargo/swiftlint/Commands/Lint.swift | 64 + Sources/Cargo/swiftlint/Commands/Rules.swift | 123 + .../Cargo/swiftlint/Commands/SwiftLint.swift | 26 + .../Cargo/swiftlint/Commands/Version.swift | 23 + .../Configuration+CommandLine.swift | 283 ++ .../Extensions/ProcessInfo+XcodeCloud.swift | 28 + .../Cargo/swiftlint/Helpers/Benchmark.swift | 52 + .../Helpers/CompilerArgumentsExtractor.swift | 108 + .../Cargo/swiftlint/Helpers/ExitHelper.swift | 12 + .../Helpers/LintOrAnalyzeArguments.swift | 63 + .../Helpers/LintOrAnalyzeCommand.swift | 342 ++ .../Helpers/LintableFilesVisitor.swift | 253 ++ .../Cargo/swiftlint/Helpers/ProgressBar.swift | 63 + .../Cargo/swiftlint/Helpers/RulesFilter.swift | 49 + .../Cargo/swiftlint/Helpers/Signposts.swift | 73 + .../swiftlint/Helpers/SwiftLintError.swift | 12 + .../Helpers/SwiftPMCompilationDB.swift | 74 + Sources/Cargo/xcframework/BuildSetting.swift | 59 + .../Cargo/xcframework/Command+Options.swift | 71 + Sources/Cargo/xcframework/Command.swift | 142 + .../Extensions/Collection+Extensions.swift | 12 + .../Extensions/PackageModel+Extensions.swift | 27 + Sources/Cargo/xcframework/Platforms.swift | 113 + Sources/Cargo/xcframework/main.swift | 9 + .../EmotionalDamage}/EmotionalDamage.swift | 3 +- .../MiniMuxerSwift/MiniMuxer.swift | 52 +- Sources/Shared/AltConstants.swift | 10 + .../Shared/CFNotificationName+AltStore.swift | 13 + .../Shared}/Connections/Connection.swift | 105 +- .../Connections/ConnectionManager.swift | 170 +- .../Connections/NetworkConnection.swift | 41 +- .../Shared}/Connections/XPCConnection.swift | 114 +- .../Shared}/Extensions/Bundle+AltStore.swift | 49 +- .../Shared/Extensions/NSError+AltStore.swift | 128 + .../NSXPCConnection+MachServices.swift | 15 +- .../Extensions/Result+Conveniences.swift | 61 +- Sources/Shared/XPC/AltXPCProtocol.swift | 21 + .../AltBackup.entitlements | 0 .../AppDelegate.swift | 92 +- .../AppIcon.appiconset/Contents.json | 0 .../Background.colorset/Contents.json | 0 .../SideBackup/Assets.xcassets}/Contents.json | 0 .../Text.colorset/Contents.json | 0 .../BackupController.swift | 234 +- .../Base.lproj/LaunchScreen.storyboard | 0 Sources/{AltBackup => SideBackup}/Info.plist | 0 .../UIColor+AltBackup.swift | 3 +- Sources/SideBackup/ViewController.swift | 189 + .../SideDaemon}/AltDaemon-Bridging-Header.h | 0 .../SideDaemon}/AltDaemon.entitlements | 0 .../SideDaemon}/AnisetteDataManager.swift | 39 +- .../SideDaemon}/AppManager.swift | 116 +- .../SideDaemon}/DaemonRequestHandler.swift | 100 +- .../SideDaemon}/XPCConnectionHandler.swift | 63 +- {AltDaemon => Sources/SideDaemon}/main.swift | 0 .../SideDaemon}/package/DEBIAN/control | 0 .../SideDaemon}/package/DEBIAN/postinst | 0 .../SideDaemon}/package/DEBIAN/preinst | 0 .../SideDaemon}/package/DEBIAN/prerm | 0 .../com.rileytestut.altdaemon.plist | 0 .../SideDaemon}/package/usr/bin/AltDaemon | Bin .../ALTApplication+AltStoreApp.swift | 7 +- .../Analytics/AnalyticsManager.swift | 55 +- .../App Detail/AppContentViewController.swift | 229 +- .../AppContentViewControllerCells.swift | 35 +- .../App Detail/AppViewController.swift | 503 +++ .../PermissionPopoverViewController.swift | 18 +- .../App IDs/AppIDsViewController.swift | 201 +- .../SideStore}/AppDelegate.swift | 332 +- .../Authentication/Authentication.storyboard | 0 .../AuthenticationViewController.swift | 150 + .../InstructionsViewController.swift | 46 + .../RefreshAltStoreViewController.swift | 70 +- .../SelectTeamViewController.swift | 49 +- .../Browse/BrowseCollectionViewCell.swift | 69 +- .../Browse/BrowseCollectionViewCell.xib | 0 .../Browse/BrowseViewController.swift | 352 +- .../Browse/ScreenshotCollectionViewCell.swift | 39 + .../SideStore/Components/AppBannerView.swift | 128 + .../SideStore}/Components/AppBannerView.xib | 0 .../Components/AppIconImageView.swift | 36 + .../Components/BackgroundTaskManager.swift | 89 +- .../Components/BannerCollectionViewCell.swift | 29 +- .../SideStore}/Components/Button.swift | 54 +- .../Components/CollapsingTextView.swift | 106 + .../ForwardingNavigationController.swift | 9 +- .../SideStore}/Components/NavigationBar.swift | 91 +- Sources/SideStore/Components/PillButton.swift | 172 + .../TextCollectionReusableView.swift | 5 +- .../SideStore}/Components/ToastView.swift | 119 +- .../SideStore}/Consts/Consts+Proxy.swift | 2 +- .../SideStore}/Consts/Consts.swift | 4 +- .../FileManager+DirectorySize.swift | 26 +- .../Extensions/INInteraction+AltStore.swift | 8 +- .../Extensions/OSLog+SideStore.swift | 15 +- .../Extensions/UIDevice+Jailbreak.swift | 25 +- .../Extensions/UIDevice+Vibration.swift | 24 +- .../Extensions/UIScreen+CompactHeight.swift | 5 +- .../SideStore}/Intents/IntentHandler.swift | 116 +- .../Intents/Intents.intentdefinition | 0 .../SideStore}/LaunchViewController.swift | 160 +- .../SideStore}/Managing Apps/AppManager.swift | 1514 ++++---- .../Managing Apps/AppManagerErrors.swift | 73 +- .../InstalledAppsCollectionHeaderView.swift | 43 + .../InstalledAppsCollectionHeaderView.xib | 0 .../SideStore}/My Apps/MyAppsComponents.swift | 79 +- .../My Apps/MyAppsViewController.swift | 1879 ++++----- .../My Apps/UpdateCollectionViewCell.swift | 94 + .../My Apps/UpdateCollectionViewCell.xib | 0 .../News/NewsCollectionViewCell.swift | 28 + .../SideStore}/News/NewsViewController.swift | 528 ++- .../Operations/AuthenticationOperation.swift | 638 ++- .../BackgroundRefreshAppsOperation.swift | 217 +- .../Operations/BackupAppOperation.swift | 143 +- .../Operations/DeactivateAppOperation.swift | 38 +- .../Operations/DownloadAppOperation.swift | 291 +- .../Operations/EnableJITOperation.swift | 45 +- .../FetchAnisetteDataOperation.swift | 37 +- .../Operations/FetchAppIDsOperation.swift | 53 +- .../FetchProvisioningProfilesOperation.swift | 449 +-- .../Operations/FetchSourceOperation.swift | 79 +- .../FetchTrustedSourcesOperation.swift | 44 +- .../Operations/InstallAppOperation.swift | 162 +- Sources/SideStore/Operations/Operation.swift | 80 + .../Operations/OperationContexts.swift | 91 +- .../Operations/OperationError.swift | 64 +- .../Patch App/PatchAppOperation.swift | 228 +- .../Patch App/PatchViewController.swift | 443 +++ .../Operations/RefreshAppOperation.swift | 55 +- .../SideStore}/Operations/RefreshGroup.swift | 82 +- .../Operations/RemoveAppBackupOperation.swift | 70 +- .../Operations/RemoveAppOperation.swift | 41 +- .../Operations/ResignAppOperation.swift | 202 +- .../Operations/SendAppOperation.swift | 52 +- .../Operations/UpdatePatronsOperation.swift | 78 +- .../Operations/VerifyAppOperation.swift | 158 +- .../SideStore}/Resources/AltBackup.ipa | Bin .../Resources}/AltStore.entitlements | 0 .../AppIcon.appiconset/100.png | Bin .../AppIcon.appiconset/1024.png | Bin .../AppIcon.appiconset/114.png | Bin .../AppIcon.appiconset/120.png | Bin .../AppIcon.appiconset/144.png | Bin .../AppIcon.appiconset/152.png | Bin .../AppIcon.appiconset/167.png | Bin .../AppIcon.appiconset/180.png | Bin .../Assets.xcassets/AppIcon.appiconset/20.png | Bin .../Assets.xcassets/AppIcon.appiconset/29.png | Bin .../Assets.xcassets/AppIcon.appiconset/40.png | Bin .../Assets.xcassets/AppIcon.appiconset/50.png | Bin .../Assets.xcassets/AppIcon.appiconset/57.png | Bin .../Assets.xcassets/AppIcon.appiconset/58.png | Bin .../Assets.xcassets/AppIcon.appiconset/60.png | Bin .../Assets.xcassets/AppIcon.appiconset/72.png | Bin .../Assets.xcassets/AppIcon.appiconset/76.png | Bin .../Assets.xcassets/AppIcon.appiconset/80.png | Bin .../Assets.xcassets/AppIcon.appiconset/87.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Back.imageset/Back@2x.png | Bin .../Back.imageset/Contents.json | 0 .../BetaBadge.imageset/BETA.png | Bin .../BetaBadge.imageset/BETA@2x.png | Bin .../BetaBadge.imageset/BETA@3x.png | Bin .../BetaBadge.imageset/Contents.json | 0 .../Colors/Background.colorset/Contents.json | 0 .../Colors/BlurTint.colorset/Contents.json | 0 .../Assets.xcassets/Colors}/Contents.json | 0 .../SettingsBackground.colorset/Contents.json | 0 .../Contents.json | 0 .../Resources/Assets.xcassets}/Contents.json | 0 .../Assets.xcassets/Next.imageset/Back@2x.png | Bin .../Next.imageset/Contents.json | 0 .../Riley.imageset/Contents.json | 0 .../Assets.xcassets/Riley.imageset/riley.jpg | Bin .../Shane.imageset/Contents.json | 0 .../Assets.xcassets/Shane.imageset/shane.jpeg | Bin .../Tabs/Browse.imageset/Combined Shape.png | Bin .../Browse.imageset/Combined Shape@2x.png | Bin .../Browse.imageset/Combined Shape@3x.png | Bin .../Tabs/Browse.imageset/Contents.json | 0 .../Assets.xcassets/Tabs/Contents.json | 0 .../Tabs/MyApps.imageset/Contents.json | 0 .../Tabs/MyApps.imageset/Group 10.png | Bin .../Tabs/MyApps.imageset/Group 11.png | Bin .../Tabs/MyApps.imageset/Group 12.png | Bin .../Tabs/News.imageset/Contents.json | 0 .../Tabs/News.imageset/Group 6@2x.png | Bin .../Tabs/News.imageset/Group 6@3x.png | Bin .../Tabs/News.imageset/Group 8.png | Bin .../Tabs/Settings.imageset/Contents.json | 0 .../noun_Settings_1187813.png | Bin .../noun_Settings_1187813@2x.png | Bin .../noun_Settings_1187813@3x.png | Bin .../Base.lproj/LaunchScreen.storyboard | 0 .../Resources}/Base.lproj/Main.storyboard | 0 .../SideStore/Resources}/Info.plist | 0 .../Resources}/NewsCollectionViewCell.xib | 0 .../SideStore/Resources}/PatchApp.storyboard | 0 .../Resources}/Settings.bundle/Root.plist | 0 .../Settings.bundle/en.lproj/Root.strings | Bin .../SideStore}/Resources/Silence.m4a | Bin .../SideStore}/Resources/apps-alpha.json | 0 .../SideStore}/Resources/apps.json | 0 .../SideStore}/Resources/tempEnt.plist | 0 .../SideStore}/SceneDelegate.swift | 95 +- .../Settings/AboutPatreonHeaderView.xib | 0 .../SideStore}/Settings/AnisetteManager.swift | 25 +- .../Error Log/ErrorLogTableViewCell.swift | 41 +- .../Error Log/ErrorLogViewController.swift | 227 +- .../Settings/InsetGroupTableViewCell.swift | 114 + .../Settings/LicensesViewController.swift | 48 + .../Settings/PatreonComponents.swift | 87 + .../Settings/PatreonViewController.swift | 292 +- .../RefreshAttemptsViewController.swift | 42 +- .../SideStore}/Settings/Settings.storyboard | 0 .../Settings/SettingsHeaderFooterView.swift | 34 + .../Settings/SettingsHeaderFooterView.xib | 0 .../Settings/SettingsViewController.swift | 531 ++- .../Sources/SourcesViewController.swift | 503 +-- .../SideStore}/TabBarController.swift | 117 +- .../SideStore}/Types/LoadingState.swift | 3 +- .../SideStore}/Types/Managed.swift | 31 +- .../Types/ScreenshotProcessor.swift | 11 +- .../SideStoreCore}/Components/Keychain.swift | 68 +- .../Extensions/Date+RelativeDate.swift | 22 +- .../FileManager+SharedDirectories.swift | 18 +- .../Extensions/JSONDecoder+Properties.swift | 31 +- .../UIApplication+AppExtension.swift | 5 +- .../Extensions/UIColor+AltStore.swift | 9 +- .../Extensions/UIColor+Hex.swift | 16 +- .../Extensions/UserDefaults+AltStore.swift | 48 +- .../Intents/ViewAppIntentHandler.swift | 23 +- .../SideStoreCore}/Model/Account.swift | 56 +- .../SideStoreCore}/Model/AppID.swift | 39 +- .../SideStoreCore}/Model/AppPermission.swift | 66 +- .../SideStoreCore}/Model/AppVersion.swift | 82 +- .../Model/DatabaseManager.swift | 369 +- .../SideStoreCore}/Model/InstalledApp.swift | 279 +- .../Model/InstalledExtension.swift | 67 + .../SideStoreCore}/Model/LoggedError.swift | 99 +- .../SideStoreCore}/Model/ManagedPatron.swift | 25 +- .../SideStoreCore}/Model/MergePolicy.swift | 77 +- .../SideStoreCore}/Model/NewsItem.swift | 71 +- .../SideStoreCore}/Model/PatreonAccount.swift | 54 +- .../SideStoreCore}/Model/RefreshAttempt.swift | 51 +- .../Model/SecureValueTransformer.swift | 12 +- .../SideStoreCore}/Model/Source.swift | 209 +- .../SideStoreCore}/Model/StoreApp.swift | 284 +- .../SideStoreCore}/Model/Team.swift | 59 +- Sources/SideStoreCore/Patreon/Benefit.swift | 29 + .../SideStoreCore}/Patreon/Campaign.swift | 16 +- .../SideStoreCore}/Patreon/PatreonAPI.swift | 360 +- .../SideStoreCore}/Patreon/Patron.swift | 63 +- Sources/SideStoreCore/Patreon/Tier.swift | 43 + .../Protocols/AppProtocol.swift | 28 +- .../SideStoreCore}/Protocols/Fetchable.swift | 59 +- .../AltStore.xcdatamodeld/.xccurrentversion | 0 .../AltStore 10.xcdatamodel/contents | 0 .../AltStore 11.xcdatamodel/contents | 0 .../AltStore 2.xcdatamodel/contents | 0 .../AltStore 3.xcdatamodel/contents | 0 .../AltStore 4.xcdatamodel/contents | 0 .../AltStore 5.xcdatamodel/contents | 0 .../AltStore 6.xcdatamodel/contents | 0 .../AltStore 7.xcdatamodel/contents | 0 .../AltStore 8.xcdatamodel/contents | 0 .../AltStore 9.xcdatamodel/contents | 0 .../AltStore.xcdatamodel/contents | 0 .../Resources/Colors.xcassets}/Contents.json | 0 .../DeltaPrimary.colorset/Contents.json | 0 .../Pink.colorset/Contents.json | 0 .../Primary.colorset/Contents.json | 0 .../RefreshGreen.colorset/Contents.json | 0 .../RefreshOrange.colorset/Contents.json | 0 .../RefreshRed.colorset/Contents.json | 0 .../RefreshYellow.colorset/Contents.json | 0 .../SideStoreCore/Resources}/Info.plist | 0 .../Intents/ViewApp.intentdefinition | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../xcmapping.xml | 0 .../Policies/InstalledAppPolicy.swift | 38 +- .../StoreApp10ToStoreApp11Policy.swift | 62 +- .../Migrations/Policies/StoreAppPolicy.swift | 15 +- .../Types/ALTAppPermission.swift | 69 + .../Types/ALTSourceUserInfoKey.swift | 21 + .../SideWidget}/AltWidget.swift | 182 +- .../SideWidget}/ComplicationView.swift | 83 +- .../SideWidget}/Countdown.swift | 39 +- .../AltWidgetExtension.entitlements | 0 .../AccentColor.colorset/Contents.json | 0 .../AltStore.imageset/Contents.json | 0 .../AltStore.imageset/Group 23_120.png | Bin .../AltStore.imageset/Group 23_180.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../Badge.imageset/Contents.json | 0 .../Badge.imageset/group16Copy2.pdf | Bin .../Resources}/Assets.xcassets/Contents.json | 0 .../Delta.imageset/Contents.json | 0 .../Delta.imageset/icon-120.png | Bin .../Delta.imageset/icon-180.png | Bin .../SmallIcon.imageset/Contents.json | 0 .../SmallIcon.imageset/altminicon.pdf | Bin .../WidgetBackground.colorset/Contents.json | 0 .../SideWidget/Resources}/Info.plist | 0 .../SideWidget}/WidgetView.swift | 99 +- .../libfragmentzip/include}/fragmentzip.h | 0 .../libfragmentzip/libfragmentzip-source | 0 Tests/CargoTests/CargoTests.swift | 34 + .../EmotionalDamageTests.swift | 34 + Tests/MiniMuxerTests/MiniMuxerTests.swift | 34 + Tests/SharedTests/SharedTests.swift | 34 + Tests/SideDaemonTests/SideDaemonTests.swift | 34 + .../SideStoreCoreTests.swift | 34 + Tests/SideStoreTests/SideStoreTests.swift | 34 + Tests/SideWidgetTests/SideWidgetTests.swift | 34 + .../libfragmentzipTests.swift | 34 + 409 files changed, 13707 insertions(+), 16923 deletions(-) create mode 100644 .codecov.yml create mode 100644 .jazzy.yaml create mode 100644 .swiftformat create mode 100644 .swiftlint.yml create mode 100644 AltStore-SPM.xcodeproj/project.pbxproj rename {AltStore.xcodeproj => AltStore-SPM.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename {AltStore.xcodeproj => AltStore-SPM.xcodeproj}/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {AltStore.xcodeproj => AltStore-SPM.xcodeproj}/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (78%) delete mode 100644 AltStore.xcodeproj/project.pbxproj delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltDaemon.xcscheme delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltPlugin.xcscheme delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltServer.xcscheme delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltStore - Release.xcscheme delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltStore.xcscheme delete mode 100644 AltStore.xcodeproj/xcshareddata/xcschemes/AltXPC.xcscheme delete mode 100644 AltStore/AltStore-Bridging-Header.h delete mode 100644 AltStore/App Detail/AppViewController.swift delete mode 100644 AltStore/Authentication/AuthenticationViewController.swift delete mode 100644 AltStore/Authentication/InstructionsViewController.swift delete mode 100644 AltStore/Browse/ScreenshotCollectionViewCell.swift delete mode 100644 AltStore/Components/AppBannerView.swift delete mode 100644 AltStore/Components/AppIconImageView.swift delete mode 100644 AltStore/Components/CollapsingTextView.swift delete mode 100644 AltStore/Components/PillButton.swift delete mode 100644 AltStore/My Apps/InstalledAppsCollectionHeaderView.swift delete mode 100644 AltStore/My Apps/UpdateCollectionViewCell.swift delete mode 100644 AltStore/News/NewsCollectionViewCell.swift delete mode 100644 AltStore/Operations/Operation.swift delete mode 100644 AltStore/Operations/Patch App/PatchViewController.swift delete mode 100644 AltStore/Settings/InsetGroupTableViewCell.swift delete mode 100644 AltStore/Settings/LicensesViewController.swift delete mode 100644 AltStore/Settings/PatreonComponents.swift delete mode 100644 AltStore/Settings/SettingsHeaderFooterView.swift delete mode 100644 AltStoreCore/AltStoreCore.h delete mode 100644 AltStoreCore/Model/InstalledExtension.swift delete mode 100644 AltStoreCore/Patreon/Benefit.swift delete mode 100644 AltStoreCore/Patreon/Tier.swift delete mode 100644 AltStoreCore/Types/ALTAppPermission.h delete mode 100644 AltStoreCore/Types/ALTAppPermission.m delete mode 100644 AltStoreCore/Types/ALTPatreonBenefitType.h delete mode 100644 AltStoreCore/Types/ALTPatreonBenefitType.m delete mode 100644 AltStoreCore/Types/ALTSourceUserInfoKey.h delete mode 100644 AltStoreCore/Types/ALTSourceUserInfoKey.m create mode 100644 Configurations/Archive.xcconfig create mode 100644 Configurations/Debug.xcconfig create mode 100644 Configurations/Release.xcconfig create mode 100644 Configurations/Shared.xcconfig delete mode 160000 Dependencies/MarkdownAttributedString create mode 160000 Dependencies/em_proxy delete mode 100644 Dependencies/em_proxy.xcodeproj/project.pbxproj delete mode 100644 Dependencies/em_proxy/.gitkeep delete mode 100644 Dependencies/fetch-prebuilt.sh delete mode 100644 Dependencies/libcurl/libcurl.a create mode 160000 Dependencies/minimuxer delete mode 100644 Dependencies/minimuxer.xcodeproj/project.pbxproj delete mode 100644 Dependencies/minimuxer/.gitkeep create mode 100644 Package.resolved create mode 100644 Package.swift create mode 100644 Plugins/CargoPlugin-Generate/Plugin.swift create mode 100644 Plugins/CargoPlugin/Plugin.swift delete mode 100644 Shared/ALTConstants.h delete mode 100644 Shared/ALTConstants.m delete mode 100644 Shared/Categories/CFNotificationName+AltStore.h delete mode 100644 Shared/Categories/CFNotificationName+AltStore.m delete mode 100644 Shared/Extensions/NSError+AltStore.swift delete mode 100644 Shared/XPC/AltXPCProtocol.h delete mode 100644 Sources/AltBackup/ViewController.swift rename {AltStore/Operations/Patch App => Sources/AltPatcher}/ALTAppPatcher.h (100%) rename {AltStore/Operations/Patch App => Sources/AltPatcher}/ALTAppPatcher.m (100%) create mode 100644 Sources/AltPatcher/include/ALTAppPatcher/ALTAppPatcher.h create mode 120000 Sources/AltPatcher/include/ALTAppPatcher/_ALTAppPatcher.h create mode 100644 Sources/Cargo/Commands/Build.swift create mode 100644 Sources/Cargo/Commands/Cargo.swift create mode 100644 Sources/Cargo/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift create mode 100644 Sources/Cargo/Commands/Common/RulesFilterOptions.swift create mode 100644 Sources/Cargo/Commands/Version.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Analyze.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Common/RulesFilterOptions.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Docs.swift create mode 100644 Sources/Cargo/swiftlint/Commands/GenerateDocs.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Lint.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Rules.swift create mode 100644 Sources/Cargo/swiftlint/Commands/SwiftLint.swift create mode 100644 Sources/Cargo/swiftlint/Commands/Version.swift create mode 100644 Sources/Cargo/swiftlint/Extensions/Configuration+CommandLine.swift create mode 100644 Sources/Cargo/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/Benchmark.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/CompilerArgumentsExtractor.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/ExitHelper.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeArguments.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeCommand.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/LintableFilesVisitor.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/ProgressBar.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/RulesFilter.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/Signposts.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/SwiftLintError.swift create mode 100644 Sources/Cargo/swiftlint/Helpers/SwiftPMCompilationDB.swift create mode 100644 Sources/Cargo/xcframework/BuildSetting.swift create mode 100644 Sources/Cargo/xcframework/Command+Options.swift create mode 100644 Sources/Cargo/xcframework/Command.swift create mode 100644 Sources/Cargo/xcframework/Extensions/Collection+Extensions.swift create mode 100644 Sources/Cargo/xcframework/Extensions/PackageModel+Extensions.swift create mode 100644 Sources/Cargo/xcframework/Platforms.swift create mode 100644 Sources/Cargo/xcframework/main.swift rename {EmotionalDamage => Sources/EmotionalDamage}/EmotionalDamage.swift (85%) rename minimuxer/minimuxer.swift => Sources/MiniMuxerSwift/MiniMuxer.swift (67%) create mode 100644 Sources/Shared/AltConstants.swift create mode 100644 Sources/Shared/CFNotificationName+AltStore.swift rename {Shared => Sources/Shared}/Connections/Connection.swift (66%) rename {Shared => Sources/Shared}/Connections/ConnectionManager.swift (62%) rename {Shared => Sources/Shared}/Connections/NetworkConnection.swift (52%) rename {Shared => Sources/Shared}/Connections/XPCConnection.swift (65%) rename {Shared => Sources/Shared}/Extensions/Bundle+AltStore.swift (61%) create mode 100644 Sources/Shared/Extensions/NSError+AltStore.swift rename {Shared => Sources/Shared}/Extensions/NSXPCConnection+MachServices.swift (85%) rename {Shared => Sources/Shared}/Extensions/Result+Conveniences.swift (51%) create mode 100644 Sources/Shared/XPC/AltXPCProtocol.swift rename Sources/{AltBackup => SideBackup}/AltBackup.entitlements (100%) rename Sources/{AltBackup => SideBackup}/AppDelegate.swift (73%) rename {AltWidget => Sources/SideBackup}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename Sources/{AltBackup => SideBackup}/Assets.xcassets/Background.colorset/Contents.json (100%) rename {AltStore/Resources/Assets.xcassets/Colors => Sources/SideBackup/Assets.xcassets}/Contents.json (100%) rename Sources/{AltBackup => SideBackup}/Assets.xcassets/Text.colorset/Contents.json (100%) rename Sources/{AltBackup => SideBackup}/BackupController.swift (76%) rename Sources/{AltBackup => SideBackup}/Base.lproj/LaunchScreen.storyboard (100%) rename Sources/{AltBackup => SideBackup}/Info.plist (100%) rename Sources/{AltBackup => SideBackup}/UIColor+AltBackup.swift (93%) create mode 100644 Sources/SideBackup/ViewController.swift rename {AltDaemon => Sources/SideDaemon}/AltDaemon-Bridging-Header.h (100%) rename {AltDaemon => Sources/SideDaemon}/AltDaemon.entitlements (100%) rename {AltDaemon => Sources/SideDaemon}/AnisetteDataManager.swift (79%) rename {AltDaemon => Sources/SideDaemon}/AppManager.swift (73%) rename {AltDaemon => Sources/SideDaemon}/DaemonRequestHandler.swift (71%) rename {AltDaemon => Sources/SideDaemon}/XPCConnectionHandler.swift (75%) rename {AltDaemon => Sources/SideDaemon}/main.swift (100%) rename {AltDaemon => Sources/SideDaemon}/package/DEBIAN/control (100%) rename {AltDaemon => Sources/SideDaemon}/package/DEBIAN/postinst (100%) rename {AltDaemon => Sources/SideDaemon}/package/DEBIAN/preinst (100%) rename {AltDaemon => Sources/SideDaemon}/package/DEBIAN/prerm (100%) rename {AltDaemon => Sources/SideDaemon}/package/Library/LaunchDaemons/com.rileytestut.altdaemon.plist (100%) rename {AltDaemon => Sources/SideDaemon}/package/usr/bin/AltDaemon (100%) rename {Shared/Extensions => Sources/SideStore}/ALTApplication+AltStoreApp.swift (71%) rename {AltStore => Sources/SideStore}/Analytics/AnalyticsManager.swift (77%) rename {AltStore => Sources/SideStore}/App Detail/AppContentViewController.swift (51%) rename {AltStore => Sources/SideStore}/App Detail/AppContentViewControllerCells.swift (57%) create mode 100644 Sources/SideStore/App Detail/AppViewController.swift rename {AltStore => Sources/SideStore}/App Detail/PermissionPopoverViewController.swift (55%) rename {AltStore => Sources/SideStore}/App IDs/AppIDsViewController.swift (73%) rename {AltStore => Sources/SideStore}/AppDelegate.swift (72%) rename {AltStore => Sources/SideStore}/Authentication/Authentication.storyboard (100%) create mode 100644 Sources/SideStore/Authentication/AuthenticationViewController.swift create mode 100644 Sources/SideStore/Authentication/InstructionsViewController.swift rename {AltStore => Sources/SideStore}/Authentication/RefreshAltStoreViewController.swift (58%) rename {AltStore => Sources/SideStore}/Authentication/SelectTeamViewController.swift (57%) rename {AltStore => Sources/SideStore}/Browse/BrowseCollectionViewCell.swift (61%) rename {AltStore => Sources/SideStore}/Browse/BrowseCollectionViewCell.xib (100%) rename {AltStore => Sources/SideStore}/Browse/BrowseViewController.swift (53%) create mode 100644 Sources/SideStore/Browse/ScreenshotCollectionViewCell.swift create mode 100644 Sources/SideStore/Components/AppBannerView.swift rename {AltStore => Sources/SideStore}/Components/AppBannerView.xib (100%) create mode 100644 Sources/SideStore/Components/AppIconImageView.swift rename {AltStore => Sources/SideStore}/Components/BackgroundTaskManager.swift (57%) rename {AltStore => Sources/SideStore}/Components/BannerCollectionViewCell.swift (82%) rename {AltStore => Sources/SideStore}/Components/Button.swift (50%) create mode 100644 Sources/SideStore/Components/CollapsingTextView.swift rename {AltStore => Sources/SideStore}/Components/ForwardingNavigationController.swift (81%) rename {AltStore => Sources/SideStore}/Components/NavigationBar.swift (60%) create mode 100644 Sources/SideStore/Components/PillButton.swift rename {AltStore => Sources/SideStore}/Components/TextCollectionReusableView.swift (87%) rename {AltStore => Sources/SideStore}/Components/ToastView.swift (58%) rename {AltStore => Sources/SideStore}/Consts/Consts+Proxy.swift (94%) rename {AltStore => Sources/SideStore}/Consts/Consts.swift (87%) rename {AltStore => Sources/SideStore}/Extensions/FileManager+DirectorySize.swift (69%) rename {AltStore => Sources/SideStore}/Extensions/INInteraction+AltStore.swift (85%) rename {AltStore => Sources/SideStore}/Extensions/OSLog+SideStore.swift (77%) rename {AltStore => Sources/SideStore}/Extensions/UIDevice+Jailbreak.swift (75%) rename {AltStore => Sources/SideStore}/Extensions/UIDevice+Vibration.swift (64%) rename {AltStore => Sources/SideStore}/Extensions/UIScreen+CompactHeight.swift (72%) rename {AltStore => Sources/SideStore}/Intents/IntentHandler.swift (67%) rename {AltStore => Sources/SideStore}/Intents/Intents.intentdefinition (100%) rename {AltStore => Sources/SideStore}/LaunchViewController.swift (73%) rename {AltStore => Sources/SideStore}/Managing Apps/AppManager.swift (68%) rename {AltStore => Sources/SideStore}/Managing Apps/AppManagerErrors.swift (58%) create mode 100644 Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.swift rename {AltStore => Sources/SideStore}/My Apps/InstalledAppsCollectionHeaderView.xib (100%) rename {AltStore => Sources/SideStore}/My Apps/MyAppsComponents.swift (65%) rename {AltStore => Sources/SideStore}/My Apps/MyAppsViewController.swift (66%) create mode 100644 Sources/SideStore/My Apps/UpdateCollectionViewCell.swift rename {AltStore => Sources/SideStore}/My Apps/UpdateCollectionViewCell.xib (100%) create mode 100644 Sources/SideStore/News/NewsCollectionViewCell.swift rename {AltStore => Sources/SideStore}/News/NewsViewController.swift (52%) rename {AltStore => Sources/SideStore}/Operations/AuthenticationOperation.swift (67%) rename {AltStore => Sources/SideStore}/Operations/BackgroundRefreshAppsOperation.swift (73%) rename {AltStore => Sources/SideStore}/Operations/BackupAppOperation.swift (68%) rename {AltStore => Sources/SideStore}/Operations/DeactivateAppOperation.swift (78%) rename {AltStore => Sources/SideStore}/Operations/DownloadAppOperation.swift (62%) rename {AltStore => Sources/SideStore}/Operations/EnableJITOperation.swift (68%) rename {AltStore => Sources/SideStore}/Operations/FetchAnisetteDataOperation.swift (81%) rename {AltStore => Sources/SideStore}/Operations/FetchAppIDsOperation.swift (75%) rename {AltStore => Sources/SideStore}/Operations/FetchProvisioningProfilesOperation.swift (63%) rename {AltStore => Sources/SideStore}/Operations/FetchSourceOperation.swift (73%) rename {AltStore => Sources/SideStore}/Operations/FetchTrustedSourcesOperation.swift (60%) rename {AltStore => Sources/SideStore}/Operations/InstallAppOperation.swift (72%) create mode 100644 Sources/SideStore/Operations/Operation.swift rename {AltStore => Sources/SideStore}/Operations/OperationContexts.swift (67%) rename {AltStore => Sources/SideStore}/Operations/OperationError.swift (89%) rename {AltStore => Sources/SideStore}/Operations/Patch App/PatchAppOperation.swift (54%) create mode 100644 Sources/SideStore/Operations/Patch App/PatchViewController.swift rename {AltStore => Sources/SideStore}/Operations/RefreshAppOperation.swift (71%) rename {AltStore => Sources/SideStore}/Operations/RefreshGroup.swift (61%) rename {AltStore => Sources/SideStore}/Operations/RemoveAppBackupOperation.swift (51%) rename {AltStore => Sources/SideStore}/Operations/RemoveAppOperation.swift (67%) rename {AltStore => Sources/SideStore}/Operations/ResignAppOperation.swift (74%) rename {AltStore => Sources/SideStore}/Operations/SendAppOperation.swift (62%) rename {AltStore => Sources/SideStore}/Operations/UpdatePatronsOperation.swift (67%) rename {AltStore => Sources/SideStore}/Operations/VerifyAppOperation.swift (59%) rename {AltStore => Sources/SideStore}/Resources/AltBackup.ipa (100%) rename {AltStore => Sources/SideStore/Resources}/AltStore.entitlements (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/100.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/1024.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/114.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/120.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/144.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/152.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/167.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/180.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/20.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/29.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/40.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/50.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/57.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/58.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/60.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/72.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/76.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/80.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/87.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Back.imageset/Back@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Back.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/BetaBadge.imageset/BETA.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/BetaBadge.imageset/BETA@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/BetaBadge.imageset/BETA@3x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/BetaBadge.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json (100%) rename {AltStore/Resources/Assets.xcassets => Sources/SideStore/Resources/Assets.xcassets/Colors}/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json (100%) rename {AltStoreCore/Resources/Colors.xcassets => Sources/SideStore/Resources/Assets.xcassets}/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Next.imageset/Back@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Next.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Riley.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Riley.imageset/riley.jpg (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Shane.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Shane.imageset/shane.jpeg (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@3x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Browse.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/MyApps.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 10.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 11.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 12.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/News.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@3x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/News.imageset/Group 8.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Settings.imageset/Contents.json (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@2x.png (100%) rename {AltStore => Sources/SideStore}/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@3x.png (100%) rename {AltStore => Sources/SideStore/Resources}/Base.lproj/LaunchScreen.storyboard (100%) rename {AltStore => Sources/SideStore/Resources}/Base.lproj/Main.storyboard (100%) rename {AltStore => Sources/SideStore/Resources}/Info.plist (100%) rename {AltStore/News => Sources/SideStore/Resources}/NewsCollectionViewCell.xib (100%) rename {AltStore/Operations/Patch App => Sources/SideStore/Resources}/PatchApp.storyboard (100%) rename {AltStore => Sources/SideStore/Resources}/Settings.bundle/Root.plist (100%) rename {AltStore => Sources/SideStore/Resources}/Settings.bundle/en.lproj/Root.strings (100%) rename {AltStore => Sources/SideStore}/Resources/Silence.m4a (100%) rename {AltStore => Sources/SideStore}/Resources/apps-alpha.json (100%) rename {AltStore => Sources/SideStore}/Resources/apps.json (100%) rename {AltStore => Sources/SideStore}/Resources/tempEnt.plist (100%) rename {AltStore => Sources/SideStore}/SceneDelegate.swift (80%) rename {AltStore => Sources/SideStore}/Settings/AboutPatreonHeaderView.xib (100%) rename {AltStore => Sources/SideStore}/Settings/AnisetteManager.swift (82%) rename {AltStore => Sources/SideStore}/Settings/Error Log/ErrorLogTableViewCell.swift (69%) rename {AltStore => Sources/SideStore}/Settings/Error Log/ErrorLogViewController.swift (72%) create mode 100644 Sources/SideStore/Settings/InsetGroupTableViewCell.swift create mode 100644 Sources/SideStore/Settings/LicensesViewController.swift create mode 100644 Sources/SideStore/Settings/PatreonComponents.swift rename {AltStore => Sources/SideStore}/Settings/PatreonViewController.swift (63%) rename {AltStore => Sources/SideStore}/Settings/RefreshAttemptsViewController.swift (83%) rename {AltStore => Sources/SideStore}/Settings/Settings.storyboard (100%) create mode 100644 Sources/SideStore/Settings/SettingsHeaderFooterView.swift rename {AltStore => Sources/SideStore}/Settings/SettingsHeaderFooterView.xib (100%) rename {AltStore => Sources/SideStore}/Settings/SettingsViewController.swift (62%) rename {AltStore => Sources/SideStore}/Sources/SourcesViewController.swift (72%) rename {AltStore => Sources/SideStore}/TabBarController.swift (67%) rename {AltStore => Sources/SideStore}/Types/LoadingState.swift (91%) rename {AltStore => Sources/SideStore}/Types/Managed.swift (77%) rename {AltStore => Sources/SideStore}/Types/ScreenshotProcessor.swift (69%) rename {AltStoreCore => Sources/SideStoreCore}/Components/Keychain.swift (69%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/Date+RelativeDate.swift (65%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/FileManager+SharedDirectories.swift (50%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/JSONDecoder+Properties.swift (73%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/UIApplication+AppExtension.swift (74%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/UIColor+AltStore.swift (95%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/UIColor+Hex.swift (81%) rename {AltStoreCore => Sources/SideStoreCore}/Extensions/UserDefaults+AltStore.swift (85%) rename {AltStoreCore => Sources/SideStoreCore}/Intents/ViewAppIntentHandler.swift (51%) rename {AltStoreCore => Sources/SideStoreCore}/Model/Account.swift (59%) rename {AltStoreCore => Sources/SideStoreCore}/Model/AppID.swift (56%) rename {AltStoreCore => Sources/SideStoreCore}/Model/AppPermission.swift (82%) rename {AltStoreCore => Sources/SideStoreCore}/Model/AppVersion.swift (65%) rename {AltStoreCore => Sources/SideStoreCore}/Model/DatabaseManager.swift (69%) rename {AltStoreCore => Sources/SideStoreCore}/Model/InstalledApp.swift (72%) create mode 100644 Sources/SideStoreCore/Model/InstalledExtension.swift rename {AltStoreCore => Sources/SideStoreCore}/Model/LoggedError.swift (64%) rename {AltStoreCore => Sources/SideStoreCore}/Model/ManagedPatron.swift (59%) rename {AltStoreCore => Sources/SideStoreCore}/Model/MergePolicy.swift (77%) rename {AltStoreCore => Sources/SideStoreCore}/Model/NewsItem.swift (62%) rename {AltStoreCore => Sources/SideStoreCore}/Model/PatreonAccount.swift (61%) rename {AltStoreCore => Sources/SideStoreCore}/Model/RefreshAttempt.swift (57%) rename {AltStoreCore => Sources/SideStoreCore}/Model/SecureValueTransformer.swift (82%) rename {AltStoreCore => Sources/SideStoreCore}/Model/Source.swift (66%) rename {AltStoreCore => Sources/SideStoreCore}/Model/StoreApp.swift (66%) rename {AltStoreCore => Sources/SideStoreCore}/Model/Team.swift (66%) create mode 100644 Sources/SideStoreCore/Patreon/Benefit.swift rename {AltStoreCore => Sources/SideStoreCore}/Patreon/Campaign.swift (54%) rename {AltStoreCore => Sources/SideStoreCore}/Patreon/PatreonAPI.swift (67%) rename {AltStoreCore => Sources/SideStoreCore}/Patreon/Patron.swift (54%) create mode 100644 Sources/SideStoreCore/Patreon/Tier.swift rename {AltStoreCore => Sources/SideStoreCore}/Protocols/AppProtocol.swift (69%) rename {AltStoreCore => Sources/SideStoreCore}/Protocols/Fetchable.swift (78%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/.xccurrentversion (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 11.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 2.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 3.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 4.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 5.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 6.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 7.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 8.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore 9.xcdatamodel/contents (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/AltStore.xcdatamodeld/AltStore.xcdatamodel/contents (100%) rename {AltWidget/Assets.xcassets => Sources/SideStoreCore/Resources/Colors.xcassets}/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/DeltaPrimary.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/Pink.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/Primary.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/RefreshGreen.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/RefreshOrange.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/RefreshRed.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore}/Resources/Colors.xcassets/RefreshYellow.colorset/Contents.json (100%) rename {AltStoreCore => Sources/SideStoreCore/Resources}/Info.plist (100%) rename {AltStoreCore => Sources/SideStoreCore/Resources}/Intents/ViewApp.intentdefinition (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore10ToAltStore11.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore2ToAltStore3.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore3ToAltStore4.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore4ToAltStore5.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore5ToAltStore6.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore6ToAltStore7.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore8ToAltStore9.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStore9ToAltStore10.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Mapping Models/AltStoreToAltStore2.xcmappingmodel/xcmapping.xml (100%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Policies/InstalledAppPolicy.swift (84%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift (76%) rename {AltStoreCore/Model => Sources/SideStoreCore/Resources}/Migrations/Policies/StoreAppPolicy.swift (64%) create mode 100644 Sources/SideStoreCore/Types/ALTAppPermission.swift create mode 100644 Sources/SideStoreCore/Types/ALTSourceUserInfoKey.swift rename {AltWidget => Sources/SideWidget}/AltWidget.swift (72%) rename {AltWidget => Sources/SideWidget}/ComplicationView.swift (76%) rename {AltWidget => Sources/SideWidget}/Countdown.swift (76%) rename {AltWidget => Sources/SideWidget/Resources}/AltWidgetExtension.entitlements (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/AltStore.imageset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/AltStore.imageset/Group 23_120.png (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/AltStore.imageset/Group 23_180.png (100%) rename Sources/{AltBackup => SideWidget/Resources}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/Badge.imageset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/Badge.imageset/group16Copy2.pdf (100%) rename Sources/{AltBackup => SideWidget/Resources}/Assets.xcassets/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/Delta.imageset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/Delta.imageset/icon-120.png (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/Delta.imageset/icon-180.png (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/SmallIcon.imageset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/SmallIcon.imageset/altminicon.pdf (100%) rename {AltWidget => Sources/SideWidget/Resources}/Assets.xcassets/WidgetBackground.colorset/Contents.json (100%) rename {AltWidget => Sources/SideWidget/Resources}/Info.plist (100%) rename {AltWidget => Sources/SideWidget}/WidgetView.swift (81%) rename {AltStore/Operations/Patch App => Sources/libfragmentzip/include}/fragmentzip.h (100%) rename Dependencies/libfragmentzip => Sources/libfragmentzip/libfragmentzip-source (100%) create mode 100644 Tests/CargoTests/CargoTests.swift create mode 100644 Tests/EmotionalDamageTests/EmotionalDamageTests.swift create mode 100644 Tests/MiniMuxerTests/MiniMuxerTests.swift create mode 100644 Tests/SharedTests/SharedTests.swift create mode 100644 Tests/SideDaemonTests/SideDaemonTests.swift create mode 100644 Tests/SideStoreCoreTests/SideStoreCoreTests.swift create mode 100644 Tests/SideStoreTests/SideStoreTests.swift create mode 100644 Tests/SideWidgetTests/SideWidgetTests.swift create mode 100644 Tests/libfragmentzipTests/libfragmentzipTests.swift diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000..4191746e --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,21 @@ +# https://docs.codecov.io/docs/codecov-yaml + +codecov: + require_ci_to_pass: true + +coverage: + precision: 2 + round: down + range: "70...100" + ignore: + - Dependencies + status: + patch: + default: + if_no_uploads: error + changes: true + project: + default: + target: auto + if_no_uploads: error +comment: false diff --git a/.editorconfig b/.editorconfig index 1082d2c8..bc141890 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,39 +1,35 @@ -# EditorConfig is awesome: https://EditorConfig.org +# http://editorconfig.org -# top-most EditorConfig file root = true -# Unix-style newlines with a newline ending every file [*] +indent_style = space +charset = utf-8 +indent_size = 4 end_of_line = lf +trim_trailing_whitespace = true insert_final_newline = true -# Matches multiple files with brace expansion notation -# Set default charset -[*.{js,py}] -charset = utf-8# 4 space indentation +[*.{md,markdown}] +trim_trailing_whitespace = false -# Swift files -[*.swift] +[*.{c,h,m,mm}] +trim_trailing_whitespace = true indent_style = space -indent_size = 4 -charset = utf-8# 4 space indentation +indent_size = 2 -# 4 space indentation -[*.py] -indent_style = space -indent_size = 4 +[*.js] +indent_size = 2 -# Tab indentation (no size specified) -[Makefile] +[*.{swift}] +trim_trailing_whitespace = true indent_style = tab +indent_size = 4 -# Indentation override for all JS under lib directory -[lib/**.js] -indent_style = space -indent_size = 2 +[Makefile] +trim_trailing_whitespace = true +indent_style = tab +indent_size = 8 -# Matches the exact files either package.json or .travis.yml -[{package.json,.travis.yml}] -indent_style = space +[*.{yaml|yml}] indent_size = 2 diff --git a/.gitmodules b/.gitmodules index 5bb0834a..70b14234 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,12 +7,15 @@ [submodule "Dependencies/libplist"] path = Dependencies/libplist url = https://github.com/libimobiledevice/libplist.git -[submodule "Dependencies/MarkdownAttributedString"] - path = Dependencies/MarkdownAttributedString - url = https://github.com/chockenberry/MarkdownAttributedString.git [submodule "Dependencies/libimobiledevice-glue"] path = Dependencies/libimobiledevice-glue url = https://github.com/libimobiledevice/libimobiledevice-glue -[submodule "Dependencies/libfragmentzip"] - path = Dependencies/libfragmentzip +[submodule "Sources/libfragmentzip"] + path = Sources/libfragmentzip/libfragmentzip-source url = https://github.com/SideStore/libfragmentzip.git +[submodule "Dependencies/em_proxy"] + path = Dependencies/em_proxy + url = https://github.com/SideStore/em_proxy.git +[submodule "Dependencies/minimuxer"] + path = Dependencies/minimuxer + url = https://github.com/SideStore/minimuxer.git diff --git a/.jazzy.yaml b/.jazzy.yaml new file mode 100644 index 00000000..cc215750 --- /dev/null +++ b/.jazzy.yaml @@ -0,0 +1,28 @@ +# ---- About ---- +module: SideStore +module_version: 1.0,0 +author: SideStore +readme: README.md +copyright: 'See [license](https://github.com/SideStore/SideStore/blob/develop/LICENSE) for more details.' + +# ---- URLs ---- +author_url: https://sidestore.io +dash_url: https://sidestore.io/docsets/SideStore.xml +github_url: https://github.com/SideStore/SideStore/ +github_file_prefix: https://github.com/SideStore/SideStore/tree/1.0.2/ + +# ---- Sources ---- +source_directory: Sources +documentation: .build/x86_64-apple-macosx/debug/SideStore.docc + +# ---- Generation ---- +clean: true +output: docs +min_acl: public +hide_documentation_coverage: false +skip_undocumented: false +objc: false +swift_version: 5.1.0 + +# ---- Formatting ---- +theme: fullwidth diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 00000000..70491138 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,42 @@ +# .swiftformat + +## file options + +--exclude .build,.github,.swiftpm,.vscode,Configurations,Dependencies + +## format options + +--allman false +--binarygrouping 4,8 +--commas always +--comments indent +--decimalgrouping 3,6 +--elseposition same-line +--empty void +--exponentcase lowercase +--exponentgrouping disabled +--fractiongrouping disabled +--header ignore +--hexgrouping 4,8 +--hexliteralcase uppercase +--ifdef indent +--importgrouping testable-bottom +--indent 4 +--indentcase false +--linebreaks lf +--maxwidth none +--octalgrouping 4,8 +--operatorfunc spaced +--patternlet hoist +--ranges spaced +--self remove +--semicolons inline +--stripunusedargs always +--swiftversion 5.1 +--trimwhitespace always +--wraparguments preserve +--wrapcollections preserve + +## rules + +--enable isEmpty,andOperator,assertionFailures diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..385f5fbc --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,76 @@ +disabled_rules: +- block_based_kvo +- colon +- control_statement +- cyclomatic_complexity +- discarded_notification_center_observer +- file_length +- function_parameter_count +- generic_type_name +- identifier_name +- multiple_closures_with_trailing_closure +- nesting +- switch_case_alignment +- todo +- type_name +- type_body_length +- function_body_length +- unused_closure_parameter + +# parameterized rules can be customized from this configuration file +line_length: 200 +# parameterized rules are first parameterized as a warning level, then error level. +type_body_length: +- 300 # warning +- 600 # error +# parameterized rules are first parameterized as a warning level, then error level. +# identifier_name_max_length: +# - 40 # warning +# - 60 # error +# # parameterized rules are first parameterized as a warning level, then error level. +# identifier_name_min_length: +# - 3 # warning +# - 2 # error +function_body_length: +- 200 # warning +- 500 # error +large_tuple: +- 4 # warning +- 6 # error + +opt_in_rules: +- empty_count +- force_unwrapping + +excluded: # paths to ignore during linting. overridden byincluded. +- .build +- .github +- .swiftpm +- .vscode +- Dependencies + +analyzer_rules: # Rules run by `swiftlint analyze` (experimental) +- explicit_self + +# Override these rules to be warnings for now +force_cast: warning +force_try: warning +empty_count: warning + +reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit) + +custom_rules: + placeholders_in_comments: + included: ".*\\.swift" + name: "No Placeholders in Comments" + regex: "<#([^#]+)#>" + match_kinds: + - comment + - doccomment + message: "Placeholder left in comment." + tiles_deprecated: + included: ".*\\.swift" + name: "Tiles are deprecated in favor of Frame" + regex: "([T,t]ile$|^[T,t]il[e,es])" + message: "Tiles are deprecated in favor of Frame" + severity: warning diff --git a/AltStore-SPM.xcodeproj/project.pbxproj b/AltStore-SPM.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2d8358ea --- /dev/null +++ b/AltStore-SPM.xcodeproj/project.pbxproj @@ -0,0 +1,720 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + 191E6087290C7B50001A3B7C /* libminimuxer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */; }; + 4879A9622861049C00FC1BBD /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 4879A9612861049C00FC1BBD /* OpenSSL */; }; + B34AFD0A29A9CEDD00E637B4 /* SideKit in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0929A9CEDD00E637B4 /* SideKit */; }; + B34AFD0D29A9CF4000E637B4 /* Roxas in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0C29A9CF4000E637B4 /* Roxas */; }; + B34AFD0F29A9CF4000E637B4 /* RoxasUI in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0E29A9CF4000E637B4 /* RoxasUI */; }; + B3C395F4284F35DD00DA9E2F /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F3284F35DD00DA9E2F /* Nuke */; }; + B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F6284F362400DA9E2F /* AppCenterAnalytics */; }; + B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F8284F362400DA9E2F /* AppCenterCrashes */; }; + BF989177250AABF4002ACF50 /* SideWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BF989167250AABF3002ACF50 /* SideWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8B62727841800A9B5DD /* libAppleArchive.tbd */; settings = {ATTRIBUTES = (Weak, ); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + BF989175250AABF4002ACF50 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFD247622284B9A500981D42 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BF989166250AABF3002ACF50; + remoteInfo = AltWidgetExtension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + BF088D2B2501A087008082D9 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + BF98917B250AABF4002ACF50 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + BF989177250AABF4002ACF50 /* SideWidgetExtension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libminimuxer.a; path = "Dependencies/minimuxer/target/aarch64-apple-ios/debug/libminimuxer.a"; sourceTree = ""; }; + B32C055D29AF6867004789CF /* SideStore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SideStore; sourceTree = ""; }; + B343F86C295F759E002B1159 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk/usr/lib/libresolv.tbd; sourceTree = DEVELOPER_DIR; }; + B39575F4284F29E20080B4FF /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CodeSigning.xcconfig; sourceTree = ""; }; + B3C39607284F4C8400DA9E2F /* Build.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Build.xcconfig; sourceTree = ""; }; + B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */ = {isa = PBXFileReference; lastKnownFileType = text; path = CodeSigning.xcconfig.sample; sourceTree = ""; }; + B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStore.xcconfig; sourceTree = ""; }; + B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltWidgetExtension.xcconfig; sourceTree = ""; }; + B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = ""; }; + B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = ""; }; + BF4588872298DD3F00BD7491 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; }; + BF580497246A3D19008AE704 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + BF989167250AABF3002ACF50 /* SideWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SideWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + BFD2476A2284B9A500981D42 /* SideStore.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SideStore.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BFD247862284BB3B00981D42 /* Roxas.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D533E8B62727841800A9B5DD /* libAppleArchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libAppleArchive.tbd; path = usr/lib/libAppleArchive.tbd; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BF989164250AABF3002ACF50 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BFD247672284B9A500981D42 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 191E6087290C7B50001A3B7C /* libminimuxer.a in Frameworks */, + B34AFD0F29A9CF4000E637B4 /* RoxasUI in Frameworks */, + D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */, + B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */, + B34AFD0A29A9CEDD00E637B4 /* SideKit in Frameworks */, + 4879A9622861049C00FC1BBD /* OpenSSL in Frameworks */, + B3C395F4284F35DD00DA9E2F /* Nuke in Frameworks */, + B34AFD0D29A9CF4000E637B4 /* Roxas in Frameworks */, + B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B3E8749729AF639C00745374 /* Packages */ = { + isa = PBXGroup; + children = ( + B32C055D29AF6867004789CF /* SideStore */, + ); + name = Packages; + sourceTree = ""; + }; + BFD247612284B9A500981D42 = { + isa = PBXGroup; + children = ( + B3E8749729AF639C00745374 /* Packages */, + B3C39607284F4C8400DA9E2F /* Build.xcconfig */, + B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */, + B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */, + B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */, + B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */, + B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */, + B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */, + BFD247852284BB3300981D42 /* Frameworks */, + BFD2476B2284B9A500981D42 /* Products */, + ); + sourceTree = ""; + }; + BFD2476B2284B9A500981D42 /* Products */ = { + isa = PBXGroup; + children = ( + BFD2476A2284B9A500981D42 /* SideStore.app */, + BF989167250AABF3002ACF50 /* SideWidgetExtension.appex */, + ); + name = Products; + sourceTree = ""; + }; + BFD247852284BB3300981D42 /* Frameworks */ = { + isa = PBXGroup; + children = ( + B343F86C295F759E002B1159 /* libresolv.tbd */, + 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */, + B39575F4284F29E20080B4FF /* Roxas.framework */, + D533E8B62727841800A9B5DD /* libAppleArchive.tbd */, + BF580497246A3D19008AE704 /* UIKit.framework */, + BF4588872298DD3F00BD7491 /* libxml2.tbd */, + BFD247862284BB3B00981D42 /* Roxas.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BF989166250AABF3002ACF50 /* SideWidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = BF989178250AABF4002ACF50 /* Build configuration list for PBXNativeTarget "SideWidgetExtension" */; + buildPhases = ( + BF989163250AABF3002ACF50 /* Sources */, + BF989164250AABF3002ACF50 /* Frameworks */, + BF989165250AABF3002ACF50 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SideWidgetExtension; + productName = AltWidgetExtension; + productReference = BF989167250AABF3002ACF50 /* SideWidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; + BFD247692284B9A500981D42 /* SideStore */ = { + isa = PBXNativeTarget; + buildConfigurationList = BFD2477E2284B9A700981D42 /* Build configuration list for PBXNativeTarget "SideStore" */; + buildPhases = ( + BFD247662284B9A500981D42 /* Sources */, + BFD247672284B9A500981D42 /* Frameworks */, + BFD247682284B9A500981D42 /* Resources */, + BF088D2B2501A087008082D9 /* Embed Frameworks */, + BF98917B250AABF4002ACF50 /* Embed App Extensions */, + ); + buildRules = ( + ); + dependencies = ( + BF989176250AABF4002ACF50 /* PBXTargetDependency */, + ); + name = SideStore; + packageProductDependencies = ( + B3C395F3284F35DD00DA9E2F /* Nuke */, + B3C395F6284F362400DA9E2F /* AppCenterAnalytics */, + B3C395F8284F362400DA9E2F /* AppCenterCrashes */, + 4879A9612861049C00FC1BBD /* OpenSSL */, + B34AFD0929A9CEDD00E637B4 /* SideKit */, + B34AFD0C29A9CF4000E637B4 /* Roxas */, + B34AFD0E29A9CF4000E637B4 /* RoxasUI */, + ); + productName = AltStore; + productReference = BFD2476A2284B9A500981D42 /* SideStore.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFD247622284B9A500981D42 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1400; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = SideStore; + TargetAttributes = { + BF989166250AABF3002ACF50 = { + CreatedOnToolsVersion = 12.0; + LastSwiftMigration = 1200; + }; + BFD247692284B9A500981D42 = { + CreatedOnToolsVersion = 10.2.1; + LastSwiftMigration = 1020; + SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 1; + }; + com.apple.Push = { + enabled = 1; + }; + }; + }; + }; + }; + buildConfigurationList = BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BFD247612284B9A500981D42; + packageReferences = ( + D58D5F2C26DFE68E00E55E38 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */, + B3C395EF284F2DE700DA9E2F /* XCRemoteSwiftPackageReference "KeychainAccess" */, + B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */, + B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */, + B3C395FA284F3B2400DA9E2F /* XCRemoteSwiftPackageReference "Sparkle" */, + B3C395FD284F3C0900DA9E2F /* XCRemoteSwiftPackageReference "STPrivilegedTask" */, + 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */, + 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */, + 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */, + B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */, + B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */, + ); + productRefGroup = BFD2476B2284B9A500981D42 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BFD247692284B9A500981D42 /* SideStore */, + BF989166250AABF3002ACF50 /* SideWidgetExtension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BF989165250AABF3002ACF50 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BFD247682284B9A500981D42 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BF989163250AABF3002ACF50 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BFD247662284B9A500981D42 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + BF989176250AABF4002ACF50 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BF989166250AABF3002ACF50 /* SideWidgetExtension */; + targetProxy = BF989175250AABF4002ACF50 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + BF989179250AABF4002ACF50 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_ENTITLEMENTS = AltWidget/AltWidgetExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = AltWidget/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BF98917A250AABF4002ACF50 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_ENTITLEMENTS = AltWidget/AltWidgetExtension.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = AltWidget/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + BFD2477C2284B9A700981D42 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C39607284F4C8400DA9E2F /* Build.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + 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 = NO; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + 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; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-Wno-module-import-in-extern-c", + ); + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\""; + }; + name = Debug; + }; + BFD2477D2284B9A700981D42 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C39607284F4C8400DA9E2F /* Build.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + 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 = NO; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + 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; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-Wno-module-import-in-extern-c", + ); + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\""; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BFD2477F2284B9A700981D42 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = AltStore/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Dependencies/fragmentzip", + "$(PROJECT_DIR)/Dependencies/libcurl", + ); + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BFD247802284B9A700981D42 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = AltStore/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Dependencies/fragmentzip", + "$(PROJECT_DIR)/Dependencies/libcurl", + ); + PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BF989178250AABF4002ACF50 /* Build configuration list for PBXNativeTarget "SideWidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF989179250AABF4002ACF50 /* Debug */, + BF98917A250AABF4002ACF50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BFD2477C2284B9A700981D42 /* Debug */, + BFD2477D2284B9A700981D42 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BFD2477E2284B9A700981D42 /* Build configuration list for PBXNativeTarget "SideStore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BFD2477F2284B9A700981D42 /* Debug */, + BFD247802284B9A700981D42 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SideStore/AltSign"; + requirement = { + branch = master; + kind = branch; + }; + }; + 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/krzyzanowskim/OpenSSL"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 1.1.180; + }; + }; + 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SwiftPackageIndex/SemanticVersion.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.3.5; + }; + }; + B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SideStore/SideKit.git"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 0.1.0; + }; + }; + B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/JoeMatt/Roxas.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.2.2; + }; + }; + B3C395EF284F2DE700DA9E2F /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.2.0; + }; + }; + B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kean/Nuke.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 7.0.0; + }; + }; + B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/microsoft/appcenter-sdk-apple.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.2.0; + }; + }; + B3C395FA284F3B2400DA9E2F /* XCRemoteSwiftPackageReference "Sparkle" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sparkle-project/Sparkle.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.0; + }; + }; + B3C395FD284F3C0900DA9E2F /* XCRemoteSwiftPackageReference "STPrivilegedTask" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/JoeMatt/STPrivilegedTask.git"; + requirement = { + branch = master; + kind = branch; + }; + }; + D58D5F2C26DFE68E00E55E38 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.1.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 4879A9612861049C00FC1BBD /* OpenSSL */ = { + isa = XCSwiftPackageProductDependency; + package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */; + productName = OpenSSL; + }; + B34AFD0929A9CEDD00E637B4 /* SideKit */ = { + isa = XCSwiftPackageProductDependency; + package = B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */; + productName = SideKit; + }; + B34AFD0C29A9CF4000E637B4 /* Roxas */ = { + isa = XCSwiftPackageProductDependency; + package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; + productName = Roxas; + }; + B34AFD0E29A9CF4000E637B4 /* RoxasUI */ = { + isa = XCSwiftPackageProductDependency; + package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; + productName = RoxasUI; + }; + B3C395F3284F35DD00DA9E2F /* Nuke */ = { + isa = XCSwiftPackageProductDependency; + package = B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */; + productName = Nuke; + }; + B3C395F6284F362400DA9E2F /* AppCenterAnalytics */ = { + isa = XCSwiftPackageProductDependency; + package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; + productName = AppCenterAnalytics; + }; + B3C395F8284F362400DA9E2F /* AppCenterCrashes */ = { + isa = XCSwiftPackageProductDependency; + package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; + productName = AppCenterCrashes; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = BFD247622284B9A500981D42 /* Project object */; +} diff --git a/AltStore.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AltStore-SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from AltStore.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to AltStore-SPM.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/AltStore.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AltStore-SPM.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from AltStore.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to AltStore-SPM.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/AltStore.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AltStore-SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved similarity index 78% rename from AltStore.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved rename to AltStore-SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f9861ff9..c5f84ac1 100644 --- a/AltStore.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AltStore-SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/microsoft/appcenter-sdk-apple.git", "state" : { - "revision" : "8354a50fe01a7e54e196d3b5493b5ab53dd5866a", - "version" : "4.4.2" + "revision" : "b2dc99cfedead0bad4e6573d86c5228c89cff332", + "version" : "4.4.3" + } + }, + { + "identity" : "down", + "kind" : "remoteSourceControl", + "location" : "https://github.com/johnxnguyen/Down", + "state" : { + "branch" : "master", + "revision" : "e754ab1c80920dd51a8e08290c912ac1c2ac8b58" } }, { @@ -50,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/krzyzanowskim/OpenSSL", "state" : { - "revision" : "033fcb41dac96b1b6effa945ca1f9ade002370b2", - "version" : "1.1.1501" + "revision" : "87f41bf9488e7dd2b0de2ab97cb3eafc7304e0e6", + "version" : "1.1.2000" } }, { @@ -59,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/microsoft/PLCrashReporter.git", "state" : { - "revision" : "6b27393cad517c067dceea85fadf050e70c4ceaa", - "version" : "1.10.1" + "revision" : "81cdec2b3827feb03286cb297f4c501a8eb98df1", + "version" : "1.10.2" } }, { @@ -84,10 +93,10 @@ { "identity" : "sidekit", "kind" : "remoteSourceControl", - "location" : "https://github.com/SideStore/SideKit.git", + "location" : "https://github.com/SideStore/SideKit", "state" : { - "revision" : "7ea34a09b52c104077dea8e0b90f8dc55d43b36b", - "version" : "0.1.0" + "branch" : "main", + "revision" : "7ea34a09b52c104077dea8e0b90f8dc55d43b36b" } }, { @@ -95,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sparkle-project/Sparkle.git", "state" : { - "revision" : "286edd1fa22505a9e54d170e9fd07d775ea233f2", - "version" : "2.1.0" + "revision" : "dda155c7d3ef38c53d29f8584cb2aad2a1a54dba", + "version" : "2.3.2" } }, { diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj deleted file mode 100644 index c2fb3c60..00000000 --- a/AltStore.xcodeproj/project.pbxproj +++ /dev/null @@ -1,3435 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - 03F06CD52942C27E001C4D68 /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; }; - 19104D952909BAEA00C49C7B /* libimobiledevice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF45872B2298D31600BD7491 /* libimobiledevice.a */; }; - 19104DB52909C06D00C49C7B /* EmotionalDamage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19104DB42909C06D00C49C7B /* EmotionalDamage.swift */; }; - 19104DBC2909C4E500C49C7B /* libEmotionalDamage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19104DB22909C06C00C49C7B /* libEmotionalDamage.a */; }; - 191E5FAE290A5D92001A3B7C /* minimuxer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191E5FAD290A5D92001A3B7C /* minimuxer.swift */; }; - 191E5FB4290A5DA0001A3B7C /* libminimuxer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 191E5FAB290A5D92001A3B7C /* libminimuxer.a */; }; - 191E5FDC290AFA5C001A3B7C /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 191E5FDB290AFA5C001A3B7C /* OpenSSL */; }; - 191E607D290B2EA5001A3B7C /* jsmn.c in Sources */ = {isa = PBXBuildFile; fileRef = 191E5FD0290A651D001A3B7C /* jsmn.c */; }; - 191E607E290B2EA7001A3B7C /* jplist.c in Sources */ = {isa = PBXBuildFile; fileRef = 191E5FCF290A651D001A3B7C /* jplist.c */; }; - 191E6087290C7B50001A3B7C /* libminimuxer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */; }; - 1920B04F2924AC8300744F60 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 1920B04E2924AC8300744F60 /* Settings.bundle */; }; - 19B9B7452845E6DF0076EF69 /* SelectTeamViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B9B7442845E6DF0076EF69 /* SelectTeamViewController.swift */; }; - 4879A95F2861046500FC1BBD /* AltSign in Frameworks */ = {isa = PBXBuildFile; productRef = 4879A95E2861046500FC1BBD /* AltSign */; }; - 4879A9622861049C00FC1BBD /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 4879A9612861049C00FC1BBD /* OpenSSL */; }; - 99C4EF4D2979132100CB538D /* SemanticVersion in Frameworks */ = {isa = PBXBuildFile; productRef = 99C4EF4C2979132100CB538D /* SemanticVersion */; }; - B33FFBA8295F8E98002259E6 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B343F894295F7F9B002B1159 /* libfragmentzip.a */; }; - B33FFBAA295F8F78002259E6 /* preboard.c in Sources */ = {isa = PBXBuildFile; fileRef = B33FFBA9295F8F78002259E6 /* preboard.c */; }; - B33FFBAC295F8F98002259E6 /* companion_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = B33FFBAB295F8F98002259E6 /* companion_proxy.c */; }; - B343F858295F6331002B1159 /* libminimuxer_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B343F84C295F6321002B1159 /* libminimuxer_static.a */; }; - B343F859295F6335002B1159 /* libem_proxy_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B343F853295F6323002B1159 /* libem_proxy_static.a */; }; - B343F86D295F759E002B1159 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B343F86C295F759E002B1159 /* libresolv.tbd */; }; - B343F87C295F7C5D002B1159 /* opack.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F872295F7C5C002B1159 /* opack.c */; }; - B343F87D295F7C5D002B1159 /* cbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F873295F7C5C002B1159 /* cbuf.c */; }; - B343F87E295F7C5D002B1159 /* collection.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F874295F7C5D002B1159 /* collection.c */; }; - B343F87F295F7C5D002B1159 /* glue.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F875295F7C5D002B1159 /* glue.c */; }; - B343F880295F7C5D002B1159 /* socket.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F876295F7C5D002B1159 /* socket.c */; }; - B343F881295F7C5D002B1159 /* termcolors.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F877295F7C5D002B1159 /* termcolors.c */; }; - B343F883295F7C5D002B1159 /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F879295F7C5D002B1159 /* thread.c */; }; - B343F884295F7C5D002B1159 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F87A295F7C5D002B1159 /* utils.c */; }; - B343F885295F7C5D002B1159 /* tlv.c in Sources */ = {isa = PBXBuildFile; fileRef = B343F87B295F7C5D002B1159 /* tlv.c */; }; - B34AFD0A29A9CEDD00E637B4 /* SideKit in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0929A9CEDD00E637B4 /* SideKit */; }; - B34AFD0D29A9CF4000E637B4 /* Roxas in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0C29A9CF4000E637B4 /* Roxas */; }; - B34AFD0F29A9CF4000E637B4 /* RoxasUI in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD0E29A9CF4000E637B4 /* RoxasUI */; }; - B34AFD1129A9CF5C00E637B4 /* Roxas in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD1029A9CF5C00E637B4 /* Roxas */; }; - B34AFD1429A9D31100E637B4 /* ServerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34AFD1229A9D2C100E637B4 /* ServerProtocol.swift */; }; - B34AFD1529A9D31200E637B4 /* ServerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34AFD1229A9D2C100E637B4 /* ServerProtocol.swift */; }; - B34AFD1729A9D9FC00E637B4 /* RoxasUI in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD1629A9D9FC00E637B4 /* RoxasUI */; }; - B34AFD1929A9DB0200E637B4 /* SideKit in Frameworks */ = {isa = PBXBuildFile; productRef = B34AFD1829A9DB0200E637B4 /* SideKit */; }; - B34AFD1B29A9DFA200E637B4 /* NSError+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34AFD1A29A9DFA200E637B4 /* NSError+AltStore.swift */; }; - B34AFD1C29A9DFA200E637B4 /* NSError+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B34AFD1A29A9DFA200E637B4 /* NSError+AltStore.swift */; }; - B376FE3E29258C8900E18883 /* OSLog+SideStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B376FE3D29258C8900E18883 /* OSLog+SideStore.swift */; }; - B39F16132918D7C5002E9404 /* Consts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B39F16122918D7C5002E9404 /* Consts.swift */; }; - B39F16152918D7DA002E9404 /* Consts+Proxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B39F16142918D7DA002E9404 /* Consts+Proxy.swift */; }; - B3C395F1284F2DE700DA9E2F /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F0284F2DE700DA9E2F /* KeychainAccess */; }; - B3C395F4284F35DD00DA9E2F /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F3284F35DD00DA9E2F /* Nuke */; }; - B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F6284F362400DA9E2F /* AppCenterAnalytics */; }; - B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F8284F362400DA9E2F /* AppCenterCrashes */; }; - B3EE16B62925E27D00B3B1F5 /* AnisetteManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */; }; - BF02419622F2199300129732 /* RefreshAttemptsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */; }; - BF08858322DE795100DE9F1E /* MyAppsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858222DE795100DE9F1E /* MyAppsViewController.swift */; }; - BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */; }; - BF0C4EBD22A1BD8B009A2DD7 /* AppManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0C4EBC22A1BD8B009A2DD7 /* AppManager.swift */; }; - BF0DCA662433BDF500E3A595 /* AnalyticsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0DCA652433BDF500E3A595 /* AnalyticsManager.swift */; }; - BF10EB34248730750055E6DB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF10EB33248730750055E6DB /* main.swift */; }; - BF18B0F122E25DF9005C4CF5 /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18B0F022E25DF9005C4CF5 /* ToastView.swift */; }; - BF1FE358251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1FE357251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift */; }; - BF1FE359251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1FE357251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift */; }; - BF29012F2318F6B100D88A45 /* AppBannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF29012E2318F6B100D88A45 /* AppBannerView.xib */; }; - BF2901312318F7A800D88A45 /* AppBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF2901302318F7A800D88A45 /* AppBannerView.swift */; }; - BF340E9A250AD39500A192CB /* ViewApp.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = BF989191250AAE86002ACF50 /* ViewApp.intentdefinition */; }; - BF3432FB246B894F0052F4A1 /* BackupAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3432FA246B894F0052F4A1 /* BackupAppOperation.swift */; }; - BF3BEFBF2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3BEFBE2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift */; }; - BF3BEFC124086A1E00DE7D55 /* RefreshAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3BEFC024086A1E00DE7D55 /* RefreshAppOperation.swift */; }; - BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3D649C22E7AC1B00E9056B /* PermissionPopoverViewController.swift */; }; - BF3D649F22E7B24C00E9056B /* CollapsingTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3D649E22E7B24C00E9056B /* CollapsingTextView.swift */; }; - BF3D64B022E8D4B800E9056B /* AppContentViewControllerCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3D64AF22E8D4B800E9056B /* AppContentViewControllerCells.swift */; }; - BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF41B805233423AE00C593A3 /* TabBarController.swift */; }; - BF41B808233433C100C593A3 /* LoadingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF41B807233433C100C593A3 /* LoadingState.swift */; }; - BF42345A25101C35006D1EB2 /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF42345825101C1D006D1EB2 /* WidgetView.swift */; }; - BF44EEF0246B08BA002A52F2 /* BackupController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF44EEEF246B08BA002A52F2 /* BackupController.swift */; }; - BF44EEF3246B3A17002A52F2 /* AltBackup.ipa in Resources */ = {isa = PBXBuildFile; fileRef = BF44EEF2246B3A17002A52F2 /* AltBackup.ipa */; }; - BF44EEFC246B4550002A52F2 /* RemoveAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF44EEFB246B4550002A52F2 /* RemoveAppOperation.swift */; }; - BF4587F82298D3AB00BD7491 /* service.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587C82298D3A800BD7491 /* service.h */; }; - BF4587F92298D3AB00BD7491 /* diagnostics_relay.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587C92298D3A800BD7491 /* diagnostics_relay.c */; }; - BF4587FA2298D3AB00BD7491 /* diagnostics_relay.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587CA2298D3A800BD7491 /* diagnostics_relay.h */; }; - BF4587FB2298D3AB00BD7491 /* notification_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587CB2298D3A800BD7491 /* notification_proxy.c */; }; - BF4587FC2298D3AB00BD7491 /* sbservices.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587CC2298D3A800BD7491 /* sbservices.c */; }; - BF4587FD2298D3AB00BD7491 /* sbservices.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587CD2298D3A800BD7491 /* sbservices.h */; }; - BF4587FE2298D3AB00BD7491 /* mobilebackup2.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587CE2298D3A800BD7491 /* mobilebackup2.h */; }; - BF4587FF2298D3AB00BD7491 /* heartbeat.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587CF2298D3A800BD7491 /* heartbeat.c */; }; - BF4588002298D3AB00BD7491 /* restore.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587D02298D3A800BD7491 /* restore.h */; }; - BF4588012298D3AB00BD7491 /* installation_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587D12298D3A800BD7491 /* installation_proxy.h */; }; - BF4588022298D3AB00BD7491 /* file_relay.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D22298D3A800BD7491 /* file_relay.c */; }; - BF4588032298D3AB00BD7491 /* syslog_relay.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D32298D3A800BD7491 /* syslog_relay.c */; }; - BF4588042298D3AB00BD7491 /* lockdown.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587D42298D3A800BD7491 /* lockdown.h */; }; - BF4588052298D3AB00BD7491 /* idevice.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587D52298D3A800BD7491 /* idevice.h */; }; - BF4588062298D3AB00BD7491 /* webinspector.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D62298D3A800BD7491 /* webinspector.c */; }; - BF4588072298D3AB00BD7491 /* afc.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D72298D3A800BD7491 /* afc.c */; }; - BF4588082298D3AB00BD7491 /* mobile_image_mounter.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D82298D3A800BD7491 /* mobile_image_mounter.c */; }; - BF4588092298D3AB00BD7491 /* installation_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587D92298D3A900BD7491 /* installation_proxy.c */; }; - BF45880A2298D3AB00BD7491 /* screenshotr.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587DA2298D3A900BD7491 /* screenshotr.h */; }; - BF45880B2298D3AB00BD7491 /* mobilesync.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587DB2298D3A900BD7491 /* mobilesync.h */; }; - BF45880C2298D3AB00BD7491 /* mobilebackup2.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587DC2298D3A900BD7491 /* mobilebackup2.c */; }; - BF45880D2298D3AB00BD7491 /* mobilebackup.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587DD2298D3A900BD7491 /* mobilebackup.c */; }; - BF45880E2298D3AB00BD7491 /* debugserver.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587DE2298D3A900BD7491 /* debugserver.h */; }; - BF45880F2298D3AB00BD7491 /* debugserver.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587DF2298D3A900BD7491 /* debugserver.c */; }; - BF4588102298D3AB00BD7491 /* heartbeat.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E02298D3A900BD7491 /* heartbeat.h */; }; - BF4588112298D3AB00BD7491 /* misagent.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E12298D3A900BD7491 /* misagent.h */; }; - BF4588122298D3AB00BD7491 /* house_arrest.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E22298D3A900BD7491 /* house_arrest.h */; }; - BF4588132298D3AB00BD7491 /* notification_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E32298D3A900BD7491 /* notification_proxy.h */; }; - BF4588142298D3AB00BD7491 /* device_link_service.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587E42298D3A900BD7491 /* device_link_service.c */; }; - BF4588152298D3AB00BD7491 /* mobilebackup.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E52298D3A900BD7491 /* mobilebackup.h */; }; - BF4588162298D3AB00BD7491 /* restore.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587E62298D3A900BD7491 /* restore.c */; }; - BF4588172298D3AB00BD7491 /* screenshotr.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587E72298D3A900BD7491 /* screenshotr.c */; }; - BF4588182298D3AB00BD7491 /* syslog_relay.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E82298D3A900BD7491 /* syslog_relay.h */; }; - BF4588192298D3AB00BD7491 /* webinspector.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587E92298D3AA00BD7491 /* webinspector.h */; }; - BF45881A2298D3AB00BD7491 /* mobileactivation.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587EA2298D3AA00BD7491 /* mobileactivation.h */; }; - BF45881B2298D3AB00BD7491 /* house_arrest.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587EB2298D3AA00BD7491 /* house_arrest.c */; }; - BF45881C2298D3AB00BD7491 /* afc.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587EC2298D3AA00BD7491 /* afc.h */; }; - BF45881D2298D3AB00BD7491 /* file_relay.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587ED2298D3AA00BD7491 /* file_relay.h */; }; - BF45881E2298D3AB00BD7491 /* misagent.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587EE2298D3AA00BD7491 /* misagent.c */; }; - BF45881F2298D3AB00BD7491 /* device_link_service.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587EF2298D3AA00BD7491 /* device_link_service.h */; }; - BF4588202298D3AB00BD7491 /* mobile_image_mounter.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587F02298D3AA00BD7491 /* mobile_image_mounter.h */; }; - BF4588212298D3AB00BD7491 /* idevice.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F12298D3AA00BD7491 /* idevice.c */; }; - BF4588222298D3AB00BD7491 /* mobileactivation.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F22298D3AA00BD7491 /* mobileactivation.c */; }; - BF4588232298D3AB00BD7491 /* mobilesync.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F32298D3AA00BD7491 /* mobilesync.c */; }; - BF4588242298D3AB00BD7491 /* property_list_service.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F42298D3AA00BD7491 /* property_list_service.c */; }; - BF4588252298D3AB00BD7491 /* property_list_service.h in Headers */ = {isa = PBXBuildFile; fileRef = BF4587F52298D3AA00BD7491 /* property_list_service.h */; }; - BF4588262298D3AB00BD7491 /* lockdown.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F62298D3AB00BD7491 /* lockdown.c */; }; - BF4588272298D3AB00BD7491 /* service.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4587F72298D3AB00BD7491 /* service.c */; }; - BF4588342298D3C100BD7491 /* userpref.h in Headers */ = {isa = PBXBuildFile; fileRef = BF45882A2298D3C000BD7491 /* userpref.h */; }; - BF4588352298D3C100BD7491 /* userpref.c in Sources */ = {isa = PBXBuildFile; fileRef = BF45882B2298D3C000BD7491 /* userpref.c */; }; - BF4588362298D3C100BD7491 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = BF45882C2298D3C000BD7491 /* debug.h */; }; - BF45883A2298D3C100BD7491 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4588302298D3C000BD7491 /* debug.c */; }; - BF4588432298D40000BD7491 /* libusbmuxd.c in Sources */ = {isa = PBXBuildFile; fileRef = BF4588422298D40000BD7491 /* libusbmuxd.c */; }; - BF4B78FE24B3D1DB008AB4AC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4B78FD24B3D1DB008AB4AC /* SceneDelegate.swift */; }; - BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */; }; - BF56D2AF23DF9E310006506D /* AppIDsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */; }; - BF58047E246A28F7008AE704 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF58047D246A28F7008AE704 /* AppDelegate.swift */; }; - BF580482246A28F7008AE704 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF580481246A28F7008AE704 /* ViewController.swift */; }; - BF580487246A28F9008AE704 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF580486246A28F9008AE704 /* Assets.xcassets */; }; - BF58048A246A28F9008AE704 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF580488246A28F9008AE704 /* LaunchScreen.storyboard */; }; - BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF580495246A3CB5008AE704 /* UIColor+AltBackup.swift */; }; - BF580498246A3D19008AE704 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF580497246A3D19008AE704 /* UIKit.framework */; }; - BF663C4F2433ED8200DAA738 /* FileManager+DirectorySize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */; }; - BF66EE822501AE50007EE018 /* AltStoreCore.h in Headers */ = {isa = PBXBuildFile; fileRef = BF66EE802501AE50007EE018 /* AltStoreCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF66EE852501AE50007EE018 /* AltStoreCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */; }; - BF66EE862501AE50007EE018 /* AltStoreCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - BF66EE8C2501AEB2007EE018 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE8B2501AEB1007EE018 /* Keychain.swift */; }; - BF66EE942501AEBC007EE018 /* ALTAppPermission.h in Headers */ = {isa = PBXBuildFile; fileRef = BF66EE8E2501AEBC007EE018 /* ALTAppPermission.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF66EE952501AEBC007EE018 /* ALTSourceUserInfoKey.h in Headers */ = {isa = PBXBuildFile; fileRef = BF66EE8F2501AEBC007EE018 /* ALTSourceUserInfoKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF66EE962501AEBC007EE018 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE902501AEBC007EE018 /* ALTPatreonBenefitType.m */; }; - BF66EE972501AEBC007EE018 /* ALTAppPermission.m in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE912501AEBC007EE018 /* ALTAppPermission.m */; }; - BF66EE982501AEBC007EE018 /* ALTPatreonBenefitType.h in Headers */ = {isa = PBXBuildFile; fileRef = BF66EE922501AEBC007EE018 /* ALTPatreonBenefitType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BF66EE992501AEBC007EE018 /* ALTSourceUserInfoKey.m in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE932501AEBC007EE018 /* ALTSourceUserInfoKey.m */; }; - BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE9B2501AEC1007EE018 /* AppProtocol.swift */; }; - BF66EE9E2501AEC1007EE018 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EE9C2501AEC1007EE018 /* Fetchable.swift */; }; - BF66EEA52501AEC5007EE018 /* Benefit.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEA02501AEC5007EE018 /* Benefit.swift */; }; - BF66EEA62501AEC5007EE018 /* PatreonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEA12501AEC5007EE018 /* PatreonAPI.swift */; }; - BF66EEA72501AEC5007EE018 /* Campaign.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEA22501AEC5007EE018 /* Campaign.swift */; }; - BF66EEA82501AEC5007EE018 /* Patron.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEA32501AEC5007EE018 /* Patron.swift */; }; - BF66EEA92501AEC5007EE018 /* Tier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEA42501AEC5007EE018 /* Tier.swift */; }; - BF66EECC2501AECA007EE018 /* Source.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEAB2501AECA007EE018 /* Source.swift */; }; - BF66EECD2501AECA007EE018 /* StoreAppPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEAE2501AECA007EE018 /* StoreAppPolicy.swift */; }; - BF66EECE2501AECA007EE018 /* InstalledAppPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEAF2501AECA007EE018 /* InstalledAppPolicy.swift */; }; - BF66EECF2501AECA007EE018 /* AltStoreToAltStore2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB12501AECA007EE018 /* AltStoreToAltStore2.xcmappingmodel */; }; - BF66EED02501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB22501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel */; }; - BF66EED12501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB32501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel */; }; - BF66EED22501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB42501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel */; }; - BF66EED32501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB52501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel */; }; - BF66EED42501AECA007EE018 /* AltStore5ToAltStore6.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB62501AECA007EE018 /* AltStore5ToAltStore6.xcmappingmodel */; }; - BF66EED52501AECA007EE018 /* AltStore.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEB72501AECA007EE018 /* AltStore.xcdatamodeld */; }; - BF66EED62501AECA007EE018 /* NewsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEBF2501AECA007EE018 /* NewsItem.swift */; }; - BF66EED72501AECA007EE018 /* InstalledApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC02501AECA007EE018 /* InstalledApp.swift */; }; - BF66EED82501AECA007EE018 /* SecureValueTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC12501AECA007EE018 /* SecureValueTransformer.swift */; }; - BF66EED92501AECA007EE018 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC22501AECA007EE018 /* Team.swift */; }; - BF66EEDA2501AECA007EE018 /* RefreshAttempt.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC32501AECA007EE018 /* RefreshAttempt.swift */; }; - BF66EEDB2501AECA007EE018 /* StoreApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC42501AECA007EE018 /* StoreApp.swift */; }; - BF66EEDC2501AECA007EE018 /* MergePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC52501AECA007EE018 /* MergePolicy.swift */; }; - BF66EEDD2501AECA007EE018 /* AppPermission.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC62501AECA007EE018 /* AppPermission.swift */; }; - BF66EEDE2501AECA007EE018 /* AppID.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC72501AECA007EE018 /* AppID.swift */; }; - BF66EEDF2501AECA007EE018 /* PatreonAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC82501AECA007EE018 /* PatreonAccount.swift */; }; - BF66EEE02501AECA007EE018 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEC92501AECA007EE018 /* Account.swift */; }; - BF66EEE12501AECA007EE018 /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EECA2501AECA007EE018 /* DatabaseManager.swift */; }; - BF66EEE22501AECA007EE018 /* InstalledExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EECB2501AECA007EE018 /* InstalledExtension.swift */; }; - BF66EEE82501AED0007EE018 /* UserDefaults+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEE42501AED0007EE018 /* UserDefaults+AltStore.swift */; }; - BF66EEE92501AED0007EE018 /* JSONDecoder+Properties.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEE52501AED0007EE018 /* JSONDecoder+Properties.swift */; }; - BF66EEEA2501AED0007EE018 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEE62501AED0007EE018 /* UIColor+Hex.swift */; }; - BF66EEEB2501AED0007EE018 /* UIApplication+AppExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF66EEE72501AED0007EE018 /* UIApplication+AppExtension.swift */; }; - BF6C8FAC242935ED00125131 /* NSAttributedString+Markdown.m in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */; }; - BF6C8FAE2429597900125131 /* BannerCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAD2429597900125131 /* BannerCollectionViewCell.swift */; }; - BF6C8FB02429599900125131 /* TextCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C8FAF2429599900125131 /* TextCollectionReusableView.swift */; }; - BF6F439223644C6E00A0B879 /* RefreshAltStoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6F439123644C6E00A0B879 /* RefreshAltStoreViewController.swift */; }; - BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */; }; - BF770E5122BB1CF6002A40FE /* InstallAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */; }; - BF770E5422BC044E002A40FE /* OperationContexts.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5322BC044E002A40FE /* OperationContexts.swift */; }; - BF770E5822BC3D0F002A40FE /* RefreshGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5722BC3D0F002A40FE /* RefreshGroup.swift */; }; - BF770E6722BD57C4002A40FE /* BackgroundTaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E6622BD57C3002A40FE /* BackgroundTaskManager.swift */; }; - BF770E6922BD57DD002A40FE /* Silence.m4a in Resources */ = {isa = PBXBuildFile; fileRef = BF770E6822BD57DD002A40FE /* Silence.m4a */; }; - BF88F97224F8727D00BB75DF /* AppManagerErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF88F97124F8727D00BB75DF /* AppManagerErrors.swift */; }; - BF8B17EB250AC40000F8157F /* FileManager+SharedDirectories.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */; }; - BF8CAE452489E772004D6CCE /* AnisetteDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE422489E772004D6CCE /* AnisetteDataManager.swift */; }; - BF8CAE462489E772004D6CCE /* AppManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE432489E772004D6CCE /* AppManager.swift */; }; - BF8CAE472489E772004D6CCE /* DaemonRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE442489E772004D6CCE /* DaemonRequestHandler.swift */; }; - BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */; }; - BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; }; - BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; }; - BF989171250AABF4002ACF50 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF989170250AABF4002ACF50 /* Assets.xcassets */; }; - BF989177250AABF4002ACF50 /* AltWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - BF98917E250AAC4F002ACF50 /* Countdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF98917C250AAC4F002ACF50 /* Countdown.swift */; }; - BF98917F250AAC4F002ACF50 /* AltWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF98917D250AAC4F002ACF50 /* AltWidget.swift */; }; - BF989184250AACFC002ACF50 /* Date+RelativeDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */; }; - BF989185250AAD1D002ACF50 /* UIColor+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD2479E2284FBD000981D42 /* UIColor+AltStore.swift */; }; - BF9ABA4522DCFF43008935CF /* BrowseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */; }; - BF9ABA4722DD0638008935CF /* BrowseCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */; }; - BF9ABA4922DD0742008935CF /* ScreenshotCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4822DD0742008935CF /* ScreenshotCollectionViewCell.swift */; }; - BF9ABA4B22DD1380008935CF /* NavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4A22DD137F008935CF /* NavigationBar.swift */; }; - BF9ABA4D22DD16DE008935CF /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF9ABA4C22DD16DE008935CF /* PillButton.swift */; }; - BFA8172B23C5633D001B5953 /* FetchAnisetteDataOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */; }; - BFAECC552501B0A400528F27 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18BFF624858BDE00DD5981 /* Connection.swift */; }; - BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18BFF22485828200DD5981 /* ConnectionManager.swift */; }; - BFAECC582501B0A400528F27 /* ALTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = BF718BD723C93DB700A89F2D /* ALTConstants.m */; }; - BFAECC592501B0A400528F27 /* Result+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAC8852295C90300587369 /* Result+Conveniences.swift */; }; - BFAECC5A2501B0A400528F27 /* NetworkConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF767CD2489ABE90097E58C /* NetworkConnection.swift */; }; - BFAECC5B2501B0A400528F27 /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; }; - BFAECC5C2501B0A400528F27 /* CFNotificationName+AltStore.m in Sources */ = {isa = PBXBuildFile; fileRef = BF718BC823C919E300A89F2D /* CFNotificationName+AltStore.m */; }; - BFAECC5E2501B0BF00528F27 /* CFNotificationName+AltStore.h in Headers */ = {isa = PBXBuildFile; fileRef = BF718BC723C919CC00A89F2D /* CFNotificationName+AltStore.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BFAECC5F2501B0BF00528F27 /* ALTConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BD222A06EFB000B7ED1 /* ALTConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BFB39B5C252BC10E00D1BE50 /* Managed.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB39B5B252BC10E00D1BE50 /* Managed.swift */; }; - BFB4323F22DE852000B7F8BC /* UpdateCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFB4323E22DE852000B7F8BC /* UpdateCollectionViewCell.xib */; }; - BFB6B21E231870160022A802 /* NewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB6B21D231870160022A802 /* NewsViewController.swift */; }; - BFB6B220231870B00022A802 /* NewsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFB6B21F231870B00022A802 /* NewsCollectionViewCell.swift */; }; - BFB6B22423187A3D0022A802 /* NewsCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFB6B22323187A3D0022A802 /* NewsCollectionViewCell.xib */; }; - BFBE0004250ACFFB0080826E /* ViewApp.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = BF989191250AAE86002ACF50 /* ViewApp.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; }; - BFBE0007250AD0E70080826E /* ViewAppIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF989190250AAE86002ACF50 /* ViewAppIntentHandler.swift */; }; - BFBF331B2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BFBF331A2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel */; }; - BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC1F38C22AEE3A4003AC21A /* DownloadAppOperation.swift */; }; - BFC57A652416C72400EB891E /* DeactivateAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC57A642416C72400EB891E /* DeactivateAppOperation.swift */; }; - BFC57A6E2416FC5D00EB891E /* InstalledAppsCollectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC57A6D2416FC5D00EB891E /* InstalledAppsCollectionHeaderView.swift */; }; - BFC57A702416FC7600EB891E /* InstalledAppsCollectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFC57A6F2416FC7600EB891E /* InstalledAppsCollectionHeaderView.xib */; }; - BFC712C32512D5F100AB5EBE /* XPCConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC712C12512D5F100AB5EBE /* XPCConnection.swift */; }; - BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC712C12512D5F100AB5EBE /* XPCConnection.swift */; }; - BFC712C52512D5F100AB5EBE /* XPCConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC712C22512D5F100AB5EBE /* XPCConnectionHandler.swift */; }; - BFC84A4D2421A19100853474 /* SourcesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC84A4C2421A19100853474 /* SourcesViewController.swift */; }; - BFCB9207250AB2120057B44E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BFCB9206250AB2120057B44E /* Colors.xcassets */; }; - BFCCB51A245E3401001853EA /* VerifyAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCB519245E3401001853EA /* VerifyAppOperation.swift */; }; - BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD2476D2284B9A500981D42 /* AppDelegate.swift */; }; - BFD247752284B9A500981D42 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFD247732284B9A500981D42 /* Main.storyboard */; }; - BFD247772284B9A700981D42 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BFD247762284B9A700981D42 /* Assets.xcassets */; }; - BFD2477A2284B9A700981D42 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFD247782284B9A700981D42 /* LaunchScreen.storyboard */; }; - BFD2478C2284C4C300981D42 /* AppIconImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD2478B2284C4C300981D42 /* AppIconImageView.swift */; }; - BFD2478F2284C8F900981D42 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD2478E2284C8F900981D42 /* Button.swift */; }; - BFD52C0122A1A9CB000B7ED1 /* ptrarray.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BE522A1A9CA000B7ED1 /* ptrarray.c */; }; - BFD52C0222A1A9CB000B7ED1 /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BE622A1A9CA000B7ED1 /* base64.c */; }; - BFD52C0322A1A9CB000B7ED1 /* hashtable.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BE722A1A9CA000B7ED1 /* hashtable.c */; }; - BFD52C0422A1A9CB000B7ED1 /* Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BE822A1A9CA000B7ED1 /* Dictionary.cpp */; }; - BFD52C0522A1A9CB000B7ED1 /* ptrarray.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BE922A1A9CA000B7ED1 /* ptrarray.h */; }; - BFD52C0622A1A9CB000B7ED1 /* bplist.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BEA22A1A9CA000B7ED1 /* bplist.c */; }; - BFD52C0722A1A9CB000B7ED1 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BEB22A1A9CA000B7ED1 /* String.cpp */; }; - BFD52C0822A1A9CB000B7ED1 /* time64.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BEC22A1A9CA000B7ED1 /* time64.c */; }; - BFD52C0922A1A9CB000B7ED1 /* plist.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BED22A1A9CA000B7ED1 /* plist.h */; }; - BFD52C0A22A1A9CB000B7ED1 /* plist.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BEE22A1A9CA000B7ED1 /* plist.c */; }; - BFD52C0B22A1A9CB000B7ED1 /* hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BEF22A1A9CA000B7ED1 /* hashtable.h */; }; - BFD52C0C22A1A9CB000B7ED1 /* Date.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF022A1A9CA000B7ED1 /* Date.cpp */; }; - BFD52C0D22A1A9CB000B7ED1 /* Uid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF122A1A9CA000B7ED1 /* Uid.cpp */; }; - BFD52C0E22A1A9CB000B7ED1 /* Boolean.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF222A1A9CA000B7ED1 /* Boolean.cpp */; }; - BFD52C0F22A1A9CB000B7ED1 /* Real.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF322A1A9CA000B7ED1 /* Real.cpp */; }; - BFD52C1022A1A9CB000B7ED1 /* strbuf.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BF422A1A9CA000B7ED1 /* strbuf.h */; }; - BFD52C1122A1A9CB000B7ED1 /* bytearray.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF522A1A9CA000B7ED1 /* bytearray.c */; }; - BFD52C1222A1A9CB000B7ED1 /* base64.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BF622A1A9CA000B7ED1 /* base64.h */; }; - BFD52C1322A1A9CB000B7ED1 /* Data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF722A1A9CA000B7ED1 /* Data.cpp */; }; - BFD52C1422A1A9CB000B7ED1 /* Array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF822A1A9CB000B7ED1 /* Array.cpp */; }; - BFD52C1522A1A9CB000B7ED1 /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BF922A1A9CB000B7ED1 /* Node.cpp */; }; - BFD52C1622A1A9CB000B7ED1 /* bytearray.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BFA22A1A9CB000B7ED1 /* bytearray.h */; }; - BFD52C1722A1A9CB000B7ED1 /* Key.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BFB22A1A9CB000B7ED1 /* Key.cpp */; }; - BFD52C1822A1A9CB000B7ED1 /* Integer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BFC22A1A9CB000B7ED1 /* Integer.cpp */; }; - BFD52C1922A1A9CB000B7ED1 /* Structure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFD52BFD22A1A9CB000B7ED1 /* Structure.cpp */; }; - BFD52C1A22A1A9CB000B7ED1 /* time64_limits.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BFE22A1A9CB000B7ED1 /* time64_limits.h */; }; - BFD52C1B22A1A9CB000B7ED1 /* time64.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD52BFF22A1A9CB000B7ED1 /* time64.h */; }; - BFD52C1C22A1A9CB000B7ED1 /* xplist.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52C0022A1A9CB000B7ED1 /* xplist.c */; }; - BFD52C2022A1A9EC000B7ED1 /* node.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52C1D22A1A9EC000B7ED1 /* node.c */; }; - BFD52C2122A1A9EC000B7ED1 /* node_list.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52C1E22A1A9EC000B7ED1 /* node_list.c */; }; - BFD52C2222A1A9EC000B7ED1 /* cnary.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52C1F22A1A9EC000B7ED1 /* cnary.c */; }; - BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */; }; - BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */; }; - BFDB6A0822AAED73007EA6D6 /* ResignAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */; }; - BFDB6A0B22AAEDB7007EA6D6 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */; }; - BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0C22AAFC19007EA6D6 /* OperationError.swift */; }; - BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0E22AB2776007EA6D6 /* SendAppOperation.swift */; }; - BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDBBD7F246CB84F004ED2F3 /* RemoveAppBackupOperation.swift */; }; - BFE00A202503097F00EB4D0C /* INInteraction+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE00A1F2503097F00EB4D0C /* INInteraction+AltStore.swift */; }; - BFE338DF22F0EADB002E24B9 /* FetchSourceOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */; }; - BFE338E822F10E56002E24B9 /* LaunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE338E722F10E56002E24B9 /* LaunchViewController.swift */; }; - BFE60738231ADF49002B0E8E /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFE60737231ADF49002B0E8E /* Settings.storyboard */; }; - BFE6073A231ADF82002B0E8E /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE60739231ADF82002B0E8E /* SettingsViewController.swift */; }; - BFE6073C231AE1E7002B0E8E /* SettingsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */; }; - BFE60740231AFD2A002B0E8E /* InsetGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */; }; - BFE60742231B07E6002B0E8E /* SettingsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */; }; - BFE6325A22A83BEB00F30809 /* Authentication.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFE6325922A83BEB00F30809 /* Authentication.storyboard */; }; - BFE6326C22A86FF300F30809 /* AuthenticationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */; }; - BFECAC8924FD950E0077C41F /* ConnectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18BFF22485828200DD5981 /* ConnectionManager.swift */; }; - BFECAC8D24FD950E0077C41F /* ALTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = BF718BD723C93DB700A89F2D /* ALTConstants.m */; }; - BFECAC8E24FD950E0077C41F /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18BFF624858BDE00DD5981 /* Connection.swift */; }; - BFECAC8F24FD950E0077C41F /* Result+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAC8852295C90300587369 /* Result+Conveniences.swift */; }; - BFECAC9024FD950E0077C41F /* Bundle+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */; }; - BFECAC9524FD98BB0077C41F /* CFNotificationName+AltStore.m in Sources */ = {isa = PBXBuildFile; fileRef = BF718BC823C919E300A89F2D /* CFNotificationName+AltStore.m */; }; - BFF00D302501BD7D00746320 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = BFF00D2F2501BD7D00746320 /* Intents.intentdefinition */; }; - BFF00D322501BDA100746320 /* BackgroundRefreshAppsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF00D312501BDA100746320 /* BackgroundRefreshAppsOperation.swift */; }; - BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF00D332501BDCF00746320 /* IntentHandler.swift */; }; - BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B68D23219520007A79E1 /* PatreonViewController.swift */; }; - BFF0B69023219C6D007A79E1 /* PatreonComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */; }; - BFF0B6922321A305007A79E1 /* AboutPatreonHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */; }; - BFF0B6942321CB85007A79E1 /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B6932321CB85007A79E1 /* AuthenticationViewController.swift */; }; - BFF0B696232242D3007A79E1 /* LicensesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B695232242D3007A79E1 /* LicensesViewController.swift */; }; - BFF0B6982322CAB8007A79E1 /* InstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B6972322CAB8007A79E1 /* InstructionsViewController.swift */; }; - BFF0B69A2322D7D0007A79E1 /* UIScreen+CompactHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */; }; - BFF435D8255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */; }; - BFF615A82510042B00484D3B /* AltStoreCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */; }; - D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */; }; - D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8B62727841800A9B5DD /* libAppleArchive.tbd */; settings = {ATTRIBUTES = (Weak, ); }; }; - D533E8BE2727BBF800A9B5DD /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8BD2727BBF800A9B5DD /* libcurl.a */; }; - D54DED1428CBC44B008B27A0 /* ErrorLogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */; }; - D55E163728776CB700A627A1 /* ComplicationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55E163528776CB000A627A1 /* ComplicationView.swift */; }; - D57DF638271E32F000677701 /* PatchApp.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D57DF637271E32F000677701 /* PatchApp.storyboard */; }; - D57DF63F271E51E400677701 /* ALTAppPatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D57DF63E271E51E400677701 /* ALTAppPatcher.m */; }; - D57F2C9126E0070200B9FA39 /* EnableJITOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */; }; - D57F2C9426E01BC700B9FA39 /* UIDevice+Vibration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57F2C9326E01BC700B9FA39 /* UIDevice+Vibration.swift */; }; - D57FE84428C7DB7100216002 /* ErrorLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57FE84328C7DB7100216002 /* ErrorLogViewController.swift */; }; - D58916FE28C7C55C00E39C8B /* LoggedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58916FD28C7C55C00E39C8B /* LoggedError.swift */; }; - D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D593F1932717749A006E82DE /* PatchAppOperation.swift */; }; - D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4A280E141900469595 /* ManagedPatron.swift */; }; - D5CA0C4E280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */; }; - D5DAE0942804B0B80034D8D4 /* ScreenshotProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DAE0932804B0B80034D8D4 /* ScreenshotProcessor.swift */; }; - D5DAE0962804DF430034D8D4 /* UpdatePatronsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */; }; - D5E1E7C128077DE90016FC96 /* FetchTrustedSourcesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5E1E7C028077DE90016FC96 /* FetchTrustedSourcesOperation.swift */; }; - D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F2F6A82720B7C20081CCF5 /* PatchViewController.swift */; }; - D5F99A1828D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */; }; - D5F99A1A28D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 19104D932909BADB00C49C7B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = BF45872A2298D31600BD7491; - remoteInfo = libimobiledevice; - }; - 19104DB92909C0F200C49C7B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 19104DB12909C06C00C49C7B; - remoteInfo = EmotionalDamage; - }; - 191E5FB2290A5D9B001A3B7C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 191E5FAA290A5D92001A3B7C; - remoteInfo = minimuxer; - }; - B343F84B295F6321002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F847295F6321002B1159 /* minimuxer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA609C732349C7AAD9FA67C4; - remoteInfo = "minimuxer-staticlib"; - }; - B343F852295F6323002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F84D295F6323002B1159 /* em_proxy.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA60C44C93D7916DE57E6EBD; - remoteInfo = "em_proxy-staticlib"; - }; - B343F854295F6323002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F84D295F6323002B1159 /* em_proxy.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CA60058A9FBE4D17AF51A7D5; - remoteInfo = "run-bin"; - }; - B343F86E295F76FD002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F847295F6321002B1159 /* minimuxer.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = CA609C732349A560B9642892; - remoteInfo = "minimuxer-staticlib"; - }; - B343F870295F7704002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F84D295F6323002B1159 /* em_proxy.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = CA60C44C93D7A30E3695DD59; - remoteInfo = "em_proxy-staticlib"; - }; - B343F88D295F7F9B002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 87B8C3401E0E9C37002F817D; - remoteInfo = "fragmentzip-cli-macOS"; - }; - B343F88F295F7F9B002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = B315FDB02866CCF8002E243C; - remoteInfo = "fragmentzip-cli-iOS"; - }; - B343F891295F7F9B002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = B315FDB52866CD91002E243C; - remoteInfo = "fragmentzip-macOS"; - }; - B343F893295F7F9B002B1159 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = B315FDCE2866CDD3002E243C; - remoteInfo = "fragmentzip-iOS"; - }; - BF66EE832501AE50007EE018 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = BF66EE7D2501AE50007EE018; - remoteInfo = AltStoreCore; - }; - BF989175250AABF4002ACF50 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = BF989166250AABF3002ACF50; - remoteInfo = AltWidgetExtension; - }; - BFF615AA2510042B00484D3B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFD247622284B9A500981D42 /* Project object */; - proxyType = 1; - remoteGlobalIDString = BF66EE7D2501AE50007EE018; - remoteInfo = AltStoreCore; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - BF088D2B2501A087008082D9 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - BF66EE862501AE50007EE018 /* AltStoreCore.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; - BF98917B250AABF4002ACF50 /* Embed App Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - BF989177250AABF4002ACF50 /* AltWidgetExtension.appex in Embed App Extensions */, - ); - name = "Embed App Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 19104DB22909C06C00C49C7B /* libEmotionalDamage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libEmotionalDamage.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 19104DB42909C06D00C49C7B /* EmotionalDamage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmotionalDamage.swift; sourceTree = ""; }; - 191E5FAB290A5D92001A3B7C /* libminimuxer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminimuxer.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 191E5FAD290A5D92001A3B7C /* minimuxer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = minimuxer.swift; sourceTree = ""; }; - 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libminimuxer.a; path = "Dependencies/minimuxer/target/aarch64-apple-ios/debug/libminimuxer.a"; sourceTree = ""; }; - 191E5FCF290A651D001A3B7C /* jplist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jplist.c; path = Dependencies/libplist/src/jplist.c; sourceTree = SOURCE_ROOT; }; - 191E5FD0290A651D001A3B7C /* jsmn.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jsmn.c; path = Dependencies/libplist/src/jsmn.c; sourceTree = SOURCE_ROOT; }; - 191E5FD1290A651D001A3B7C /* jsmn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jsmn.h; path = Dependencies/libplist/src/jsmn.h; sourceTree = SOURCE_ROOT; }; - 1920B04E2924AC8300744F60 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; - 19B9B7442845E6DF0076EF69 /* SelectTeamViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTeamViewController.swift; sourceTree = ""; }; - B33FFBA9295F8F78002259E6 /* preboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = preboard.c; path = src/preboard.c; sourceTree = ""; }; - B33FFBAB295F8F98002259E6 /* companion_proxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = companion_proxy.c; path = src/companion_proxy.c; sourceTree = ""; }; - B343F847295F6321002B1159 /* minimuxer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = minimuxer.xcodeproj; path = Dependencies/minimuxer.xcodeproj; sourceTree = SOURCE_ROOT; }; - B343F84D295F6323002B1159 /* em_proxy.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = em_proxy.xcodeproj; path = Dependencies/em_proxy.xcodeproj; sourceTree = SOURCE_ROOT; }; - B343F86C295F759E002B1159 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk/usr/lib/libresolv.tbd; sourceTree = DEVELOPER_DIR; }; - B343F872295F7C5C002B1159 /* opack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = opack.c; sourceTree = ""; }; - B343F873295F7C5C002B1159 /* cbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cbuf.c; sourceTree = ""; }; - B343F874295F7C5D002B1159 /* collection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = collection.c; sourceTree = ""; }; - B343F875295F7C5D002B1159 /* glue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glue.c; sourceTree = ""; }; - B343F876295F7C5D002B1159 /* socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = socket.c; sourceTree = ""; }; - B343F877295F7C5D002B1159 /* termcolors.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = termcolors.c; sourceTree = ""; }; - B343F879295F7C5D002B1159 /* thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = thread.c; sourceTree = ""; }; - B343F87A295F7C5D002B1159 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; - B343F87B295F7C5D002B1159 /* tlv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tlv.c; sourceTree = ""; }; - B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libfragmentzip.xcodeproj; path = Dependencies/libfragmentzip/libfragmentzip.xcodeproj; sourceTree = ""; }; - B34AFD1229A9D2C100E637B4 /* ServerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ServerProtocol.swift; path = ../../../../Downloads/ServerProtocol.swift; sourceTree = ""; }; - B34AFD1A29A9DFA200E637B4 /* NSError+AltStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+AltStore.swift"; sourceTree = ""; }; - B376FE3D29258C8900E18883 /* OSLog+SideStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSLog+SideStore.swift"; sourceTree = ""; }; - B39575F4284F29E20080B4FF /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - B39F16122918D7C5002E9404 /* Consts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Consts.swift; sourceTree = ""; }; - B39F16142918D7DA002E9404 /* Consts+Proxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Consts+Proxy.swift"; sourceTree = ""; }; - B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CodeSigning.xcconfig; sourceTree = ""; }; - B3C39607284F4C8400DA9E2F /* Build.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Build.xcconfig; sourceTree = ""; }; - B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */ = {isa = PBXFileReference; lastKnownFileType = text; path = CodeSigning.xcconfig.sample; sourceTree = ""; }; - B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStore.xcconfig; sourceTree = ""; }; - B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltWidgetExtension.xcconfig; sourceTree = ""; }; - B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = ""; }; - B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = ""; }; - B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnisetteManager.swift; sourceTree = ""; }; - BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshAttemptsViewController.swift; sourceTree = ""; }; - BF08858222DE795100DE9F1E /* MyAppsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsViewController.swift; sourceTree = ""; }; - BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCollectionViewCell.swift; sourceTree = ""; }; - BF0C4EBC22A1BD8B009A2DD7 /* AppManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppManager.swift; sourceTree = ""; }; - BF0DCA652433BDF500E3A595 /* AnalyticsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsManager.swift; sourceTree = ""; }; - BF10EB33248730750055E6DB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; - BF18B0F022E25DF9005C4CF5 /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = ""; }; - BF18BFE724857D7900DD5981 /* AltDaemon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = AltDaemon; sourceTree = BUILT_PRODUCTS_DIR; }; - BF18BFF22485828200DD5981 /* ConnectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionManager.swift; sourceTree = ""; }; - BF18BFF624858BDE00DD5981 /* Connection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; }; - BF18C0032485B4DE00DD5981 /* AltDaemon-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AltDaemon-Bridging-Header.h"; sourceTree = ""; }; - BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+AltStore.swift"; sourceTree = ""; }; - BF1E314722A060F300370A3C /* AltStore-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AltStore-Bridging-Header.h"; sourceTree = ""; }; - BF1FE357251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSXPCConnection+MachServices.swift"; sourceTree = ""; }; - BF219A7E22CAC431007676A6 /* AltStore.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AltStore.entitlements; sourceTree = ""; }; - BF29012E2318F6B100D88A45 /* AppBannerView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AppBannerView.xib; sourceTree = ""; }; - BF2901302318F7A800D88A45 /* AppBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppBannerView.swift; sourceTree = ""; }; - BF3432FA246B894F0052F4A1 /* BackupAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupAppOperation.swift; sourceTree = ""; }; - BF3BEFBE2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchProvisioningProfilesOperation.swift; sourceTree = ""; }; - BF3BEFC024086A1E00DE7D55 /* RefreshAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshAppOperation.swift; sourceTree = ""; }; - BF3D649C22E7AC1B00E9056B /* PermissionPopoverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionPopoverViewController.swift; sourceTree = ""; }; - BF3D649E22E7B24C00E9056B /* CollapsingTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsingTextView.swift; sourceTree = ""; }; - BF3D64AF22E8D4B800E9056B /* AppContentViewControllerCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewControllerCells.swift; sourceTree = ""; }; - BF41B805233423AE00C593A3 /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; - BF41B807233433C100C593A3 /* LoadingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingState.swift; sourceTree = ""; }; - BF42345825101C1D006D1EB2 /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; - BF44EEEF246B08BA002A52F2 /* BackupController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupController.swift; sourceTree = ""; }; - BF44EEF2246B3A17002A52F2 /* AltBackup.ipa */ = {isa = PBXFileReference; lastKnownFileType = file; path = AltBackup.ipa; sourceTree = ""; }; - BF44EEFB246B4550002A52F2 /* RemoveAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppOperation.swift; sourceTree = ""; }; - BF45872B2298D31600BD7491 /* libimobiledevice.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libimobiledevice.a; sourceTree = BUILT_PRODUCTS_DIR; }; - BF4587C82298D3A800BD7491 /* service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = service.h; path = Dependencies/libimobiledevice/src/service.h; sourceTree = SOURCE_ROOT; }; - BF4587C92298D3A800BD7491 /* diagnostics_relay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = diagnostics_relay.c; path = Dependencies/libimobiledevice/src/diagnostics_relay.c; sourceTree = SOURCE_ROOT; }; - BF4587CA2298D3A800BD7491 /* diagnostics_relay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = diagnostics_relay.h; path = Dependencies/libimobiledevice/src/diagnostics_relay.h; sourceTree = SOURCE_ROOT; }; - BF4587CB2298D3A800BD7491 /* notification_proxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notification_proxy.c; path = Dependencies/libimobiledevice/src/notification_proxy.c; sourceTree = SOURCE_ROOT; }; - BF4587CC2298D3A800BD7491 /* sbservices.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sbservices.c; path = Dependencies/libimobiledevice/src/sbservices.c; sourceTree = SOURCE_ROOT; }; - BF4587CD2298D3A800BD7491 /* sbservices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sbservices.h; path = Dependencies/libimobiledevice/src/sbservices.h; sourceTree = SOURCE_ROOT; }; - BF4587CE2298D3A800BD7491 /* mobilebackup2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mobilebackup2.h; path = Dependencies/libimobiledevice/src/mobilebackup2.h; sourceTree = SOURCE_ROOT; }; - BF4587CF2298D3A800BD7491 /* heartbeat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = heartbeat.c; path = Dependencies/libimobiledevice/src/heartbeat.c; sourceTree = SOURCE_ROOT; }; - BF4587D02298D3A800BD7491 /* restore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = restore.h; path = Dependencies/libimobiledevice/src/restore.h; sourceTree = SOURCE_ROOT; }; - BF4587D12298D3A800BD7491 /* installation_proxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = installation_proxy.h; path = Dependencies/libimobiledevice/src/installation_proxy.h; sourceTree = SOURCE_ROOT; }; - BF4587D22298D3A800BD7491 /* file_relay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_relay.c; path = Dependencies/libimobiledevice/src/file_relay.c; sourceTree = SOURCE_ROOT; }; - BF4587D32298D3A800BD7491 /* syslog_relay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = syslog_relay.c; path = Dependencies/libimobiledevice/src/syslog_relay.c; sourceTree = SOURCE_ROOT; }; - BF4587D42298D3A800BD7491 /* lockdown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lockdown.h; path = Dependencies/libimobiledevice/src/lockdown.h; sourceTree = SOURCE_ROOT; }; - BF4587D52298D3A800BD7491 /* idevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = idevice.h; path = Dependencies/libimobiledevice/src/idevice.h; sourceTree = SOURCE_ROOT; }; - BF4587D62298D3A800BD7491 /* webinspector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = webinspector.c; path = Dependencies/libimobiledevice/src/webinspector.c; sourceTree = SOURCE_ROOT; }; - BF4587D72298D3A800BD7491 /* afc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = afc.c; path = Dependencies/libimobiledevice/src/afc.c; sourceTree = SOURCE_ROOT; }; - BF4587D82298D3A800BD7491 /* mobile_image_mounter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobile_image_mounter.c; path = Dependencies/libimobiledevice/src/mobile_image_mounter.c; sourceTree = SOURCE_ROOT; }; - BF4587D92298D3A900BD7491 /* installation_proxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = installation_proxy.c; path = Dependencies/libimobiledevice/src/installation_proxy.c; sourceTree = SOURCE_ROOT; }; - BF4587DA2298D3A900BD7491 /* screenshotr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = screenshotr.h; path = Dependencies/libimobiledevice/src/screenshotr.h; sourceTree = SOURCE_ROOT; }; - BF4587DB2298D3A900BD7491 /* mobilesync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mobilesync.h; path = Dependencies/libimobiledevice/src/mobilesync.h; sourceTree = SOURCE_ROOT; }; - BF4587DC2298D3A900BD7491 /* mobilebackup2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobilebackup2.c; path = Dependencies/libimobiledevice/src/mobilebackup2.c; sourceTree = SOURCE_ROOT; }; - BF4587DD2298D3A900BD7491 /* mobilebackup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobilebackup.c; path = Dependencies/libimobiledevice/src/mobilebackup.c; sourceTree = SOURCE_ROOT; }; - BF4587DE2298D3A900BD7491 /* debugserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = debugserver.h; path = Dependencies/libimobiledevice/src/debugserver.h; sourceTree = SOURCE_ROOT; }; - BF4587DF2298D3A900BD7491 /* debugserver.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debugserver.c; path = Dependencies/libimobiledevice/src/debugserver.c; sourceTree = SOURCE_ROOT; }; - BF4587E02298D3A900BD7491 /* heartbeat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = heartbeat.h; path = Dependencies/libimobiledevice/src/heartbeat.h; sourceTree = SOURCE_ROOT; }; - BF4587E12298D3A900BD7491 /* misagent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = misagent.h; path = Dependencies/libimobiledevice/src/misagent.h; sourceTree = SOURCE_ROOT; }; - BF4587E22298D3A900BD7491 /* house_arrest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = house_arrest.h; path = Dependencies/libimobiledevice/src/house_arrest.h; sourceTree = SOURCE_ROOT; }; - BF4587E32298D3A900BD7491 /* notification_proxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = notification_proxy.h; path = Dependencies/libimobiledevice/src/notification_proxy.h; sourceTree = SOURCE_ROOT; }; - BF4587E42298D3A900BD7491 /* device_link_service.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = device_link_service.c; path = Dependencies/libimobiledevice/src/device_link_service.c; sourceTree = SOURCE_ROOT; }; - BF4587E52298D3A900BD7491 /* mobilebackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mobilebackup.h; path = Dependencies/libimobiledevice/src/mobilebackup.h; sourceTree = SOURCE_ROOT; }; - BF4587E62298D3A900BD7491 /* restore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = restore.c; path = Dependencies/libimobiledevice/src/restore.c; sourceTree = SOURCE_ROOT; }; - BF4587E72298D3A900BD7491 /* screenshotr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = screenshotr.c; path = Dependencies/libimobiledevice/src/screenshotr.c; sourceTree = SOURCE_ROOT; }; - BF4587E82298D3A900BD7491 /* syslog_relay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = syslog_relay.h; path = Dependencies/libimobiledevice/src/syslog_relay.h; sourceTree = SOURCE_ROOT; }; - BF4587E92298D3AA00BD7491 /* webinspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = webinspector.h; path = Dependencies/libimobiledevice/src/webinspector.h; sourceTree = SOURCE_ROOT; }; - BF4587EA2298D3AA00BD7491 /* mobileactivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mobileactivation.h; path = Dependencies/libimobiledevice/src/mobileactivation.h; sourceTree = SOURCE_ROOT; }; - BF4587EB2298D3AA00BD7491 /* house_arrest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = house_arrest.c; path = Dependencies/libimobiledevice/src/house_arrest.c; sourceTree = SOURCE_ROOT; }; - BF4587EC2298D3AA00BD7491 /* afc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = afc.h; path = Dependencies/libimobiledevice/src/afc.h; sourceTree = SOURCE_ROOT; }; - BF4587ED2298D3AA00BD7491 /* file_relay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_relay.h; path = Dependencies/libimobiledevice/src/file_relay.h; sourceTree = SOURCE_ROOT; }; - BF4587EE2298D3AA00BD7491 /* misagent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = misagent.c; path = Dependencies/libimobiledevice/src/misagent.c; sourceTree = SOURCE_ROOT; }; - BF4587EF2298D3AA00BD7491 /* device_link_service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = device_link_service.h; path = Dependencies/libimobiledevice/src/device_link_service.h; sourceTree = SOURCE_ROOT; }; - BF4587F02298D3AA00BD7491 /* mobile_image_mounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mobile_image_mounter.h; path = Dependencies/libimobiledevice/src/mobile_image_mounter.h; sourceTree = SOURCE_ROOT; }; - BF4587F12298D3AA00BD7491 /* idevice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = idevice.c; path = Dependencies/libimobiledevice/src/idevice.c; sourceTree = SOURCE_ROOT; }; - BF4587F22298D3AA00BD7491 /* mobileactivation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobileactivation.c; path = Dependencies/libimobiledevice/src/mobileactivation.c; sourceTree = SOURCE_ROOT; }; - BF4587F32298D3AA00BD7491 /* mobilesync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobilesync.c; path = Dependencies/libimobiledevice/src/mobilesync.c; sourceTree = SOURCE_ROOT; }; - BF4587F42298D3AA00BD7491 /* property_list_service.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = property_list_service.c; path = Dependencies/libimobiledevice/src/property_list_service.c; sourceTree = SOURCE_ROOT; }; - BF4587F52298D3AA00BD7491 /* property_list_service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = property_list_service.h; path = Dependencies/libimobiledevice/src/property_list_service.h; sourceTree = SOURCE_ROOT; }; - BF4587F62298D3AB00BD7491 /* lockdown.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lockdown.c; path = Dependencies/libimobiledevice/src/lockdown.c; sourceTree = SOURCE_ROOT; }; - BF4587F72298D3AB00BD7491 /* service.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = service.c; path = Dependencies/libimobiledevice/src/service.c; sourceTree = SOURCE_ROOT; }; - BF45882A2298D3C000BD7491 /* userpref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = userpref.h; path = Dependencies/libimobiledevice/common/userpref.h; sourceTree = SOURCE_ROOT; }; - BF45882B2298D3C000BD7491 /* userpref.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = userpref.c; path = Dependencies/libimobiledevice/common/userpref.c; sourceTree = SOURCE_ROOT; }; - BF45882C2298D3C000BD7491 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = debug.h; path = Dependencies/libimobiledevice/common/debug.h; sourceTree = SOURCE_ROOT; }; - BF4588302298D3C000BD7491 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = Dependencies/libimobiledevice/common/debug.c; sourceTree = SOURCE_ROOT; }; - BF4588422298D40000BD7491 /* libusbmuxd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = libusbmuxd.c; path = Dependencies/libusbmuxd/src/libusbmuxd.c; sourceTree = SOURCE_ROOT; }; - BF4588872298DD3F00BD7491 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; }; - BF4B78FD24B3D1DB008AB4AC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAppIDsOperation.swift; sourceTree = ""; }; - BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIDsViewController.swift; sourceTree = ""; }; - BF58047B246A28F7008AE704 /* AltBackup.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AltBackup.app; sourceTree = BUILT_PRODUCTS_DIR; }; - BF58047D246A28F7008AE704 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - BF580481246A28F7008AE704 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - BF580486246A28F9008AE704 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - BF580489246A28F9008AE704 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - BF58048B246A28F9008AE704 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BF580495246A3CB5008AE704 /* UIColor+AltBackup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+AltBackup.swift"; sourceTree = ""; }; - BF580497246A3D19008AE704 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - BF580499246A4153008AE704 /* AltBackup.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AltBackup.entitlements; sourceTree = ""; }; - BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+DirectorySize.swift"; sourceTree = ""; }; - BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AltStoreCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BF66EE802501AE50007EE018 /* AltStoreCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AltStoreCore.h; sourceTree = ""; }; - BF66EE812501AE50007EE018 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BF66EE8B2501AEB1007EE018 /* Keychain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; - BF66EE8E2501AEBC007EE018 /* ALTAppPermission.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTAppPermission.h; sourceTree = ""; }; - BF66EE8F2501AEBC007EE018 /* ALTSourceUserInfoKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTSourceUserInfoKey.h; sourceTree = ""; }; - BF66EE902501AEBC007EE018 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = ""; }; - BF66EE912501AEBC007EE018 /* ALTAppPermission.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTAppPermission.m; sourceTree = ""; }; - BF66EE922501AEBC007EE018 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = ""; }; - BF66EE932501AEBC007EE018 /* ALTSourceUserInfoKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ALTSourceUserInfoKey.m; sourceTree = ""; }; - BF66EE9B2501AEC1007EE018 /* AppProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppProtocol.swift; sourceTree = ""; }; - BF66EE9C2501AEC1007EE018 /* Fetchable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = ""; }; - BF66EEA02501AEC5007EE018 /* Benefit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Benefit.swift; sourceTree = ""; }; - BF66EEA12501AEC5007EE018 /* PatreonAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PatreonAPI.swift; sourceTree = ""; }; - BF66EEA22501AEC5007EE018 /* Campaign.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Campaign.swift; sourceTree = ""; }; - BF66EEA32501AEC5007EE018 /* Patron.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Patron.swift; sourceTree = ""; }; - BF66EEA42501AEC5007EE018 /* Tier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tier.swift; sourceTree = ""; }; - BF66EEAB2501AECA007EE018 /* Source.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Source.swift; sourceTree = ""; }; - BF66EEAE2501AECA007EE018 /* StoreAppPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreAppPolicy.swift; sourceTree = ""; }; - BF66EEAF2501AECA007EE018 /* InstalledAppPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstalledAppPolicy.swift; sourceTree = ""; }; - BF66EEB12501AECA007EE018 /* AltStoreToAltStore2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStoreToAltStore2.xcmappingmodel; sourceTree = ""; }; - BF66EEB22501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore6ToAltStore7.xcmappingmodel; sourceTree = ""; }; - BF66EEB32501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore3ToAltStore4.xcmappingmodel; sourceTree = ""; }; - BF66EEB42501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore4ToAltStore5.xcmappingmodel; sourceTree = ""; }; - BF66EEB52501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore2ToAltStore3.xcmappingmodel; sourceTree = ""; }; - BF66EEB62501AECA007EE018 /* AltStore5ToAltStore6.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore5ToAltStore6.xcmappingmodel; sourceTree = ""; }; - BF66EEB82501AECA007EE018 /* AltStore 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 3.xcdatamodel"; sourceTree = ""; }; - BF66EEB92501AECA007EE018 /* AltStore.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = AltStore.xcdatamodel; sourceTree = ""; }; - BF66EEBA2501AECA007EE018 /* AltStore 6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 6.xcdatamodel"; sourceTree = ""; }; - BF66EEBB2501AECA007EE018 /* AltStore 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 5.xcdatamodel"; sourceTree = ""; }; - BF66EEBC2501AECA007EE018 /* AltStore 7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 7.xcdatamodel"; sourceTree = ""; }; - BF66EEBD2501AECA007EE018 /* AltStore 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 2.xcdatamodel"; sourceTree = ""; }; - BF66EEBE2501AECA007EE018 /* AltStore 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 4.xcdatamodel"; sourceTree = ""; }; - BF66EEBF2501AECA007EE018 /* NewsItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsItem.swift; sourceTree = ""; }; - BF66EEC02501AECA007EE018 /* InstalledApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstalledApp.swift; sourceTree = ""; }; - BF66EEC12501AECA007EE018 /* SecureValueTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureValueTransformer.swift; sourceTree = ""; }; - BF66EEC22501AECA007EE018 /* Team.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Team.swift; sourceTree = ""; }; - BF66EEC32501AECA007EE018 /* RefreshAttempt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshAttempt.swift; sourceTree = ""; }; - BF66EEC42501AECA007EE018 /* StoreApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreApp.swift; sourceTree = ""; }; - BF66EEC52501AECA007EE018 /* MergePolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MergePolicy.swift; sourceTree = ""; }; - BF66EEC62501AECA007EE018 /* AppPermission.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppPermission.swift; sourceTree = ""; }; - BF66EEC72501AECA007EE018 /* AppID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppID.swift; sourceTree = ""; }; - BF66EEC82501AECA007EE018 /* PatreonAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PatreonAccount.swift; sourceTree = ""; }; - BF66EEC92501AECA007EE018 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; - BF66EECA2501AECA007EE018 /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManager.swift; sourceTree = ""; }; - BF66EECB2501AECA007EE018 /* InstalledExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstalledExtension.swift; sourceTree = ""; }; - BF66EEE42501AED0007EE018 /* UserDefaults+AltStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+AltStore.swift"; sourceTree = ""; }; - BF66EEE52501AED0007EE018 /* JSONDecoder+Properties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Properties.swift"; sourceTree = ""; }; - BF66EEE62501AED0007EE018 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = ""; }; - BF66EEE72501AED0007EE018 /* UIApplication+AppExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+AppExtension.swift"; sourceTree = ""; }; - BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SharedDirectories.swift"; sourceTree = ""; }; - BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+Markdown.m"; path = "Dependencies/MarkdownAttributedString/NSAttributedString+Markdown.m"; sourceTree = SOURCE_ROOT; }; - BF6C8FAB242935ED00125131 /* NSAttributedString+Markdown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributedString+Markdown.h"; path = "Dependencies/MarkdownAttributedString/NSAttributedString+Markdown.h"; sourceTree = SOURCE_ROOT; }; - BF6C8FAD2429597900125131 /* BannerCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerCollectionViewCell.swift; sourceTree = ""; }; - BF6C8FAF2429599900125131 /* TextCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCollectionReusableView.swift; sourceTree = ""; }; - BF6F439123644C6E00A0B879 /* RefreshAltStoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshAltStoreViewController.swift; sourceTree = ""; }; - BF718BC723C919CC00A89F2D /* CFNotificationName+AltStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CFNotificationName+AltStore.h"; sourceTree = ""; }; - BF718BC823C919E300A89F2D /* CFNotificationName+AltStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CFNotificationName+AltStore.m"; sourceTree = ""; }; - BF718BD723C93DB700A89F2D /* ALTConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTConstants.m; sourceTree = ""; }; - BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardingNavigationController.swift; sourceTree = ""; }; - BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallAppOperation.swift; sourceTree = ""; }; - BF770E5322BC044E002A40FE /* OperationContexts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationContexts.swift; sourceTree = ""; }; - BF770E5722BC3D0F002A40FE /* RefreshGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshGroup.swift; sourceTree = ""; }; - BF770E6622BD57C3002A40FE /* BackgroundTaskManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundTaskManager.swift; sourceTree = ""; }; - BF770E6822BD57DD002A40FE /* Silence.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Silence.m4a; sourceTree = ""; }; - BF88F97124F8727D00BB75DF /* AppManagerErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppManagerErrors.swift; sourceTree = ""; }; - BF8B17F0250AC62400F8157F /* AltWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AltWidgetExtension.entitlements; sourceTree = ""; }; - BF8CAE422489E772004D6CCE /* AnisetteDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnisetteDataManager.swift; sourceTree = ""; }; - BF8CAE432489E772004D6CCE /* AppManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppManager.swift; sourceTree = ""; }; - BF8CAE442489E772004D6CCE /* DaemonRequestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DaemonRequestHandler.swift; sourceTree = ""; }; - BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Jailbreak.swift"; sourceTree = ""; }; - BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = ""; }; - BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = ""; }; - BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AltWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - BF989170250AABF4002ACF50 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - BF989172250AABF4002ACF50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BF98917C250AAC4F002ACF50 /* Countdown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Countdown.swift; sourceTree = ""; }; - BF98917D250AAC4F002ACF50 /* AltWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AltWidget.swift; sourceTree = ""; }; - BF989190250AAE86002ACF50 /* ViewAppIntentHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewAppIntentHandler.swift; sourceTree = ""; }; - BF989191250AAE86002ACF50 /* ViewApp.intentdefinition */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.intentdefinition; path = ViewApp.intentdefinition; sourceTree = ""; }; - BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseViewController.swift; sourceTree = ""; }; - BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseCollectionViewCell.swift; sourceTree = ""; }; - BF9ABA4822DD0742008935CF /* ScreenshotCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotCollectionViewCell.swift; sourceTree = ""; }; - BF9ABA4A22DD137F008935CF /* NavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBar.swift; sourceTree = ""; }; - BF9ABA4C22DD16DE008935CF /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = ""; }; - BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchAnisetteDataOperation.swift; sourceTree = ""; }; - BFB1169C22932DB100BB457C /* apps.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = apps.json; sourceTree = ""; }; - BFB39B5B252BC10E00D1BE50 /* Managed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Managed.swift; sourceTree = ""; }; - BFB4323E22DE852000B7F8BC /* UpdateCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UpdateCollectionViewCell.xib; sourceTree = ""; }; - BFB6B21D231870160022A802 /* NewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsViewController.swift; sourceTree = ""; }; - BFB6B21F231870B00022A802 /* NewsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsCollectionViewCell.swift; sourceTree = ""; }; - BFB6B22323187A3D0022A802 /* NewsCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NewsCollectionViewCell.xib; sourceTree = ""; }; - BFBAC8852295C90300587369 /* Result+Conveniences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Result+Conveniences.swift"; sourceTree = ""; }; - BFBF33142526754700B7B8C9 /* AltStore 9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 9.xcdatamodel"; sourceTree = ""; }; - BFBF331A2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore8ToAltStore9.xcmappingmodel; sourceTree = ""; }; - BFC1F38C22AEE3A4003AC21A /* DownloadAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadAppOperation.swift; sourceTree = ""; }; - BFC57A642416C72400EB891E /* DeactivateAppOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeactivateAppOperation.swift; sourceTree = ""; }; - BFC57A6D2416FC5D00EB891E /* InstalledAppsCollectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledAppsCollectionHeaderView.swift; sourceTree = ""; }; - BFC57A6F2416FC7600EB891E /* InstalledAppsCollectionHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InstalledAppsCollectionHeaderView.xib; sourceTree = ""; }; - BFC712C12512D5F100AB5EBE /* XPCConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XPCConnection.swift; sourceTree = ""; }; - BFC712C22512D5F100AB5EBE /* XPCConnectionHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XPCConnectionHandler.swift; sourceTree = ""; }; - BFC84A4C2421A19100853474 /* SourcesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourcesViewController.swift; sourceTree = ""; }; - BFCB9206250AB2120057B44E /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; - BFCCB519245E3401001853EA /* VerifyAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyAppOperation.swift; sourceTree = ""; }; - BFD2476A2284B9A500981D42 /* SideStore.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SideStore.app; sourceTree = BUILT_PRODUCTS_DIR; }; - BFD2476D2284B9A500981D42 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - BFD247742284B9A500981D42 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - BFD247762284B9A700981D42 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - BFD247792284B9A700981D42 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - BFD2477B2284B9A700981D42 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - BFD247862284BB3B00981D42 /* Roxas.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BFD2478B2284C4C300981D42 /* AppIconImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconImageView.swift; sourceTree = ""; }; - BFD2478E2284C8F900981D42 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; - BFD2479E2284FBD000981D42 /* UIColor+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+AltStore.swift"; sourceTree = ""; }; - BFD52BD222A06EFB000B7ED1 /* ALTConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTConstants.h; sourceTree = ""; }; - BFD52BE522A1A9CA000B7ED1 /* ptrarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ptrarray.c; path = Dependencies/libplist/src/ptrarray.c; sourceTree = SOURCE_ROOT; }; - BFD52BE622A1A9CA000B7ED1 /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = base64.c; path = Dependencies/libplist/src/base64.c; sourceTree = SOURCE_ROOT; }; - BFD52BE722A1A9CA000B7ED1 /* hashtable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hashtable.c; path = Dependencies/libplist/src/hashtable.c; sourceTree = SOURCE_ROOT; }; - BFD52BE822A1A9CA000B7ED1 /* Dictionary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Dictionary.cpp; path = Dependencies/libplist/src/Dictionary.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BE922A1A9CA000B7ED1 /* ptrarray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ptrarray.h; path = Dependencies/libplist/src/ptrarray.h; sourceTree = SOURCE_ROOT; }; - BFD52BEA22A1A9CA000B7ED1 /* bplist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bplist.c; path = Dependencies/libplist/src/bplist.c; sourceTree = SOURCE_ROOT; }; - BFD52BEB22A1A9CA000B7ED1 /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = String.cpp; path = Dependencies/libplist/src/String.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BEC22A1A9CA000B7ED1 /* time64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = time64.c; path = Dependencies/libplist/src/time64.c; sourceTree = SOURCE_ROOT; }; - BFD52BED22A1A9CA000B7ED1 /* plist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = plist.h; path = Dependencies/libplist/src/plist.h; sourceTree = SOURCE_ROOT; }; - BFD52BEE22A1A9CA000B7ED1 /* plist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = plist.c; path = Dependencies/libplist/src/plist.c; sourceTree = SOURCE_ROOT; }; - BFD52BEF22A1A9CA000B7ED1 /* hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hashtable.h; path = Dependencies/libplist/src/hashtable.h; sourceTree = SOURCE_ROOT; }; - BFD52BF022A1A9CA000B7ED1 /* Date.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Date.cpp; path = Dependencies/libplist/src/Date.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF122A1A9CA000B7ED1 /* Uid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Uid.cpp; path = Dependencies/libplist/src/Uid.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF222A1A9CA000B7ED1 /* Boolean.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Boolean.cpp; path = Dependencies/libplist/src/Boolean.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF322A1A9CA000B7ED1 /* Real.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Real.cpp; path = Dependencies/libplist/src/Real.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF422A1A9CA000B7ED1 /* strbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = strbuf.h; path = Dependencies/libplist/src/strbuf.h; sourceTree = SOURCE_ROOT; }; - BFD52BF522A1A9CA000B7ED1 /* bytearray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bytearray.c; path = Dependencies/libplist/src/bytearray.c; sourceTree = SOURCE_ROOT; }; - BFD52BF622A1A9CA000B7ED1 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = base64.h; path = Dependencies/libplist/src/base64.h; sourceTree = SOURCE_ROOT; }; - BFD52BF722A1A9CA000B7ED1 /* Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Data.cpp; path = Dependencies/libplist/src/Data.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF822A1A9CB000B7ED1 /* Array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Array.cpp; path = Dependencies/libplist/src/Array.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BF922A1A9CB000B7ED1 /* Node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Node.cpp; path = Dependencies/libplist/src/Node.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BFA22A1A9CB000B7ED1 /* bytearray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytearray.h; path = Dependencies/libplist/src/bytearray.h; sourceTree = SOURCE_ROOT; }; - BFD52BFB22A1A9CB000B7ED1 /* Key.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Key.cpp; path = Dependencies/libplist/src/Key.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BFC22A1A9CB000B7ED1 /* Integer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Integer.cpp; path = Dependencies/libplist/src/Integer.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BFD22A1A9CB000B7ED1 /* Structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Structure.cpp; path = Dependencies/libplist/src/Structure.cpp; sourceTree = SOURCE_ROOT; }; - BFD52BFE22A1A9CB000B7ED1 /* time64_limits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = time64_limits.h; path = Dependencies/libplist/src/time64_limits.h; sourceTree = SOURCE_ROOT; }; - BFD52BFF22A1A9CB000B7ED1 /* time64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = time64.h; path = Dependencies/libplist/src/time64.h; sourceTree = SOURCE_ROOT; }; - BFD52C0022A1A9CB000B7ED1 /* xplist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xplist.c; path = Dependencies/libplist/src/xplist.c; sourceTree = SOURCE_ROOT; }; - BFD52C1D22A1A9EC000B7ED1 /* node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = node.c; path = Dependencies/libplist/libcnary/node.c; sourceTree = SOURCE_ROOT; }; - BFD52C1E22A1A9EC000B7ED1 /* node_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = node_list.c; path = Dependencies/libplist/libcnary/node_list.c; sourceTree = SOURCE_ROOT; }; - BFD52C1F22A1A9EC000B7ED1 /* cnary.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cnary.c; path = Dependencies/libplist/libcnary/cnary.c; sourceTree = SOURCE_ROOT; }; - BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsComponents.swift; sourceTree = ""; }; - BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+RelativeDate.swift"; sourceTree = ""; }; - BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BrowseCollectionViewCell.xib; sourceTree = ""; }; - BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResignAppOperation.swift; sourceTree = ""; }; - BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = ""; }; - BFDB6A0C22AAFC19007EA6D6 /* OperationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationError.swift; sourceTree = ""; }; - BFDB6A0E22AB2776007EA6D6 /* SendAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendAppOperation.swift; sourceTree = ""; }; - BFDBBD7F246CB84F004ED2F3 /* RemoveAppBackupOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveAppBackupOperation.swift; sourceTree = ""; }; - BFE00A1F2503097F00EB4D0C /* INInteraction+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "INInteraction+AltStore.swift"; sourceTree = ""; }; - BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchSourceOperation.swift; sourceTree = ""; }; - BFE338E722F10E56002E24B9 /* LaunchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchViewController.swift; sourceTree = ""; }; - BFE60737231ADF49002B0E8E /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; - BFE60739231ADF82002B0E8E /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; - BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsHeaderFooterView.xib; sourceTree = ""; }; - BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsetGroupTableViewCell.swift; sourceTree = ""; }; - BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeaderFooterView.swift; sourceTree = ""; }; - BFE6325922A83BEB00F30809 /* Authentication.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Authentication.storyboard; sourceTree = ""; }; - BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationOperation.swift; sourceTree = ""; }; - BFF00D2F2501BD7D00746320 /* Intents.intentdefinition */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = ""; }; - BFF00D312501BDA100746320 /* BackgroundRefreshAppsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundRefreshAppsOperation.swift; sourceTree = ""; }; - BFF00D332501BDCF00746320 /* IntentHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; - BFF0B68D23219520007A79E1 /* PatreonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonViewController.swift; sourceTree = ""; }; - BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonComponents.swift; sourceTree = ""; }; - BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutPatreonHeaderView.xib; sourceTree = ""; }; - BFF0B6932321CB85007A79E1 /* AuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = ""; }; - BFF0B695232242D3007A79E1 /* LicensesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensesViewController.swift; sourceTree = ""; }; - BFF0B6972322CAB8007A79E1 /* InstructionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionsViewController.swift; sourceTree = ""; }; - BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScreen+CompactHeight.swift"; sourceTree = ""; }; - BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ALTApplication+AltStoreApp.swift"; sourceTree = ""; }; - BFF767CD2489ABE90097E58C /* NetworkConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConnection.swift; sourceTree = ""; }; - BFF7C906257844C900E55F36 /* AltXPCProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AltXPCProtocol.h; sourceTree = ""; }; - BFF7EC4C25081E9300BDE521 /* AltStore 8.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 8.xcdatamodel"; sourceTree = ""; }; - BFFCFA45248835530077BFCE /* AltDaemon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AltDaemon.entitlements; sourceTree = ""; }; - D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; - D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 11.xcdatamodel"; sourceTree = ""; }; - D533E8B62727841800A9B5DD /* libAppleArchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libAppleArchive.tbd; path = usr/lib/libAppleArchive.tbd; sourceTree = SDKROOT; }; - D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = ""; }; - D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dependencies/fragmentzip/libfragmentzip.a; sourceTree = SOURCE_ROOT; }; - D533E8BD2727BBF800A9B5DD /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = Dependencies/libcurl/libcurl.a; sourceTree = SOURCE_ROOT; }; - D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogTableViewCell.swift; sourceTree = ""; }; - D55E163528776CB000A627A1 /* ComplicationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationView.swift; sourceTree = ""; }; - D57DF637271E32F000677701 /* PatchApp.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PatchApp.storyboard; sourceTree = ""; }; - D57DF63D271E51E400677701 /* ALTAppPatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTAppPatcher.h; sourceTree = ""; }; - D57DF63E271E51E400677701 /* ALTAppPatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTAppPatcher.m; sourceTree = ""; }; - D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableJITOperation.swift; sourceTree = ""; }; - D57F2C9326E01BC700B9FA39 /* UIDevice+Vibration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+Vibration.swift"; sourceTree = ""; }; - D57FE84328C7DB7100216002 /* ErrorLogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogViewController.swift; sourceTree = ""; }; - D58916FD28C7C55C00E39C8B /* LoggedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedError.swift; sourceTree = ""; }; - D593F1932717749A006E82DE /* PatchAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchAppOperation.swift; sourceTree = ""; }; - D5CA0C4A280E141900469595 /* ManagedPatron.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPatron.swift; sourceTree = ""; }; - D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 10.xcdatamodel"; sourceTree = ""; }; - D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore9ToAltStore10.xcmappingmodel; sourceTree = ""; }; - D5DAE0932804B0B80034D8D4 /* ScreenshotProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotProcessor.swift; sourceTree = ""; }; - D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePatronsOperation.swift; sourceTree = ""; }; - D5E1E7C028077DE90016FC96 /* FetchTrustedSourcesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchTrustedSourcesOperation.swift; sourceTree = ""; }; - D5F2F6A82720B7C20081CCF5 /* PatchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchViewController.swift; sourceTree = ""; }; - D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore10ToAltStore11.xcmappingmodel; sourceTree = ""; }; - D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp10ToStoreApp11Policy.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 19104DAF2909C06C00C49C7B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B343F86D295F759E002B1159 /* libresolv.tbd in Frameworks */, - B343F859295F6335002B1159 /* libem_proxy_static.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 191E5FA8290A5D92001A3B7C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B343F858295F6331002B1159 /* libminimuxer_static.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 678E094C3184B66357EAA4AF /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 191E5FDC290AFA5C001A3B7C /* OpenSSL in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF18BFE424857D7900DD5981 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF580478246A28F7008AE704 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - BF580498246A3D19008AE704 /* UIKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF66EE7B2501AE50007EE018 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B34AFD1929A9DB0200E637B4 /* SideKit in Frameworks */, - B3C395F1284F2DE700DA9E2F /* KeychainAccess in Frameworks */, - B34AFD1729A9D9FC00E637B4 /* RoxasUI in Frameworks */, - 99C4EF4D2979132100CB538D /* SemanticVersion in Frameworks */, - B34AFD1129A9CF5C00E637B4 /* Roxas in Frameworks */, - 4879A95F2861046500FC1BBD /* AltSign in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF989164250AABF3002ACF50 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - BFF615A82510042B00484D3B /* AltStoreCore.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BFD247672284B9A500981D42 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B33FFBA8295F8E98002259E6 /* libfragmentzip.a in Frameworks */, - 191E6087290C7B50001A3B7C /* libminimuxer.a in Frameworks */, - B34AFD0F29A9CF4000E637B4 /* RoxasUI in Frameworks */, - 191E5FB4290A5DA0001A3B7C /* libminimuxer.a in Frameworks */, - 19104DBC2909C4E500C49C7B /* libEmotionalDamage.a in Frameworks */, - 19104D952909BAEA00C49C7B /* libimobiledevice.a in Frameworks */, - D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */, - B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */, - D533E8BE2727BBF800A9B5DD /* libcurl.a in Frameworks */, - B34AFD0A29A9CEDD00E637B4 /* SideKit in Frameworks */, - 4879A9622861049C00FC1BBD /* OpenSSL in Frameworks */, - B3C395F4284F35DD00DA9E2F /* Nuke in Frameworks */, - B34AFD0D29A9CF4000E637B4 /* Roxas in Frameworks */, - B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */, - BF66EE852501AE50007EE018 /* AltStoreCore.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 19104DB32909C06D00C49C7B /* EmotionalDamage */ = { - isa = PBXGroup; - children = ( - B343F84D295F6323002B1159 /* em_proxy.xcodeproj */, - 19104DB42909C06D00C49C7B /* EmotionalDamage.swift */, - ); - path = EmotionalDamage; - sourceTree = ""; - }; - 191E5FAC290A5D92001A3B7C /* minimuxer */ = { - isa = PBXGroup; - children = ( - B343F847295F6321002B1159 /* minimuxer.xcodeproj */, - 191E5FAD290A5D92001A3B7C /* minimuxer.swift */, - ); - path = minimuxer; - sourceTree = ""; - }; - 191E5FF4290B2663001A3B7C /* libimobiledevice-glue */ = { - isa = PBXGroup; - children = ( - B343F873295F7C5C002B1159 /* cbuf.c */, - B343F874295F7C5D002B1159 /* collection.c */, - B343F875295F7C5D002B1159 /* glue.c */, - B343F872295F7C5C002B1159 /* opack.c */, - B343F876295F7C5D002B1159 /* socket.c */, - B343F877295F7C5D002B1159 /* termcolors.c */, - B343F879295F7C5D002B1159 /* thread.c */, - B343F87B295F7C5D002B1159 /* tlv.c */, - B343F87A295F7C5D002B1159 /* utils.c */, - ); - name = "libimobiledevice-glue"; - path = "libimobiledevice-glue/src"; - sourceTree = ""; - }; - B326763F29AC4FAD00B84318 /* Sources */ = { - isa = PBXGroup; - children = ( - BF58047C246A28F7008AE704 /* AltBackup */, - ); - path = Sources; - sourceTree = ""; - }; - B343F848295F6321002B1159 /* Products */ = { - isa = PBXGroup; - children = ( - B343F84C295F6321002B1159 /* libminimuxer_static.a */, - ); - name = Products; - sourceTree = ""; - }; - B343F84E295F6323002B1159 /* Products */ = { - isa = PBXGroup; - children = ( - B343F853295F6323002B1159 /* libem_proxy_static.a */, - B343F855295F6323002B1159 /* run */, - ); - name = Products; - sourceTree = ""; - }; - B343F887295F7F9B002B1159 /* Products */ = { - isa = PBXGroup; - children = ( - B343F88E295F7F9B002B1159 /* libfragmentzip */, - B343F890295F7F9B002B1159 /* libfragmentzip */, - B343F892295F7F9B002B1159 /* libfragmentzip.a */, - B343F894295F7F9B002B1159 /* libfragmentzip.a */, - ); - name = Products; - sourceTree = ""; - }; - B39F16112918D7B5002E9404 /* Consts */ = { - isa = PBXGroup; - children = ( - B39F16122918D7C5002E9404 /* Consts.swift */, - B39F16142918D7DA002E9404 /* Consts+Proxy.swift */, - ); - path = Consts; - sourceTree = ""; - }; - BF0DCA642433BDE200E3A595 /* Analytics */ = { - isa = PBXGroup; - children = ( - BF0DCA652433BDF500E3A595 /* AnalyticsManager.swift */, - ); - path = Analytics; - sourceTree = ""; - }; - BF18BFE824857D7900DD5981 /* AltDaemon */ = { - isa = PBXGroup; - children = ( - BFFCFA45248835530077BFCE /* AltDaemon.entitlements */, - BF10EB33248730750055E6DB /* main.swift */, - BFC712C22512D5F100AB5EBE /* XPCConnectionHandler.swift */, - BF8CAE442489E772004D6CCE /* DaemonRequestHandler.swift */, - BF8CAE422489E772004D6CCE /* AnisetteDataManager.swift */, - BF8CAE432489E772004D6CCE /* AppManager.swift */, - BF18C0032485B4DE00DD5981 /* AltDaemon-Bridging-Header.h */, - ); - path = AltDaemon; - sourceTree = ""; - }; - BF1E315122A0616100370A3C /* Shared */ = { - isa = PBXGroup; - children = ( - B34AFD1229A9D2C100E637B4 /* ServerProtocol.swift */, - BFD52BD222A06EFB000B7ED1 /* ALTConstants.h */, - BF718BD723C93DB700A89F2D /* ALTConstants.m */, - BFF767CF2489AC240097E58C /* Connections */, - BFF7C92D2578464D00E55F36 /* XPC */, - BFF767C32489A6800097E58C /* Extensions */, - BFF767C42489A6980097E58C /* Categories */, - ); - path = Shared; - sourceTree = ""; - }; - BF3D648922E79A7700E9056B /* Types */ = { - isa = PBXGroup; - children = ( - BF41B807233433C100C593A3 /* LoadingState.swift */, - BFB39B5B252BC10E00D1BE50 /* Managed.swift */, - D5DAE0932804B0B80034D8D4 /* ScreenshotProcessor.swift */, - ); - path = Types; - sourceTree = ""; - }; - BF3D64A022E7FAD800E9056B /* App Detail */ = { - isa = PBXGroup; - children = ( - BF8F69C322E662D300049BA1 /* AppViewController.swift */, - BF8F69C122E659F700049BA1 /* AppContentViewController.swift */, - BF3D64AF22E8D4B800E9056B /* AppContentViewControllerCells.swift */, - BF3D649C22E7AC1B00E9056B /* PermissionPopoverViewController.swift */, - ); - path = "App Detail"; - sourceTree = ""; - }; - BF45872C2298D31600BD7491 /* libimobiledevice */ = { - isa = PBXGroup; - children = ( - 191E5FF4290B2663001A3B7C /* libimobiledevice-glue */, - BF4588562298DC6D00BD7491 /* libplist */, - BF4587972298D36400BD7491 /* libimobiledevice */, - BF45883D2298D3E800BD7491 /* libusbmuxd */, - ); - name = libimobiledevice; - path = Dependencies; - sourceTree = ""; - }; - BF4587972298D36400BD7491 /* libimobiledevice */ = { - isa = PBXGroup; - children = ( - BF4587D72298D3A800BD7491 /* afc.c */, - B33FFBAB295F8F98002259E6 /* companion_proxy.c */, - BF4587DF2298D3A900BD7491 /* debugserver.c */, - BF4587E42298D3A900BD7491 /* device_link_service.c */, - BF4587C92298D3A800BD7491 /* diagnostics_relay.c */, - BF4587D22298D3A800BD7491 /* file_relay.c */, - BF4587CF2298D3A800BD7491 /* heartbeat.c */, - BF4587EB2298D3AA00BD7491 /* house_arrest.c */, - BF4587F12298D3AA00BD7491 /* idevice.c */, - BF4587D92298D3A900BD7491 /* installation_proxy.c */, - BF4587F62298D3AB00BD7491 /* lockdown.c */, - BF4587EE2298D3AA00BD7491 /* misagent.c */, - BF4587D82298D3A800BD7491 /* mobile_image_mounter.c */, - BF4587F22298D3AA00BD7491 /* mobileactivation.c */, - BF4587DD2298D3A900BD7491 /* mobilebackup.c */, - BF4587DC2298D3A900BD7491 /* mobilebackup2.c */, - BF4587F32298D3AA00BD7491 /* mobilesync.c */, - BF4587CB2298D3A800BD7491 /* notification_proxy.c */, - B33FFBA9295F8F78002259E6 /* preboard.c */, - BF4587F42298D3AA00BD7491 /* property_list_service.c */, - BF4587E62298D3A900BD7491 /* restore.c */, - BF4587CC2298D3A800BD7491 /* sbservices.c */, - BF4587E72298D3A900BD7491 /* screenshotr.c */, - BF4587F72298D3AB00BD7491 /* service.c */, - BF4587D32298D3A800BD7491 /* syslog_relay.c */, - BF4587D62298D3A800BD7491 /* webinspector.c */, - BF4587EC2298D3AA00BD7491 /* afc.h */, - BF4587DE2298D3A900BD7491 /* debugserver.h */, - BF4587EF2298D3AA00BD7491 /* device_link_service.h */, - BF4587CA2298D3A800BD7491 /* diagnostics_relay.h */, - BF4587ED2298D3AA00BD7491 /* file_relay.h */, - BF4587E02298D3A900BD7491 /* heartbeat.h */, - BF4587E22298D3A900BD7491 /* house_arrest.h */, - BF4587D52298D3A800BD7491 /* idevice.h */, - BF4587D12298D3A800BD7491 /* installation_proxy.h */, - BF4587D42298D3A800BD7491 /* lockdown.h */, - BF4587E12298D3A900BD7491 /* misagent.h */, - BF4587F02298D3AA00BD7491 /* mobile_image_mounter.h */, - BF4587EA2298D3AA00BD7491 /* mobileactivation.h */, - BF4587E52298D3A900BD7491 /* mobilebackup.h */, - BF4587CE2298D3A800BD7491 /* mobilebackup2.h */, - BF4587DB2298D3A900BD7491 /* mobilesync.h */, - BF4587E32298D3A900BD7491 /* notification_proxy.h */, - BF4587F52298D3AA00BD7491 /* property_list_service.h */, - BF4587D02298D3A800BD7491 /* restore.h */, - BF4587CD2298D3A800BD7491 /* sbservices.h */, - BF4587DA2298D3A900BD7491 /* screenshotr.h */, - BF4587C82298D3A800BD7491 /* service.h */, - BF4587E82298D3A900BD7491 /* syslog_relay.h */, - BF4587E92298D3AA00BD7491 /* webinspector.h */, - BF4588282298D3B400BD7491 /* common */, - ); - path = libimobiledevice; - sourceTree = ""; - }; - BF4588282298D3B400BD7491 /* common */ = { - isa = PBXGroup; - children = ( - BF4588302298D3C000BD7491 /* debug.c */, - BF45882B2298D3C000BD7491 /* userpref.c */, - BF45882C2298D3C000BD7491 /* debug.h */, - BF45882A2298D3C000BD7491 /* userpref.h */, - ); - name = common; - sourceTree = ""; - }; - BF45883D2298D3E800BD7491 /* libusbmuxd */ = { - isa = PBXGroup; - children = ( - BF4588422298D40000BD7491 /* libusbmuxd.c */, - ); - path = libusbmuxd; - sourceTree = ""; - }; - BF4588562298DC6D00BD7491 /* libplist */ = { - isa = PBXGroup; - children = ( - BFD52BE622A1A9CA000B7ED1 /* base64.c */, - BFD52BEA22A1A9CA000B7ED1 /* bplist.c */, - BFD52BF522A1A9CA000B7ED1 /* bytearray.c */, - BFD52BE722A1A9CA000B7ED1 /* hashtable.c */, - 191E5FCF290A651D001A3B7C /* jplist.c */, - 191E5FD0290A651D001A3B7C /* jsmn.c */, - BFD52BEE22A1A9CA000B7ED1 /* plist.c */, - BFD52BE522A1A9CA000B7ED1 /* ptrarray.c */, - BFD52BEC22A1A9CA000B7ED1 /* time64.c */, - BFD52C0022A1A9CB000B7ED1 /* xplist.c */, - BFD52BF822A1A9CB000B7ED1 /* Array.cpp */, - BFD52BF222A1A9CA000B7ED1 /* Boolean.cpp */, - BFD52BF722A1A9CA000B7ED1 /* Data.cpp */, - BFD52BF022A1A9CA000B7ED1 /* Date.cpp */, - BFD52BE822A1A9CA000B7ED1 /* Dictionary.cpp */, - BFD52BFC22A1A9CB000B7ED1 /* Integer.cpp */, - BFD52BFB22A1A9CB000B7ED1 /* Key.cpp */, - BFD52BF922A1A9CB000B7ED1 /* Node.cpp */, - BFD52BF322A1A9CA000B7ED1 /* Real.cpp */, - BFD52BEB22A1A9CA000B7ED1 /* String.cpp */, - BFD52BFD22A1A9CB000B7ED1 /* Structure.cpp */, - BFD52BF122A1A9CA000B7ED1 /* Uid.cpp */, - BFD52BF622A1A9CA000B7ED1 /* base64.h */, - BFD52BFA22A1A9CB000B7ED1 /* bytearray.h */, - BFD52BEF22A1A9CA000B7ED1 /* hashtable.h */, - 191E5FD1290A651D001A3B7C /* jsmn.h */, - BFD52BED22A1A9CA000B7ED1 /* plist.h */, - BFD52BE922A1A9CA000B7ED1 /* ptrarray.h */, - BFD52BF422A1A9CA000B7ED1 /* strbuf.h */, - BFD52BFE22A1A9CB000B7ED1 /* time64_limits.h */, - BFD52BFF22A1A9CB000B7ED1 /* time64.h */, - BF4588892298DDEA00BD7491 /* libcnary */, - ); - path = libplist; - sourceTree = ""; - }; - BF4588892298DDEA00BD7491 /* libcnary */ = { - isa = PBXGroup; - children = ( - BFD52C1F22A1A9EC000B7ED1 /* cnary.c */, - BFD52C1E22A1A9EC000B7ED1 /* node_list.c */, - BFD52C1D22A1A9EC000B7ED1 /* node.c */, - ); - name = libcnary; - sourceTree = ""; - }; - BF56D2AD23DF9E170006506D /* App IDs */ = { - isa = PBXGroup; - children = ( - BF56D2AE23DF9E310006506D /* AppIDsViewController.swift */, - ); - path = "App IDs"; - sourceTree = ""; - }; - BF58047C246A28F7008AE704 /* AltBackup */ = { - isa = PBXGroup; - children = ( - BF580499246A4153008AE704 /* AltBackup.entitlements */, - BF58047D246A28F7008AE704 /* AppDelegate.swift */, - BF580481246A28F7008AE704 /* ViewController.swift */, - BF44EEEF246B08BA002A52F2 /* BackupController.swift */, - BF580495246A3CB5008AE704 /* UIColor+AltBackup.swift */, - BF580486246A28F9008AE704 /* Assets.xcassets */, - BF580488246A28F9008AE704 /* LaunchScreen.storyboard */, - BF58048B246A28F9008AE704 /* Info.plist */, - ); - path = AltBackup; - sourceTree = ""; - }; - BF66EE7F2501AE50007EE018 /* AltStoreCore */ = { - isa = PBXGroup; - children = ( - BF66EE802501AE50007EE018 /* AltStoreCore.h */, - BF66EE8A2501AEB1007EE018 /* Components */, - BF66EEE32501AED0007EE018 /* Extensions */, - BF66EEAA2501AECA007EE018 /* Model */, - BF66EE9F2501AEC5007EE018 /* Patreon */, - BF98918B250AAE18002ACF50 /* Intents */, - BF66EE9A2501AEC1007EE018 /* Protocols */, - BF66EE8D2501AEBC007EE018 /* Types */, - BF66EE812501AE50007EE018 /* Info.plist */, - BFCB9205250AB1FF0057B44E /* Resources */, - ); - path = AltStoreCore; - sourceTree = ""; - }; - BF66EE8A2501AEB1007EE018 /* Components */ = { - isa = PBXGroup; - children = ( - BF66EE8B2501AEB1007EE018 /* Keychain.swift */, - ); - path = Components; - sourceTree = ""; - }; - BF66EE8D2501AEBC007EE018 /* Types */ = { - isa = PBXGroup; - children = ( - BF66EE8E2501AEBC007EE018 /* ALTAppPermission.h */, - BF66EE912501AEBC007EE018 /* ALTAppPermission.m */, - BF66EE922501AEBC007EE018 /* ALTPatreonBenefitType.h */, - BF66EE902501AEBC007EE018 /* ALTPatreonBenefitType.m */, - BF66EE8F2501AEBC007EE018 /* ALTSourceUserInfoKey.h */, - BF66EE932501AEBC007EE018 /* ALTSourceUserInfoKey.m */, - ); - path = Types; - sourceTree = ""; - }; - BF66EE9A2501AEC1007EE018 /* Protocols */ = { - isa = PBXGroup; - children = ( - BF66EE9B2501AEC1007EE018 /* AppProtocol.swift */, - BF66EE9C2501AEC1007EE018 /* Fetchable.swift */, - ); - path = Protocols; - sourceTree = ""; - }; - BF66EE9F2501AEC5007EE018 /* Patreon */ = { - isa = PBXGroup; - children = ( - BF66EEA02501AEC5007EE018 /* Benefit.swift */, - BF66EEA22501AEC5007EE018 /* Campaign.swift */, - BF66EEA12501AEC5007EE018 /* PatreonAPI.swift */, - BF66EEA32501AEC5007EE018 /* Patron.swift */, - BF66EEA42501AEC5007EE018 /* Tier.swift */, - ); - path = Patreon; - sourceTree = ""; - }; - BF66EEAA2501AECA007EE018 /* Model */ = { - isa = PBXGroup; - children = ( - BF66EEB72501AECA007EE018 /* AltStore.xcdatamodeld */, - BF66EEC92501AECA007EE018 /* Account.swift */, - BF66EEC72501AECA007EE018 /* AppID.swift */, - BF66EEC62501AECA007EE018 /* AppPermission.swift */, - D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */, - BF66EECA2501AECA007EE018 /* DatabaseManager.swift */, - BF66EEC02501AECA007EE018 /* InstalledApp.swift */, - BF66EECB2501AECA007EE018 /* InstalledExtension.swift */, - D58916FD28C7C55C00E39C8B /* LoggedError.swift */, - BF66EEC52501AECA007EE018 /* MergePolicy.swift */, - BF66EEBF2501AECA007EE018 /* NewsItem.swift */, - BF66EEC82501AECA007EE018 /* PatreonAccount.swift */, - D5CA0C4A280E141900469595 /* ManagedPatron.swift */, - BF66EEC32501AECA007EE018 /* RefreshAttempt.swift */, - BF66EEC12501AECA007EE018 /* SecureValueTransformer.swift */, - BF66EEAB2501AECA007EE018 /* Source.swift */, - BF66EEC42501AECA007EE018 /* StoreApp.swift */, - BF66EEC22501AECA007EE018 /* Team.swift */, - BF66EEAC2501AECA007EE018 /* Migrations */, - ); - path = Model; - sourceTree = ""; - }; - BF66EEAC2501AECA007EE018 /* Migrations */ = { - isa = PBXGroup; - children = ( - BF66EEAD2501AECA007EE018 /* Policies */, - BF66EEB02501AECA007EE018 /* Mapping Models */, - ); - path = Migrations; - sourceTree = ""; - }; - BF66EEAD2501AECA007EE018 /* Policies */ = { - isa = PBXGroup; - children = ( - BF66EEAE2501AECA007EE018 /* StoreAppPolicy.swift */, - D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */, - BF66EEAF2501AECA007EE018 /* InstalledAppPolicy.swift */, - ); - path = Policies; - sourceTree = ""; - }; - BF66EEB02501AECA007EE018 /* Mapping Models */ = { - isa = PBXGroup; - children = ( - BF66EEB12501AECA007EE018 /* AltStoreToAltStore2.xcmappingmodel */, - BF66EEB22501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel */, - BF66EEB32501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel */, - BF66EEB42501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel */, - BF66EEB52501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel */, - BF66EEB62501AECA007EE018 /* AltStore5ToAltStore6.xcmappingmodel */, - BFBF331A2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel */, - D5CA0C4D280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel */, - D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */, - ); - path = "Mapping Models"; - sourceTree = ""; - }; - BF66EEE32501AED0007EE018 /* Extensions */ = { - isa = PBXGroup; - children = ( - BFD2479E2284FBD000981D42 /* UIColor+AltStore.swift */, - BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */, - BF66EEE52501AED0007EE018 /* JSONDecoder+Properties.swift */, - BF66EEE72501AED0007EE018 /* UIApplication+AppExtension.swift */, - BF66EEE62501AED0007EE018 /* UIColor+Hex.swift */, - BF66EEE42501AED0007EE018 /* UserDefaults+AltStore.swift */, - BF6A531F246DC1B0004F59C8 /* FileManager+SharedDirectories.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - BF6C8FA8242935CA00125131 /* Dependencies */ = { - isa = PBXGroup; - children = ( - BF6C8FA9242935DB00125131 /* MarkdownAttributedString */, - ); - name = Dependencies; - sourceTree = ""; - }; - BF6C8FA9242935DB00125131 /* MarkdownAttributedString */ = { - isa = PBXGroup; - children = ( - BF6C8FAB242935ED00125131 /* NSAttributedString+Markdown.h */, - BF6C8FAA242935ED00125131 /* NSAttributedString+Markdown.m */, - ); - name = MarkdownAttributedString; - sourceTree = ""; - }; - BF7B44062725A4B8005288A4 /* Patch App */ = { - isa = PBXGroup; - children = ( - D593F1932717749A006E82DE /* PatchAppOperation.swift */, - D5F2F6A82720B7C20081CCF5 /* PatchViewController.swift */, - D57DF637271E32F000677701 /* PatchApp.storyboard */, - D57DF63D271E51E400677701 /* ALTAppPatcher.h */, - D57DF63E271E51E400677701 /* ALTAppPatcher.m */, - D533E8B82727B61400A9B5DD /* fragmentzip.h */, - D533E8BD2727BBF800A9B5DD /* libcurl.a */, - D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */, - ); - path = "Patch App"; - sourceTree = ""; - }; - BF98916C250AABF3002ACF50 /* AltWidget */ = { - isa = PBXGroup; - children = ( - BF8B17F0250AC62400F8157F /* AltWidgetExtension.entitlements */, - BF98917D250AAC4F002ACF50 /* AltWidget.swift */, - BF42345825101C1D006D1EB2 /* WidgetView.swift */, - BF98917C250AAC4F002ACF50 /* Countdown.swift */, - D55E163528776CB000A627A1 /* ComplicationView.swift */, - BF989170250AABF4002ACF50 /* Assets.xcassets */, - BF989172250AABF4002ACF50 /* Info.plist */, - ); - path = AltWidget; - sourceTree = ""; - }; - BF98918B250AAE18002ACF50 /* Intents */ = { - isa = PBXGroup; - children = ( - BF989191250AAE86002ACF50 /* ViewApp.intentdefinition */, - BF989190250AAE86002ACF50 /* ViewAppIntentHandler.swift */, - ); - path = Intents; - sourceTree = ""; - }; - BF9ABA4322DCFF33008935CF /* Browse */ = { - isa = PBXGroup; - children = ( - BF9ABA4422DCFF43008935CF /* BrowseViewController.swift */, - BF9ABA4622DD0638008935CF /* BrowseCollectionViewCell.swift */, - BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */, - BF9ABA4822DD0742008935CF /* ScreenshotCollectionViewCell.swift */, - ); - path = Browse; - sourceTree = ""; - }; - BFB6B21C2318700D0022A802 /* News */ = { - isa = PBXGroup; - children = ( - BFB6B21D231870160022A802 /* NewsViewController.swift */, - BFB6B21F231870B00022A802 /* NewsCollectionViewCell.swift */, - BFB6B22323187A3D0022A802 /* NewsCollectionViewCell.xib */, - ); - path = News; - sourceTree = ""; - }; - BFBBE2E2229320A2002097FA /* My Apps */ = { - isa = PBXGroup; - children = ( - BF08858222DE795100DE9F1E /* MyAppsViewController.swift */, - BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */, - BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */, - BFB4323E22DE852000B7F8BC /* UpdateCollectionViewCell.xib */, - BFC57A6D2416FC5D00EB891E /* InstalledAppsCollectionHeaderView.swift */, - BFC57A6F2416FC7600EB891E /* InstalledAppsCollectionHeaderView.xib */, - ); - path = "My Apps"; - sourceTree = ""; - }; - BFC84A4B2421A13000853474 /* Sources */ = { - isa = PBXGroup; - children = ( - BFC84A4C2421A19100853474 /* SourcesViewController.swift */, - ); - path = Sources; - sourceTree = ""; - }; - BFCB9205250AB1FF0057B44E /* Resources */ = { - isa = PBXGroup; - children = ( - BFCB9206250AB2120057B44E /* Colors.xcassets */, - ); - path = Resources; - sourceTree = ""; - }; - BFD247612284B9A500981D42 = { - isa = PBXGroup; - children = ( - B326763F29AC4FAD00B84318 /* Sources */, - B3C39607284F4C8400DA9E2F /* Build.xcconfig */, - B3C39606284F4C8400DA9E2F /* CodeSigning.xcconfig */, - B3C39608284F4C8400DA9E2F /* CodeSigning.xcconfig.sample */, - B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */, - B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */, - B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */, - B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */, - BFD2476C2284B9A500981D42 /* AltStore */, - BF66EE7F2501AE50007EE018 /* AltStoreCore */, - BF1E315122A0616100370A3C /* Shared */, - BF45872C2298D31600BD7491 /* libimobiledevice */, - BF18BFE824857D7900DD5981 /* AltDaemon */, - BF98916C250AABF3002ACF50 /* AltWidget */, - 19104DB32909C06D00C49C7B /* EmotionalDamage */, - 191E5FAC290A5D92001A3B7C /* minimuxer */, - B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */, - BFD247852284BB3300981D42 /* Frameworks */, - BFD2476B2284B9A500981D42 /* Products */, - ); - sourceTree = ""; - }; - BFD2476B2284B9A500981D42 /* Products */ = { - isa = PBXGroup; - children = ( - BFD2476A2284B9A500981D42 /* SideStore.app */, - BF45872B2298D31600BD7491 /* libimobiledevice.a */, - BF58047B246A28F7008AE704 /* AltBackup.app */, - BF18BFE724857D7900DD5981 /* AltDaemon */, - BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */, - BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */, - 19104DB22909C06C00C49C7B /* libEmotionalDamage.a */, - 191E5FAB290A5D92001A3B7C /* libminimuxer.a */, - ); - name = Products; - sourceTree = ""; - }; - BFD2476C2284B9A500981D42 /* AltStore */ = { - isa = PBXGroup; - children = ( - B39F16112918D7B5002E9404 /* Consts */, - BF219A7E22CAC431007676A6 /* AltStore.entitlements */, - BFD2476D2284B9A500981D42 /* AppDelegate.swift */, - BF4B78FD24B3D1DB008AB4AC /* SceneDelegate.swift */, - BFD247732284B9A500981D42 /* Main.storyboard */, - BFE338E722F10E56002E24B9 /* LaunchViewController.swift */, - BF41B805233423AE00C593A3 /* TabBarController.swift */, - BFE6325822A83BA800F30809 /* Authentication */, - BFB6B21C2318700D0022A802 /* News */, - BF9ABA4322DCFF33008935CF /* Browse */, - BF3D64A022E7FAD800E9056B /* App Detail */, - BFBBE2E2229320A2002097FA /* My Apps */, - BFDB69FB22A9A7A6007EA6D6 /* Settings */, - BFD2478A2284C49000981D42 /* Managing Apps */, - BF56D2AD23DF9E170006506D /* App IDs */, - BFC84A4B2421A13000853474 /* Sources */, - BF0DCA642433BDE200E3A595 /* Analytics */, - BFF00D2E2501BD4B00746320 /* Intents */, - BFDB6A0922AAEDA1007EA6D6 /* Operations */, - BFD2478D2284C4C700981D42 /* Components */, - BF3D648922E79A7700E9056B /* Types */, - BFD2479D2284FBBD00981D42 /* Extensions */, - BFD247962284D7C100981D42 /* Resources */, - BF6C8FA8242935CA00125131 /* Dependencies */, - BFD247972284D7D800981D42 /* Supporting Files */, - 1920B04E2924AC8300744F60 /* Settings.bundle */, - ); - path = AltStore; - sourceTree = ""; - }; - BFD247852284BB3300981D42 /* Frameworks */ = { - isa = PBXGroup; - children = ( - B343F86C295F759E002B1159 /* libresolv.tbd */, - 191E5FB5290A5E1F001A3B7C /* libminimuxer.a */, - B39575F4284F29E20080B4FF /* Roxas.framework */, - D533E8B62727841800A9B5DD /* libAppleArchive.tbd */, - BF580497246A3D19008AE704 /* UIKit.framework */, - BF4588872298DD3F00BD7491 /* libxml2.tbd */, - BFD247862284BB3B00981D42 /* Roxas.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - BFD2478A2284C49000981D42 /* Managing Apps */ = { - isa = PBXGroup; - children = ( - BF0C4EBC22A1BD8B009A2DD7 /* AppManager.swift */, - BF88F97124F8727D00BB75DF /* AppManagerErrors.swift */, - ); - path = "Managing Apps"; - sourceTree = ""; - }; - BFD2478D2284C4C700981D42 /* Components */ = { - isa = PBXGroup; - children = ( - BFD2478B2284C4C300981D42 /* AppIconImageView.swift */, - BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */, - BFD2478E2284C8F900981D42 /* Button.swift */, - BF770E6622BD57C3002A40FE /* BackgroundTaskManager.swift */, - BF9ABA4A22DD137F008935CF /* NavigationBar.swift */, - BF9ABA4C22DD16DE008935CF /* PillButton.swift */, - BF18B0F022E25DF9005C4CF5 /* ToastView.swift */, - BF3D649E22E7B24C00E9056B /* CollapsingTextView.swift */, - BF2901302318F7A800D88A45 /* AppBannerView.swift */, - BF29012E2318F6B100D88A45 /* AppBannerView.xib */, - BF6C8FAD2429597900125131 /* BannerCollectionViewCell.swift */, - BF6C8FAF2429599900125131 /* TextCollectionReusableView.swift */, - ); - path = Components; - sourceTree = ""; - }; - BFD247962284D7C100981D42 /* Resources */ = { - isa = PBXGroup; - children = ( - BF44EEF2246B3A17002A52F2 /* AltBackup.ipa */, - BFB1169C22932DB100BB457C /* apps.json */, - BFD247762284B9A700981D42 /* Assets.xcassets */, - BF770E6822BD57DD002A40FE /* Silence.m4a */, - ); - path = Resources; - sourceTree = ""; - }; - BFD247972284D7D800981D42 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - BFD247782284B9A700981D42 /* LaunchScreen.storyboard */, - BFD2477B2284B9A700981D42 /* Info.plist */, - BF1E314722A060F300370A3C /* AltStore-Bridging-Header.h */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - BFD2479D2284FBBD00981D42 /* Extensions */ = { - isa = PBXGroup; - children = ( - BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */, - BF663C4E2433ED8200DAA738 /* FileManager+DirectorySize.swift */, - BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */, - BFE00A1F2503097F00EB4D0C /* INInteraction+AltStore.swift */, - D57F2C9326E01BC700B9FA39 /* UIDevice+Vibration.swift */, - B376FE3D29258C8900E18883 /* OSLog+SideStore.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - BFDB69FB22A9A7A6007EA6D6 /* Settings */ = { - isa = PBXGroup; - children = ( - BFE60737231ADF49002B0E8E /* Settings.storyboard */, - BFE60739231ADF82002B0E8E /* SettingsViewController.swift */, - BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */, - BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */, - BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */, - BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */, - BFF0B68D23219520007A79E1 /* PatreonViewController.swift */, - BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */, - BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */, - BFF0B695232242D3007A79E1 /* LicensesViewController.swift */, - D589170128C7D93500E39C8B /* Error Log */, - B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */, - ); - path = Settings; - sourceTree = ""; - }; - BFDB6A0922AAEDA1007EA6D6 /* Operations */ = { - isa = PBXGroup; - children = ( - BFDB6A0C22AAFC19007EA6D6 /* OperationError.swift */, - BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */, - BF770E5722BC3D0F002A40FE /* RefreshGroup.swift */, - BF770E5322BC044E002A40FE /* OperationContexts.swift */, - BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */, - BFC1F38C22AEE3A4003AC21A /* DownloadAppOperation.swift */, - BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */, - BF3BEFBE2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift */, - BF3BEFC024086A1E00DE7D55 /* RefreshAppOperation.swift */, - BFDB6A0E22AB2776007EA6D6 /* SendAppOperation.swift */, - BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */, - BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */, - BFA8172A23C5633D001B5953 /* FetchAnisetteDataOperation.swift */, - BF56D2AB23DF8E170006506D /* FetchAppIDsOperation.swift */, - BFC57A642416C72400EB891E /* DeactivateAppOperation.swift */, - BFCCB519245E3401001853EA /* VerifyAppOperation.swift */, - BF44EEFB246B4550002A52F2 /* RemoveAppOperation.swift */, - BF3432FA246B894F0052F4A1 /* BackupAppOperation.swift */, - BFDBBD7F246CB84F004ED2F3 /* RemoveAppBackupOperation.swift */, - BFF00D312501BDA100746320 /* BackgroundRefreshAppsOperation.swift */, - D57F2C9026E0070200B9FA39 /* EnableJITOperation.swift */, - D5DAE0952804DF430034D8D4 /* UpdatePatronsOperation.swift */, - D5E1E7C028077DE90016FC96 /* FetchTrustedSourcesOperation.swift */, - BF7B44062725A4B8005288A4 /* Patch App */, - ); - path = Operations; - sourceTree = ""; - }; - BFE6325822A83BA800F30809 /* Authentication */ = { - isa = PBXGroup; - children = ( - BFE6325922A83BEB00F30809 /* Authentication.storyboard */, - BFF0B6932321CB85007A79E1 /* AuthenticationViewController.swift */, - BFF0B6972322CAB8007A79E1 /* InstructionsViewController.swift */, - BF6F439123644C6E00A0B879 /* RefreshAltStoreViewController.swift */, - 19B9B7442845E6DF0076EF69 /* SelectTeamViewController.swift */, - ); - path = Authentication; - sourceTree = ""; - }; - BFF00D2E2501BD4B00746320 /* Intents */ = { - isa = PBXGroup; - children = ( - BFF00D2F2501BD7D00746320 /* Intents.intentdefinition */, - BFF00D332501BDCF00746320 /* IntentHandler.swift */, - ); - path = Intents; - sourceTree = ""; - }; - BFF767C32489A6800097E58C /* Extensions */ = { - isa = PBXGroup; - children = ( - B34AFD1A29A9DFA200E637B4 /* NSError+AltStore.swift */, - BFBAC8852295C90300587369 /* Result+Conveniences.swift */, - BF1E314122A05D4C00370A3C /* Bundle+AltStore.swift */, - BF1FE357251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift */, - BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - BFF767C42489A6980097E58C /* Categories */ = { - isa = PBXGroup; - children = ( - BF718BC723C919CC00A89F2D /* CFNotificationName+AltStore.h */, - BF718BC823C919E300A89F2D /* CFNotificationName+AltStore.m */, - ); - path = Categories; - sourceTree = ""; - }; - BFF767CF2489AC240097E58C /* Connections */ = { - isa = PBXGroup; - children = ( - BF18BFF22485828200DD5981 /* ConnectionManager.swift */, - BF18BFF624858BDE00DD5981 /* Connection.swift */, - BFF767CD2489ABE90097E58C /* NetworkConnection.swift */, - BFC712C12512D5F100AB5EBE /* XPCConnection.swift */, - ); - path = Connections; - sourceTree = ""; - }; - BFF7C92D2578464D00E55F36 /* XPC */ = { - isa = PBXGroup; - children = ( - BFF7C906257844C900E55F36 /* AltXPCProtocol.h */, - ); - path = XPC; - sourceTree = ""; - }; - D589170128C7D93500E39C8B /* Error Log */ = { - isa = PBXGroup; - children = ( - D57FE84328C7DB7100216002 /* ErrorLogViewController.swift */, - D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */, - ); - path = "Error Log"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 191E5FD4290A6EE0001A3B7C /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF4587272298D31600BD7491 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - BF4588112298D3AB00BD7491 /* misagent.h in Headers */, - BF4588042298D3AB00BD7491 /* lockdown.h in Headers */, - BF45880B2298D3AB00BD7491 /* mobilesync.h in Headers */, - BF4588002298D3AB00BD7491 /* restore.h in Headers */, - BF4588152298D3AB00BD7491 /* mobilebackup.h in Headers */, - BF4588182298D3AB00BD7491 /* syslog_relay.h in Headers */, - BFD52C1022A1A9CB000B7ED1 /* strbuf.h in Headers */, - BF45881D2298D3AB00BD7491 /* file_relay.h in Headers */, - BFD52C0922A1A9CB000B7ED1 /* plist.h in Headers */, - BF4587FD2298D3AB00BD7491 /* sbservices.h in Headers */, - BF4588362298D3C100BD7491 /* debug.h in Headers */, - BF4588202298D3AB00BD7491 /* mobile_image_mounter.h in Headers */, - BF4588122298D3AB00BD7491 /* house_arrest.h in Headers */, - BF45881F2298D3AB00BD7491 /* device_link_service.h in Headers */, - BFD52C1A22A1A9CB000B7ED1 /* time64_limits.h in Headers */, - BF45880E2298D3AB00BD7491 /* debugserver.h in Headers */, - BF4588102298D3AB00BD7491 /* heartbeat.h in Headers */, - BF4587FA2298D3AB00BD7491 /* diagnostics_relay.h in Headers */, - BFD52C1622A1A9CB000B7ED1 /* bytearray.h in Headers */, - BFD52C1222A1A9CB000B7ED1 /* base64.h in Headers */, - BF4588192298D3AB00BD7491 /* webinspector.h in Headers */, - BF4588342298D3C100BD7491 /* userpref.h in Headers */, - BF45880A2298D3AB00BD7491 /* screenshotr.h in Headers */, - BFD52C0B22A1A9CB000B7ED1 /* hashtable.h in Headers */, - BF4587FE2298D3AB00BD7491 /* mobilebackup2.h in Headers */, - BFD52C0522A1A9CB000B7ED1 /* ptrarray.h in Headers */, - BF45881C2298D3AB00BD7491 /* afc.h in Headers */, - BF45881A2298D3AB00BD7491 /* mobileactivation.h in Headers */, - BF4588052298D3AB00BD7491 /* idevice.h in Headers */, - BF4588012298D3AB00BD7491 /* installation_proxy.h in Headers */, - BF4587F82298D3AB00BD7491 /* service.h in Headers */, - BF4588252298D3AB00BD7491 /* property_list_service.h in Headers */, - BF4588132298D3AB00BD7491 /* notification_proxy.h in Headers */, - BFD52C1B22A1A9CB000B7ED1 /* time64.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF66EE792501AE50007EE018 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - BF66EE822501AE50007EE018 /* AltStoreCore.h in Headers */, - BF66EE952501AEBC007EE018 /* ALTSourceUserInfoKey.h in Headers */, - BF66EE982501AEBC007EE018 /* ALTPatreonBenefitType.h in Headers */, - BFAECC5F2501B0BF00528F27 /* ALTConstants.h in Headers */, - BF66EE942501AEBC007EE018 /* ALTAppPermission.h in Headers */, - BFAECC5E2501B0BF00528F27 /* CFNotificationName+AltStore.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 19104DB12909C06C00C49C7B /* EmotionalDamage */ = { - isa = PBXNativeTarget; - buildConfigurationList = 19104DB62909C06D00C49C7B /* Build configuration list for PBXNativeTarget "EmotionalDamage" */; - buildPhases = ( - 19104DAE2909C06C00C49C7B /* Sources */, - 19104DAF2909C06C00C49C7B /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - B343F871295F7704002B1159 /* PBXTargetDependency */, - ); - name = EmotionalDamage; - productName = EmotionalDamage; - productReference = 19104DB22909C06C00C49C7B /* libEmotionalDamage.a */; - productType = "com.apple.product-type.library.static"; - }; - 191E5FAA290A5D92001A3B7C /* minimuxer */ = { - isa = PBXNativeTarget; - buildConfigurationList = 191E5FAF290A5D92001A3B7C /* Build configuration list for PBXNativeTarget "minimuxer" */; - buildPhases = ( - 191E5FD4290A6EE0001A3B7C /* Headers */, - 191E5FA7290A5D92001A3B7C /* Sources */, - 191E5FA8290A5D92001A3B7C /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - B343F86F295F76FD002B1159 /* PBXTargetDependency */, - ); - name = minimuxer; - productName = minimuxer; - productReference = 191E5FAB290A5D92001A3B7C /* libminimuxer.a */; - productType = "com.apple.product-type.library.static"; - }; - BF18BFE624857D7900DD5981 /* AltDaemon */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF18BFEB24857D7900DD5981 /* Build configuration list for PBXNativeTarget "AltDaemon" */; - buildPhases = ( - BF18BFE324857D7900DD5981 /* Sources */, - BF18BFE424857D7900DD5981 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = AltDaemon; - packageProductDependencies = ( - ); - productName = AltDaemon; - productReference = BF18BFE724857D7900DD5981 /* AltDaemon */; - productType = "com.apple.product-type.library.dynamic"; - }; - BF45872A2298D31600BD7491 /* libimobiledevice */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF4587332298D31600BD7491 /* Build configuration list for PBXNativeTarget "libimobiledevice" */; - buildPhases = ( - BF4587272298D31600BD7491 /* Headers */, - BF4587282298D31600BD7491 /* Sources */, - 678E094C3184B66357EAA4AF /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 191E5FDA290AFA49001A3B7C /* PBXTargetDependency */, - ); - name = libimobiledevice; - packageProductDependencies = ( - 191E5FDB290AFA5C001A3B7C /* OpenSSL */, - ); - productName = libimobiledevice; - productReference = BF45872B2298D31600BD7491 /* libimobiledevice.a */; - productType = "com.apple.product-type.library.static"; - }; - BF58047A246A28F7008AE704 /* AltBackup */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF58048E246A28F9008AE704 /* Build configuration list for PBXNativeTarget "AltBackup" */; - buildPhases = ( - BF580477246A28F7008AE704 /* Sources */, - BF580478246A28F7008AE704 /* Frameworks */, - BF580479246A28F7008AE704 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = AltBackup; - productName = AltBackup; - productReference = BF58047B246A28F7008AE704 /* AltBackup.app */; - productType = "com.apple.product-type.application"; - }; - BF66EE7D2501AE50007EE018 /* AltStoreCore */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF66EE892501AE50007EE018 /* Build configuration list for PBXNativeTarget "AltStoreCore" */; - buildPhases = ( - BF66EE792501AE50007EE018 /* Headers */, - BF66EE7A2501AE50007EE018 /* Sources */, - BF66EE7B2501AE50007EE018 /* Frameworks */, - BF66EE7C2501AE50007EE018 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = AltStoreCore; - packageProductDependencies = ( - B3C395F0284F2DE700DA9E2F /* KeychainAccess */, - 4879A95E2861046500FC1BBD /* AltSign */, - 99C4EF4C2979132100CB538D /* SemanticVersion */, - B34AFD1029A9CF5C00E637B4 /* Roxas */, - B34AFD1629A9D9FC00E637B4 /* RoxasUI */, - B34AFD1829A9DB0200E637B4 /* SideKit */, - ); - productName = AltStoreCore; - productReference = BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */; - productType = "com.apple.product-type.framework"; - }; - BF989166250AABF3002ACF50 /* AltWidgetExtension */ = { - isa = PBXNativeTarget; - buildConfigurationList = BF989178250AABF4002ACF50 /* Build configuration list for PBXNativeTarget "AltWidgetExtension" */; - buildPhases = ( - BF989163250AABF3002ACF50 /* Sources */, - BF989164250AABF3002ACF50 /* Frameworks */, - BF989165250AABF3002ACF50 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - BFF615AB2510042B00484D3B /* PBXTargetDependency */, - ); - name = AltWidgetExtension; - productName = AltWidgetExtension; - productReference = BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */; - productType = "com.apple.product-type.app-extension"; - }; - BFD247692284B9A500981D42 /* SideStore */ = { - isa = PBXNativeTarget; - buildConfigurationList = BFD2477E2284B9A700981D42 /* Build configuration list for PBXNativeTarget "SideStore" */; - buildPhases = ( - BFD247662284B9A500981D42 /* Sources */, - BFD247672284B9A500981D42 /* Frameworks */, - BFD247682284B9A500981D42 /* Resources */, - BF088D2B2501A087008082D9 /* Embed Frameworks */, - BF98917B250AABF4002ACF50 /* Embed App Extensions */, - ); - buildRules = ( - ); - dependencies = ( - 191E5FB3290A5D9B001A3B7C /* PBXTargetDependency */, - 19104DBA2909C0F200C49C7B /* PBXTargetDependency */, - 19104D942909BADB00C49C7B /* PBXTargetDependency */, - BF66EE842501AE50007EE018 /* PBXTargetDependency */, - BF989176250AABF4002ACF50 /* PBXTargetDependency */, - ); - name = SideStore; - packageProductDependencies = ( - B3C395F3284F35DD00DA9E2F /* Nuke */, - B3C395F6284F362400DA9E2F /* AppCenterAnalytics */, - B3C395F8284F362400DA9E2F /* AppCenterCrashes */, - 4879A9612861049C00FC1BBD /* OpenSSL */, - B34AFD0929A9CEDD00E637B4 /* SideKit */, - B34AFD0C29A9CF4000E637B4 /* Roxas */, - B34AFD0E29A9CF4000E637B4 /* RoxasUI */, - ); - productName = AltStore; - productReference = BFD2476A2284B9A500981D42 /* SideStore.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - BFD247622284B9A500981D42 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1400; - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = SideStore; - TargetAttributes = { - 19104DB12909C06C00C49C7B = { - CreatedOnToolsVersion = 14.0; - }; - 191E5FAA290A5D92001A3B7C = { - CreatedOnToolsVersion = 14.0; - }; - BF18BFE624857D7900DD5981 = { - CreatedOnToolsVersion = 11.5; - LastSwiftMigration = 1150; - }; - BF45872A2298D31600BD7491 = { - CreatedOnToolsVersion = 10.2.1; - }; - BF58047A246A28F7008AE704 = { - CreatedOnToolsVersion = 11.4.1; - }; - BF66EE7D2501AE50007EE018 = { - CreatedOnToolsVersion = 12.0; - }; - BF989166250AABF3002ACF50 = { - CreatedOnToolsVersion = 12.0; - LastSwiftMigration = 1200; - }; - BFD247692284B9A500981D42 = { - CreatedOnToolsVersion = 10.2.1; - LastSwiftMigration = 1020; - SystemCapabilities = { - com.apple.BackgroundModes = { - enabled = 1; - }; - com.apple.Push = { - enabled = 1; - }; - }; - }; - }; - }; - buildConfigurationList = BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = BFD247612284B9A500981D42; - packageReferences = ( - D58D5F2C26DFE68E00E55E38 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */, - B3C395EF284F2DE700DA9E2F /* XCRemoteSwiftPackageReference "KeychainAccess" */, - B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */, - B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */, - B3C395FA284F3B2400DA9E2F /* XCRemoteSwiftPackageReference "Sparkle" */, - B3C395FD284F3C0900DA9E2F /* XCRemoteSwiftPackageReference "STPrivilegedTask" */, - 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */, - 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */, - 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */, - B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */, - B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */, - ); - productRefGroup = BFD2476B2284B9A500981D42 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = B343F84E295F6323002B1159 /* Products */; - ProjectRef = B343F84D295F6323002B1159 /* em_proxy.xcodeproj */; - }, - { - ProductGroup = B343F887295F7F9B002B1159 /* Products */; - ProjectRef = B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */; - }, - { - ProductGroup = B343F848295F6321002B1159 /* Products */; - ProjectRef = B343F847295F6321002B1159 /* minimuxer.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - BFD247692284B9A500981D42 /* SideStore */, - BF45872A2298D31600BD7491 /* libimobiledevice */, - BF58047A246A28F7008AE704 /* AltBackup */, - BF18BFE624857D7900DD5981 /* AltDaemon */, - BF66EE7D2501AE50007EE018 /* AltStoreCore */, - BF989166250AABF3002ACF50 /* AltWidgetExtension */, - 19104DB12909C06C00C49C7B /* EmotionalDamage */, - 191E5FAA290A5D92001A3B7C /* minimuxer */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - B343F84C295F6321002B1159 /* libminimuxer_static.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libminimuxer_static.a; - remoteRef = B343F84B295F6321002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F853295F6323002B1159 /* libem_proxy_static.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libem_proxy_static.a; - remoteRef = B343F852295F6323002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F855295F6323002B1159 /* run */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = run; - remoteRef = B343F854295F6323002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F88E295F7F9B002B1159 /* libfragmentzip */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = libfragmentzip; - remoteRef = B343F88D295F7F9B002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F890295F7F9B002B1159 /* libfragmentzip */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = libfragmentzip; - remoteRef = B343F88F295F7F9B002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F892295F7F9B002B1159 /* libfragmentzip.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libfragmentzip.a; - remoteRef = B343F891295F7F9B002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - B343F894295F7F9B002B1159 /* libfragmentzip.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libfragmentzip.a; - remoteRef = B343F893295F7F9B002B1159 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - BF580479246A28F7008AE704 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF58048A246A28F9008AE704 /* LaunchScreen.storyboard in Resources */, - BF580487246A28F9008AE704 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF66EE7C2501AE50007EE018 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BFCB9207250AB2120057B44E /* Colors.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF989165250AABF3002ACF50 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF989171250AABF4002ACF50 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BFD247682284B9A500981D42 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BFC57A702416FC7600EB891E /* InstalledAppsCollectionHeaderView.xib in Resources */, - BFB4323F22DE852000B7F8BC /* UpdateCollectionViewCell.xib in Resources */, - BFE60738231ADF49002B0E8E /* Settings.storyboard in Resources */, - D57DF638271E32F000677701 /* PatchApp.storyboard in Resources */, - BFD2477A2284B9A700981D42 /* LaunchScreen.storyboard in Resources */, - BF44EEF3246B3A17002A52F2 /* AltBackup.ipa in Resources */, - BF770E6922BD57DD002A40FE /* Silence.m4a in Resources */, - BFD247772284B9A700981D42 /* Assets.xcassets in Resources */, - 1920B04F2924AC8300744F60 /* Settings.bundle in Resources */, - BFF0B6922321A305007A79E1 /* AboutPatreonHeaderView.xib in Resources */, - BFB6B22423187A3D0022A802 /* NewsCollectionViewCell.xib in Resources */, - BFD247752284B9A500981D42 /* Main.storyboard in Resources */, - BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */, - BFE6073C231AE1E7002B0E8E /* SettingsHeaderFooterView.xib in Resources */, - BF29012F2318F6B100D88A45 /* AppBannerView.xib in Resources */, - BFE6325A22A83BEB00F30809 /* Authentication.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 19104DAE2909C06C00C49C7B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 19104DB52909C06D00C49C7B /* EmotionalDamage.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 191E5FA7290A5D92001A3B7C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 191E5FAE290A5D92001A3B7C /* minimuxer.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF18BFE324857D7900DD5981 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF8CAE452489E772004D6CCE /* AnisetteDataManager.swift in Sources */, - BF1FE358251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */, - BFECAC8F24FD950E0077C41F /* Result+Conveniences.swift in Sources */, - BF8CAE472489E772004D6CCE /* DaemonRequestHandler.swift in Sources */, - B34AFD1429A9D31100E637B4 /* ServerProtocol.swift in Sources */, - BFC712C32512D5F100AB5EBE /* XPCConnection.swift in Sources */, - BFC712C52512D5F100AB5EBE /* XPCConnectionHandler.swift in Sources */, - BFECAC8D24FD950E0077C41F /* ALTConstants.m in Sources */, - BFECAC8924FD950E0077C41F /* ConnectionManager.swift in Sources */, - BFECAC9524FD98BB0077C41F /* CFNotificationName+AltStore.m in Sources */, - BFECAC8E24FD950E0077C41F /* Connection.swift in Sources */, - B34AFD1B29A9DFA200E637B4 /* NSError+AltStore.swift in Sources */, - BF10EB34248730750055E6DB /* main.swift in Sources */, - BF8CAE462489E772004D6CCE /* AppManager.swift in Sources */, - BFECAC9024FD950E0077C41F /* Bundle+AltStore.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF4587282298D31600BD7491 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF45881B2298D3AB00BD7491 /* house_arrest.c in Sources */, - BFD52C0622A1A9CB000B7ED1 /* bplist.c in Sources */, - BF4588232298D3AB00BD7491 /* mobilesync.c in Sources */, - BF4588072298D3AB00BD7491 /* afc.c in Sources */, - 191E607D290B2EA5001A3B7C /* jsmn.c in Sources */, - 191E607E290B2EA7001A3B7C /* jplist.c in Sources */, - BF4588082298D3AB00BD7491 /* mobile_image_mounter.c in Sources */, - BFD52C1122A1A9CB000B7ED1 /* bytearray.c in Sources */, - BF4588022298D3AB00BD7491 /* file_relay.c in Sources */, - BF45880F2298D3AB00BD7491 /* debugserver.c in Sources */, - BF4588162298D3AB00BD7491 /* restore.c in Sources */, - BFD52C0422A1A9CB000B7ED1 /* Dictionary.cpp in Sources */, - BFD52C0222A1A9CB000B7ED1 /* base64.c in Sources */, - BFD52C2022A1A9EC000B7ED1 /* node.c in Sources */, - BF4588092298D3AB00BD7491 /* installation_proxy.c in Sources */, - BF4587FF2298D3AB00BD7491 /* heartbeat.c in Sources */, - BF4588222298D3AB00BD7491 /* mobileactivation.c in Sources */, - BFD52C1822A1A9CB000B7ED1 /* Integer.cpp in Sources */, - BF4588212298D3AB00BD7491 /* idevice.c in Sources */, - B343F885295F7C5D002B1159 /* tlv.c in Sources */, - BFD52C1C22A1A9CB000B7ED1 /* xplist.c in Sources */, - BF4587F92298D3AB00BD7491 /* diagnostics_relay.c in Sources */, - B343F87D295F7C5D002B1159 /* cbuf.c in Sources */, - BF4588062298D3AB00BD7491 /* webinspector.c in Sources */, - BFD52C1722A1A9CB000B7ED1 /* Key.cpp in Sources */, - B343F883295F7C5D002B1159 /* thread.c in Sources */, - BF45880D2298D3AB00BD7491 /* mobilebackup.c in Sources */, - BFD52C0C22A1A9CB000B7ED1 /* Date.cpp in Sources */, - BFD52C0A22A1A9CB000B7ED1 /* plist.c in Sources */, - BFD52C1322A1A9CB000B7ED1 /* Data.cpp in Sources */, - BF45883A2298D3C100BD7491 /* debug.c in Sources */, - B343F881295F7C5D002B1159 /* termcolors.c in Sources */, - B343F87E295F7C5D002B1159 /* collection.c in Sources */, - BFD52C0F22A1A9CB000B7ED1 /* Real.cpp in Sources */, - B33FFBAA295F8F78002259E6 /* preboard.c in Sources */, - B33FFBAC295F8F98002259E6 /* companion_proxy.c in Sources */, - BF4587FB2298D3AB00BD7491 /* notification_proxy.c in Sources */, - BF4588352298D3C100BD7491 /* userpref.c in Sources */, - BFD52C0122A1A9CB000B7ED1 /* ptrarray.c in Sources */, - B343F87C295F7C5D002B1159 /* opack.c in Sources */, - BFD52C0E22A1A9CB000B7ED1 /* Boolean.cpp in Sources */, - BFD52C0822A1A9CB000B7ED1 /* time64.c in Sources */, - B343F884295F7C5D002B1159 /* utils.c in Sources */, - BFD52C2122A1A9EC000B7ED1 /* node_list.c in Sources */, - B343F87F295F7C5D002B1159 /* glue.c in Sources */, - BFD52C1422A1A9CB000B7ED1 /* Array.cpp in Sources */, - BF4588242298D3AB00BD7491 /* property_list_service.c in Sources */, - BF45881E2298D3AB00BD7491 /* misagent.c in Sources */, - B343F880295F7C5D002B1159 /* socket.c in Sources */, - BF4587FC2298D3AB00BD7491 /* sbservices.c in Sources */, - BFD52C1522A1A9CB000B7ED1 /* Node.cpp in Sources */, - BF4588142298D3AB00BD7491 /* device_link_service.c in Sources */, - BF4588172298D3AB00BD7491 /* screenshotr.c in Sources */, - BFD52C0D22A1A9CB000B7ED1 /* Uid.cpp in Sources */, - BFD52C0322A1A9CB000B7ED1 /* hashtable.c in Sources */, - BF4588432298D40000BD7491 /* libusbmuxd.c in Sources */, - BF4588032298D3AB00BD7491 /* syslog_relay.c in Sources */, - BF4588272298D3AB00BD7491 /* service.c in Sources */, - BFD52C0722A1A9CB000B7ED1 /* String.cpp in Sources */, - BF4588262298D3AB00BD7491 /* lockdown.c in Sources */, - BFD52C2222A1A9EC000B7ED1 /* cnary.c in Sources */, - BF45880C2298D3AB00BD7491 /* mobilebackup2.c in Sources */, - BFD52C1922A1A9CB000B7ED1 /* Structure.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF580477246A28F7008AE704 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF580496246A3CB5008AE704 /* UIColor+AltBackup.swift in Sources */, - BF580482246A28F7008AE704 /* ViewController.swift in Sources */, - BF44EEF0246B08BA002A52F2 /* BackupController.swift in Sources */, - 03F06CD52942C27E001C4D68 /* Bundle+AltStore.swift in Sources */, - BF58047E246A28F7008AE704 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF66EE7A2501AE50007EE018 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF66EED32501AECA007EE018 /* AltStore2ToAltStore3.xcmappingmodel in Sources */, - BF66EEA52501AEC5007EE018 /* Benefit.swift in Sources */, - BF66EED22501AECA007EE018 /* AltStore4ToAltStore5.xcmappingmodel in Sources */, - BFAECC5B2501B0A400528F27 /* Bundle+AltStore.swift in Sources */, - BF66EECD2501AECA007EE018 /* StoreAppPolicy.swift in Sources */, - BF66EEE82501AED0007EE018 /* UserDefaults+AltStore.swift in Sources */, - BF340E9A250AD39500A192CB /* ViewApp.intentdefinition in Sources */, - BF66EE9E2501AEC1007EE018 /* Fetchable.swift in Sources */, - BF66EEDF2501AECA007EE018 /* PatreonAccount.swift in Sources */, - BFAECC572501B0A400528F27 /* ConnectionManager.swift in Sources */, - BF66EE9D2501AEC1007EE018 /* AppProtocol.swift in Sources */, - BFC712C42512D5F100AB5EBE /* XPCConnection.swift in Sources */, - D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */, - BF66EE8C2501AEB2007EE018 /* Keychain.swift in Sources */, - BF66EED42501AECA007EE018 /* AltStore5ToAltStore6.xcmappingmodel in Sources */, - BF66EE972501AEBC007EE018 /* ALTAppPermission.m in Sources */, - B34AFD1529A9D31200E637B4 /* ServerProtocol.swift in Sources */, - BFAECC552501B0A400528F27 /* Connection.swift in Sources */, - BF66EEDA2501AECA007EE018 /* RefreshAttempt.swift in Sources */, - BF66EEA92501AEC5007EE018 /* Tier.swift in Sources */, - BF66EEDB2501AECA007EE018 /* StoreApp.swift in Sources */, - BF66EEDE2501AECA007EE018 /* AppID.swift in Sources */, - BF66EECF2501AECA007EE018 /* AltStoreToAltStore2.xcmappingmodel in Sources */, - BF66EEA82501AEC5007EE018 /* Patron.swift in Sources */, - BF66EEDD2501AECA007EE018 /* AppPermission.swift in Sources */, - D58916FE28C7C55C00E39C8B /* LoggedError.swift in Sources */, - BFBF331B2526762200B7B8C9 /* AltStore8ToAltStore9.xcmappingmodel in Sources */, - D5CA0C4E280E249E00469595 /* AltStore9ToAltStore10.xcmappingmodel in Sources */, - BF989184250AACFC002ACF50 /* Date+RelativeDate.swift in Sources */, - BF66EE962501AEBC007EE018 /* ALTPatreonBenefitType.m in Sources */, - BFAECC5A2501B0A400528F27 /* NetworkConnection.swift in Sources */, - D5F99A1828D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel in Sources */, - BF66EEE92501AED0007EE018 /* JSONDecoder+Properties.swift in Sources */, - BF66EEEB2501AED0007EE018 /* UIApplication+AppExtension.swift in Sources */, - BF66EED92501AECA007EE018 /* Team.swift in Sources */, - BF66EED12501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel in Sources */, - BFAECC5C2501B0A400528F27 /* CFNotificationName+AltStore.m in Sources */, - BF66EED82501AECA007EE018 /* SecureValueTransformer.swift in Sources */, - BF8B17EB250AC40000F8157F /* FileManager+SharedDirectories.swift in Sources */, - BF66EEE02501AECA007EE018 /* Account.swift in Sources */, - BF66EED52501AECA007EE018 /* AltStore.xcdatamodeld in Sources */, - B34AFD1C29A9DFA200E637B4 /* NSError+AltStore.swift in Sources */, - BFAECC582501B0A400528F27 /* ALTConstants.m in Sources */, - D5F99A1A28D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift in Sources */, - BFAECC592501B0A400528F27 /* Result+Conveniences.swift in Sources */, - BF66EEE12501AECA007EE018 /* DatabaseManager.swift in Sources */, - D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */, - BF66EEEA2501AED0007EE018 /* UIColor+Hex.swift in Sources */, - BF66EECC2501AECA007EE018 /* Source.swift in Sources */, - BF66EED72501AECA007EE018 /* InstalledApp.swift in Sources */, - BF66EECE2501AECA007EE018 /* InstalledAppPolicy.swift in Sources */, - BF1FE359251A9FB000C3CE09 /* NSXPCConnection+MachServices.swift in Sources */, - BF66EEA62501AEC5007EE018 /* PatreonAPI.swift in Sources */, - BF66EED02501AECA007EE018 /* AltStore6ToAltStore7.xcmappingmodel in Sources */, - BF66EEDC2501AECA007EE018 /* MergePolicy.swift in Sources */, - BF66EEE22501AECA007EE018 /* InstalledExtension.swift in Sources */, - BF66EED62501AECA007EE018 /* NewsItem.swift in Sources */, - BF66EEA72501AEC5007EE018 /* Campaign.swift in Sources */, - BF66EE992501AEBC007EE018 /* ALTSourceUserInfoKey.m in Sources */, - BF989185250AAD1D002ACF50 /* UIColor+AltStore.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BF989163250AABF3002ACF50 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BF98917E250AAC4F002ACF50 /* Countdown.swift in Sources */, - BF42345A25101C35006D1EB2 /* WidgetView.swift in Sources */, - D55E163728776CB700A627A1 /* ComplicationView.swift in Sources */, - BF98917F250AAC4F002ACF50 /* AltWidget.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - BFD247662284B9A500981D42 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */, - BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */, - BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */, - BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */, - D57F2C9426E01BC700B9FA39 /* UIDevice+Vibration.swift in Sources */, - BFD2478F2284C8F900981D42 /* Button.swift in Sources */, - BF56D2AC23DF8E170006506D /* FetchAppIDsOperation.swift in Sources */, - BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */, - BFE6073A231ADF82002B0E8E /* SettingsViewController.swift in Sources */, - D57F2C9126E0070200B9FA39 /* EnableJITOperation.swift in Sources */, - BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */, - D5E1E7C128077DE90016FC96 /* FetchTrustedSourcesOperation.swift in Sources */, - BFE338DF22F0EADB002E24B9 /* FetchSourceOperation.swift in Sources */, - D54DED1428CBC44B008B27A0 /* ErrorLogTableViewCell.swift in Sources */, - BFB6B21E231870160022A802 /* NewsViewController.swift in Sources */, - BFC57A652416C72400EB891E /* DeactivateAppOperation.swift in Sources */, - BF3BEFC124086A1E00DE7D55 /* RefreshAppOperation.swift in Sources */, - BFE60740231AFD2A002B0E8E /* InsetGroupTableViewCell.swift in Sources */, - BF0DCA662433BDF500E3A595 /* AnalyticsManager.swift in Sources */, - BFCCB51A245E3401001853EA /* VerifyAppOperation.swift in Sources */, - BFF0B6982322CAB8007A79E1 /* InstructionsViewController.swift in Sources */, - BF9ABA4522DCFF43008935CF /* BrowseViewController.swift in Sources */, - BF770E5422BC044E002A40FE /* OperationContexts.swift in Sources */, - BFD2478C2284C4C300981D42 /* AppIconImageView.swift in Sources */, - BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */, - BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */, - BFF00D302501BD7D00746320 /* Intents.intentdefinition in Sources */, - D5DAE0942804B0B80034D8D4 /* ScreenshotProcessor.swift in Sources */, - BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */, - BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */, - BFE00A202503097F00EB4D0C /* INInteraction+AltStore.swift in Sources */, - BFDB6A0B22AAEDB7007EA6D6 /* Operation.swift in Sources */, - BF770E6722BD57C4002A40FE /* BackgroundTaskManager.swift in Sources */, - BF44EEFC246B4550002A52F2 /* RemoveAppOperation.swift in Sources */, - BF3D64B022E8D4B800E9056B /* AppContentViewControllerCells.swift in Sources */, - BFC57A6E2416FC5D00EB891E /* InstalledAppsCollectionHeaderView.swift in Sources */, - B3EE16B62925E27D00B3B1F5 /* AnisetteManager.swift in Sources */, - BF88F97224F8727D00BB75DF /* AppManagerErrors.swift in Sources */, - B39F16152918D7DA002E9404 /* Consts+Proxy.swift in Sources */, - BF6C8FAE2429597900125131 /* BannerCollectionViewCell.swift in Sources */, - BF6F439223644C6E00A0B879 /* RefreshAltStoreViewController.swift in Sources */, - BFE60742231B07E6002B0E8E /* SettingsHeaderFooterView.swift in Sources */, - BFE338E822F10E56002E24B9 /* LaunchViewController.swift in Sources */, - BFA8172B23C5633D001B5953 /* FetchAnisetteDataOperation.swift in Sources */, - BF9ABA4722DD0638008935CF /* BrowseCollectionViewCell.swift in Sources */, - BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */, - BF41B808233433C100C593A3 /* LoadingState.swift in Sources */, - BFF0B69A2322D7D0007A79E1 /* UIScreen+CompactHeight.swift in Sources */, - D5F2F6A92720B7C20081CCF5 /* PatchViewController.swift in Sources */, - B39F16132918D7C5002E9404 /* Consts.swift in Sources */, - BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */, - BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */, - BFB39B5C252BC10E00D1BE50 /* Managed.swift in Sources */, - BF770E5822BC3D0F002A40FE /* RefreshGroup.swift in Sources */, - 19B9B7452845E6DF0076EF69 /* SelectTeamViewController.swift in Sources */, - BF18B0F122E25DF9005C4CF5 /* ToastView.swift in Sources */, - BF3D649F22E7B24C00E9056B /* CollapsingTextView.swift in Sources */, - BF02419622F2199300129732 /* RefreshAttemptsViewController.swift in Sources */, - B376FE3E29258C8900E18883 /* OSLog+SideStore.swift in Sources */, - BF08858322DE795100DE9F1E /* MyAppsViewController.swift in Sources */, - BFC84A4D2421A19100853474 /* SourcesViewController.swift in Sources */, - BFF0B696232242D3007A79E1 /* LicensesViewController.swift in Sources */, - D57FE84428C7DB7100216002 /* ErrorLogViewController.swift in Sources */, - BFBE0007250AD0E70080826E /* ViewAppIntentHandler.swift in Sources */, - BFDB6A0822AAED73007EA6D6 /* ResignAppOperation.swift in Sources */, - D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */, - BF770E5122BB1CF6002A40FE /* InstallAppOperation.swift in Sources */, - BF9ABA4B22DD1380008935CF /* NavigationBar.swift in Sources */, - BF6C8FAC242935ED00125131 /* NSAttributedString+Markdown.m in Sources */, - BFF00D322501BDA100746320 /* BackgroundRefreshAppsOperation.swift in Sources */, - BF0C4EBD22A1BD8B009A2DD7 /* AppManager.swift in Sources */, - BF2901312318F7A800D88A45 /* AppBannerView.swift in Sources */, - BFF00D342501BDCF00746320 /* IntentHandler.swift in Sources */, - BFDBBD80246CB84F004ED2F3 /* RemoveAppBackupOperation.swift in Sources */, - BFF0B6942321CB85007A79E1 /* AuthenticationViewController.swift in Sources */, - BF3432FB246B894F0052F4A1 /* BackupAppOperation.swift in Sources */, - BF9ABA4922DD0742008935CF /* ScreenshotCollectionViewCell.swift in Sources */, - BF9ABA4D22DD16DE008935CF /* PillButton.swift in Sources */, - D5DAE0962804DF430034D8D4 /* UpdatePatronsOperation.swift in Sources */, - BFE6326C22A86FF300F30809 /* AuthenticationOperation.swift in Sources */, - BFF435D8255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */, - BF4B78FE24B3D1DB008AB4AC /* SceneDelegate.swift in Sources */, - BF6C8FB02429599900125131 /* TextCollectionReusableView.swift in Sources */, - BF663C4F2433ED8200DAA738 /* FileManager+DirectorySize.swift in Sources */, - D57DF63F271E51E400677701 /* ALTAppPatcher.m in Sources */, - BFB6B220231870B00022A802 /* NewsCollectionViewCell.swift in Sources */, - BF3BEFBF2408673400DE7D55 /* FetchProvisioningProfilesOperation.swift in Sources */, - BFF0B69023219C6D007A79E1 /* PatreonComponents.swift in Sources */, - BFBE0004250ACFFB0080826E /* ViewApp.intentdefinition in Sources */, - BF56D2AF23DF9E310006506D /* AppIDsViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 19104D942909BADB00C49C7B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BF45872A2298D31600BD7491 /* libimobiledevice */; - targetProxy = 19104D932909BADB00C49C7B /* PBXContainerItemProxy */; - }; - 19104DBA2909C0F200C49C7B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 19104DB12909C06C00C49C7B /* EmotionalDamage */; - targetProxy = 19104DB92909C0F200C49C7B /* PBXContainerItemProxy */; - }; - 191E5FB3290A5D9B001A3B7C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 191E5FAA290A5D92001A3B7C /* minimuxer */; - targetProxy = 191E5FB2290A5D9B001A3B7C /* PBXContainerItemProxy */; - }; - 191E5FDA290AFA49001A3B7C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = 191E5FD9290AFA49001A3B7C /* OpenSSL */; - }; - B343F86F295F76FD002B1159 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "minimuxer-staticlib"; - targetProxy = B343F86E295F76FD002B1159 /* PBXContainerItemProxy */; - }; - B343F871295F7704002B1159 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "em_proxy-staticlib"; - targetProxy = B343F870295F7704002B1159 /* PBXContainerItemProxy */; - }; - BF66EE842501AE50007EE018 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BF66EE7D2501AE50007EE018 /* AltStoreCore */; - targetProxy = BF66EE832501AE50007EE018 /* PBXContainerItemProxy */; - }; - BF989176250AABF4002ACF50 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BF989166250AABF3002ACF50 /* AltWidgetExtension */; - targetProxy = BF989175250AABF4002ACF50 /* PBXContainerItemProxy */; - }; - BFF615AB2510042B00484D3B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BF66EE7D2501AE50007EE018 /* AltStoreCore */; - targetProxy = BFF615AA2510042B00484D3B /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - BF580488246A28F9008AE704 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - BF580489246A28F9008AE704 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; - BFD247732284B9A500981D42 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - BFD247742284B9A500981D42 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - BFD247782284B9A700981D42 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - BFD247792284B9A700981D42 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 19104DB72909C06D00C49C7B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 4FW3Q8784L; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/em_proxy", - ); - MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OBJC_BRIDGING_HEADER = Dependencies/em_proxy/em_proxy.h; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 14.0; - WATCHOS_DEPLOYMENT_TARGET = 7.0; - }; - name = Debug; - }; - 19104DB82909C06D00C49C7B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4FW3Q8784L; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/em_proxy", - ); - MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = Dependencies/em_proxy/em_proxy.h; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TVOS_DEPLOYMENT_TARGET = 14.0; - WATCHOS_DEPLOYMENT_TARGET = 7.0; - }; - name = Release; - }; - 191E5FB0290A5D92001A3B7C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 4FW3Q8784L; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/minimuxer", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OBJC_BRIDGING_HEADER = Dependencies/minimuxer/minimuxer.h; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 191E5FB1290A5D92001A3B7C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4FW3Q8784L; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/minimuxer", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OBJC_BRIDGING_HEADER = Dependencies/minimuxer/minimuxer.h; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - BF18BFEC24857D7900DD5981 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CLANG_MODULES_AUTOLINK = NO; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = AltDaemon/AltDaemon.entitlements; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - DYLIB_COMPATIBILITY_VERSION = ""; - DYLIB_CURRENT_VERSION = ""; - EXECUTABLE_EXTENSION = ""; - EXECUTABLE_SUFFIX = ""; - INSTALL_PATH = /usr/bin; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - LD_DYLIB_INSTALL_NAME = /usr/bin/AltDaemon; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Roxas\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/OpenSSL/ios/lib\"", - ); - MACH_O_TYPE = mh_execute; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - "-lcrypto", - "-lssl", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = NO; - SWIFT_OBJC_BRIDGING_HEADER = "AltDaemon/AltDaemon-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BF18BFED24857D7900DD5981 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CLANG_MODULES_AUTOLINK = NO; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = AltDaemon/AltDaemon.entitlements; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - DYLIB_COMPATIBILITY_VERSION = ""; - DYLIB_CURRENT_VERSION = ""; - EXECUTABLE_EXTENSION = ""; - EXECUTABLE_SUFFIX = ""; - GCC_OPTIMIZATION_LEVEL = z; - INSTALL_PATH = /usr/bin; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - LD_DYLIB_INSTALL_NAME = /usr/bin/AltDaemon; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Roxas\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/OpenSSL/ios/lib\"", - ); - MACH_O_TYPE = mh_execute; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - "-lcrypto", - "-lssl", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = NO; - SWIFT_OBJC_BRIDGING_HEADER = "AltDaemon/AltDaemon-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - BF4587342298D31600BD7491 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "Mac Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - EXECUTABLE_PREFIX = lib; - GCC_ENABLE_CPP_EXCEPTIONS = YES; - GCC_ENABLE_CPP_RTTI = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - HAVE_OPENSSL, - HAVE_STPNCPY, - HAVE_STPCPY, - HAVE_VASPRINTF, - HAVE_ASPRINTF, - "\"PACKAGE_STRING=\\\"AltServer 1.0\\\"\"", - HAVE_GETIFADDRS, - HAVE_STRNDUP, - ); - GCC_WARN_INHIBIT_ALL_WARNINGS = YES; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/Dependencies/libplist/include\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice/include\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/OpenSSL/macosx/include\"", - "\"$(SRCROOT)/Dependencies/libusbmuxd/include\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/libzip/lib\"", - "\"$(SRCROOT)/Dependencies/libplist/libcnary/include\"", - "\"${SDKROOT}/usr/include/libxml2\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/libzip/xcode\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice-glue/include\"/**", - ); - MACOSX_DEPLOYMENT_TARGET = 10.14; - PRODUCT_NAME = imobiledevice; - SDKROOT = macosx; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - BF4587352298D31600BD7491 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "Mac Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - EXECUTABLE_PREFIX = lib; - GCC_ENABLE_CPP_EXCEPTIONS = YES; - GCC_ENABLE_CPP_RTTI = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - HAVE_OPENSSL, - HAVE_STPNCPY, - HAVE_STPCPY, - HAVE_VASPRINTF, - HAVE_ASPRINTF, - "\"PACKAGE_STRING=\\\"AltServer 1.0\\\"\"", - HAVE_GETIFADDRS, - HAVE_STRNDUP, - ); - GCC_WARN_INHIBIT_ALL_WARNINGS = YES; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/Dependencies/libplist/include\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice/include\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/OpenSSL/macosx/include\"", - "\"$(SRCROOT)/Dependencies/libusbmuxd/include\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/libzip/lib\"", - "\"$(SRCROOT)/Dependencies/libplist/libcnary/include\"", - "\"${SDKROOT}/usr/include/libxml2\"", - "\"$(SRCROOT)/Dependencies/AltSign/Dependencies/libzip/xcode\"", - "\"$(SRCROOT)/Dependencies/libimobiledevice-glue/include\"/**", - ); - MACOSX_DEPLOYMENT_TARGET = 10.14; - PRODUCT_NAME = imobiledevice; - SDKROOT = macosx; - SKIP_INSTALL = YES; - }; - name = Release; - }; - BF58048C246A28F9008AE704 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */; - buildSettings = { - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = AltBackup/AltBackup.entitlements; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - INFOPLIST_FILE = AltBackup/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BF58048D246A28F9008AE704 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */; - buildSettings = { - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = AltBackup/AltBackup.entitlements; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - INFOPLIST_FILE = AltBackup/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - BF66EE872501AE50007EE018 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = AltStoreCore/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - BF66EE882501AE50007EE018 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = AltStoreCore/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - BF989179250AABF4002ACF50 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_ENTITLEMENTS = AltWidget/AltWidgetExtension.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = AltWidget/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BF98917A250AABF4002ACF50 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960D284F4E4B00DA9E2F /* AltWidgetExtension.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_ENTITLEMENTS = AltWidget/AltWidgetExtension.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = AltWidget/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - BFD2477C2284B9A700981D42 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C39607284F4C8400DA9E2F /* Build.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - 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 = NO; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - 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; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_CPLUSPLUSFLAGS = ( - "$(OTHER_CFLAGS)", - "-Wno-module-import-in-extern-c", - ); - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\""; - }; - name = Debug; - }; - BFD2477D2284B9A700981D42 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C39607284F4C8400DA9E2F /* Build.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - 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 = NO; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - 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; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.2; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - OTHER_CPLUSPLUSFLAGS = ( - "$(OTHER_CFLAGS)", - "-Wno-module-import-in-extern-c", - ); - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG BETA"; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - SYSTEM_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/AltSign/Dependencies\""; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - BFD2477F2284B9A700981D42 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = AltStore/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/fragmentzip", - "$(PROJECT_DIR)/Dependencies/libcurl", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BFD247802284B9A700981D42 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3C3960B284F4C9800DA9E2F /* AltStore.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = AltStore/AltStore.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = AltStore/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Dependencies/fragmentzip", - "$(PROJECT_DIR)/Dependencies/libcurl", - ); - PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; - SWIFT_OBJC_BRIDGING_HEADER = "AltStore/AltStore-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 19104DB62909C06D00C49C7B /* Build configuration list for PBXNativeTarget "EmotionalDamage" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 19104DB72909C06D00C49C7B /* Debug */, - 19104DB82909C06D00C49C7B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 191E5FAF290A5D92001A3B7C /* Build configuration list for PBXNativeTarget "minimuxer" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 191E5FB0290A5D92001A3B7C /* Debug */, - 191E5FB1290A5D92001A3B7C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF18BFEB24857D7900DD5981 /* Build configuration list for PBXNativeTarget "AltDaemon" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF18BFEC24857D7900DD5981 /* Debug */, - BF18BFED24857D7900DD5981 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF4587332298D31600BD7491 /* Build configuration list for PBXNativeTarget "libimobiledevice" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF4587342298D31600BD7491 /* Debug */, - BF4587352298D31600BD7491 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF58048E246A28F9008AE704 /* Build configuration list for PBXNativeTarget "AltBackup" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF58048C246A28F9008AE704 /* Debug */, - BF58048D246A28F9008AE704 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF66EE892501AE50007EE018 /* Build configuration list for PBXNativeTarget "AltStoreCore" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF66EE872501AE50007EE018 /* Debug */, - BF66EE882501AE50007EE018 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BF989178250AABF4002ACF50 /* Build configuration list for PBXNativeTarget "AltWidgetExtension" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BF989179250AABF4002ACF50 /* Debug */, - BF98917A250AABF4002ACF50 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BFD2477C2284B9A700981D42 /* Debug */, - BFD2477D2284B9A700981D42 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BFD2477E2284B9A700981D42 /* Build configuration list for PBXNativeTarget "SideStore" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BFD2477F2284B9A700981D42 /* Debug */, - BFD247802284B9A700981D42 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SideStore/AltSign"; - requirement = { - branch = master; - kind = branch; - }; - }; - 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/krzyzanowskim/OpenSSL"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 1.1.180; - }; - }; - 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SwiftPackageIndex/SemanticVersion.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.3.5; - }; - }; - B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SideStore/SideKit.git"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 0.1.0; - }; - }; - B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/JoeMatt/Roxas.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.2.2; - }; - }; - B3C395EF284F2DE700DA9E2F /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.2.0; - }; - }; - B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kean/Nuke.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 7.0.0; - }; - }; - B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/microsoft/appcenter-sdk-apple.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.2.0; - }; - }; - B3C395FA284F3B2400DA9E2F /* XCRemoteSwiftPackageReference "Sparkle" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/sparkle-project/Sparkle.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.1.0; - }; - }; - B3C395FD284F3C0900DA9E2F /* XCRemoteSwiftPackageReference "STPrivilegedTask" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/JoeMatt/STPrivilegedTask.git"; - requirement = { - branch = master; - kind = branch; - }; - }; - D58D5F2C26DFE68E00E55E38 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.1.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 191E5FD9290AFA49001A3B7C /* OpenSSL */ = { - isa = XCSwiftPackageProductDependency; - package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */; - productName = OpenSSL; - }; - 191E5FDB290AFA5C001A3B7C /* OpenSSL */ = { - isa = XCSwiftPackageProductDependency; - package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */; - productName = OpenSSL; - }; - 4879A95E2861046500FC1BBD /* AltSign */ = { - isa = XCSwiftPackageProductDependency; - package = 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */; - productName = AltSign; - }; - 4879A9612861049C00FC1BBD /* OpenSSL */ = { - isa = XCSwiftPackageProductDependency; - package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */; - productName = OpenSSL; - }; - 99C4EF4C2979132100CB538D /* SemanticVersion */ = { - isa = XCSwiftPackageProductDependency; - package = 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */; - productName = SemanticVersion; - }; - B34AFD0929A9CEDD00E637B4 /* SideKit */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */; - productName = SideKit; - }; - B34AFD0C29A9CF4000E637B4 /* Roxas */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; - productName = Roxas; - }; - B34AFD0E29A9CF4000E637B4 /* RoxasUI */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; - productName = RoxasUI; - }; - B34AFD1029A9CF5C00E637B4 /* Roxas */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; - productName = Roxas; - }; - B34AFD1629A9D9FC00E637B4 /* RoxasUI */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0B29A9CF4000E637B4 /* XCRemoteSwiftPackageReference "Roxas" */; - productName = RoxasUI; - }; - B34AFD1829A9DB0200E637B4 /* SideKit */ = { - isa = XCSwiftPackageProductDependency; - package = B34AFD0829A9CEDD00E637B4 /* XCRemoteSwiftPackageReference "SideKit" */; - productName = SideKit; - }; - B3C395F0284F2DE700DA9E2F /* KeychainAccess */ = { - isa = XCSwiftPackageProductDependency; - package = B3C395EF284F2DE700DA9E2F /* XCRemoteSwiftPackageReference "KeychainAccess" */; - productName = KeychainAccess; - }; - B3C395F3284F35DD00DA9E2F /* Nuke */ = { - isa = XCSwiftPackageProductDependency; - package = B3C395F2284F35DD00DA9E2F /* XCRemoteSwiftPackageReference "Nuke" */; - productName = Nuke; - }; - B3C395F6284F362400DA9E2F /* AppCenterAnalytics */ = { - isa = XCSwiftPackageProductDependency; - package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; - productName = AppCenterAnalytics; - }; - B3C395F8284F362400DA9E2F /* AppCenterCrashes */ = { - isa = XCSwiftPackageProductDependency; - package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; - productName = AppCenterCrashes; - }; -/* End XCSwiftPackageProductDependency section */ - -/* Begin XCVersionGroup section */ - BF66EEB72501AECA007EE018 /* AltStore.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */, - D5CA0C4C280E242500469595 /* AltStore 10.xcdatamodel */, - BFBF33142526754700B7B8C9 /* AltStore 9.xcdatamodel */, - BFF7EC4C25081E9300BDE521 /* AltStore 8.xcdatamodel */, - BF66EEB82501AECA007EE018 /* AltStore 3.xcdatamodel */, - BF66EEB92501AECA007EE018 /* AltStore.xcdatamodel */, - BF66EEBA2501AECA007EE018 /* AltStore 6.xcdatamodel */, - BF66EEBB2501AECA007EE018 /* AltStore 5.xcdatamodel */, - BF66EEBC2501AECA007EE018 /* AltStore 7.xcdatamodel */, - BF66EEBD2501AECA007EE018 /* AltStore 2.xcdatamodel */, - BF66EEBE2501AECA007EE018 /* AltStore 4.xcdatamodel */, - ); - currentVersion = D52E988928D002D30032BE6B /* AltStore 11.xcdatamodel */; - path = AltStore.xcdatamodeld; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ - }; - rootObject = BFD247622284B9A500981D42 /* Project object */; -} diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltDaemon.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltDaemon.xcscheme deleted file mode 100644 index c65d4dbf..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltDaemon.xcscheme +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltPlugin.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltPlugin.xcscheme deleted file mode 100644 index 2bfc3556..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltPlugin.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltServer.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltServer.xcscheme deleted file mode 100644 index 46e59030..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltServer.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore - Release.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore - Release.xcscheme deleted file mode 100644 index b86d9086..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore - Release.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore.xcscheme deleted file mode 100644 index 2c21e935..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltStore.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore.xcodeproj/xcshareddata/xcschemes/AltXPC.xcscheme b/AltStore.xcodeproj/xcshareddata/xcschemes/AltXPC.xcscheme deleted file mode 100644 index 4aca1860..00000000 --- a/AltStore.xcodeproj/xcshareddata/xcschemes/AltXPC.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AltStore/AltStore-Bridging-Header.h b/AltStore/AltStore-Bridging-Header.h deleted file mode 100644 index f75b06b6..00000000 --- a/AltStore/AltStore-Bridging-Header.h +++ /dev/null @@ -1,8 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "NSAttributedString+Markdown.h" -#import "ALTAppPatcher.h" - -#include "fragmentzip.h" diff --git a/AltStore/App Detail/AppViewController.swift b/AltStore/App Detail/AppViewController.swift deleted file mode 100644 index a2c2e565..00000000 --- a/AltStore/App Detail/AppViewController.swift +++ /dev/null @@ -1,570 +0,0 @@ -// -// AppViewController.swift -// AltStore -// -// Created by Riley Testut on 7/22/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -import AltStoreCore -import RoxasUI - -import Nuke - -final class AppViewController: UIViewController -{ - var app: StoreApp! - - private var contentViewController: AppContentViewController! - private var contentViewControllerShadowView: UIView! - - private var blurAnimator: UIViewPropertyAnimator? - private var navigationBarAnimator: UIViewPropertyAnimator? - - private var contentSizeObservation: NSKeyValueObservation? - - @IBOutlet private var scrollView: UIScrollView! - @IBOutlet private var contentView: UIView! - - @IBOutlet private var bannerView: AppBannerView! - - @IBOutlet private var backButton: UIButton! - @IBOutlet private var backButtonContainerView: UIVisualEffectView! - - @IBOutlet private var backgroundAppIconImageView: UIImageView! - @IBOutlet private var backgroundBlurView: UIVisualEffectView! - - @IBOutlet private var navigationBarTitleView: UIView! - @IBOutlet private var navigationBarDownloadButton: PillButton! - @IBOutlet private var navigationBarAppIconImageView: UIImageView! - @IBOutlet private var navigationBarAppNameLabel: UILabel! - - private var _shouldResetLayout = false - private var _backgroundBlurEffect: UIBlurEffect? - private var _backgroundBlurTintColor: UIColor? - - private var _preferredStatusBarStyle: UIStatusBarStyle = .default - - override var preferredStatusBarStyle: UIStatusBarStyle { - return _preferredStatusBarStyle - } - - override func viewDidLoad() - { - super.viewDidLoad() - - self.navigationBarTitleView.sizeToFit() - self.navigationItem.titleView = self.navigationBarTitleView - - self.contentViewControllerShadowView = UIView() - self.contentViewControllerShadowView.backgroundColor = .white - self.contentViewControllerShadowView.layer.cornerRadius = 38 - self.contentViewControllerShadowView.layer.shadowColor = UIColor.black.cgColor - self.contentViewControllerShadowView.layer.shadowOffset = CGSize(width: 0, height: -1) - self.contentViewControllerShadowView.layer.shadowRadius = 10 - self.contentViewControllerShadowView.layer.shadowOpacity = 0.3 - self.contentViewController.view.superview?.insertSubview(self.contentViewControllerShadowView, at: 0) - - self.contentView.addGestureRecognizer(self.scrollView.panGestureRecognizer) - - self.contentViewController.view.layer.cornerRadius = 38 - self.contentViewController.view.layer.masksToBounds = true - - self.contentViewController.tableView.panGestureRecognizer.require(toFail: self.scrollView.panGestureRecognizer) - self.contentViewController.tableView.showsVerticalScrollIndicator = false - - // Bring to front so the scroll indicators are visible. - self.view.bringSubviewToFront(self.scrollView) - self.scrollView.isUserInteractionEnabled = false - - self.bannerView.frame = CGRect(x: 0, y: 0, width: 300, height: 93) - self.bannerView.backgroundEffectView.effect = UIBlurEffect(style: .regular) - self.bannerView.backgroundEffectView.backgroundColor = .clear - self.bannerView.iconImageView.image = nil - self.bannerView.iconImageView.tintColor = self.app.tintColor - self.bannerView.button.tintColor = self.app.tintColor - self.bannerView.tintColor = self.app.tintColor - - self.bannerView.configure(for: self.app) - self.bannerView.accessibilityTraits.remove(.button) - - self.bannerView.button.addTarget(self, action: #selector(AppViewController.performAppAction(_:)), for: .primaryActionTriggered) - - self.backButtonContainerView.tintColor = self.app.tintColor - - self.navigationController?.navigationBar.tintColor = self.app.tintColor - self.navigationBarDownloadButton.tintColor = self.app.tintColor - self.navigationBarAppNameLabel.text = self.app.name - self.navigationBarAppIconImageView.tintColor = self.app.tintColor - - self.contentSizeObservation = self.contentViewController.tableView.observe(\.contentSize) { [weak self] (tableView, change) in - self?.view.setNeedsLayout() - self?.view.layoutIfNeeded() - } - - self.update() - - NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.didChangeApp(_:)), name: .NSManagedObjectContextObjectsDidChange, object: DatabaseManager.shared.viewContext) - NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.didBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) - - self._backgroundBlurEffect = self.backgroundBlurView.effect as? UIBlurEffect - self._backgroundBlurTintColor = self.backgroundBlurView.contentView.backgroundColor - - // Load Images - for imageView in [self.bannerView.iconImageView!, self.backgroundAppIconImageView!, self.navigationBarAppIconImageView!] - { - imageView.isIndicatingActivity = true - - Nuke.loadImage(with: self.app.iconURL, options: .shared, into: imageView, progress: nil) { [weak imageView] (response, error) in - if response?.image != nil - { - imageView?.isIndicatingActivity = false - } - } - } - } - - override func viewWillAppear(_ animated: Bool) - { - super.viewWillAppear(animated) - - self.prepareBlur() - - // Update blur immediately. - self.view.setNeedsLayout() - self.view.layoutIfNeeded() - - self.transitionCoordinator?.animate(alongsideTransition: { (context) in - self.hideNavigationBar() - }, completion: nil) - } - - override func viewDidAppear(_ animated: Bool) - { - super.viewDidAppear(animated) - - self._shouldResetLayout = true - self.view.setNeedsLayout() - self.view.layoutIfNeeded() - } - - override func viewWillDisappear(_ animated: Bool) - { - super.viewWillDisappear(animated) - - // Guard against "dismissing" when presenting via 3D Touch pop. - guard self.navigationController != nil else { return } - - // Store reference since self.navigationController will be nil after disappearing. - let navigationController = self.navigationController - navigationController?.navigationBar.barStyle = .default // Don't animate, or else status bar might appear messed-up. - - self.transitionCoordinator?.animate(alongsideTransition: { (context) in - self.showNavigationBar(for: navigationController) - }, completion: { (context) in - if !context.isCancelled - { - self.showNavigationBar(for: navigationController) - } - }) - } - - override func viewDidDisappear(_ animated: Bool) - { - super.viewDidDisappear(animated) - - if self.navigationController == nil - { - self.resetNavigationBarAnimation() - } - } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) - { - guard segue.identifier == "embedAppContentViewController" else { return } - - self.contentViewController = segue.destination as? AppContentViewController - self.contentViewController.app = self.app - - if #available(iOS 15, *) - { - // Fix navigation bar + tab bar appearance on iOS 15. - self.setContentScrollView(self.scrollView) - self.navigationItem.scrollEdgeAppearance = self.navigationController?.navigationBar.standardAppearance - } - } - - override func viewDidLayoutSubviews() - { - super.viewDidLayoutSubviews() - - if self._shouldResetLayout - { - // Various events can cause UI to mess up, so reset affected components now. - - if self.navigationController?.topViewController == self - { - self.hideNavigationBar() - } - - self.prepareBlur() - - // Reset navigation bar animation, and create a new one later in this method if necessary. - self.resetNavigationBarAnimation() - - self._shouldResetLayout = false - } - - let statusBarHeight = UIApplication.shared.statusBarFrame.height - let cornerRadius = self.contentViewControllerShadowView.layer.cornerRadius - - let inset = 12 as CGFloat - let padding = 20 as CGFloat - - let backButtonSize = self.backButton.sizeThatFits(CGSize(width: 1000, height: 1000)) - var backButtonFrame = CGRect(x: inset, y: statusBarHeight, - width: backButtonSize.width + 20, height: backButtonSize.height + 20) - - var headerFrame = CGRect(x: inset, y: 0, width: self.view.bounds.width - inset * 2, height: self.bannerView.bounds.height) - var contentFrame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height) - var backgroundIconFrame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.width) - - let minimumHeaderY = backButtonFrame.maxY + 8 - - let minimumContentY = minimumHeaderY + headerFrame.height + padding - let maximumContentY = self.view.bounds.width * 0.667 - - // A full blur is too much, so we reduce the visible blur by 0.3, resulting in 70% blur. - let minimumBlurFraction = 0.3 as CGFloat - - contentFrame.origin.y = maximumContentY - self.scrollView.contentOffset.y - headerFrame.origin.y = contentFrame.origin.y - padding - headerFrame.height - - // Stretch the app icon image to fill additional vertical space if necessary. - let height = max(contentFrame.origin.y + cornerRadius * 2, backgroundIconFrame.height) - backgroundIconFrame.size.height = height - - let blurThreshold = 0 as CGFloat - if self.scrollView.contentOffset.y < blurThreshold - { - // Determine how much to lessen blur by. - - let range = 75 as CGFloat - let difference = -self.scrollView.contentOffset.y - - let fraction = min(difference, range) / range - - let fractionComplete = (fraction * (1.0 - minimumBlurFraction)) + minimumBlurFraction - self.blurAnimator?.fractionComplete = fractionComplete - } - else - { - // Set blur to default. - - self.blurAnimator?.fractionComplete = minimumBlurFraction - } - - // Animate navigation bar. - let showNavigationBarThreshold = (maximumContentY - minimumContentY) + backButtonFrame.origin.y - if self.scrollView.contentOffset.y > showNavigationBarThreshold - { - if self.navigationBarAnimator == nil - { - self.prepareNavigationBarAnimation() - } - - let difference = self.scrollView.contentOffset.y - showNavigationBarThreshold - let range = (headerFrame.height + padding) - (self.navigationController?.navigationBar.bounds.height ?? self.view.safeAreaInsets.top) - - let fractionComplete = min(difference, range) / range - self.navigationBarAnimator?.fractionComplete = fractionComplete - } - else - { - self.resetNavigationBarAnimation() - } - - let beginMovingBackButtonThreshold = (maximumContentY - minimumContentY) - if self.scrollView.contentOffset.y > beginMovingBackButtonThreshold - { - let difference = self.scrollView.contentOffset.y - beginMovingBackButtonThreshold - backButtonFrame.origin.y -= difference - } - - let pinContentToTopThreshold = maximumContentY - if self.scrollView.contentOffset.y > pinContentToTopThreshold - { - contentFrame.origin.y = 0 - backgroundIconFrame.origin.y = 0 - - let difference = self.scrollView.contentOffset.y - pinContentToTopThreshold - self.contentViewController.tableView.contentOffset.y = difference - } - else - { - // Keep content table view's content offset at the top. - self.contentViewController.tableView.contentOffset.y = 0 - } - - // Keep background app icon centered in gap between top of content and top of screen. - backgroundIconFrame.origin.y = (contentFrame.origin.y / 2) - backgroundIconFrame.height / 2 - - // Set frames. - self.contentViewController.view.superview?.frame = contentFrame - self.bannerView.frame = headerFrame - self.backgroundAppIconImageView.frame = backgroundIconFrame - self.backgroundBlurView.frame = backgroundIconFrame - self.backButtonContainerView.frame = backButtonFrame - - self.contentViewControllerShadowView.frame = self.contentViewController.view.frame - - self.backButtonContainerView.layer.cornerRadius = self.backButtonContainerView.bounds.midY - - self.scrollView.scrollIndicatorInsets.top = statusBarHeight - - // Adjust content offset + size. - let contentOffset = self.scrollView.contentOffset - - var contentSize = self.contentViewController.tableView.contentSize - contentSize.height += maximumContentY - - self.scrollView.contentSize = contentSize - self.scrollView.contentOffset = contentOffset - - self.bannerView.backgroundEffectView.backgroundColor = .clear - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) - { - super.traitCollectionDidChange(previousTraitCollection) - self._shouldResetLayout = true - } - - deinit - { - self.blurAnimator?.stopAnimation(true) - self.navigationBarAnimator?.stopAnimation(true) - } -} - -extension AppViewController -{ - final class func makeAppViewController(app: StoreApp) -> AppViewController - { - let storyboard = UIStoryboard(name: "Main", bundle: nil) - - let appViewController = storyboard.instantiateViewController(withIdentifier: "appViewController") as! AppViewController - appViewController.app = app - return appViewController - } -} - -private extension AppViewController -{ - func update() - { - for button in [self.bannerView.button!, self.navigationBarDownloadButton!] - { - button.tintColor = self.app.tintColor - button.isIndicatingActivity = false - - if self.app.installedApp == nil - { - button.setTitle(NSLocalizedString("FREE", comment: ""), for: .normal) - } - else - { - button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) - } - - let progress = AppManager.shared.installationProgress(for: self.app) - button.progress = progress - } - - if let versionDate = self.app.latestVersion?.date, versionDate > Date() - { - self.bannerView.button.countdownDate = versionDate - self.navigationBarDownloadButton.countdownDate = versionDate - } - else - { - self.bannerView.button.countdownDate = nil - self.navigationBarDownloadButton.countdownDate = nil - } - - let barButtonItem = self.navigationItem.rightBarButtonItem - self.navigationItem.rightBarButtonItem = nil - self.navigationItem.rightBarButtonItem = barButtonItem - } - - func showNavigationBar(for navigationController: UINavigationController? = nil) - { - let navigationController = navigationController ?? self.navigationController - navigationController?.navigationBar.alpha = 1.0 - navigationController?.navigationBar.tintColor = .altPrimary - navigationController?.navigationBar.setNeedsLayout() - - if self.traitCollection.userInterfaceStyle == .dark - { - self._preferredStatusBarStyle = .lightContent - } - else - { - self._preferredStatusBarStyle = .default - } - - navigationController?.setNeedsStatusBarAppearanceUpdate() - } - - func hideNavigationBar(for navigationController: UINavigationController? = nil) - { - let navigationController = navigationController ?? self.navigationController - navigationController?.navigationBar.alpha = 0.0 - - self._preferredStatusBarStyle = .lightContent - navigationController?.setNeedsStatusBarAppearanceUpdate() - } - - func prepareBlur() - { - if let animator = self.blurAnimator - { - animator.stopAnimation(true) - } - - self.backgroundBlurView.effect = self._backgroundBlurEffect - self.backgroundBlurView.contentView.backgroundColor = self._backgroundBlurTintColor - - self.blurAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) { [weak self] in - self?.backgroundBlurView.effect = nil - self?.backgroundBlurView.contentView.backgroundColor = .clear - } - - self.blurAnimator?.startAnimation() - self.blurAnimator?.pauseAnimation() - } - - func prepareNavigationBarAnimation() - { - self.resetNavigationBarAnimation() - - self.navigationBarAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) { [weak self] in - self?.showNavigationBar() - self?.navigationController?.navigationBar.tintColor = self?.app.tintColor - self?.navigationController?.navigationBar.barTintColor = nil - self?.contentViewController.view.layer.cornerRadius = 0 - } - - self.navigationBarAnimator?.startAnimation() - self.navigationBarAnimator?.pauseAnimation() - - self.update() - } - - func resetNavigationBarAnimation() - { - self.navigationBarAnimator?.stopAnimation(true) - self.navigationBarAnimator = nil - - self.hideNavigationBar() - - self.contentViewController.view.layer.cornerRadius = self.contentViewControllerShadowView.layer.cornerRadius - } -} - -extension AppViewController -{ - @IBAction func popViewController(_ sender: UIButton) - { - self.navigationController?.popViewController(animated: true) - } - - @IBAction func performAppAction(_ sender: PillButton) - { - if let installedApp = self.app.installedApp - { - self.open(installedApp) - } - else - { - self.downloadApp() - } - } - - func downloadApp() - { - guard self.app.installedApp == nil else { return } - - let group = AppManager.shared.install(self.app, presentingViewController: self) { (result) in - do - { - _ = try result.get() - } - catch OperationError.cancelled - { - // Ignore - } - catch - { - DispatchQueue.main.async { - let toastView = ToastView(error: error) - toastView.show(in: self) - } - } - - DispatchQueue.main.async { - self.bannerView.button.progress = nil - self.navigationBarDownloadButton.progress = nil - self.update() - } - } - - self.bannerView.button.progress = group.progress - self.navigationBarDownloadButton.progress = group.progress - } - - func open(_ installedApp: InstalledApp) - { - UIApplication.shared.open(installedApp.openAppURL) - } -} - -private extension AppViewController -{ - @objc func didChangeApp(_ notification: Notification) - { - // Async so that AppManager.installationProgress(for:) is nil when we update. - DispatchQueue.main.async { - self.update() - } - } - - @objc func willEnterForeground(_ notification: Notification) - { - guard let navigationController = self.navigationController, navigationController.topViewController == self else { return } - - self._shouldResetLayout = true - self.view.setNeedsLayout() - } - - @objc func didBecomeActive(_ notification: Notification) - { - guard let navigationController = self.navigationController, navigationController.topViewController == self else { return } - - // Fixes Navigation Bar appearing after app becomes inactive -> active again. - self._shouldResetLayout = true - self.view.setNeedsLayout() - } -} - -extension AppViewController: UIScrollViewDelegate -{ - func scrollViewDidScroll(_ scrollView: UIScrollView) - { - self.view.setNeedsLayout() - self.view.layoutIfNeeded() - } -} diff --git a/AltStore/Authentication/AuthenticationViewController.swift b/AltStore/Authentication/AuthenticationViewController.swift deleted file mode 100644 index fad4bead..00000000 --- a/AltStore/Authentication/AuthenticationViewController.swift +++ /dev/null @@ -1,171 +0,0 @@ -// -// AuthenticationViewController.swift -// AltStore -// -// Created by Riley Testut on 9/5/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -import AltSign - -final class AuthenticationViewController: UIViewController -{ - var authenticationHandler: ((String, String, @escaping (Result<(ALTAccount, ALTAppleAPISession), Error>) -> Void) -> Void)? - var completionHandler: (((ALTAccount, ALTAppleAPISession, String)?) -> Void)? - - private weak var toastView: ToastView? - - @IBOutlet private var appleIDTextField: UITextField! - @IBOutlet private var passwordTextField: UITextField! - @IBOutlet private var signInButton: UIButton! - - @IBOutlet private var appleIDBackgroundView: UIView! - @IBOutlet private var passwordBackgroundView: UIView! - - @IBOutlet private var scrollView: UIScrollView! - @IBOutlet private var contentStackView: UIStackView! - - override func viewDidLoad() - { - super.viewDidLoad() - - self.signInButton.activityIndicatorView.style = .medium - - for view in [self.appleIDBackgroundView!, self.passwordBackgroundView!, self.signInButton!] - { - view.clipsToBounds = true - view.layer.cornerRadius = 16 - } - - if UIScreen.main.isExtraCompactHeight - { - self.contentStackView.spacing = 20 - } - - NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: self.appleIDTextField) - NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: self.passwordTextField) - - self.update() - } - - override func viewDidDisappear(_ animated: Bool) - { - super.viewDidDisappear(animated) - - self.signInButton.isIndicatingActivity = false - self.toastView?.dismiss() - } -} - -private extension AuthenticationViewController -{ - func update() - { - if let _ = self.validate() - { - self.signInButton.isEnabled = true - self.signInButton.alpha = 1.0 - } - else - { - self.signInButton.isEnabled = false - self.signInButton.alpha = 0.6 - } - } - - func validate() -> (String, String)? - { - guard - let emailAddress = self.appleIDTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !emailAddress.isEmpty, - let password = self.passwordTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !password.isEmpty - else { return nil } - - return (emailAddress, password) - } -} - -private extension AuthenticationViewController -{ - @IBAction func authenticate() - { - guard let (emailAddress, password) = self.validate() else { return } - - self.appleIDTextField.resignFirstResponder() - self.passwordTextField.resignFirstResponder() - - self.signInButton.isIndicatingActivity = true - - self.authenticationHandler?(emailAddress, password) { (result) in - switch result - { - case .failure(ALTAppleAPIError.requiresTwoFactorAuthentication): - // Ignore - DispatchQueue.main.async { - self.signInButton.isIndicatingActivity = false - } - - case .failure(let error as NSError): - DispatchQueue.main.async { - let error = error.withLocalizedFailure(NSLocalizedString("Failed to Log In", comment: "")) - - let toastView = ToastView(error: error) - toastView.textLabel.textColor = .altPink - toastView.detailTextLabel.textColor = .altPink - toastView.show(in: self) - self.toastView = toastView - - self.signInButton.isIndicatingActivity = false - } - - case .success((let account, let session)): - self.completionHandler?((account, session, password)) - } - - DispatchQueue.main.async { - self.scrollView.setContentOffset(CGPoint(x: 0, y: -self.view.safeAreaInsets.top), animated: true) - } - } - } - - @IBAction func cancel(_ sender: UIBarButtonItem) - { - self.completionHandler?(nil) - } -} - -extension AuthenticationViewController: UITextFieldDelegate -{ - func textFieldShouldReturn(_ textField: UITextField) -> Bool - { - switch textField - { - case self.appleIDTextField: self.passwordTextField.becomeFirstResponder() - case self.passwordTextField: self.authenticate() - default: break - } - - self.update() - - return false - } - - func textFieldDidBeginEditing(_ textField: UITextField) - { - guard UIScreen.main.isExtraCompactHeight else { return } - - // Position all the controls within visible frame. - var contentOffset = self.scrollView.contentOffset - contentOffset.y = 44 - self.scrollView.setContentOffset(contentOffset, animated: true) - } -} - -extension AuthenticationViewController -{ - @objc func textFieldDidChangeText(_ notification: Notification) - { - self.update() - } -} diff --git a/AltStore/Authentication/InstructionsViewController.swift b/AltStore/Authentication/InstructionsViewController.swift deleted file mode 100644 index dc50eca5..00000000 --- a/AltStore/Authentication/InstructionsViewController.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// InstructionsViewController.swift -// AltStore -// -// Created by Riley Testut on 9/6/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class InstructionsViewController: UIViewController -{ - var completionHandler: (() -> Void)? - - var showsBottomButton: Bool = false - - @IBOutlet private var contentStackView: UIStackView! - @IBOutlet private var dismissButton: UIButton! - - override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent - } - - override func viewDidLoad() - { - super.viewDidLoad() - - if UIScreen.main.isExtraCompactHeight - { - self.contentStackView.layoutMargins.top = 0 - self.contentStackView.layoutMargins.bottom = self.contentStackView.layoutMargins.left - } - - self.dismissButton.clipsToBounds = true - self.dismissButton.layer.cornerRadius = 16 - - if self.showsBottomButton - { - self.navigationItem.hidesBackButton = true - } - else - { - self.dismissButton.isHidden = true - } - } -} - -private extension InstructionsViewController -{ - @IBAction func dismiss() - { - self.completionHandler?() - } -} diff --git a/AltStore/Browse/ScreenshotCollectionViewCell.swift b/AltStore/Browse/ScreenshotCollectionViewCell.swift deleted file mode 100644 index d470e39f..00000000 --- a/AltStore/Browse/ScreenshotCollectionViewCell.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// ScreenshotCollectionViewCell.swift -// AltStore -// -// Created by Riley Testut on 7/15/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -import RoxasUI - -@objc(ScreenshotCollectionViewCell) -class ScreenshotCollectionViewCell: UICollectionViewCell -{ - let imageView = UIImageView(image: nil) - - override init(frame: CGRect) - { - super.init(frame: frame) - - self.initialize() - } - - required init?(coder aDecoder: NSCoder) - { - super.init(coder: aDecoder) - - self.initialize() - } - - private func initialize() - { - self.imageView.layer.masksToBounds = true - self.addSubview(self.imageView, pinningEdgesWith: .zero) - } - - override func layoutSubviews() - { - super.layoutSubviews() - - self.imageView.layer.cornerRadius = 4 - } -} diff --git a/AltStore/Components/AppBannerView.swift b/AltStore/Components/AppBannerView.swift deleted file mode 100644 index 665be4f1..00000000 --- a/AltStore/Components/AppBannerView.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// AppBannerView.swift -// AltStore -// -// Created by Riley Testut on 8/29/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -import AltStoreCore -import RoxasUI - -class AppBannerView: RSTNibView -{ - override var accessibilityLabel: String? { - get { return self.accessibilityView?.accessibilityLabel } - set { self.accessibilityView?.accessibilityLabel = newValue } - } - - override open var accessibilityAttributedLabel: NSAttributedString? { - get { return self.accessibilityView?.accessibilityAttributedLabel } - set { self.accessibilityView?.accessibilityAttributedLabel = newValue } - } - - override var accessibilityValue: String? { - get { return self.accessibilityView?.accessibilityValue } - set { self.accessibilityView?.accessibilityValue = newValue } - } - - override open var accessibilityAttributedValue: NSAttributedString? { - get { return self.accessibilityView?.accessibilityAttributedValue } - set { self.accessibilityView?.accessibilityAttributedValue = newValue } - } - - override open var accessibilityTraits: UIAccessibilityTraits { - get { return self.accessibilityView?.accessibilityTraits ?? [] } - set { self.accessibilityView?.accessibilityTraits = newValue } - } - - private var originalTintColor: UIColor? - - @IBOutlet var titleLabel: UILabel! - @IBOutlet var subtitleLabel: UILabel! - @IBOutlet var iconImageView: AppIconImageView! - @IBOutlet var button: PillButton! - @IBOutlet var buttonLabel: UILabel! - @IBOutlet var betaBadgeView: UIView! - - @IBOutlet var backgroundEffectView: UIVisualEffectView! - - @IBOutlet private var vibrancyView: UIVisualEffectView! - @IBOutlet private var accessibilityView: UIView! - - override init(frame: CGRect) - { - super.init(frame: frame) - - self.initialize() - } - - required init?(coder: NSCoder) - { - super.init(coder: coder) - - self.initialize() - } - - private func initialize() - { - self.accessibilityView.accessibilityTraits.formUnion(.button) - - self.isAccessibilityElement = false - self.accessibilityElements = [self.accessibilityView, self.button].compactMap { $0 } - - self.betaBadgeView.isHidden = true - } - - override func tintColorDidChange() - { - super.tintColorDidChange() - - if self.tintAdjustmentMode != .dimmed - { - self.originalTintColor = self.tintColor - } - - self.update() - } -} - -extension AppBannerView -{ - func configure(for app: AppProtocol) - { - struct AppValues - { - var name: String - var developerName: String? = nil - var isBeta: Bool = false - - init(app: AppProtocol) - { - self.name = app.name - - guard let storeApp = (app as? StoreApp) ?? (app as? InstalledApp)?.storeApp else { return } - self.developerName = storeApp.developerName - - if storeApp.isBeta - { - self.name = String(format: NSLocalizedString("%@ beta", comment: ""), app.name) - self.isBeta = true - } - } - } - - let values = AppValues(app: app) - self.titleLabel.text = app.name // Don't use values.name since that already includes "beta". - self.betaBadgeView.isHidden = !values.isBeta - - if let developerName = values.developerName - { - self.subtitleLabel.text = developerName - self.accessibilityLabel = String(format: NSLocalizedString("%@ by %@", comment: ""), values.name, developerName) - } - else - { - self.subtitleLabel.text = NSLocalizedString("Sideloaded", comment: "") - self.accessibilityLabel = values.name - } - } -} - -private extension AppBannerView -{ - func update() - { - self.clipsToBounds = true - self.layer.cornerRadius = 22 - - self.subtitleLabel.textColor = self.originalTintColor ?? self.tintColor - self.backgroundEffectView.backgroundColor = self.originalTintColor ?? self.tintColor - } -} diff --git a/AltStore/Components/AppIconImageView.swift b/AltStore/Components/AppIconImageView.swift deleted file mode 100644 index ccb207d8..00000000 --- a/AltStore/Components/AppIconImageView.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// AppIconImageView.swift -// AltStore -// -// Created by Riley Testut on 5/9/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class AppIconImageView: UIImageView -{ - override func awakeFromNib() - { - super.awakeFromNib() - - self.contentMode = .scaleAspectFill - self.clipsToBounds = true - - self.backgroundColor = .white - - if #available(iOS 13, *) - { - self.layer.cornerCurve = .continuous - } - else - { - if self.layer.responds(to: Selector(("continuousCorners"))) - { - self.layer.setValue(true, forKey: "continuousCorners") - } - } - } - - override func layoutSubviews() - { - super.layoutSubviews() - - // Based off of 60pt icon having 12pt radius. - let radius = self.bounds.height / 5 - self.layer.cornerRadius = radius - } -} diff --git a/AltStore/Components/CollapsingTextView.swift b/AltStore/Components/CollapsingTextView.swift deleted file mode 100644 index be966c54..00000000 --- a/AltStore/Components/CollapsingTextView.swift +++ /dev/null @@ -1,119 +0,0 @@ -// -// CollapsingTextView.swift -// AltStore -// -// Created by Riley Testut on 7/23/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class CollapsingTextView: UITextView -{ - var isCollapsed = true { - didSet { - self.setNeedsLayout() - } - } - - var maximumNumberOfLines = 2 { - didSet { - self.setNeedsLayout() - } - } - - var lineSpacing: CGFloat = 2 { - didSet { - self.setNeedsLayout() - } - } - - let moreButton = UIButton(type: .system) - - override func awakeFromNib() - { - super.awakeFromNib() - - self.layoutManager.delegate = self - - self.textContainerInset = .zero - self.textContainer.lineFragmentPadding = 0 - self.textContainer.lineBreakMode = .byTruncatingTail - self.textContainer.heightTracksTextView = true - self.textContainer.widthTracksTextView = true - - self.moreButton.setTitle(NSLocalizedString("More", comment: ""), for: .normal) - self.moreButton.addTarget(self, action: #selector(CollapsingTextView.toggleCollapsed(_:)), for: .primaryActionTriggered) - self.addSubview(self.moreButton) - - self.setNeedsLayout() - } - - override func layoutSubviews() - { - super.layoutSubviews() - - guard let font = self.font else { return } - - let buttonFont = UIFont.systemFont(ofSize: font.pointSize, weight: .medium) - self.moreButton.titleLabel?.font = buttonFont - - let buttonY = (font.lineHeight + self.lineSpacing) * CGFloat(self.maximumNumberOfLines - 1) - let size = self.moreButton.sizeThatFits(CGSize(width: 1000, height: 1000)) - - let moreButtonFrame = CGRect(x: self.bounds.width - self.moreButton.bounds.width, - y: buttonY, - width: size.width, - height: font.lineHeight) - self.moreButton.frame = moreButtonFrame - - if self.isCollapsed - { - self.textContainer.maximumNumberOfLines = self.maximumNumberOfLines - - let boundingSize = self.attributedText.boundingRect(with: CGSize(width: self.textContainer.size.width, height: .infinity), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) - let maximumCollapsedHeight = font.lineHeight * Double(self.maximumNumberOfLines) - - if boundingSize.height.rounded() > maximumCollapsedHeight.rounded() - { - var exclusionFrame = moreButtonFrame - exclusionFrame.origin.y += self.moreButton.bounds.midY - exclusionFrame.size.width = self.bounds.width // Extra wide to make sure it wraps to next line. - self.textContainer.exclusionPaths = [UIBezierPath(rect: exclusionFrame)] - - self.moreButton.isHidden = false - } - else - { - self.textContainer.exclusionPaths = [] - - self.moreButton.isHidden = true - } - } - else - { - self.textContainer.maximumNumberOfLines = 0 - self.textContainer.exclusionPaths = [] - - self.moreButton.isHidden = true - } - - self.invalidateIntrinsicContentSize() - } -} - -private extension CollapsingTextView -{ - @objc func toggleCollapsed(_ sender: UIButton) - { - self.isCollapsed.toggle() - } -} - -extension CollapsingTextView: NSLayoutManagerDelegate -{ - func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat - { - return self.lineSpacing - } -} diff --git a/AltStore/Components/PillButton.swift b/AltStore/Components/PillButton.swift deleted file mode 100644 index 3527fe02..00000000 --- a/AltStore/Components/PillButton.swift +++ /dev/null @@ -1,192 +0,0 @@ -// -// PillButton.swift -// AltStore -// -// Created by Riley Testut on 7/15/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class PillButton: UIButton -{ - override var accessibilityValue: String? { - get { - guard self.progress != nil else { return super.accessibilityValue } - return self.progressView.accessibilityValue - } - set { super.accessibilityValue = newValue } - } - - var progress: Progress? { - didSet { - self.progressView.progress = Float(self.progress?.fractionCompleted ?? 0) - self.progressView.observedProgress = self.progress - - let isUserInteractionEnabled = self.isUserInteractionEnabled - self.isIndicatingActivity = (self.progress != nil) - self.isUserInteractionEnabled = isUserInteractionEnabled - - self.update() - } - } - - var progressTintColor: UIColor? { - get { - return self.progressView.progressTintColor - } - set { - self.progressView.progressTintColor = newValue - } - } - - var countdownDate: Date? { - didSet { - self.isEnabled = (self.countdownDate == nil) - self.displayLink.isPaused = (self.countdownDate == nil) - - if self.countdownDate == nil - { - self.setTitle(nil, for: .disabled) - } - } - } - - private let progressView = UIProgressView(progressViewStyle: .default) - - private lazy var displayLink: CADisplayLink = { - let displayLink = CADisplayLink(target: self, selector: #selector(PillButton.updateCountdown)) - displayLink.preferredFramesPerSecond = 15 - displayLink.isPaused = true - displayLink.add(to: .main, forMode: .common) - return displayLink - }() - - private let dateComponentsFormatter: DateComponentsFormatter = { - let dateComponentsFormatter = DateComponentsFormatter() - dateComponentsFormatter.zeroFormattingBehavior = [.pad] - dateComponentsFormatter.collapsesLargestUnit = false - return dateComponentsFormatter - }() - - override var intrinsicContentSize: CGSize { - var size = super.intrinsicContentSize - size.width += 26 - size.height += 3 - return size - } - - deinit - { - self.displayLink.remove(from: .main, forMode: RunLoop.Mode.default) - } - - override func awakeFromNib() - { - super.awakeFromNib() - - self.layer.masksToBounds = true - self.accessibilityTraits.formUnion([.updatesFrequently, .button]) - - self.activityIndicatorView.style = .medium - self.activityIndicatorView.isUserInteractionEnabled = false - - self.progressView.progress = 0 - self.progressView.trackImage = UIImage() - self.progressView.isUserInteractionEnabled = false - self.addSubview(self.progressView) - - self.update() - } - - override func layoutSubviews() - { - super.layoutSubviews() - - self.progressView.bounds.size.width = self.bounds.width - - let scale = self.bounds.height / self.progressView.bounds.height - - self.progressView.transform = CGAffineTransform.identity.scaledBy(x: 1, y: scale) - self.progressView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) - - self.layer.cornerRadius = self.bounds.midY - } - - override func tintColorDidChange() - { - super.tintColorDidChange() - - self.update() - } -} - -private extension PillButton -{ - func update() - { - if self.progress == nil - { - self.setTitleColor(.white, for: .normal) - self.backgroundColor = self.tintColor - } - else - { - self.setTitleColor(self.tintColor, for: .normal) - self.backgroundColor = self.tintColor.withAlphaComponent(0.15) - } - - self.progressView.progressTintColor = self.tintColor - } - - @objc func updateCountdown() - { - guard let endDate = self.countdownDate else { return } - - let startDate = Date() - - let interval = endDate.timeIntervalSince(startDate) - guard interval > 0 else { - self.isEnabled = true - return - } - - let text: String? - - if interval < (1 * 60 * 60) - { - self.dateComponentsFormatter.unitsStyle = .positional - self.dateComponentsFormatter.allowedUnits = [.minute, .second] - - text = self.dateComponentsFormatter.string(from: startDate, to: endDate) - } - else if interval < (2 * 24 * 60 * 60) - { - self.dateComponentsFormatter.unitsStyle = .positional - self.dateComponentsFormatter.allowedUnits = [.hour, .minute, .second] - - text = self.dateComponentsFormatter.string(from: startDate, to: endDate) - } - else - { - self.dateComponentsFormatter.unitsStyle = .full - self.dateComponentsFormatter.allowedUnits = [.day] - - let numberOfDays = endDate.numberOfCalendarDays(since: startDate) - text = String(format: NSLocalizedString("%@ DAYS", comment: ""), NSNumber(value: numberOfDays)) - } - - if let text = text - { - UIView.performWithoutAnimation { - self.isEnabled = false - self.setTitle(text, for: .disabled) - self.layoutIfNeeded() - } - } - else - { - self.isEnabled = true - } - } -} diff --git a/AltStore/My Apps/InstalledAppsCollectionHeaderView.swift b/AltStore/My Apps/InstalledAppsCollectionHeaderView.swift deleted file mode 100644 index 519dcfe6..00000000 --- a/AltStore/My Apps/InstalledAppsCollectionHeaderView.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// InstalledAppsCollectionHeaderView.swift -// AltStore -// -// Created by Riley Testut on 3/9/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -import UIKit - -final class InstalledAppsCollectionHeaderView: UICollectionReusableView -{ - let textLabel: UILabel - let button: UIButton - - override init(frame: CGRect) - { - self.textLabel = UILabel() - self.textLabel.translatesAutoresizingMaskIntoConstraints = false - self.textLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) - self.textLabel.accessibilityTraits.insert(.header) - - self.button = UIButton(type: .system) - self.button.translatesAutoresizingMaskIntoConstraints = false - self.button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium) - - super.init(frame: frame) - - self.addSubview(self.textLabel) - self.addSubview(self.button) - - NSLayoutConstraint.activate([self.textLabel.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor), - self.textLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor)]) - - NSLayoutConstraint.activate([self.button.trailingAnchor.constraint(equalTo: self.layoutMarginsGuide.trailingAnchor), - self.button.firstBaselineAnchor.constraint(equalTo: self.textLabel.firstBaselineAnchor)]) - - self.preservesSuperviewLayoutMargins = true - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/AltStore/My Apps/UpdateCollectionViewCell.swift b/AltStore/My Apps/UpdateCollectionViewCell.swift deleted file mode 100644 index b9c92791..00000000 --- a/AltStore/My Apps/UpdateCollectionViewCell.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// UpdateCollectionViewCell.swift -// AltStore -// -// Created by Riley Testut on 7/16/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -extension UpdateCollectionViewCell -{ - enum Mode - { - case collapsed - case expanded - } -} - -@objc final class UpdateCollectionViewCell: UICollectionViewCell -{ - var mode: Mode = .expanded { - didSet { - self.update() - } - } - - @IBOutlet var bannerView: AppBannerView! - @IBOutlet var versionDescriptionTitleLabel: UILabel! - @IBOutlet var versionDescriptionTextView: CollapsingTextView! - - @IBOutlet private var blurView: UIVisualEffectView! - - private var originalTintColor: UIColor? - - override func awakeFromNib() - { - super.awakeFromNib() - - // Prevent temporary unsatisfiable constraint errors due to UIView-Encapsulated-Layout constraints. - self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.contentView.preservesSuperviewLayoutMargins = true - - self.bannerView.backgroundEffectView.isHidden = true - self.bannerView.button.setTitle(NSLocalizedString("UPDATE", comment: ""), for: .normal) - - self.blurView.layer.cornerRadius = 20 - self.blurView.layer.masksToBounds = true - - self.update() - } - - override func tintColorDidChange() - { - super.tintColorDidChange() - - if self.tintAdjustmentMode != .dimmed - { - self.originalTintColor = self.tintColor - } - - self.update() - } - - override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) - { - // Animates transition to new attributes. - let animator = UIViewPropertyAnimator(springTimingParameters: UISpringTimingParameters()) { - self.layoutIfNeeded() - } - animator.startAnimation() - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? - { - let view = super.hitTest(point, with: event) - - if view == self.versionDescriptionTextView - { - // Forward touches on the text view (but not on the nested "more" button) - // so cell selection works as expected. - return self - } - else - { - return view - } - } -} - -private extension UpdateCollectionViewCell -{ - func update() - { - switch self.mode - { - case .collapsed: self.versionDescriptionTextView.isCollapsed = true - case .expanded: self.versionDescriptionTextView.isCollapsed = false - } - - self.versionDescriptionTitleLabel.textColor = self.originalTintColor ?? self.tintColor - self.blurView.backgroundColor = self.originalTintColor ?? self.tintColor - self.bannerView.button.progressTintColor = self.originalTintColor ?? self.tintColor - - self.setNeedsLayout() - self.layoutIfNeeded() - } -} diff --git a/AltStore/News/NewsCollectionViewCell.swift b/AltStore/News/NewsCollectionViewCell.swift deleted file mode 100644 index 3fae6638..00000000 --- a/AltStore/News/NewsCollectionViewCell.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// NewsCollectionViewCell.swift -// AltStore -// -// Created by Riley Testut on 8/29/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class NewsCollectionViewCell: UICollectionViewCell -{ - @IBOutlet var titleLabel: UILabel! - @IBOutlet var captionLabel: UILabel! - @IBOutlet var imageView: UIImageView! - @IBOutlet var contentBackgroundView: UIView! - - override func awakeFromNib() - { - super.awakeFromNib() - - self.contentView.preservesSuperviewLayoutMargins = true - - self.contentBackgroundView.layer.cornerRadius = 30 - self.contentBackgroundView.clipsToBounds = true - - self.imageView.layer.cornerRadius = 30 - self.imageView.clipsToBounds = true - } -} diff --git a/AltStore/Operations/Operation.swift b/AltStore/Operations/Operation.swift deleted file mode 100644 index a6ba1cf4..00000000 --- a/AltStore/Operations/Operation.swift +++ /dev/null @@ -1,93 +0,0 @@ -// -// Operation.swift -// AltStore -// -// Created by Riley Testut on 6/7/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import Foundation -import RoxasUI - -class ResultOperation: Operation -{ - var resultHandler: ((Result) -> Void)? - - @available(*, unavailable) - override func finish() - { - super.finish() - } - - func finish(_ result: Result) - { - guard !self.isFinished else { return } - - if self.isCancelled - { - self.resultHandler?(.failure(OperationError.cancelled)) - } - else - { - self.resultHandler?(result) - } - - super.finish() - } -} - -class Operation: RSTOperation, ProgressReporting -{ - let progress = Progress.discreteProgress(totalUnitCount: 1) - - private var backgroundTaskID: UIBackgroundTaskIdentifier? - - override var isAsynchronous: Bool { - return true - } - - override init() - { - super.init() - - self.progress.cancellationHandler = { [weak self] in self?.cancel() } - } - - override func cancel() - { - super.cancel() - - if !self.progress.isCancelled - { - self.progress.cancel() - } - } - - override func main() - { - super.main() - - let name = "com.altstore." + NSStringFromClass(type(of: self)) - self.backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: name) { [weak self] in - guard let backgroundTask = self?.backgroundTaskID else { return } - - self?.cancel() - - UIApplication.shared.endBackgroundTask(backgroundTask) - self?.backgroundTaskID = .invalid - } - } - - override func finish() - { - guard !self.isFinished else { return } - - super.finish() - - if let backgroundTaskID = self.backgroundTaskID - { - UIApplication.shared.endBackgroundTask(backgroundTaskID) - self.backgroundTaskID = .invalid - } - } -} diff --git a/AltStore/Operations/Patch App/PatchViewController.swift b/AltStore/Operations/Patch App/PatchViewController.swift deleted file mode 100644 index 2349fe94..00000000 --- a/AltStore/Operations/Patch App/PatchViewController.swift +++ /dev/null @@ -1,499 +0,0 @@ -// -// PatchViewController.swift -// AltStore -// -// Created by Riley Testut on 10/20/21. -// Copyright © 2021 Riley Testut. All rights reserved. -// - -import UIKit -import Combine - -import AltStoreCore -import AltSign -import RoxasUI - -@available(iOS 14.0, *) -extension PatchViewController -{ - enum Step - { - case confirm - case install - case openApp - case patchApp - case reboot - case refresh - case finish - } -} - -@available(iOS 14.0, *) -final class PatchViewController: UIViewController -{ - var patchApp: AnyApp? - var installedApp: InstalledApp? - - var completionHandler: ((Result) -> Void)? - - private let context = AuthenticatedOperationContext() - - private var currentStep: Step = .confirm { - didSet { - DispatchQueue.main.async { - self.update() - } - } - } - - private var buttonHandler: (() -> Void)? - private var resignedApp: ALTApplication? - - private lazy var temporaryDirectory: URL = FileManager.default.uniqueTemporaryURL() - - private var didEnterBackgroundObservation: NSObjectProtocol? - private weak var cancellableProgress: Progress? - - @IBOutlet private var placeholderView: RSTPlaceholderView! - @IBOutlet private var taskDescriptionLabel: UILabel! - @IBOutlet private var pillButton: PillButton! - @IBOutlet private var cancelBarButtonItem: UIBarButtonItem! - @IBOutlet private var cancelButton: UIButton! - - override func viewDidLoad() - { - super.viewDidLoad() - - self.isModalInPresentation = true - - self.placeholderView.stackView.spacing = 20 - self.placeholderView.textLabel.textColor = .white - - self.placeholderView.detailTextLabel.textAlignment = .left - self.placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6) - - self.buttonHandler = { [weak self] in - self?.startProcess() - } - - do - { - try FileManager.default.createDirectory(at: self.temporaryDirectory, withIntermediateDirectories: true, attributes: nil) - } - catch - { - print("Failed to create temporary directory:", error) - } - - self.update() - } - - override func viewWillAppear(_ animated: Bool) - { - super.viewWillAppear(animated) - - if self.installedApp != nil - { - self.refreshApp() - } - } -} - -@available(iOS 14.0, *) -private extension PatchViewController -{ - func update() - { - self.cancelButton.alpha = 0.0 - - switch self.currentStep - { - case .confirm: - guard let app = self.patchApp else { break } - - if UIDevice.current.isUntetheredJailbreakRequired - { - self.placeholderView.textLabel.text = NSLocalizedString("Jailbreak Requires Untethering", comment: "") - self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak is untethered, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name) - } - else - { - self.placeholderView.textLabel.text = NSLocalizedString("Jailbreak Supports Untethering", comment: "") - self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak has an untethered version, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name) - } - - self.pillButton.setTitle(NSLocalizedString("Install Untethered Jailbreak", comment: ""), for: .normal) - - self.cancelButton.alpha = 1.0 - - case .install: - guard let app = self.patchApp else { break } - - self.placeholderView.textLabel.text = String(format: NSLocalizedString("Installing %@ placeholder…", comment: ""), app.name) - self.placeholderView.detailTextLabel.text = NSLocalizedString("A placeholder app needs to be installed in order to prepare your device for untethering.\n\nThis may take a few moments.", comment: "") - - case .openApp: - self.placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "") - self.placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "") - - self.pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal) - - case .patchApp: - guard let app = self.patchApp else { break } - - self.placeholderView.textLabel.text = String(format: NSLocalizedString("Patching %@ placeholder…", comment: ""), app.name) - self.placeholderView.detailTextLabel.text = NSLocalizedString("This will take a few moments. Please do not turn off the screen or leave the app until patching is complete.", comment: "") - - self.pillButton.setTitle(NSLocalizedString("Patch Placeholder", comment: ""), for: .normal) - - case .reboot: - self.placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "") - self.placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "") - - self.pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal) - - case .refresh: - guard let installedApp = self.installedApp else { break } - - self.placeholderView.textLabel.text = String(format: NSLocalizedString("Finish installing %@?", comment: ""), installedApp.name) - self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("In order to finish jailbreaking this device, you need to install %@ then follow the instructions in the app.", comment: ""), installedApp.name) - - self.pillButton.setTitle(String(format: NSLocalizedString("Install %@", comment: ""), installedApp.name), for: .normal) - - case .finish: - guard let installedApp = self.installedApp else { break } - - self.placeholderView.textLabel.text = String(format: NSLocalizedString("Finish in %@", comment: ""), installedApp.name) - self.placeholderView.detailTextLabel.text = String(format: NSLocalizedString("Follow the instructions in %@ to finish jailbreaking this device.", comment: ""), installedApp.name) - - self.pillButton.setTitle(String(format: NSLocalizedString("Open %@", comment: ""), installedApp.name), for: .normal) - } - } - - func present(_ error: Error, title: String) - { - DispatchQueue.main.async { - let nsError = error as NSError - - let alertController = UIAlertController(title: nsError.localizedFailure ?? title, message: error.localizedDescription, preferredStyle: .alert) - alertController.addAction(.ok) - self.present(alertController, animated: true, completion: nil) - - self.setProgress(nil, description: nil) - } - } - - func setProgress(_ progress: Progress?, description: String?) - { - DispatchQueue.main.async { - self.pillButton.progress = progress - self.taskDescriptionLabel.text = description ?? " " // Use non-empty string to prevent label resizing itself. - } - } - - func finish(with result: Result) - { - do - { - try FileManager.default.removeItem(at: self.temporaryDirectory) - } - catch - { - print("Failed to remove temporary directory:", error) - } - - if let observation = self.didEnterBackgroundObservation - { - NotificationCenter.default.removeObserver(observation) - } - - self.completionHandler?(result) - self.completionHandler = nil - } -} - -@available(iOS 14.0, *) -private extension PatchViewController -{ - @IBAction func performButtonAction() - { - self.buttonHandler?() - } - - @IBAction func cancel() - { - self.finish(with: .success(())) - - self.cancellableProgress?.cancel() - } - - @IBAction func installRegularJailbreak() - { - guard let app = self.patchApp else { return } - - let title: String - let message: String - - if UIDevice.current.isUntetheredJailbreakRequired - { - title = NSLocalizedString("Untethering Required", comment: "") - message = String(format: NSLocalizedString("%@ can not jailbreak this device unless you untether it first. Are you sure you want to install without untethering?", comment: ""), app.name) - } - else - { - title = NSLocalizedString("Untethering Recommended", comment: "") - message = String(format: NSLocalizedString("Untethering this jailbreak will prevent %@ from expiring, even after 7 days or rebooting the device. Are you sure you want to install without untethering?", comment: ""), app.name) - } - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Install Without Untethering", comment: ""), style: .default) { _ in - self.finish(with: .failure(OperationError.cancelled)) - }) - alertController.addAction(.cancel) - self.present(alertController, animated: true, completion: nil) - } -} - -@available(iOS 14.0, *) -private extension PatchViewController -{ - func startProcess() - { - guard let patchApp = self.patchApp else { return } - - self.currentStep = .install - - if let progress = AppManager.shared.installationProgress(for: patchApp) - { - // Cancel pending jailbreak app installation so we can start a new one. - progress.cancel() - } - - let appURL = InstalledApp.fileURL(for: patchApp) - let cachedAppURL = self.temporaryDirectory.appendingPathComponent("Cached.app") - - do - { - // Make copy of original app, so we can replace the cached patch app with it later. - try FileManager.default.copyItem(at: appURL, to: cachedAppURL, shouldReplace: true) - } - catch - { - self.present(error, title: NSLocalizedString("Could not back up jailbreak app.", comment: "")) - return - } - - var unzippingError: Error? - let refreshGroup = AppManager.shared.install(patchApp, presentingViewController: self, context: self.context) { result in - do - { - _ = try result.get() - - if let unzippingError = unzippingError - { - throw unzippingError - } - - // Replace cached patch app with original app so we can resume installing it post-reboot. - try FileManager.default.copyItem(at: cachedAppURL, to: appURL, shouldReplace: true) - - self.openApp() - } - catch - { - self.present(error, title: String(format: NSLocalizedString("Could not install %@ placeholder.", comment: ""), patchApp.name)) - } - } - refreshGroup.beginInstallationHandler = { (installedApp) in - do - { - // Replace patch app name with correct name. - installedApp.name = patchApp.name - - let ipaURL = installedApp.refreshedIPAURL - let resignedAppURL = try FileManager.default.unzipAppBundle(at: ipaURL, toDirectory: self.temporaryDirectory) - - self.resignedApp = ALTApplication(fileURL: resignedAppURL) - } - catch - { - print("Error unzipping app bundle:", error) - unzippingError = error - } - } - self.setProgress(refreshGroup.progress, description: nil) - - self.cancellableProgress = refreshGroup.progress - } - - func openApp() - { - guard let patchApp = self.patchApp else { return } - - self.setProgress(nil, description: nil) - self.currentStep = .openApp - - // This observation is willEnterForeground because patching starts immediately upon return. - self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { (notification) in - self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } - self.patchApplication() - } - - self.buttonHandler = { [weak self] in - guard let self = self else { return } - - #if !targetEnvironment(simulator) - - let openURL = InstalledApp.openAppURL(for: patchApp) - UIApplication.shared.open(openURL) { success in - guard !success else { return } - self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name)) - } - - #endif - } - } - - func patchApplication() - { - guard let resignedApp = self.resignedApp else { return } - - self.currentStep = .patchApp - - self.buttonHandler = { [weak self] in - self?.patchApplication() - } - - let patchAppOperation = AppManager.shared.patch(resignedApp: resignedApp, presentingViewController: self, context: self.context) { result in - switch result - { - case .failure(let error): self.present(error, title: String(format: NSLocalizedString("Could not patch %@ placeholder.", comment: ""), resignedApp.name)) - case .success: self.rebootDevice() - } - } - patchAppOperation.progressHandler = { (progress, description) in - self.setProgress(progress, description: description) - } - self.cancellableProgress = patchAppOperation.progress - } - - func rebootDevice() - { - guard let patchApp = self.patchApp else { return } - - self.setProgress(nil, description: nil) - self.currentStep = .reboot - - self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { (notification) in - self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } - - var patchedApps = UserDefaults.standard.patchedApps ?? [] - if !patchedApps.contains(patchApp.bundleIdentifier) - { - patchedApps.append(patchApp.bundleIdentifier) - UserDefaults.standard.patchedApps = patchedApps - } - - self.finish(with: .success(())) - } - - self.buttonHandler = { [weak self] in - guard let self = self else { return } - - #if !targetEnvironment(simulator) - - let openURL = InstalledApp.openAppURL(for: patchApp) - UIApplication.shared.open(openURL) { success in - guard !success else { return } - self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name)) - } - - #endif - } - } - - func refreshApp() - { - guard let installedApp = self.installedApp else { return } - - self.currentStep = .refresh - - self.buttonHandler = { [weak self] in - guard let self = self else { return } - DatabaseManager.shared.persistentContainer.performBackgroundTask { context in - let tempApp = context.object(with: installedApp.objectID) as! InstalledApp - tempApp.needsResign = true - - let errorTitle = String(format: NSLocalizedString("Could not install %@.", comment: ""), tempApp.name) - - do - { - try context.save() - - installedApp.managedObjectContext?.perform { - // Refreshing ensures we don't attempt to patch the app again, - // since that is only checked when installing a new app. - let refreshGroup = AppManager.shared.refresh([installedApp], presentingViewController: self, group: nil) - refreshGroup.completionHandler = { [weak refreshGroup, weak self] (results) in - guard let self = self else { return } - - do - { - guard let (bundleIdentifier, result) = results.first else { throw refreshGroup?.context.error ?? OperationError.unknown } - _ = try result.get() - - if var patchedApps = UserDefaults.standard.patchedApps, let index = patchedApps.firstIndex(of: bundleIdentifier) - { - patchedApps.remove(at: index) - UserDefaults.standard.patchedApps = patchedApps - } - - self.finish() - } - catch - { - self.present(error, title: errorTitle) - } - } - self.setProgress(refreshGroup.progress, description: String(format: NSLocalizedString("Installing %@...", comment: ""), installedApp.name)) - } - } - catch - { - self.present(error, title: errorTitle) - } - } - } - } - - func finish() - { - guard let installedApp = self.installedApp else { return } - - self.setProgress(nil, description: nil) - self.currentStep = .finish - - self.didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { (notification) in - self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } - self.finish(with: .success(())) - } - - installedApp.managedObjectContext?.perform { - let appName = installedApp.name - let openURL = installedApp.openAppURL - - self.buttonHandler = { [weak self] in - guard let self = self else { return } - - #if !targetEnvironment(simulator) - - UIApplication.shared.open(openURL) { success in - guard !success else { return } - self.present(OperationError.openAppFailed(name: appName), title: String(format: NSLocalizedString("Could not open %@.", comment: ""), appName)) - } - - #endif - } - } - } -} diff --git a/AltStore/Settings/InsetGroupTableViewCell.swift b/AltStore/Settings/InsetGroupTableViewCell.swift deleted file mode 100644 index 47a4e887..00000000 --- a/AltStore/Settings/InsetGroupTableViewCell.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// InsetGroupTableViewCell.swift -// AltStore -// -// Created by Riley Testut on 8/31/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -extension InsetGroupTableViewCell -{ - @objc enum Style: Int - { - case single - case top - case middle - case bottom - } -} - -final class InsetGroupTableViewCell: UITableViewCell -{ -#if !TARGET_INTERFACE_BUILDER - @IBInspectable var style: Style = .single { - didSet { - self.update() - } - } -#else - @IBInspectable var style: Int = 0 -#endif - - @IBInspectable var isSelectable: Bool = false - - private let separatorView = UIView() - private let insetView = UIView() - - override func awakeFromNib() - { - super.awakeFromNib() - - self.selectionStyle = .none - - self.separatorView.translatesAutoresizingMaskIntoConstraints = false - self.separatorView.backgroundColor = UIColor.white.withAlphaComponent(0.25) - self.addSubview(self.separatorView) - - self.insetView.layer.masksToBounds = true - self.insetView.layer.cornerRadius = 16 - - // Get the preferred background color from Interface Builder. - self.insetView.backgroundColor = self.backgroundColor - self.backgroundColor = nil - - self.addSubview(self.insetView, pinningEdgesWith: UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)) - self.sendSubviewToBack(self.insetView) - - NSLayoutConstraint.activate([self.separatorView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 30), - self.separatorView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -30), - self.separatorView.bottomAnchor.constraint(equalTo: self.bottomAnchor), - self.separatorView.heightAnchor.constraint(equalToConstant: 1)]) - - self.update() - } - - override func setSelected(_ selected: Bool, animated: Bool) - { - super.setSelected(selected, animated: animated) - - if animated - { - UIView.animate(withDuration: 0.4) { - self.update() - } - } - else - { - self.update() - } - } - - override func setHighlighted(_ highlighted: Bool, animated: Bool) - { - super.setHighlighted(highlighted, animated: animated) - - if animated - { - UIView.animate(withDuration: 0.4) { - self.update() - } - } - else - { - self.update() - } - } -} - -private extension InsetGroupTableViewCell -{ - func update() - { - switch self.style - { - case .single: - self.insetView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner] - self.separatorView.isHidden = true - - case .top: - self.insetView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] - self.separatorView.isHidden = false - - case .middle: - self.insetView.layer.maskedCorners = [] - self.separatorView.isHidden = false - - case .bottom: - self.insetView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] - self.separatorView.isHidden = true - } - - if self.isSelectable && (self.isHighlighted || self.isSelected) - { - self.insetView.backgroundColor = UIColor.white.withAlphaComponent(0.55) - } - else - { - self.insetView.backgroundColor = UIColor.white.withAlphaComponent(0.25) - } - } -} diff --git a/AltStore/Settings/LicensesViewController.swift b/AltStore/Settings/LicensesViewController.swift deleted file mode 100644 index d6ffc6ff..00000000 --- a/AltStore/Settings/LicensesViewController.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// LicensesViewController.swift -// AltStore -// -// Created by Riley Testut on 9/6/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class LicensesViewController: UIViewController -{ - private var _didAppear = false - - @IBOutlet private var textView: UITextView! - - override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent - } - - override func viewWillAppear(_ animated: Bool) - { - super.viewWillAppear(animated) - - self.view.setNeedsLayout() - self.view.layoutIfNeeded() - - // Fix incorrect initial offset on iPhone SE. - self.textView.contentOffset.y = 0 - } - - override func viewDidAppear(_ animated: Bool) - { - super.viewDidAppear(animated) - - _didAppear = true - } - - override func viewDidLayoutSubviews() - { - super.viewDidLayoutSubviews() - - self.textView.textContainerInset.left = self.view.layoutMargins.left - self.textView.textContainerInset.right = self.view.layoutMargins.right - self.textView.textContainer.lineFragmentPadding = 0 - - if !_didAppear - { - // Fix incorrect initial offset on iPhone SE. - self.textView.contentOffset.y = 0 - } - } -} diff --git a/AltStore/Settings/PatreonComponents.swift b/AltStore/Settings/PatreonComponents.swift deleted file mode 100644 index 4f2ec8ea..00000000 --- a/AltStore/Settings/PatreonComponents.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// PatreonComponents.swift -// AltStore -// -// Created by Riley Testut on 9/5/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -final class PatronCollectionViewCell: UICollectionViewCell -{ - @IBOutlet var textLabel: UILabel! -} - -final class PatronsHeaderView: UICollectionReusableView -{ - let textLabel = UILabel() - - override init(frame: CGRect) - { - super.init(frame: frame) - - self.textLabel.font = UIFont.boldSystemFont(ofSize: 17) - self.textLabel.textColor = .white - self.addSubview(self.textLabel, pinningEdgesWith: UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -final class PatronsFooterView: UICollectionReusableView -{ - let button = UIButton(type: .system) - - override init(frame: CGRect) - { - super.init(frame: frame) - - self.button.translatesAutoresizingMaskIntoConstraints = false - self.button.activityIndicatorView.style = .medium - self.button.titleLabel?.textColor = .white - self.addSubview(self.button) - - NSLayoutConstraint.activate([self.button.centerXAnchor.constraint(equalTo: self.centerXAnchor), - self.button.centerYAnchor.constraint(equalTo: self.centerYAnchor)]) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -final class AboutPatreonHeaderView: UICollectionReusableView -{ - @IBOutlet var supportButton: UIButton! - @IBOutlet var accountButton: UIButton! - @IBOutlet var textView: UITextView! - - @IBOutlet private var rileyLabel: UILabel! - @IBOutlet private var shaneLabel: UILabel! - - @IBOutlet private var rileyImageView: UIImageView! - @IBOutlet private var shaneImageView: UIImageView! - - override func awakeFromNib() - { - super.awakeFromNib() - - self.textView.clipsToBounds = true - self.textView.layer.cornerRadius = 20 - self.textView.textContainer.lineFragmentPadding = 0 - - for imageView in [self.rileyImageView, self.shaneImageView].compactMap({ $0 }) - { - imageView.clipsToBounds = true - imageView.layer.cornerRadius = imageView.bounds.midY - } - - for button in [self.supportButton, self.accountButton].compactMap({ $0 }) - { - button.clipsToBounds = true - button.layer.cornerRadius = 16 - } - } - - override func layoutMarginsDidChange() - { - super.layoutMarginsDidChange() - - self.textView.textContainerInset = UIEdgeInsets(top: self.layoutMargins.left, left: self.layoutMargins.left, bottom: self.layoutMargins.right, right: self.layoutMargins.right) - } -} - diff --git a/AltStore/Settings/SettingsHeaderFooterView.swift b/AltStore/Settings/SettingsHeaderFooterView.swift deleted file mode 100644 index 8dbb179e..00000000 --- a/AltStore/Settings/SettingsHeaderFooterView.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// SettingsHeaderFooterView.swift -// AltStore -// -// Created by Riley Testut on 8/31/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import UIKit - -import RoxasUI - -final class SettingsHeaderFooterView: UITableViewHeaderFooterView -{ - @IBOutlet var primaryLabel: UILabel! - @IBOutlet var secondaryLabel: UILabel! - @IBOutlet var button: UIButton! - - @IBOutlet private var stackView: UIStackView! - - override func awakeFromNib() - { - super.awakeFromNib() - - self.contentView.layoutMargins = .zero - self.contentView.preservesSuperviewLayoutMargins = true - - self.stackView.translatesAutoresizingMaskIntoConstraints = false - self.contentView.addSubview(self.stackView) - - NSLayoutConstraint.activate([self.stackView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor), - self.stackView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor), - self.stackView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor), - self.stackView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor)]) - } -} diff --git a/AltStoreCore/AltStoreCore.h b/AltStoreCore/AltStoreCore.h deleted file mode 100644 index b9a1f388..00000000 --- a/AltStoreCore/AltStoreCore.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// AltStoreCore.h -// AltStoreCore -// -// Created by Riley Testut on 9/3/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -#import - -//! Project version number for AltStoreCore. -FOUNDATION_EXPORT double AltStoreCoreVersionNumber; - -//! Project version string for AltStoreCore. -FOUNDATION_EXPORT const unsigned char AltStoreCoreVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - -#import -#import -#import - -// Shared -#import -#import diff --git a/AltStoreCore/Model/InstalledExtension.swift b/AltStoreCore/Model/InstalledExtension.swift deleted file mode 100644 index 8ed8736c..00000000 --- a/AltStoreCore/Model/InstalledExtension.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// InstalledExtension.swift -// AltStore -// -// Created by Riley Testut on 1/7/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -import Foundation -import CoreData - -import AltSign - -@objc(InstalledExtension) -public class InstalledExtension: NSManagedObject, InstalledAppProtocol -{ - /* Properties */ - @NSManaged public var name: String - @NSManaged public var bundleIdentifier: String - @NSManaged public var resignedBundleIdentifier: String - @NSManaged public var version: String - - @NSManaged public var refreshedDate: Date - @NSManaged public var expirationDate: Date - @NSManaged public var installedDate: Date - - /* Relationships */ - @NSManaged public var parentApp: InstalledApp? - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { - super.init(entity: entity, insertInto: context) - } - - public init(resignedAppExtension: ALTApplication, originalBundleIdentifier: String, context: NSManagedObjectContext) - { - super.init(entity: InstalledExtension.entity(), insertInto: context) - - self.bundleIdentifier = originalBundleIdentifier - - self.refreshedDate = Date() - self.installedDate = Date() - - self.expirationDate = self.refreshedDate.addingTimeInterval(60 * 60 * 24 * 7) // Rough estimate until we get real values from provisioning profile. - - self.update(resignedAppExtension: resignedAppExtension) - } - - public func update(resignedAppExtension: ALTApplication) - { - self.name = resignedAppExtension.name - - self.resignedBundleIdentifier = resignedAppExtension.bundleIdentifier - self.version = resignedAppExtension.version - - if let provisioningProfile = resignedAppExtension.provisioningProfile - { - self.update(provisioningProfile: provisioningProfile) - } - } - - public func update(provisioningProfile: ALTProvisioningProfile) - { - self.refreshedDate = provisioningProfile.creationDate - self.expirationDate = provisioningProfile.expirationDate - } -} - -public extension InstalledExtension -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "InstalledExtension") - } -} diff --git a/AltStoreCore/Patreon/Benefit.swift b/AltStoreCore/Patreon/Benefit.swift deleted file mode 100644 index 63a29e9a..00000000 --- a/AltStoreCore/Patreon/Benefit.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Benefit.swift -// AltStore -// -// Created by Riley Testut on 8/21/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import Foundation - -extension PatreonAPI -{ - struct BenefitResponse: Decodable - { - var id: String - } -} - -public struct Benefit: Hashable -{ - public var type: ALTPatreonBenefitType - - init(response: PatreonAPI.BenefitResponse) - { - self.type = ALTPatreonBenefitType(response.id) - } -} diff --git a/AltStoreCore/Patreon/Tier.swift b/AltStoreCore/Patreon/Tier.swift deleted file mode 100644 index 0bf0dc88..00000000 --- a/AltStoreCore/Patreon/Tier.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Tier.swift -// AltStore -// -// Created by Riley Testut on 8/21/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -import Foundation - -extension PatreonAPI -{ - struct TierResponse: Decodable - { - struct Attributes: Decodable - { - var title: String - } - - struct Relationships: Decodable - { - struct Benefits: Decodable - { - var data: [BenefitResponse] - } - - var benefits: Benefits - } - - var id: String - var attributes: Attributes - - var relationships: Relationships - } -} - -public struct Tier -{ - public var name: String - public var identifier: String - - public var benefits: [Benefit] = [] - - init(response: PatreonAPI.TierResponse) - { - self.name = response.attributes.title - self.identifier = response.id - self.benefits = response.relationships.benefits.data.map(Benefit.init(response:)) - } -} diff --git a/AltStoreCore/Types/ALTAppPermission.h b/AltStoreCore/Types/ALTAppPermission.h deleted file mode 100644 index d84e616c..00000000 --- a/AltStoreCore/Types/ALTAppPermission.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// ALTAppPermission.h -// AltStore -// -// Created by Riley Testut on 7/23/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import - -typedef NSString *ALTAppPermissionType NS_TYPED_EXTENSIBLE_ENUM; -extern ALTAppPermissionType const ALTAppPermissionTypePhotos; -extern ALTAppPermissionType const ALTAppPermissionTypeCamera; -extern ALTAppPermissionType const ALTAppPermissionTypeLocation; -extern ALTAppPermissionType const ALTAppPermissionTypeContacts; -extern ALTAppPermissionType const ALTAppPermissionTypeReminders; -extern ALTAppPermissionType const ALTAppPermissionTypeAppleMusic; -extern ALTAppPermissionType const ALTAppPermissionTypeMicrophone; -extern ALTAppPermissionType const ALTAppPermissionTypeSpeechRecognition; -extern ALTAppPermissionType const ALTAppPermissionTypeBackgroundAudio; -extern ALTAppPermissionType const ALTAppPermissionTypeBackgroundFetch; -extern ALTAppPermissionType const ALTAppPermissionTypeBluetooth; -extern ALTAppPermissionType const ALTAppPermissionTypeNetwork; -extern ALTAppPermissionType const ALTAppPermissionTypeCalendars; -extern ALTAppPermissionType const ALTAppPermissionTypeTouchID; -extern ALTAppPermissionType const ALTAppPermissionTypeFaceID; -extern ALTAppPermissionType const ALTAppPermissionTypeSiri; -extern ALTAppPermissionType const ALTAppPermissionTypeMotion; diff --git a/AltStoreCore/Types/ALTAppPermission.m b/AltStoreCore/Types/ALTAppPermission.m deleted file mode 100644 index a67e536d..00000000 --- a/AltStoreCore/Types/ALTAppPermission.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// ALTAppPermission.m -// AltStore -// -// Created by Riley Testut on 7/23/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import "ALTAppPermission.h" - -ALTAppPermissionType const ALTAppPermissionTypePhotos = @"photos"; -ALTAppPermissionType const ALTAppPermissionTypeCamera = @"camera"; -ALTAppPermissionType const ALTAppPermissionTypeLocation = @"location"; -ALTAppPermissionType const ALTAppPermissionTypeContacts = @"contacts"; -ALTAppPermissionType const ALTAppPermissionTypeReminders = @"reminders"; -ALTAppPermissionType const ALTAppPermissionTypeAppleMusic = @"music"; -ALTAppPermissionType const ALTAppPermissionTypeMicrophone = @"microphone"; -ALTAppPermissionType const ALTAppPermissionTypeSpeechRecognition = @"speech-recognition"; -ALTAppPermissionType const ALTAppPermissionTypeBackgroundAudio = @"background-audio"; -ALTAppPermissionType const ALTAppPermissionTypeBackgroundFetch = @"background-fetch"; -ALTAppPermissionType const ALTAppPermissionTypeBluetooth = @"bluetooth"; -ALTAppPermissionType const ALTAppPermissionTypeNetwork = @"network"; -ALTAppPermissionType const ALTAppPermissionTypeCalendars = @"calendars"; -ALTAppPermissionType const ALTAppPermissionTypeTouchID = @"touchid"; -ALTAppPermissionType const ALTAppPermissionTypeFaceID = @"faceid"; -ALTAppPermissionType const ALTAppPermissionTypeSiri = @"siri"; -ALTAppPermissionType const ALTAppPermissionTypeMotion = @"motion"; diff --git a/AltStoreCore/Types/ALTPatreonBenefitType.h b/AltStoreCore/Types/ALTPatreonBenefitType.h deleted file mode 100644 index 83ad9b66..00000000 --- a/AltStoreCore/Types/ALTPatreonBenefitType.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// ALTPatreonBenefitType.h -// AltStore -// -// Created by Riley Testut on 8/27/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import - -typedef NSString *ALTPatreonBenefitType NS_TYPED_EXTENSIBLE_ENUM; -extern ALTPatreonBenefitType const ALTPatreonBenefitTypeBetaAccess; -extern ALTPatreonBenefitType const ALTPatreonBenefitTypeCredits; diff --git a/AltStoreCore/Types/ALTPatreonBenefitType.m b/AltStoreCore/Types/ALTPatreonBenefitType.m deleted file mode 100644 index 7f6bf5af..00000000 --- a/AltStoreCore/Types/ALTPatreonBenefitType.m +++ /dev/null @@ -1,12 +0,0 @@ -// -// ALTPatreonBenefitType.m -// AltStore -// -// Created by Riley Testut on 8/27/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import "ALTPatreonBenefitType.h" - -ALTPatreonBenefitType const ALTPatreonBenefitTypeBetaAccess = @"1186336"; -ALTPatreonBenefitType const ALTPatreonBenefitTypeCredits = @"1186340"; diff --git a/AltStoreCore/Types/ALTSourceUserInfoKey.h b/AltStoreCore/Types/ALTSourceUserInfoKey.h deleted file mode 100644 index f18a0365..00000000 --- a/AltStoreCore/Types/ALTSourceUserInfoKey.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// ALTSourceUserInfoKey.h -// AltStore -// -// Created by Riley Testut on 11/4/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import - -typedef NSString *ALTSourceUserInfoKey NS_TYPED_EXTENSIBLE_ENUM; -extern ALTSourceUserInfoKey const ALTSourceUserInfoKeyPatreonAccessToken; diff --git a/AltStoreCore/Types/ALTSourceUserInfoKey.m b/AltStoreCore/Types/ALTSourceUserInfoKey.m deleted file mode 100644 index 4d715cdc..00000000 --- a/AltStoreCore/Types/ALTSourceUserInfoKey.m +++ /dev/null @@ -1,11 +0,0 @@ -// -// ALTSourceUserInfoKey.m -// AltStore -// -// Created by Riley Testut on 11/4/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import "ALTSourceUserInfoKey.h" - -ALTSourceUserInfoKey const ALTSourceUserInfoKeyPatreonAccessToken = @"patreonAccessToken"; diff --git a/Configurations/Archive.xcconfig b/Configurations/Archive.xcconfig new file mode 100644 index 00000000..ce559eb9 --- /dev/null +++ b/Configurations/Archive.xcconfig @@ -0,0 +1 @@ +#include "Shared.xcconfig" diff --git a/Configurations/Debug.xcconfig b/Configurations/Debug.xcconfig new file mode 100644 index 00000000..ce559eb9 --- /dev/null +++ b/Configurations/Debug.xcconfig @@ -0,0 +1 @@ +#include "Shared.xcconfig" diff --git a/Configurations/Release.xcconfig b/Configurations/Release.xcconfig new file mode 100644 index 00000000..ce559eb9 --- /dev/null +++ b/Configurations/Release.xcconfig @@ -0,0 +1 @@ +#include "Shared.xcconfig" diff --git a/Configurations/Shared.xcconfig b/Configurations/Shared.xcconfig new file mode 100644 index 00000000..5672f104 --- /dev/null +++ b/Configurations/Shared.xcconfig @@ -0,0 +1 @@ +#include "../Build.xcconfig" diff --git a/Dependencies/MarkdownAttributedString b/Dependencies/MarkdownAttributedString deleted file mode 160000 index 750e8d5c..00000000 --- a/Dependencies/MarkdownAttributedString +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 750e8d5cb455dcc592a9b6d1cacaa19837e7abff diff --git a/Dependencies/em_proxy b/Dependencies/em_proxy new file mode 160000 index 00000000..fd120e5f --- /dev/null +++ b/Dependencies/em_proxy @@ -0,0 +1 @@ +Subproject commit fd120e5ff539859e22d2c297f3d39ffe57620130 diff --git a/Dependencies/em_proxy.xcodeproj/project.pbxproj b/Dependencies/em_proxy.xcodeproj/project.pbxproj deleted file mode 100644 index d35e5c8c..00000000 --- a/Dependencies/em_proxy.xcodeproj/project.pbxproj +++ /dev/null @@ -1,343 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 53; - objects = { - -/* Begin PBXBuildFile section */ - 9987603429A4555300818586 /* em_proxy.h in Sources */ = {isa = PBXBuildFile; fileRef = 9999259129A45319005CF020 /* em_proxy.h */; }; -/* End PBXBuildFile section */ - -/* Begin PBXBuildRule section */ - CA6094FFF692AC6C1400ACA8 /* PBXBuildRule */ = { - isa = PBXBuildRule; - compilerSpec = com.apple.compilers.proxy.script; - filePatterns = "*/em_proxy.h"; - fileType = pattern.proxy; - inputFiles = ( - ); - isEditable = 0; - name = "Cargo project build"; - outputFiles = ( - "$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)", - ); - script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./em_proxy/$LIB_FILE_NAME.a\"\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n"; - }; -/* End PBXBuildRule section */ - -/* Begin PBXFileReference section */ - 9999259129A45319005CF020 /* em_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = em_proxy.h; path = em_proxy/em_proxy.h; sourceTree = ""; }; - ADDEDBA66A6E1 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; - CA60058A9FBE4D17AF51A7D5 /* run */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = run; sourceTree = BUILT_PRODUCTS_DIR; }; - CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libem_proxy_static.a; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXGroup section */ - ADDEDBA66A6E2 /* Required for static linking */ = { - isa = PBXGroup; - children = ( - ADDEDBA66A6E1 /* libresolv.tbd */, - ); - name = "Required for static linking"; - sourceTree = ""; - }; - CA6094FFF69222869D176AE5 /* Products */ = { - isa = PBXGroup; - children = ( - CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */, - CA60058A9FBE4D17AF51A7D5 /* run */, - ); - name = Products; - sourceTree = ""; - }; - CA6094FFF69298AF0B5890DB /* Frameworks */ = { - isa = PBXGroup; - children = ( - ADDEDBA66A6E2 /* Required for static linking */, - ); - name = Frameworks; - sourceTree = ""; - }; - CA6094FFF692D65BC3C892A8 = { - isa = PBXGroup; - children = ( - 9999259129A45319005CF020 /* em_proxy.h */, - CA6094FFF69222869D176AE5 /* Products */, - CA6094FFF69298AF0B5890DB /* Frameworks */, - ); - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - CA60058A9FBE37FC563E4BCC /* run-bin */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA603DD75FB437FC563E4BCC /* Build configuration list for PBXNativeTarget "run-bin" */; - buildPhases = ( - CA60445C303637FC563E4BCC /* Sources */, - CA6094FFF692AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA6094FFF692AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "run-bin"; - productName = run; - productReference = CA60058A9FBE4D17AF51A7D5 /* run */; - productType = "com.apple.product-type.tool"; - }; - CA60C44C93D7A30E3695DD59 /* em_proxy-staticlib */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA603DD75FB4A30E3695DD59 /* Build configuration list for PBXNativeTarget "em_proxy-staticlib" */; - buildPhases = ( - 9987603529A4610700818586 /* ShellScript */, - CA60445C3036A30E3695DD59 /* Sources */, - CA6094FFF692AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA6094FFF692AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "em_proxy-staticlib"; - productName = libem_proxy_static.a; - productReference = CA60C44C93D7916DE57E6EBD /* libem_proxy_static.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - CA6094FFF692E04653AD465F /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - TargetAttributes = { - CA60058A9FBE37FC563E4BCC = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - CA60C44C93D7A30E3695DD59 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = CA6094FFF69280E02D6C7F57 /* Build configuration list for PBXProject "em_proxy" */; - compatibilityVersion = "Xcode 11.4"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = CA6094FFF692D65BC3C892A8; - productRefGroup = CA6094FFF69222869D176AE5 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - CA60C44C93D7A30E3695DD59 /* em_proxy-staticlib */, - CA60058A9FBE37FC563E4BCC /* run-bin */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXShellScriptBuildPhase section */ - 9987603529A4610700818586 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ./em_proxy/em_proxy.h, - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "bash ./fetch-prebuilt.sh em_proxy\n"; - }; - CA6094FFF692AF6EBB7F357C /* Universal Binary lipo */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(DERIVED_FILE_DIR)/$(ARCHS)-$(EXECUTABLE_NAME).xcfilelist", - ); - name = "Universal Binary lipo"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# generated with cargo-xcode 1.5.0\n\n#set -eux; cat \"$DERIVED_FILE_DIR/$ARCHS-$EXECUTABLE_NAME.xcfilelist\" | tr '\\n' '\\0' | xargs -0 lipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n#if [ ${LD_DYLIB_INSTALL_NAME:+1} ]; then\n# install_name_tool -id \"$LD_DYLIB_INSTALL_NAME\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n#fi\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CA60445C303637FC563E4BCC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CA60445C3036A30E3695DD59 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9987603429A4555300818586 /* em_proxy.h in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - CA604DFE779B37FC563E4BCC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = run.d; - CARGO_XCODE_CARGO_FILE_NAME = run; - PRODUCT_NAME = run; - SUPPORTED_PLATFORMS = macosx; - }; - name = Release; - }; - CA604DFE779BA30E3695DD59 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = libem_proxy.d; - CARGO_XCODE_CARGO_FILE_NAME = libem_proxy.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - LIB_FILE_NAME = ""; - "LIB_FILE_NAME[sdk=iphoneos*]" = libem_proxy; - "LIB_FILE_NAME[sdk=iphonesimulator*]" = "libem_proxy-sim"; - PRODUCT_NAME = em_proxy_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Release; - }; - CA609A517351228BE02872F8 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; - CARGO_XCODE_BUILD_MODE = debug; - CARGO_XCODE_FEATURES = ""; - "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; - "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; - "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; - "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; - CURRENT_PROJECT_VERSION = 0.1; - MARKETING_VERSION = 0.1.0; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = em_proxy; - SDKROOT = macosx; - SUPPORTS_MACCATALYST = YES; - }; - name = Debug; - }; - CA609A5173513CC16B37690B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; - CARGO_XCODE_BUILD_MODE = release; - CARGO_XCODE_FEATURES = ""; - "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; - "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; - "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; - "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; - CURRENT_PROJECT_VERSION = 0.1; - MARKETING_VERSION = 0.1.0; - PRODUCT_NAME = em_proxy; - SDKROOT = macosx; - SUPPORTS_MACCATALYST = YES; - }; - name = Release; - }; - CA60DE07A83F37FC563E4BCC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = run.d; - CARGO_XCODE_CARGO_FILE_NAME = run; - PRODUCT_NAME = run; - SUPPORTED_PLATFORMS = macosx; - }; - name = Debug; - }; - CA60DE07A83FA30E3695DD59 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = libem_proxy.d; - CARGO_XCODE_CARGO_FILE_NAME = libem_proxy.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - LIB_FILE_NAME = ""; - "LIB_FILE_NAME[sdk=iphoneos*]" = libem_proxy; - "LIB_FILE_NAME[sdk=iphonesimulator*]" = "libem_proxy-sim"; - PRODUCT_NAME = em_proxy_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Debug; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - CA603DD75FB437FC563E4BCC /* Build configuration list for PBXNativeTarget "run-bin" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA604DFE779B37FC563E4BCC /* Release */, - CA60DE07A83F37FC563E4BCC /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA603DD75FB4A30E3695DD59 /* Build configuration list for PBXNativeTarget "em_proxy-staticlib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA604DFE779BA30E3695DD59 /* Release */, - CA60DE07A83FA30E3695DD59 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA6094FFF69280E02D6C7F57 /* Build configuration list for PBXProject "em_proxy" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA609A5173513CC16B37690B /* Release */, - CA609A517351228BE02872F8 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = CA6094FFF692E04653AD465F /* Project object */; -} diff --git a/Dependencies/em_proxy/.gitkeep b/Dependencies/em_proxy/.gitkeep deleted file mode 100644 index d338f61d..00000000 --- a/Dependencies/em_proxy/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -Use ../fetch-prebuilt.sh to fetch prebuilt Rust dependencies \ No newline at end of file diff --git a/Dependencies/fetch-prebuilt.sh b/Dependencies/fetch-prebuilt.sh deleted file mode 100644 index 0acbfae3..00000000 --- a/Dependencies/fetch-prebuilt.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -# Ensure we are in Dependencies directory -cd "$(dirname "$0")" - -check_for_update() { - if [ -f ".skip-prebuilt-fetch-$1" ]; then - echo "Skipping prebuilt fetch for $1 since .skip-prebuilt-fetch-$1 exists. If you are developing $1 alongside SideStore, don't remove this file, or this script will replace your locally built binaries with the ones built by GitHub Actions." - return - fi - - if [ ! -f ".last-prebuilt-fetch-$1" ]; then - echo "0,none" > ".last-prebuilt-fetch-$1" - fi - - LAST_FETCH=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $1'` - LAST_COMMIT=`cat .last-prebuilt-fetch-$1 | perl -n -e '/([0-9]*),([^ ]*)$/ && print $2'` - - # fetch if last fetch was over 6 hours ago - if [[ $LAST_FETCH -lt $(expr $(date +%s) - 21600) ]] || [[ "$2" == "force" ]]; then - echo "Checking $1 for update" - echo - LATEST_COMMIT=`curl https://api.github.com/repos/SideStore/$1/releases/latest | perl -n -e '/Commit: https:\\/\\/github\\.com\\/[^\\/]*\\/[^\\/]*\\/commit\\/([^"]*)/ && print $1'` - echo - echo "Last commit: $LAST_COMMIT" - echo "Latest commit: $LATEST_COMMIT" - if [[ "$LAST_COMMIT" != "$LATEST_COMMIT" ]]; then - echo "Found update, downloading binaries" - echo - wget -O "$1/lib$1.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1.a" - wget -O "$1/lib$1-sim.a" "https://github.com/SideStore/$1/releases/latest/download/lib$1-sim.a" - wget -O "$1/$1.h" "https://github.com/SideStore/$1/releases/latest/download/$1.h" - echo - else - echo "Up-to-date" - fi - echo "$(date +%s),$LATEST_COMMIT" > ".last-prebuilt-fetch-$1" - else - echo "It hasn't been 6 hours and force was not specified, skipping update check for $1" - fi -} - -# Allow for Xcode to check minimuxer and em_proxy separately by skipping the update check if the other one is specified as an argument -if [[ "$1" != "em_proxy" ]]; then - check_for_update minimuxer "$1" - if [[ "$1" != "minimuxer" ]]; then - echo - fi -fi -if [[ "$1" != "minimuxer" ]]; then - check_for_update em_proxy "$1" -fi diff --git a/Dependencies/libcurl/libcurl.a b/Dependencies/libcurl/libcurl.a deleted file mode 100644 index 0766ced737db127f72e8cb3d462e4e13a2ddf597..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2796140 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


2#~(a_9Fx)O7%UUv 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%0D7kJ3pP8Bx6VG5h;7- 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≥bhd#{=0Od`MI-lO-^WA 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

=4P0_QVm$vV9A^W9a1^Oo?6fA#Gk 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�NXKhDpwjZ4`YJR0%`x9Xe<9_3!kdFA80^4}v( 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

j5pLKXZkF;WnVs9|7Kr|6vQm2Z2i80#y0?Ee!7i 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ⅆA~02zW-m^FWAXH zt==oR$36cuZO*+*O((Va#k_03pWsff4E^r7)=?PKk1sgF$CJ6o<-e34`^lZj@2dBb zX^yk~xZDx;e{H<2f zDcxs4j?0-{=I$p{-bo@|n$;F#}Q|^@Z8TJ^4=6N25Oy9uP;yzk~J&UP!0u z>+ZATqV3PpN9=vya`B(!euwm4{e|L}XIlM<-}NQ^j_Gp7{VW-m#SV9L-tqr>M*O>_ zeog-QWBhnG|D@v`xevG~J)=$K`+eUt3hQ+l;Gl{^*6+rQEAB=P2jlUUIK!{QJIlZH z@6#QwPafm`hT1b&$tT-$LRz`9H}o^fCPOF}`y?z26M-d4&w)dJmb&j&VfOm(Q#z_efzXr7KhjE#@`2d zEIm7zSAkXLLlW`949FHU8pWz699EaB(*0%+u8lsV(zVdK9>9i#;Lq=xjV+l`cWMJb;nbd%d-g?Tj%%AC%?+& zSszEnf15LWe;i)7dzWA2VK4Yu@xeIq{o@nsUX;7>LJ!wJ>qu*8}2_zm0xbb~YSWU?dq zu`3;QFQz-zea85OJBl8A#th&8nx|U-mvtZHDaVg>Uq<@ie@$!|5kubpwD#9^|1*D`;J)*i{+i18HBKCL z=kZq@;V#7>6^s#|A&b!L3okn*Pb7d{eyA#6f ztBfBFEa-fhu58FM{pu(92x&(3E^;@I^6$6Lin>dJkud*?ecIJ<+;N?;!@Ay^U3^V znCIa6WL_BN`CS|t|1$~UU>u(1&k+}STH(vL3C2^|#pjvdjm+cLc#^xbV~z& z_~V+4Dm|`2ESBl=4b@kUS%l32+`c8bk{&`w2 za@*sD>$oHQlX$!<9pPuA{No_6=iSV_`!Cd7jPzZCw`g~Mkr4iVl)RO9Uy0-YSMdMr zbNK%ztrxkqQF^U1H&D;PK4H9M&%N2^%i@LUQ%86)yrw_sdCOepGxc1~;m705@!jhP z-+>*Oo4;M_?QXaF4)Dy?X8ys>@GYWygYlB&uR8hy2i= z%=Pr)>Wb@)!rF(1Hi-V8arMSFzCpCdn(w4e5j*y`Df#{+c4T~z%U!K*=5e>(Xf(Gc zaK|@tP3Yho4d4A--S=l(WdO5Ll;4=;;VDP>(ir|N9vG*d8<-HT@y1V2&bC)&5V=0F z^bU@rcW^?ud1`#U8Pl|0^$KfTHHXLw#)x~zb7~cgSNC;mL$DY5hGwgqn@*j`?q$B)IRDVL+9D82r%P5}J zzRZXd2Q$cjY4PKLvr$#~M(%Jdz1PRldp-GYaD2T@L$qGx-i^{58J4~0;Qi-0crQos ztT-4E$FC#EUwosCY#$@*qWpo{ugGmfZ_M=kt0VlQSZ;n3r(OSsZ&Mefl)3pOcDQ7|i~ieUP1iA3w#a^;O8=er{Et+> zK)!8;{-VF}@J-TxNWb@|zi?3Z9j@hD^dB~;?{Amz{q2UxF?Z8$xmVn9q+9D%BHMhc zkMfKoJPY^e8?ZJiFn74M)e6Q1oQvMMaLfp1ZT5mjrAL9E!fN4|1R#xnmGw)6MZrn@5%QV$xjE+ zLHCfFEDFn z>&`f?bt6|4OZUs?h_9C!!k-?YcqU4K~XMvnUz&d#3)&Y}AN`SUOFbvON0>qd^VzR%YE;W>1FNdEjVzV6_k zwQl52P+rffcMo)YYpVZx#1$*m( z^%Ym4v&fNZ@usuZBHo(Gx~WE(d!@pK?{}T;cF$VN0kYQ8a(6&(cms84IeuaNSXMdy zNyab9tko3%5HXAyQ>^&0{aKFRlJVQy@XT)!))}lV#Gm&1ItjB~Z%W9gZYzp;-`7WKAq;svC$xQopd+-&Un0q&M;}>^6PfJgiBsy z)@zSA!nY&mh+3=Co?=*e$zUDgRo}$v6aUx|&X4E*PaI*=J+{9eaD=DEDfILxt`7IuM9rzK-&c_MK zR{jVv4n3)RydAX zI%kI8W)6PCc%$Knc2nvJ2`gJe4oJ9Sx%t}HT|@92(?M#Tyt3ok(MS6?vhNkk{#NW$ zw{`9Pb5~b8Pscav>EwOymzY5tJi~Z$c$&WG>e})(AAWiELEF!M=&gU``A1jRF3jbb z@M%|90Z${3ZPv*|YKd5r&7X7j-s{Vp>0vk9{xPkso!Jhr)D2lSj{U0oGCn|V&~ zi21DJU0uaI^1e=Eq`jS(C4Qp#+2B^nxkH$D@br(P$3>Zlwv&UI zl$EL&JX>}nyj?tPJSJsmEYG^%6K1fAN8~nxyLsApI(UR{+ZP;mh;-%2$8QTjn-_?9 z7qdp_R&91Pf@l1N^yjhd>h^Dth z$?SnX$a9*f|B`xFoe)4qxP$*0m(wp5 zdG=q#>Qlsuqc8M6zRwel<{ET2gC*m0!w=$y)u$k?>c)#s)labdxc*1-!e%D>n=CmQ zPq5z)fB3ItZC-*Aj_xZ4mdxTCjG9-7oMQ;EpN_cNyiN8lzL96W7r&*@c1!wCvBDE; ze~z^WhqRKgv=LvE<~1B3{j;72%vv*XQ~FbCETqDAI$_9;KYr8oQmnlz zXYC7Qe%1D0WOyRS0VN;gwM)DVwimx!|bnTo7p;wUx||kUNOSOzmCKE zHN3at@ZN&=MjYN7@ZO2Tdk5Zoad_{+dn(ReM82;TKNE+?{9y4<;_w(R6#qC5k8wuv zD{*+Qz{v#OIyF=aM+Q zC6Y#Q+#T308S_eSP0++rOqhr7qYpCQ-&G4(f>H?r*Tvi7TW|G^i85zVCHwf0%72!(bkP zdWHE4S%3b?Hp-8gOkLB}Wqn^}ySYo1UD2uLG5Fq_W$THq=RU`685jAF+~h%Twx2kV zF;kP&qoC{!rk>9dl(C`gJ@`V_n*CkN6Mxb2Ql~`9{|osN^xE~LgfGOpKhtsXmHAxN zS9jzBPYHU?<_}iSFvVewFo2$?ihWF~*SM@08~g8d8TRG>HGpS;spD ze#&7-L+V=U;W4@4PewYnAG^xfZnqVZKVKuy*y(7l&kH9E&kfHcor=k4c38;|%@%L; z*}PWGb23-6koW0a)0m50{FjwsUD>GOt6Pq_oO8)V*8BFJciLo6`Sr6s{+nle#t>Fn zw`R46xM?P+ZxrHQJ#rV5r)ZNW*>$&@cmHj(RX!X)+fy(3@uBNmSf{*VIQJdLl`)S9ejZz=f z!IyrEZH6Bw;SX!BM8f39EtzkTxt>^kiO$MbI0L}JUR5W1RukB}nz;Sz`}%DEdZweH z>){LE|0*G2#}^6C9a5J_e{#>Fg!eBYoF4jI89enfjqq#uudD8Y?X9{`^Cfcj`x)Ma zA7p)F6Y)VpTIV{{lNQz<;@?w0lg=H;rCn;ruhC#W%KCBk@p6B0*u0N9P$Muf`3(Ds zM}BL&#EUsH)#}R_NyD}eChmhjnbl(c)Y0-b>lZ0l&6GK-{y0wklyX(7X9IaP$n#|p z{n9?Fj*@wuGvtR?K{3a@x#`GCyxO$PmC3v1=GCd5AZsj&nn%H7a?B9@{p4gH+ufNnA zqAP62p&Ngj@8-$3l$TVzt$gt?>wYBOjCUPj_E5@oE1URM-q228PSW3a6Lb6hx482r zYl8Y2%>kZP_QjD;&dSTiH3{JW-&DW&JY{?E7c*MSy1p&Jx!0{VKkv6T_(WdVOedb7 z1VDRWBuHv4gxt!V1Mm`UawyiPrQ>MZuXEyvE8R~~kFCkZlSrd3Hg>x>P ziKlLK2M*kxx#1bh?}ShK|E+wpE(SlJr(|v3mkDV*+AmD)*v9wnGqWjwi>xt+=Tdav zN8a@F4C1}oiWjxVyuH$}%&qc*{`RH4=}={E_&&-C_gXfGmZAgvJYm?5T=2_pGak6b z2w$9VVMAzMZg`kOW`O!{|08i=*X7-D&NuHbW=4(&)VNCWnB=)HKEH9h^(~rovHK;) zZzJB1as$K10k1*2$BN5z(%rZw_ILAi($OT`CjOJBop_SGBH?N$OtJKJ5fANzJtmJh zyN3F^m~=8*N&gG1@y|=SVz7#`x>MVeBt8j}tu47Kv3)C2cHiyY@E zxa#h4tay-iT+;uV)BsEBsiV*zKo{}B`Z>m5@T88}FjK;j{BAz;!tDu{?s#pcgL&iY zsHl@^fQ5ao3%{#I5v1_5;ywbj#q+Gw8JQpd~{;tn;qi@J;N0 zcc2F|t8F@x@W6}07q~k25hD_pL%+6e6ghiL+)6jGy%=tc+`C;~qiND3}HtJW> zdPnlNa&x8=-XV^FDzEVD@QDsPjMDx@>Qs4?J~D1e+z*C-&a!fQZkYQTU6JAViSE}2 zM)ZV1^hq8Re}93UA%vU!N8766IzWCfi2uVwj4Y|w1#O9*A`hL$ou@eq$nHlg_lKx{67eqfrJsO(*Rfw3Ew+CpT(=L9 zF}uhrzpD6Gb%R0M5}>R|{qQv9P09xMhK6NMK+2@JYsClr&@Xda^83oSFFhwhyhPUj zhRSD~$*(&?)2(sFl=f?^ytkRSc>K}}XxAg_CF*=}SNu4IcIkEUyts8l`?K9CaZf*; z__n{-1oeIiakn)_`TmGCEgx~F6FR%gj6L`DM|hGyg7CZQF52F;+BhqZxaAxZ@`$;} z2*2I;x|ZqmPXnBRa4ccU4hQRdj(nWZ@bQ}o4M%^P(B0Nbc%SV{U027rf;=Q{n3bs> zlYW4cv}W9K!1jZc&uGtj#RK)O6%W+2hwsY`KTr9JWp4`U*vlSuxn+;K`|xVkY2$V* zd#h=?dfB^0*;94)kR2h~G#S%LefXcCn70#_Snog_};#AX1M;|+!om{OP{_ud1S+Zw>dXV z`unVH$bS3onc)of$2Or;^0Di2N7%(!LdKBfv9sy~%xEw07iHqrRAW+zcHDfFevN}Q z5BM>3g|Qt!c8}|AmODg!kzB8Xk{&G zdyM+c_^lCU-(Ishg>iTyb@3vTZ`NzL)IgRQ5OHQ$){uP&uyVRP4;7-`XNikxDuBk+CS*-awOrF{^)S}qoI#y zTJ`Pg^j9o9*U$!H$B=kkWQ3(Y6!~KODCON8mYXBrk%k!0J!8%BAe)z@>uddfQY>|~o>W1z{L0BdxbrJrS9J=cMn%$4*fPd1;XKXsV?yR;d0TBPUZo*Ie&9mLaczGd0@{0w8ZJFzEq%6yHX zM;ZU&uFRVjTWg4n&B8bEle8tL8T<6;QFZuNQkSzwVrW0RFT|RY)Lim~^d%$e`GLfH zs*#09T)_|K;Rfg4BnReh!2cNo>W4}i5I>t{;77@Shm%yl-l}69)GgOA4+&r9MyF#p znRn*w8a`z%`i22dJd;9P(=X**JI)h;?#J1T`<(qA-$;4j8{MX#WBwfWcEbA}_3?#g za$EjUov{7WiO%iEuXb#YSuc`CQZMFHo@Bl!M7k(l$VuezTUY1WFIp7BCcUIoY zz<*7|z4Y}YzQ3YP|LRQF5XobojL~J6ut@*)^vIjGCsTinq5dd0GA1Waob4&ctyt+Q z{xDx<%+5ZG$oP`7#Tm2b4TBv%JKu_b@*NwViR^EMDIvVtiPTyo7B($!Q7~{ zX?@gMO_}p?lRu?hyk@g8$>QB-eOEfQM82nZh>!aS6Xja!hsVTB>ixsHYh|7_`KL(@ zDIX^_s5&AyTzr9fv)d8y+Uf3w&J~(`aV&*)g}M7<(Ef8ADHz?hHxsdO=BB^*`OzDiX#V&-YuSd|7wgDM}r>r=ng zj&ar^bHr*+K+Q|xuN^YJZz9i1o6+?sex*E^j-l_$dWh}Rt;cC2+NsN>4}65MeXQ5W zO8EXf70c+DYNE}E9Ix5^l-tO+>EyQxF!+-p4R62E zzu}z`0~jl}dL_<-3kNi`KK8oTkayPD2PZqjLDs_ur-H064_?a}-9^a_A;w0MhwZ+* z6;{@+O1#T=!7rK9m-OJ<+IAJLp8kLO^B0|(O*?4usY|5oQ0X?p&7SS{e#XfzaxmLQ+Ca5$~YjPz`+t}Y4F#Pd`vjklk702B!9~oIK9PKv5mTD`VaZ`dpSt|Fz+hnUkHB&^Nq)_(r)@i zDjs{cl|zY}de*#<2gA~C+{Zr1x4+)t2lI#{2tYc#0!#(@LUXWBr2L{R1s?l9!Ch0G8oNrt2)B*TO%7}!Gx^A+x2dVV&Ke>v%0Px0qH!pl8^o@?x8!1ea&9$7< z%)?kZCF2tOdKLX>hcQ{cV_EXg-$9==d1+o6bp+qEEVKWu%%10LQ1hzU%52PROU{AW zGpq+t;U{jS-sJm5^5+F>^BJp@6IaLa$Bm~7))t}nLC$@(bl!h`OG@4Kv{5Nb54*IP zXJ&WbqL3Pn%lw{`%3xdS3=qKlkY6OExpT*#7k%ZY5JPx z|7Q$7?GtiY(odB!Q)nJ-E@O@i#vJw-i~OL%IF2+nF~5DbC&>823iqvy*?BjswHqtW zcEjpB-lzF%B^=40ye?ZT+%p$F$Z(kE%nmQlaI`| zXSVoL$P1WBKT^IiNcrUbl$9?kRlaCSCcUT=j=`JmFh6;NHqWZJ(P5Vt;&twE_(hEK zj$QHGP$?6lvv9!XXT+@`1D>Xj%G!m$bTL*B%$GN(PO;3dh`aR4vEp< zkF4v07tuB{Cn0^bpHYAKsV_~h_&sf)%+H(DnTM@&vU}QYlloEhVRAj?sisxGmVccz zCHW=eJ7c7dWlsC!&aT4r`yDH`35Fdjib2sO^QFUOFD(8{znD1?!m&`|j(qX z!YJ>n`JNx@XG~G;T+i4wzaMEJYlo;WkFhpr3`m?kUQZwB*p-;YnOh7o=Vj7=JyxXh zy_5ctv~!l(Y-P4k@??xSi`5>|p6!tREFtvev$kL=Pd;l(ZT&wb??@WkeWCnR+E~ii zhnHAw?*YR3WT?mp-$0#_F+9(c&o|Ix^r=EJH~S~_fMfn5Wl83A@z8^KlaRV^xcU&_kP{=(zEO-UzH$pDbj~g-)6+W{}GXIRNShxmAR4ji2M^` z-?^lbn!hlaYfyb6DU;kQY^7Ofgu`PlrCo~CmP=WdI4}ugi0?lp`%T_&`8+wTr|>sW&<^Od2=S}*G=E9%t6#q7>vaNlzs~%vS}S1Fp_!DA`-x}P3&hpKngP=)JLF&Txz%rG zY_*y=Qu$1M*9%D*U6~s`{uAadMp*0EPTA|&WZp;V=-u!7HhGqElog_!2I;dzms^=r z6F2NSHAq~u9$DvomA_pwrx&Aa+x`1G{3&Y%{()Qh`dfR6X%xOnnYk4+aZ}>supSSX z(;E)_k?}}~{;i9#hUsvn_-Q9h&fc`gDWN!ZF!Oq0b7sSV53w(9iCtN5(j@jdBh$7o zW~P|M@OKgUM)*>9N;$OioE;A`e!OdlF)6s1G~>*L;N{>E@MiD>kafhN4;^8(Cv9+d z`Ih=Bbh+w7%J}Cs<{+C0zxqbsGp@}ij%lYn!OQYwFJiN-qf-8~(;rzqhh;8>S8Z7B zqo4l&rL0fwEld55?4RlDd_{dXfU`hCZ#eb%PNm;L=AF0DCiJ$)H@u|#t+h&0FNGdv z9wSNmZ9U_nV-HLFfcuzBctX(0^vmU})8u5s+T$tx2kFCMSM^EgUz>f5fkD0xNk5`q z(9YX@?~ypqB2Gf&<0koD!kAS0R-qX(N73^=OZdk=%WXNHAY**_M&2{VKT0_5{K`7T zOwKDT6h9Q>2k~PliN5|SQ0j*m=`Z;*7eB~&>RK=|%<0cNPH`4cA?w~^+C9Vk6>GX& z($<=+J3B^rl3AN3ai1n}|5czRbgvOUwvck#?RT}#Smr09{Vr<=&ZJ(JC3`%@KizTV zApC^Ip6lu&ePsQPg!6g&8&-PYb`yC__HIbH{p2MvXD-MUS{y(85(X=t*he9AjO)W) zLt^b+kTsfL>NSS4@8o6Xn}aK7d-C}n*T%bQUsc@^)cuOLb-&_RLh`%PN8W~C>#r=d z_8138(9h;f49Nq*m8qTp^J=Y<|Ly!im?bYi$DCT=t2n%`RGld4|2pd{AH=@>jo>4~ zQ@4Zpc;eLmK<@94u@*05c<`CzKaWQh%OKKn8n}UZgA9-Kvy4-ZA(wFp{mk0S=9%~B{@^3( zFZw^t8>nN)&_|QL^4o;pL7Wb^zLV%RA-c@yZ&%HysYg}+M!6?rCmD}-IR}5zj{T>& zza>a}^EPXO-=V#ESG70Y>!zi>iFQMDJcm8%y>Ngz)tG6^eCoNWvFI$9aS`Dw5Gv?&4fr{|iU`Vli*He61+GDb3A-!PPVZ-Cj(JSOE!@~5oxjb1|^ zYyGy!J;(P-Yu)nz{ASH>^{llfJtoyV8869LnY1a^?)!1S{Jie>tj&&hcN%re`xpCX zS^Z7P`?4;38*Y5TUNmbT6=AXCi2Y#)TJaxw<;j1+H;r5?-qR?%%>6W9Lb=EoNgIHl zM_hE*c1chByK1^IooVkr=p6cZG4;(6-7dG2e}$h5KR?0sxOu9` zvfqk-aR*oVT|NU-|98;^tsC3Ao6W`72nl!`JTp}JaJd- z`M;TG)e%j&Cwl!OX0p0yvt-gnuY!k)_urHxhP zz)UpW->}4=BlEu{=zDHSMvlnTOF6@B60?E%i9ynyEg?Vmv&Qm zNgnL+n+ltZiw^VHx}?0wIA6m48hxM0c(eBwS#fT~soEoU?tL1@`=2Ky?&xH%#u@ri z@?A&jm0{GAs{YY^C+CpIkLaDoimO1Kruo~HNr|T2SbK%?Q8sl)io5MNfpJToO`#t7^ z-t}NEez^o4U()xMeZkD(A9xkF&ZHV)*2VPdx3!ZGqzud44&$rt{l%g~m`JF-r19pi`}n#QEBkWt?Q zEmU)H~v)^i^KrIfGs1J{fCVid{7Zs#}_qbDDXnKpeZY z+2Ln-wo)&aSayeDSFJOCZmB2dbNpT$$8H_=Bu>{^Xt<`b&Pe+4@zxK080B{fr}$s) zx08BG(pu8$Day9!wc65|=U$I5^+9Rb;tH;`AM3v7-tsCVub{w~cip^s#`Oia&dWFE zURQ8S-YjEYSvgI{X5xSt;ny3*GvFxv`#!|JrqHJ-E zyL@>~$s$fD)apfU5%)%yxy!5Fi)$+?#<~}257l5;Sy9Se+wRKcW#dx}V|4Y@tFIni zZ7eHWR=IMmyV{R$O71B$uCJ_JUK$mEvF_F7HGcQXvK6&xsK#BlD6A^4DkCWO*5dcu z%W!%*B3!>d*1fQ{#=W}Cy}D$1jl0CXyli!(!jk1{SC_0!G3J(ytF>aQY)yG}P48$M zt|LV`tOK25+*}!*zAa3wviYGvh`wg0}ITbGxwaaUL3LXEqs1no7IDmP4ZUopD+3R0oAqICHcHAF&n zWyPv8l~%D?%4v&t!>pU_%tZD=HP*=jc)3KBRh6u)E_37dqRP@T0<^58e0g<>PNs#V zRYjS5apg)oV~}&IQpm|GSCL0cE6b`yht8{3f>o3+C#rkp87ps*Wk`gI3itAoWo0@D z2-@DT5;m4C(O+3rw%lE|yt4Kle|&k#z}01C%c>a!_cb;3eres+aiMptASx=-cE+<>sxnF0%@yp9Sz!=TF@pH(1l8SQ+ zh$br`M~{|jV>HaM5-aYx*UxlM&Y6-;PQGC|wMluY`-VBICc8^YOUVxu=gO7KN+{~f zD~qhWW88d8(VV%r%)i6Xw7;gNO23v=ROmPAIW0BTZCq(krQA?aQFc#Bg?o{|WF>V+ z*-B9@C7vk7d&cO@Nq5~n)i-tYU3aJW42fA~l!6)c1*TU|_bFyCVj8!uU+Z30QXw8K zD>be!oHJe$)0lO`%);^3uTd~74@3DiZn#Na<=2>ZlZaL?Lw3$Bb0&^Asw%4{8WJ38 zh=sM~6*X48)l^EQ*b_S>{p!ku|(#qtgNYAR9WF3F}iw$Ri<zia}0z2 zhr#@uK}%!Z+rG8dFdj6FiY*F#>opzF^n6VhYC0GE#xTYW)8=W~JW-ps*C>656#9ao z$ZrMLi#rN^eodEZdaR~1G`*S5qSIlFtI#+MEI`lcm4>kdJPQ6CJOmcQI;haQ7i`14 z349mK2SqLyEJALYLazz(Eo@xV3d8sn`~bKItN>a6IIbA{1Ly`jK!24rfUGE0=vx4u zzD?st5U!iY~rVBKk4NAO? z1@FS$429m4OI7?I1n0ru4~kq6yi@$A&>H|HohE=*d?@tw17F3w8Rl=nMlc9&0!414 zLSK!ht28|UB+14dDwjbg?t*vV-adui04Vm?DfAVCZy}ckihMti_1OicLhoq?8xp^V zKuaHZyXaHsZ3M-B0Q?SE2yR9H9ECmu{43^%?qP(B`9X!geW1uUg5sZT3Vmz9P0%$8 zee*%d-`U__kndb<7_-3B;0>Y|lz80_vhJ^7pF-~zZN3q_74v$9-UZ-yksk|Q2#x~9 zei~SaoJ*m%A4pV=J6)#IF9?d<9&j#lyA^sjgA$H4poF7Fp|4oe3pAY%{s(e78q+l2 zrTHDD%KmAEzJr=>)AVjlH*0!}rZ;Ok0KS6$LTx@rn~&18Thob}HZ;9&k#aYv(6>|5 zO`5I;pF(eqHm}m=gWSkgUYTi{tAK2Q576j=-mds zhI|J22G~kvcMx0;3Z1X9pT;ICt3^sQ1sM*H=?IXp|==(N&E#$ z{F-1Y{6vM`PAVTMUmXg4A+Qy>Ab1>X0;RmygW~>rg}zcy^b{-f&Id(Lp+a8)DCIF1 zd>=ePr6cjP2YeLV34R;HcV6L+^L^lsApjhbHr&VXN~(CgRyQq7+OO1N^t zJmjV+^bP}aq0R7(ATQzJ({ip#a=P!#ohvi z-a>F1^c;oWS)j;egV$g_L7{gPDEToBoQkHcF@wY{xuSWB$ zG{0E$7ij)8&Ck*N49y><`K%?h^c_{`3xX$bcQ5F{KdlPATfrRYEegHs!70!Ih2APq z@_B_qZz(t#x>%ui4)_oB&H^W4o~zL70wrD&!EDS8h2E1i7AfS@5I7O@qYAzI!7%bo z;AU_em<4~ULhmL}>en1^;5+!+f_ zz+Q$z?=Wrd0BTT6qNe$5I7#Wg9^R-K+(Ge41pEkRp0_`J|7&1 ze4#>bzBZo)j>SAzp?54O_WFSm4pX78gUVmx=OlO~@+TB}4}zPJYg6cJ1*P6-)VL8$ zBA#kA7K6;ekDH@00~GtC6#DvuQlIRn5*PRPDfI0EB_Hhs$KZaGLT>;Rf2{#CFt1VQ zb%PR5E^sS)`YZG$f}%fklVMze{85G8c2LZN;LowQ2fQ5qZiU`m+Po1Qjrlf(-pybl z_SS=kv9}H!1%Hh~Zxtx{(GQNqyi}og7TAUPSWxO$mquxPjUN`A=E=GodjLz_$EE9u;MqlLbcpvdn9Q@~B2_@e?8 z|CfT7;m=})-h5E(&r;}{0DgnqFpV8FhU?* z1{=_u4@&&zfD*rH;8EmV3VqV}3f)Pg3;GU%;-4TW_I80{Z>z?7&E>-AV07|_!U!hMrJL@H1 z%(T#V6cqorEA$0HiLdpb*b6B1m4d&(U-LE20SDqvfkN*n@K^A2XQ=*L8aM#HOQE+T zPmT9ZEA+L4FC*UuHiLV>qqw(Qp>ICef%zP812_%5AIt_n0*8UW2K#F~O(#g?4}vGa zHn2bL?^o#E4L*qeW`(|WpxEbZ8{>7*1f^Ujf)`;=I#Hmv@mj-p0P}i{6<{57K1lpD z3YH^3OVfhT-jj5i?nQ3D#$53KLZ6&w7`wzAl=x}_#b1pIecQmNFyE-n>$Q0eDEWeW zi7lL?`30Jvt?3DxPSdnY)17qA#GMX>zIII?()3gA&qU|2hc%{d%z&{dQj4{2K*(+?aS8ufeX9 z3cW#4%I{uK`m z*J%C%&7ZIN!!$ol^QH4D_B*e%(ANrz`+F4n8kKp)Hq9^9{9?_|*Zf(UZ)$#`=ARg& z^oJDsHi4plqe5Se=2vNcw&qXJ{4~vXY5x8U#wk}Cje_@)F8ees2<_br{*ZWF4@&y2 z1N$PkMxpn_70P|q7m7c8ZJ>mIzd~O#cnW(Jprl(d_&snwDCsr}6ur~HKIqL+=nY=Z zyaE0a6o2j2w4nHFEGXg5Q0Q}kR=O(mwT)K%{R(}1K;iFJ=quLz1)9%&krscJ=8pn@ zhrdklJ@CXR!}u?-85DPSDfDdxMei1cz6F{;U-M^aey--b!Tso&KT_!_ROrhEMb9*a zKIyEBJDnpe^o2m-A64jUQsxznn!ic&H)?+N|6}i6z^kgxz27-kxU7UbggcsrLJde1 zLK2edDhmiU=u$8Q#cCQt022+6kZ|)-7nQbAXq#xNDW=<~v<;MYr#9B4oBbIryE`ha zfT>Np*=^8x_Cm7TXrm??oAZ0;7$aGk;B9~BIp=x4=gefy|NM{3JMLqSIj&lNzSf_i z^`~h4(=(O)R)yKeK#||1Fnh03FAOQnE>!A;`C5OT){ocvv08tu)^G7C`6m=+9|iXy zzd>R4Jz9U4*59D@*J=G(THmMjM{0eq);}JnXLE;{vDh`qg}9z#__vg^Ek`;53m%h z1PehA^+vuzKj&&X{+X{ZyKJQL?_P!3g`oI1Utx9tq|QGmcsFvc)?5(op9Sv6of)9i zV_xtDP+sab=6gpt=x6S|HG_IgP~@a*E+}%wf)Z~d6=rwGD1US*%svKwfPRz0>Z~t)K z5A&>pf}+p55r+$k{w(kW`hud*JTHd}ivH1I%Do1K+4W#C@pMqD*JyQ_WcniNsbC2> z1(b3dt1w$$I^yr%p$=wuf-hmN9t@#gr!c#LOeyhIuQ2-v_#wPjVfI1rO?ZvMZ03Sl z{};SUVRkwAU-113v)M1hako%mc9!O=G@qh*tmb1u2_N$?o%dZwl*%71poFghlyKB5 z%&yeDT=RRthcH(P%6s=Vt-n_5r)r+0`AE&Znup2sBEMZ>b}RTtkR zw`=`D+|}wuT79kNS(?w+e4ge*G?&7LyV<90^__AI{44U9V{ZKotOXwigW%I(0DKSZ zw3L546lRA($*=7Svs=Nlm}>^5KKFrp(5ISo+^YgN&;&079|J?+li)7!M_>{7Logpa z2(AO40@s31fUCe7FavxX41oUxrh>KLd=NKA$Agc8KJdrj6z~8z7W_Ww1%Chn(%(1Q z>zU#6dfM%d*_fY?$twUhI&0sLyvK99~$OfHf;Ye zucv-k1NYWpr@5C8uN;ob@CNRc-YT!xbHdxgy~EqdeSdU$G`i6Z+^eFixz|J=xX-e-+1Ciq-9oR5{k?&?%~xPtG%9M zSmHz=H4-(a{@6F zTNjIj*kO zGxz4S<7r+`TUtB!nlB#wA~E*GqukrBYQM_s>AtF$`_ZeLuEzB*)qDxREv{dTt;NT= zmj(6*uoXDSy)Dqry*tp$yZ+OOJ35FYVwSTDEr?VPAHPd+V~( z+^f>7(~+EB&wc;$^5ukLc`f($bW1gw)tA(>e@E$4c8sL4nJJi!o56L8N?64Biv7{Y*~pE5ie zEJBgh&i&|`rZq^ushTwHx~ZG{iJMz)Cf?T8k+LOOKWk($ZG$ouyse_ir!Xj{mnG;eKp;GxxUb?c95}hj!r49o5|H zcQkN6v7?21$Bs_!WjpupBqn#(a&OvsjQi=GZQQ$e_HwV>Rke#4*j3N{_^uP&%XaVI zjrrZRyUG9eG~YAa6Z+cTuOWGl-LS{Tr+e&{J(Tc<`|YFmgS{1Y=pnH3A-hVj>wddi z)XS^w%4*D4?zOA-!b9J(_kIg(`Td3bsFHhabcI z@gLYHejsxG$*%n;u;p>P^>MJQ#@=6px$-CN$|u3vC+#CoqTckReN3?HNxNIrLqD?j z{s?}s)~>Au8*1&Nf~RZkHo?wXyGyX@kX?NUJaWjcJA}Q;!*+F^~)LZK9)_Sn}8N2rx z)H{D^cl{DYSN1W%_UG;J^WfeW?6McY-e23HV_?HE`>0^`Z|s`i zAg}8syZa?kf7w3zGFW-st~w5u{np<9Tk!aA?GwKhbHB5@e+SmQVjp}3Y<WMX~FJi?cQfG*Is6a z%f$Qx_K63CKVXLi4}ROO{Wf^?+jf)Sk?+`b-vLj2$8HfUFSjep!L~}fy%Maevg@nB zu4=nm@^i=IcIV^Z(WmUDr@-nT+BH7}+ka?>1v|cDcZ!_)a=Ss~R94wlV!!J9cD3ZM z_5*fU@>lH->?1z_n`-Q1l5bjS>{h|nC+yQti29H1V?P%Bk$vn(VB3%EcEPG6cJ&dk z<41O<{O|U0!BDfkw;8Nywhs!PXtrAfD_^v$UIgo3v>OClUbI^U zyI!=r1uI{&t6l<6zht*behU5A-uq+t!GE@E{~2EOW4l^-XN%p{0`C94UH*IU$ZK}p zYvA!#`$Q`kZnZmFF@Nk2cJm*=+E)9B!~fH6{!e)MpY6&&i@i3xt_^H&v%_tux3t-< zf=Ao!rgpIPP5bnl=+}nrBVjQYw!?x|XYJ~<;OVn=n_$&jcJ*6e%UgDD6b*B4zckO){BN2EHSgAZqvkf>*%JSEY96Ec6Pi!Ze3SO?49)M*e75FA z+WZxo@6dda=67oz(0q^PD>Q#bb2%_k{PU=mf2(lf*Qeumlh$w5=C^A8kxq|Ynh)Kn z;&YF1(z9xd;^kVuUd#W!=KreslbZil^Pgzms(HQUuWSCVn*VvXlK&gcXKVdeH2;$3 zt(q^@{EX%@7$w(Rn#XDWcg<&N-mCegnh)hmM&c`4^U<0g)c%>Q`8RcZ`840J`5eu! z)%FuLuh9BeY5u6@>6%w-e!b>5YWp{7{-Ab0NApU}^M#Wh>`muf+qM2J+WyxxU#I!E zwE0+Fo@+GU%g4K1ztp@{J|MZC)Ao<-U!(bNHD9Uuhnla|{0{A( zT+Of4{0_}mYF?uGi@H4Aqxln>e?#-X>G=JQ<{g?ps`)o`eAHSAPAbdYRx$@{=625nd;wkhe z37_&M#lL}D!t+xVmkpVPR~0J$d(Cgt>G6=ZKYy{(KcMxy3KX9Xi2Z6st?PIeo{B%^ z;?dy_;Wk~%Tjf_O8?<@pr;@8qhwr!!ADi4L|6xzA-)sBT+CM+iJg9k-=B1k7t@#wq zd$oM8cK=N+KTNzimyW-zfTEkU{RSO>x4r2h*S-{j)$q;I6W8wpP&FLdc&4BJJ;X`S;r{^RX`Tm$~>=E`EcH z|IEeLyLhRKf6K)WxcF~e{ zuXdSFaOv-L$$!O_zkle`mwxI<|L=A2cU|eZ$`$?}y7-q}@hRgGk@Cm6+`rsq|6!MZ zJ6!d{I|z%EcdILY|J5aLm`mO_T>6i=?BC`J|5%rMzjkpJLl5$gY@{CPze-nmAuE`1qah_pY;<=-Q&{Iba< zZ@Y_M?aB{-bA@-4OJ2Im{_8IL#V%g%il1+~_}wnfUaNz`C;k4B;l0eIU+LmLm-}zJ z^cnjYBu|<-k@D|!#pmB$JjxaRl`j2k7hmGy%U$lRb;b9UF8{yc@<03A4D#<|E`F2C ze5@<~#k<_^b-5?wi;?ls<f4TJk)5ZVY#nWBf z%2~!r;+##}HnIx7RI@yx`gz0lB1eOL3-XF~TRH3R+PH12F;`N$4Sg#o4;j01N?6ak z{VuJCc}L3;FWVv*fg5)f6>Niuot(|A9WTh)#-0c}Hs<8#%If+-I-!nUn=#ZfCMDa>)i=dcVrLQR5@lecjj8y##i{@ql#y(B*;&)IUKM4R1Ea69r4 z5$TZLQDB=(xr9aB8*>U-gl-&i6t-`PP;%VWJ2&K%l(GkgHp@N$r8(@@u#Hvm1zR?5 zuyS(H-@qDog6BLIY%xz8w{7Eb)6Q)LVjYpW7DuMMi5|?#>*xm&i3yrXs}&@3w)6+>~2TxJe6>h(<)t#x1wweNw?$_}`!Qg`_=k zDyd3NfRz+PvhA9oC25#jL^w>CMCyhuB}kWD6imVx)&2$N#vj@=0n07SDJV+%81)nr z2~KjWkd?5sU*|974=1$-!aF#O=L;CfiaNdux8`n;Mf=9nS~(&OB%-%mAg0-9z#{#( z751km>*V!5CfZ?@q&b7Km+Z*k>^Z`Y1KYQlyya|0u%)zcvn#_&-Z$wdvXxC;+(f~| zohd|`t70kpjj(;iMv~lFz&}V+71mW4SxWXa1wxfj<-nj&Y@{sZZpqu&pWmcLP@8*b zbB_0Su6KpNNg$_;Z{4z~;C5}cphO&2TWc&I!>LBHwrV3Lj+EEf%!4|C6xr2Z z5}e9MS-NK1*3B+!w^M31ZIa3*r%1=gKw>+)&TQPEcYjbNboI(**R4+09(9Pxp=9p$ zgnDoyn_Uoca7f}qTimdf%|Kjg{YJF}OlZ^nI*v8B;&~44+D#?s_+1;NtZgrH)QsKR zx0PfSY$oocK<8}EE!svoBrB=%UAkk-)}7ku_M#0`aw0FHrq$vlw`ybk4oX#*n|EhU zUjCgqw{OqgW@-VI=Qii=$`M<}gY2DE$;zLpqaLM5@T^C(+I>$ee~kq%0Q zMzJd)FA^BuQS#z(%3)sqHto|58#ipFUM?-z#5)Eld7G(=ooHZFk=+!>jaV;IwzfE$ z7^3zQ!KK@_IB&^2WS|$;zO3}6)XZsED4=JG?BR_21 zvO}zvZY|upbEEN|xPfa_pi0~}$LEe0@PSGn-l|S*j4J>^WrVk~L%8v-$Hqb6{G^9Sv!E>A03CSrJ1I3}FXye8W5id0H#_ElwYl`IE#~w_w zA54S~(MsRClNOO%lfAoC6;n_mTM=n1>J>m`u(7}Di!2i+){UC%aHG;cLd9*UbYmge z+GTD-L7rR5*==XAw9@k(D4_Cl$r2^Eqs}fmgN2Eb+gQow^)6wkoNws7V9I_yZetRo zE@8KCEy^c33QIS$5TY>W3Uc)VjVWLW`-{fZgZ**8p5;$X$Y25sg`KX1;+9sY}mee zGj*?S?w3+;s-Pqr3(09(CB=j?r9YU)11ZM)DappLM1e#}iU~@}BBNp?FES5FMvE0K z+Lm#2k#Tg9adeS!bdfQWM3~H5*~ATNPjr$PuPsQTZkDW{vt=u$ckR{&l8wn^<3h5r zl5G5*Y=X7Ws3aL%Nyb)^@z=tB!zNe@O|TXkFE2FFv(UJ;sQ;ngiGCF$aFMaK$Vg5y zh8G%dEKGDV80uz&o zCLt0{baBp>_Jm211x96oF`R6?m29GPq0ve-QJRPolx^csGSZ;^B2p15e1R3ib?JgD z6H|Qy*Mg+P`HNB)E=o%F`I6@^KqGO!=q{K)KP4&2=UcciRU2Oyqc`fxDa=ifn)8aS z^oyA5l@I>=9}J^A-5_$K%g(Bk2OmGKsr;nh@8d3+11;AHZN_lACY-&j=n`=*T0YWD z@4s?#vX-yS>Zkn=0r3Er$fG;S3L(fD4jN*GMBQ9DIe8R*X*H|MEzih#OY4uNuO;#l z*^w9WXq^stkjBN5tR({`=Id~Vj1vBmu*qC^w=6Mo1wWamTZX<2H;S1l{A6L=#XuW< z|Lk*W0kZdubH#F(pG4(Eepvn7*T?OD-N#ckJ*cyI4_?PWmPZ)T_0vY;(W|ZM(ur%RY8AfeLVI=jeK67hB>ik&LHW=FIAj3 z*z<;U2>yMwPd;8<(GsS15dCvEX zjH4#v;zIFxGwSa6Y$A+tq$|bBi7SKullXGSO#`yu&$AAZx67BZRlu*-tm$9Y4@?WGcq&ZSSVW{ zSd~(CO4#c?GOf>!2{q2?x$jk<9dOP_>B3A4VJ#q^F_xC(#r_@a`MZyEZ#p<>^zVE%SU!`K%O74ZhQsaM|{M?e|J&fq3_K6-GSfPqaNJC z)=H9gxoj1-@1^)uFXssSmADjq;H4{4S4<3~uK1`gSTn@_T!H9x3iZu zdGtbiSj(1^)|J;U$y%22MUdY$D{e^tqE$%G+x8+K+eWhYV~KBb0dH^F3e|KS&ZNd$ z7F@CXhAf|c-S`$=ku?8``J-YSVQem`{zt{!xMoEbyJ=oSOLL=aYr2ImlG}aau-PTo zx{`fHSKP21*KzvF;L4TPty#ss!WWjW%(|q1j9J+lSi4WE{(o@E8Y<_a5CnLbL1IzY z7s{F*Fna?pl}Ye*3bV7o8LUBx1)0B*(1|_juLN0h!}}%JuFx-QZlSB;75ZzmdL_uaFj%h8zYCOjDOH$V z2uk?Yfka{OHiiBSP{JYaQu26E+A5%*^5cYSmO_6lDB&8b&_5ECa18+^T$VzA3uz+Z zIjZrX#&V4zP{JWC1(GaSq|l$Q)o%kys^D6MetEZx`E-yd3kDSWNjq_pq;U4OU_DGA zeYj`sZNoi9rOdMR?Da4wHmWj;nX*wwxHm-|<6bwUeh71yS+RqzrxG(wLyn0 zPGIGtzIOQan*T!c8#R|PUNOH`^IvOTr1{I5@6!BL&F|9uKZN6-tBFLp-r^_n?$P@1 zX#N|`Kh*pc%_Tj>{HvOe()_gMlQgH^bS|0yB<2rmeHrr>ZrYCtE}kSDznS*n9;9%d zPd`tDW2FBoadDZN6sb?19>hg2QlEF}Abzcj=eYQI7uR3oks}whn+JM?B1aXZD(>&! zlg@f=dCMJjRN)nlCT&QKiv*ZJDnn z^Lb~!r}&&Ry|+2?R?^n`zu(N~*1)$}|JRxk%@@1+kW(LG<|EGe?2>f+#P2S?u`cx8 zwP0a#ihPIpe1pEb3N|Gc6h(e`UFf@Oog}=E9~X6o>}mF~*CCxrLK+RH4wrgQ>Kf2&+ zcSHYol87`v>U1Z(z~{U|nR2#)yUi!ccsUOAr}}ZP*bR($;#;bxz2~exv=`KG_vD^st-<@*d}b$QeY$ z1>Y}xTkxyBe|k52C-wX79OqT>9hBL_*%g1J-5JkW5@EgpyhAy=+n#vm^RyLx_~VQ| z8-$7^iFa@8AMksmx`gw6&e2K3jULWent&ORE7+H3HTGS}SvAPE$5|Dx=UEkRL`_RH zZSOr_3p^aovnzOyE$L&W!}x4<23mb+u~x!*-4&< z8uBLToFHug-u+G+fY(>TS~&l~EQS7bknkmVL1`0oVpmY!<>a4)BOqm?uvTIA22kW( z4T?D*DCSsQV#^wx7LT;5oHe_H-jP2>P2LeEum8-&*TChyat|n%)XBp2D_8tHXrAqN z;i6`)Tpl9%eJ-Bn;u$WU;Nqn&uB-Keq8%wY3{%VSms4faPghVvU!2|)-Wm0>WZbe~ zlMHRpW$o1Vyg&5lio7HG^|T1;xxvG9dR&mPXNGE-wQ&9j)_H?^>II?dW?dV9-u|xz z^A}#I9(D#moL*X88UOFr!_omFS4gAb|I>Onti(C;B=a?JlRA#ZW=OzXpVt3nU z`3ofw@sZ($4jAJ%*gpra<1fq)Q@@S zuSZ|?U8pmi#BTJxp;OWKMn5*wwq9P$c0qj4WQo1A)MF&2J{M8f^_;y)xMR0(8`4v{ zV@OXv=9+mQ7&$g_Or1weWj;q=oBK?wl?)^1I)~cG$tNWY0$x2-Y}W5C z-B@xZQwn^hb+wJpV>v6PFjvm4DU@$zIw?0ulhQiQk2p`L0i|xN0`YgSQlVecigZlK z0LhC9tbnwuFpv$8Z13j@CjrBtTzBw`TwTD4wO@Epmc|v9i-}xT{(k>q9dE9YC;-4-Na?7Q+1ej;Qz25S(xN>tGnBCg&T4Q zHRmjMJtFNBCn9|EpxSeiMxS>1A|nsOrXDfMpS3+_+;Pi8J!JF*rR+*M7jxpqd~W2M zLFHW3_z4~oi^6zt=AKiFWA18xn@ir8E9d<(?jZ}RT5YqKQ3usw|+uk z8k_{A&J#OaH5yHNnD*^wP7m#t$P-ax5g_edD$S69xjwC4Hwhr+T&^PRPsPr!*K=~1 z(UWU*IbXvyt|4`TTvA`iML(_6wl2qiF42zur;U?%bv&88F5megrxtnA4su^PIqR9m zH*mTAXX1TIL|RE&nkz!tQ8Mo_+0(~|ig-uz_geU+U>TWvEtVqRWAyh(pO0gfw($Sx zJ$9jY7fvxQU{%ncSN&QO%LzISTq)C7Ct%axvq z`|gXe-e&%DR;_2!K5MyM!P#*q@tU0FSl_(VcKXtz3zAc#=~plDM87=8p13d8j@~C` z+6MKX$2#X0i+U6GF7$4S{05@UUtWS=?U>Lh^G=IJtrE3|C&{+qR%Pg7%Q^co^6W$1 z>3gN>^tF6Jg0&_(RHzsVz-L{j7Nls^gGjT&^YVa$u^qdE03YFYS zEN9Awnxx@O%TNx6y9p@f~$A@u3rcJ@%BPt4gvi8|WZLkU@<*P&0p zx3h;5<;mGYiT+_{4<+0f9YCMF>+GRKJ>%@5MBByLLy3BJv=4py#U1xYgHrd>zu@?T zwhc;7oj^Y<$M>?268)>T>^sqHALoABZX*zK-NG;OJ(eS!fJ-3d+Qe@(bzP09aqZwI z`eU^I*Mt+HrrzDJ^^N_9T>4d7-_(CKnoFBZu3CPw=G4@?zi{zJ;kYmTmU2DMPq+;9 z%Jm{Y;a}2RDjDHRHUFdLU)KDL<~L}5R`b=GzoYprnw$RFuWCL76!{x8H~q5(nw$RF zt(r?X#eAve^c^^Sm*xvJzgKh4$aM6-uK6;}%QO#a{$0%lOkDCP=Xf~$s1PploJkso zr?@zIYLNaM7uR3Ax_#oz86B7jF=lYG? zZr`}!%Y|Fl=MK!@vW)ZrD{4}S=?XQtaL@!NW}TQWQqx0ve($ULIyc>|W)e&P?3K^b z?HV~{M~Pctrp+ucf-f)+XMrTd=WRD8FHEEjFV~=cSv4_tpxJm{J6_rvGG=7?_;FDu z$=+-qd!=d}X-CUtxM??PW!hn%Z9a^#FY+h`Rz4{0DR;Zkw0lD6Q@=W9r+||0B@E5r zJTS7|gOZbX1x2>}KJPW?%wy?$v;t|(R5$p+nG<2t=K1LE=WBgd+-nwN(efgq?CPJRr zji+5KZC^4;NWfg5_8ns6nAVgJIgyv~mr*nMb1W7lPm8{!eFj{<3-ZYT9bjbslzc8f z5go06z~{QcoTq(;w)N}GmB3=`C!WPkKmFe^zn=V?b&r}yVcNhlx8o7!a+rLr=K4%> z&R3SUJ9{0l4Q=RDJ^k>sU&_Bie>d+AXP!|vZGPG|<##i`h&@M7-oyNmvS+OuS+Uwhh|X`MEP?*jZ=+1vNbbI2r`nF|s*Pidm#cg}&Poj;K=icdZV zI=`>4PkxMdIB57Mp_u)+-zVAoe^SrwzR3POVff$mOQicEOY-Ac(u@*)>P%F$lP{U8 zbV~AOr8F%Vp+)3Q*rq8tpe^xQ)s7;?$E_30glP?G7q3KQ@k~whik^ld` z+B(z?G9Gq{O1!)pKfS-xs`y};RpDcvU0fyG)Q(v8!5j3o#t#pqJut$%Z%$7jZH~uE z>B5}{t_Y+)Fe2Jfd%(6*!aJ?BGRjK$ZY!xy%NvgEi znjxV~>WNs96L*hQeDFZvt{&!p?ZK@NIjcRNve0zLLZ@u)8ZL3`J-q9~K4(tVI_9kL zJ>blh`U`WV&Juqsh|_pmzIQ{JVZuSXwCDUXq{@HWa4YfC%1;gQOx(#kQQn909-KXU z_WZ=PL>7Udj&t?^2Aw^Bg|AZT*{7)pdB-KRg47KO_keu26z)>!%oB5(_9el4}n+--lNdJ z3#862ELE7D1v>svn4J!aKk%#A=l#BlJw5j`d&TQ1-8I~EPl(T}GJ8K;vz-{$!qk)# z&L*?n!+Lp^O=httS1Z5B@2)=!CoDAxmFrD@k$f*)+6!I+Etj+pgv)oITt)nZA3=s( zJPvAK{8sZaEk9TDa&2D5_{5I6;(3VV?(c*rUHZ#i{5cnw%pEDu=i zSI+jk)B@rQE!Vxj|2L~ubOQ~x z3-ueLfrL%Rv%K81ggXintrTyj8Hm;Qq&eDk(6a|ZwkLs8b-6gdK#e} z#93tfPrj|?M}6YNyXbx1%Y2{6{P(s#>(H4oRu9go@jc$B$g4cd+=jDwA^elTp~ZI0 zxm?<0ac{?^;>TF(h_vT;=bG=9PkfIK51j1#^`w(Myg#KKY3h4vJ4$=8_Wo(zJ!6I+ zisxMzKi^84!h3QW@0Sms8dh=U*V3mu_3)Lp70Y=^Jzp7ajXSeY^|vk<(sXK^_2fGX z?9e-%_qCmxzvs8_{Ehjc&49`M>@A6)#V zRXpVTfe&&~qaKZ2eAX_eGRoS+bNmAP#Y_h8)jtm1Ucts7%yF>X*1#@{0I zh?aRAoU_Neaq&j0IKQ_qi*zi%mj3V+yAL(Yv19i6XzxDbu@X-+=Ud#U^-ND}k>?-S z#WEgS>zSIk*l!mfM*TX%(Lp$VOE|729HR-x;sti`SEBY2zWs#n+l22y!uOp6%_8Fo zyEr8N__1Rx zaqVY@jZ5SMzM?-5;GX1BBXbfm<(r@tnH1sJaMYAU@6=>uO`Q9TXF{UnqosBzQ|x@4 z|77jOeU5*|^_w?glD3@WEtAh8Wo#3_({@_C!Y(e9xSePh@3U$$M_6Cq#@?ujPmpHO zXYYRXt*0hc1PkUgJmVQLmvSGwINL5hhkgh1qW+t<(&)hbnUw4DzmXRtofltk7tb6* z*gY2|M%pJo$1c9eE?z>sM5-6qOU6CpiJnW96TA2U@{0H+*Dkgr+`ry&fAn15`>}Jr zZQr}6OVpOG;^mW#_Yq7jnSBk!`x!b z#bHj$O#Zj5?z5D~c=EuRh0Na?Y9(J4;TIK-F-{pV{<}_vE%6VMcXWJ<+N&=9jAvBh z?;_OBMO~aI=3b0YQ}QPz9*a;r$Gj~u_gsXUGB-I<)_529p;Hp))E5<|o*0o4 z${d*<%9K1q-5>jkJ$d|J7YBMy%(N;x7h65QvjdG=`Bwkky@6L}q7O%Z`wDjd=GYB2vcGH374}yfL_dQ(cEj$UHT;fxsfl{&iX~rdc*PzO z(`QE)HxZVfS@RdYVvmgJ+r!A6@DHy{87wc*bH$#xZtDElNcAQ=@R4s%T(5*Z!M?ab z!WS3iJ$L4VzN{I#?tY*8Km3%3`rk7U_K%_}&RuTxTuxZdU2655d&;gj$NQk0IC|?c ztEXp?)gy5#VGUmvC3Ej$pBZM2lXr^~|AgJg_gWj~Js=4BtoV zJd0n88)7Y(`H#M=FLA<>*gEU&2aX%R?FG?tayKXMO{5aAVw5tGL!r zJwd%P$F?fscT1lN4GsLXZTOI%wvql4Z{euBpT;jQ_jx94J3DN`c*@2@ z&Ev}sEFKpq&XsaSym^uJ7IFXR@Lj|svWb_+a8ttOo4)*mJ7!o}(jTSzqUbk3?*rW2 zJ=r?>tUWd*e>(Mel=XHG@3I8)N*imlBGY?al1gv-qTZg%+AQPONm9mH+jU<4NL1#V zCk0aD`}&eIq5_Ta3&t*zbywofZ|9%yhHnA+k@v}K!)PPmP7LlmKo{$EWf!{+ei8yE9OW zCJfj1-S=t^e!K4G1AprC?0jb=YNN)LO`9|B!D-jpp;On6d+@+@6ZReWE8+azxbM(z zh}~x1k$kh3k7fLQ%=qu3zWtqAyKLG_d;c`agDdO@4%}rQIB>%L?g2^rw|IA7XMg`d z+vR~C-nWN8pj~_Ih!+oBe>VEDQFm-k{r0gCP$sF%GH ztfa*=t+)R+d`9BT3077ob)X2E9+KrGcJD zt+6SG$PZ_Sd(wL10zEq|Z%P4t4(m4`<@j=0^C!lKg400lxJ&H;G?!E>!UX6 z}ZJN}dC!I38oBrVd?*kw6z9Y+aXrd~2 zv}Y@%PVf0g-!o??J8h80X6lCb>6a9DHea9|)sQzN&x<{i@5A`BdEAr~cUS`C9WnPU z;zIJ1lCL`K9N!cp)QikT>mk+56<_@*S&$VLaNAPF>&^g;wPjGxx?dfbKOuU-N%{mkd74}QcwKFGyUAVl)VgO zG*S0O`qL-va>5{H#auM;@WGW-wbq1o8;t2eUp0_i;%XY_{V9}@ID|u`qx(s2NO0uT1NggEjj3G#LI2zhGBiU)|sP`qqJ^{Pyx|f{U79PV{=x zDc+*~qF+N$+K=%TZNwq^d5G1+g46NRH*HxV2mAX_mRTpCqA&lA;g}&_pNr@h={NIh z>m+sg;l4{*H*%kSs1LJZ=c)VSx^2>tcDk$;snFwbm1i#vG=|3ndZZ2Nn;N+5dD=I% z)LUntqA#W(KDBLlpojNhY;#2aIr*+f)Gfxq@Z%{dkCAx8p?U(`Qu{Pz2id?J2y@=8?1 zeENuV50ie><%9axE|f1#UK}jjQnJZgs!dM%ktb9f1bR%~icI^#_O;)z|Jm($7`L+z zxAogG`FJ3%FBB$|R_dEJ&=VNs&wjh4y^=rRp8-Ajj*fnwHnM!DN*@Pp#~At!uA@I< z&b=e1$M17(9j-9)9-(?LLTC#K*>+QdsvEth6g4f@$a@CEQ ztFzYJbo1Iia>y zCkx9IX6J*vBNEnvj4uVV6#D0B^;w|E^(oBmW`dxY?*v7?Lt%D1D015rW>e6zXKF^!V0rbfa1<^h1u1hxKj>_JNp&-*MjtsCCH!`-RlW*UIly4 z6dqHUT}j}mvx4Oc{Tbj)%!LtxR}$p>Bl2yqO`-p&R&M|)cfopv{$>o(rVh%vv7o;R zq&^ECRp<|5SlpqVCg>jmO87(w=&wWZ65Oi+>9Y>X+H}yr3KY3Ph5igsN#w)YIyZ< zj?bFdG?Bx{#&mJy=JBy7up1h`cRZ6^r&dnoP_Bv1=+;ken9MNMJd5ZaClxw-ZBAf`DsmG-9HNQsl9l}WvGiLRW);D8f-`D(3ZT{z)7i-?A`F72p z7tU`ag+#8CnjfLu%k^h%-pFqk9^w8v%<%5BcJUirT)Y)& z|5X>4vHVE=1+sXn;|jr*%*A_K$z7o7K7Cz;a6kBj&1Cyx7vskr4jp)<1K zyn5svC+`L4`mFObPfO*`CGx1+tOg(Rb42#%9QQYJJJOCHnVw*u}H_ zB)Gfz>8R!DvtOS$PJh4G*$ZzH--)mB?bpmt#^$$!yV)C$Z$dU{q#rP%-=U3uRr^o( zpR(i|aDr8TH)hw3v3ug0FK+ZcdOv$@dG~p58`BdT>urpUjcttef?jYWzr9l$e>HkZ z&%2D@JewDF^7W|Qd>c+aEPdOAsIoiH!#CS5)TZ>Sm5y1`lb?7U=RjLY`M+XZkZ(Mq z-02s67xQNv^UUGIe&{PVF!xhE*NkSLim!|o^ND3Y@-}|J7*bD;)wn%sY0roBvHX67 z%u`i+-Fd%v|EU%HV!m{AEqBW%y(UwzITadl@0^`kg)8bAMBBDdgX}A^JJ`BP5+(_58v6v>*&LHJjUDj zcuZ{LGkoVKzu))F`!cqB$*c;A)83pwWA8r8$!A^D?cMo*W<5G-GKX(N>7xnpjrTqJ zj=PCh+V8Ov9*K{~N!Q)XRou!rT`ln~ex;14K9xm$uVW@{SST~n{Cdo;dwq$c*Y+@O zUT*K6c(2HgOPtR4A!9_DABev$^;GmdHSCZo6IO+kfu-0DF~77g&feX3rM;UDoY?SH zOVgUaWTmu6c`DvmBxyN;w48DHb<#-O4@A+gx{PqpuX{Oh_FXQo{8pWkt$VSn}F*^4%ZwGx-xgkH3UCiA%SO?~Z!x zKp2@`y9^}#@N=yF__X+#Q07!SH0>k&%RYFSP8fN9AZD$My*u+k7(+;m-ksKv8yCuy zFubnwtqPCI!(H@o(l(7fGx_4gNHd~-5$d@VLbAOBXjT!u)#2tys#qO0ze#o8s><;{*AGJ$lrVp7@#bD`IxG@e^Q-{q<8aZ)UFO5souHE9))B#$yP_Vty|XFRwd({d{h;F&-dpoMHUH zxIuLt`{ZZ#FJt!Fzw5NDnaG+GJ$2vQ==4VMtIc?1zh9%rHcFhnDE^(!9x;qVe|nsp z@5U42#>}x5CO)3W?KmA5&mg;xcu$*dCCBr;xG$=>iT?bzDB~GUIg2^>b;fL>>4RHg zTRl^$Q%;DvUq=-$p`Sd`+zXUvWA1Dm`3AE_#vr{hGy3(sj7fyokLd|BRuul~81lQ? zOX9oQFS+>LNq78sA7d9X1`?)@@IHUlKF`cq70g$ z7(YtbWDZswbJqs>$K}^2Bf=r!l`y#d`8swklpe+p#?SHRqHbg^OEKSSSrX45XOC|K z#tY9MlQ;3Q8vSt8MNSzh;@RXsnklgldaY#1Lvy0DoN~K_deM~IC&-&=5#~)EctX;S zy3LdcF?S{AoIE&8<&QJuxw)uC<{jc0djn;OZ;aRnhgiv7ldYa4{O~|bhU14b|Jm2? z2Y203M*R{;UYGje3H&PWr${%RC;lV-CiZD##9qr-l;m4^7JrI4;qH1z;`uVnNIFNR zrOA`@+c@z^dnxv?%&*aP977kA=fX|+;-i&6_k7fsCFyG3*$@^Wr>=+^Ug`We&Lhz^dIS? zlzLj;i|;OD{El(t?;!guV^i^rF@@2OXYPp6Z-z^qE_p{#)K~KSA@3AK-xL+jJg-~w|HNkB@Uybt;T`;q1t9;+TC33uH(mo-3^Pi zn~SBM$4#$2bzig{;ij$JH0u3sqAqTpHEtH9HAsG!G<{vS2PI9?CRi2EJ!!pdclXJh zkjyag>iC(tZST_-GjYzElb*N{R`C)^vs;&@Wej0V^Wi|_>%8aB==VG2|8N*{bVbBU zyCsjd#TnYhVn*6&(mwXGUPa7A-xGM~t*8x8%bZ%;S@c^!d1{UodPmwgH4>M!5w1hs z$%EK6{q|DN(U@@ZgtWJ0+=MpY+g;B-K25?a?ThKGmr`v@)}YXikZ?(xCH%7`Ju-eI zYU@Yec1Tdv;wlW$FrR9t2KFBw_|_OahB@_9*Ir2&q}}%*KrWk00in@h*n`=x?(q8o9M%g4^C^K?@h)@0=ll3?r#^UVr_Ph&^v3fqB?s< zV9B@8Zh4=QPUB?{Z;4m$5Nli<&r^>4!4qWI--jA5Z7Mb>0aj9;bv@3Z&YzE?&jCgCb*t?cs%#N^Z%IN zeI{a0tuKiA&ZuG=Ge(Bgr_9SgWc(%HX*pek-5Dxs-L%c9JB_{jYOG=svEQvZf6Qa~ znH75<{t@}c58)rncj-Wx5i{ZM4px&mdyc$i=J~(w(x(Vb{^UG7n|c4%;aK9Ok~l8o zCw&U<=0)*sFW>tUY2&JNdOy$BY6E=$spOvteDlk9&w9Rl^4G8IDfsG2X`fX@k*Cg# zkvd9!)8?Zt?a>0-m0p{2HvH^j_Xj`W&_s4pnYS zsSkQtZ(7NoYf~|oM%?|K@<+RkwXasiV}xJ6^Ce!(qO5&W@Ne9I#l78(Ki|!<4yir> z^_|80HmS)oV_z8gwmswJzvnP-;AZR4>w11>FX67_JGzv;DI?8Ec#L1gkH){^=GU1! zD&O-qX%r_o_ZHW$y8JWDk43%OlF2dB^@ShIwqG+24pZ zKr?$CJ$uLQ)JbpWr1t%TdW7=)mlvXn=`_tU^?|Y1_fL#}N7NhMTXuHSZ|Lk*+C%)w zH>>PhItL6t9aS6^Q3u4|lHVQa7kN+cF6plejT?W#joOI%&3nrZXHNHDkhd(-?dwza zdG}m&(rXWXAB$Z2!_JfI4$E%lk<>ERO3H4&w1vQC@GNC$4(n@T#xN*ICtuexzxz-O>y&1C z=N=jzNIN{9GYw`&&!vyBzn=Dqdzg!({VHJ?aA#odwecHz{r;r8xBr>G4&;jE<5zz%}Wn;=PWt&!R`O%>^&iI zE&X}o_jtaG+;$gFu-?w&{my)jr={&-`o!pqbJp|If9;$pQhP^!s`DLzKgC_CW4wf? zjJAT}lVw|RzMZ6ei@qwWtmS!C))K|pQ_sDDJ12OzEFNLK{bCPp(q?&|?=It}xG`W~ z)e+&Z1zu%dont?Wc^*yJuVSv(L4I}oj`F)un}YW7;l-?t&K+fCJxtxOL-(`&o_B@x zu{DEpc>laeAMjhWH<*Bzb}jrR`hu_HyW(>C3<|XVi@bZ71Dv=5wHJ9Gy_~sw_e(eJ z-o4oNI(-m@_j*?+Q0Fsd!MYhMEt+y7dQTEp^H3j&y2vx?FQ9%Mb}pnRb}q-x2<*&t z*QxN>4K~E5gHrV z>CY!4mh2lEKYPO*YclSQV z3lkU3$MBa|5X!X+eXE=h-%L`T7X?25d{cfLV zS+lnbTC+D;^L$&jmO2@4_41i>Fui==7J5S`Cs(S&fo64%9pXR;P(7dhgrTAt1X`-Cr>wAv+~N!<*S0X zSUxA?`7W7Va*5@`b<5|+D|wc0_7#b{n8mba_43Sl;x#99eqZ+NxwrcK*|XVCv_uk@ ztU&DNkU$p6iL2=ETAR&-wR-oK(%fA>=crd-!4{tyJNBt?;HMI6jq>zh9ntuI|Kc6x zTmkO#`~R>1vt!^GjS=RJB^(8ro)m0Q=syB}6Lr>;SPz3`AboZTrJ$IXjkm;nzC!

8LjPLuYIv4H|0?h*cu=7~6%={% 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%0Dj-hTvHduM$`~&FZIEeFS8U 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

(&Kaop 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Ʈ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%0ANKkUs$W`A~qPRg0!?TGAX{#ku z@~0ME-ZM^1oH?-O=Sp|ie@IXNkaeEe*7cqyeu8^!Yk;I8-k|JPnj+`f?TNpL zy%VDc(iyovo0s$8qU%I#w>Wy1QKQV7Zw-N4SxjiUN!%-zC5dqjZVw_L26?<=wx*L~ zw4qzV-o$EY2zvu_VLy>XE14I^wrZwq1ZT7>4&F1>GUSYQ#lgF|jRHESai(#I8dOWPFzYy-N?qp24A(-eXV_0?}z+Xec#yqkqyjX;xQ#AoOoz266gSR zZ?$J#Bp4rHjpG`BcP}b2D-z%3#c?9JGs3ZL8x8;Swj&*Zy@nzf+g1rLU*u$y3t=ow zfd=CbY2SM62NG>?dZQ@_6>>TOCc3b!Ta)Y%r z89A3?qdG~H4~!#{fu1Dp1*R0*66xg(7Fq}>?VW`rTKe=wCz5??W=!eZrhu^js@TM~ znThJiBqHipgwgke6W`HC-sQY*jIV(-Jk%qJ;pv$|swM0%3E+!Np`aZul>EI1!MBrv z3hivhSh|Af`$dPJ^n4Ui*R~?1E^-&qdqmgwQ*z06ujH~iwC+Mmq}rW@!LBc=Zejdp zWhrZwk$K_79O{l&F`ea!aDpLO=VGH3*3-@&j;40%V;fXq2G*!b7NnCjkz^V*MJG@| zm8x)oscocDrG@z&CW|x#McfT?p#0bL&L|B}ea8PU&*R|l)>MRJbxU43QLO<(jH+(UR{A2>1z&uDo%;!5nInX;9LZZM@Ibz9nR@=<;tAtgOq zDS3`2azb#>BvBelU2ALYp~~CQd9PP=tNSBGD!drBv)1`iCuh=-zOGNLafX#?*h&yN zoLJ{IftC2n`X?&F~jMaYRU$UuxqfRH>%l; zyx;Z~3sM*_&HspcpUc>O*()T|q91S#Uc`NIO$R1Z=u8vv52Lkf$Z~uUcavGs4}#n8 zFJIkBI}hy~;qU&KR2$o-8lYCredkWd{myZ>c?RRG_rhZ%uFPnLIDjLK&>Dkzs!FZ0#C&Yk{Y_Juh8@3& za`Zm*BchG5&dw3hn<=3B@Qa(xczfeQZV%vh|Dfq8rIw`gC;rQ%?&2bGM&5#v5Nw2t zBS=0kUr)2P#J?6aU%tqAqAp<91AU>?n8E7Jgrd`X{nOihl?tD$a2=SbX^1|pD*(DR z&QXbYpcdw}@$V>VuDVrS&;$u7HUkZH!o2Z?zgrU{WcPfg1AWmmLf)#z4qum+Hc*t@ z`I!2<-z1*0ewg2VUD+N!Hi?t5I5aNy#<(c<=^hf-`!l?5)I=*fIP zmA$EP=t0zLPvJh~o!puou6QQ;&6(Dq{)xqXUqMjK=jVkHOK0(zK6snck-#Q8-!?Bvr8LSikgNoxV>D28z8i7WBdOR zjGK-v)zb`YBB$i%$Wva%?k1?=LPGRTXK^o}y62?`8tdueUA+|aVZKUC{o=aby58)n zN4zj~tu2!U(GVXp)9>U`03r#=QfZBCVZ)d9sQleE*_K!sk>6%?nr)cM>&~V{-hLir zYTVdRskM${K;_a2-ky{bo;x%XaX{7II2zDu30?ubsAC&5}ij2uz{IyEO-q?rluA5 zWN7O5Bkv23?Ab^G3svllOrSuUZlk|@3gS`-z0TE`VCLd?8E;My8Xqczo&yCr9QZTrS|J^4z|AIkWmOWX?932)- z|4-;Ox->g$Dt3nbHM>LDJ;g+BpZ+lVKTYlq}c;36c~&>NHNwk5G&Oi(*?~?VsGpq{$TAMR;1FN*s7HzrScTp zcC+6N);Q|PevNH4liLw`)t)HK#ApcaixfE*38!BDK&+Xl3c9wQZaR~v?O;ojH>qN4 zaBQ(eaeN$1Ji3r<(Huu6j>Myjk9PA?Lci2YkV(m;*hCUk*3V*?YY1EfeQ==Cr&qndjvZ3zh_yYA-7ksmzY{d?B5ch`%6*V69eZJiioRKpeBS8Qq$*uL`J~(6bXi8IZg?3^ z7_WHs^oM#oM}+-VM=)!+$QOI_qUagCRTsn#Ula{h#hV@(7(?k>wYj#pX@s#iyM2xn zg^Obl8N-ZH@cu<;VHHN8pTb&e?C_lE%?kYJ9NO8`os8x-ZdZOXH5ZC6@`56p<>l28 z)2-5`IR%s+AEE&`IPtmeAJzD)4+aO0qnq_|O(ME6`4U7PyTmYJC^%xo4qwQm&_D686ieh_>8LTuhfZ(u*He@o5e z0`TbR=2e8z6NjEM$VleVN8%TG-WbfL&7IQoLQP`TrpOgXOE_id2dFCghtvl|EUMJ$ zHnB=qWF)@Gqy^sU&AdyYHSy)^gZG~@x$FhX(naCks>v!$FXR=br?LyvQ|ZFwvY9MF z+qP7Eu=lR%BTUJXZP9Z~fjUA|8{G(>7vH2ZCkZXxk`SW_7y71 zDxXc+1CN~C#gPsv;50J}H79yj3)C=#L`>I6KBeWm|(ebtMZ>YIV&LYd_wP z6Ow8P#&(z)u*lukXA~wz2Td?oNLJIuvg-|Qk-=Z>jNoRPz|>{4HA;`p%!!rpsuyEH z&J3~FYGy^WeH^j5*3>~MbtGE^_C`-+15j*NcBjjvTA$YYC!pL*LPGj2!G$Kzz;PVEXmq=oJIizlPxY7n!ER;xg8yj~Fs~ zBtpOP21T1TYBJ7olsb$zOlZYLM90 zr{Q~igueQmbh?e?wn~M$UMcao_bH;w6OK>l^S(rTB2|=5(=7#Rvvomwbk;dCa*mcZ za16ydOMQLB=gkyq;Yhq$ScuyqxVGHUJ`W z#Jsgpgr<<#9I=6YSG5JMzqTg8sp?6-+WO9A%cILN2;9;*73#)iq$kpWvbYm@C8-K` zbVQp1^_XjIMlUw+6n~_dT!YUgfpgF4ICq@yI)rU#4lG&GwmdNZ>gyJWW?uDzalWc$ z9rfgWhjG0iu(XX=FJTxlGgg5iqx_ddJIDjKvxOo}nO)uyXe6D4Y9ea_Dj;O(INw~m z{{^bXWli`~qF3Cm1Y_cOMN>z!<1@~8(M4Ewo%zw5=X~IzOBP*n(M9Jp_^$MfAS0kT zav$hupkgAscjfaW--k)?iY8brZ*O6jf6MKGs5uRfc&Ih7gbg|45LhK#QL>l6seZX? zGv;3Jkhxox3q)i4KW1J7Q|@S5(N@A?^QDxbTiP0LpE}N0-Kpw=nxinpYAk6ZK>M=x zrWUw2ntZz?(Bx6gHf+U>x8eDPm$tU)7$e!D8rIR?*4oijqR70eL@gs{b81|DiwXzz z)gIg@vqK9O%t!4jZX>H3$tTra<%06kwmc?v0gmD?ZR)r%Ft@%{hJ1;TihQB(I?7TD z=k`gCVKtpY0Zy1nn{?`{X<8C#LyQhvAq@c@ z(s0z%aCR09>zJD_HdJ=LbS%50Nh)oj04=ZYbc%3J%Ety7KyVJNrZ$<}_-C>(dO_gb z#fV*EqHJhe+KQm2YH;)#PX;ysUuO$fE$}(uH9*;)75%q?=&bmIz~$gmfgb@*0@eY?0!25(2E_BB`x#L9 z)4=nKtAb)3B$D10aI9Qbrt_oddo7D%}*xd2Ex zpM55<6a4cmVcZU!0$d5yVMF1&PV?|@TX?&L<-j}eF9m)8IZgvgPk%qvi~m)i;{ORy z@vH%g@5h0+0qcO|dGR!$!kq?`+&`uwUx)u5;Mw?Z0Jh@Z0gU1vw*GT~l+ogeK;_>k z3lDPW^Jee^zz+kT2P)jRfD3^efmZ=<11i2#fz9BrpXkN=C*UOb{>tLA#~J|NY4OK^ zOy3rN+T!bhn7S%n4!i+Ai-8oS;yD(d2Batzp9s7T|1m&{O!04+X%;R!trUUce+MoG zue9#7fMjj)dw}h@C;i4AXUPC?3HaxMqW?5d@vaAwmBq_}q8|hNIPg!jH@WA8+i6mOKhnIll=gx~qX?Rq+KDKMP0}6z`-Nm;Ylx772>~9e5-7D&SIJ0Qe!` z@xXfEuCeAUXvrqv$G~p{%KyI$jUCaF{{)KPe*jT=@kcCvJ+KJ;bfEZuo&mV%J`F@= z#rFf{ez$ekPBT{t>VV_XR-lnFmBQ#T7u3T>KZ>GUeX^AW1FO`Q#4pLEs9Sp2w{J zSAit0__ILqc>sv0#Ww>Htys%g%W?k!Q1yNbFaq3U@lRQN1+WeGn}8&x_!=Ohn0@sm zp}4~0&(o+%u4jQnQT%y}ZvaA4d>@dfm@;qbvBtG?siJ~cpxT2F1;GU?!FL1afD2v@ zz7cp4xFGF`u?IUHyd8WRcnEkgxZo`C0I&jFupIm_@y-Jmyb^pbuo_&j3Vb7QHn`wr z;GMvk;DY3Ux;#ap1Gb%uV=Bv-M;Ll7XPI6Z?pIoi?6hJ zpT+O7_*RRrv3S45*I9hO#UHk~8X-NOv-l*7f7#+6xA`uzQqeDl+xetEd4l(|4+aRf3n4^ zE&tOkext?DvG^7%|AiL+sl_k0_}OQA{3riWc{BA7}WO-i#vOk zeHLG6{dZb?k;QdGywZ26#eZz^vn>8gi`QHH_ZDAg@mGY8^!ePmfWsE=JI7}pM9n$( z@*x@ro!58v3a{Z^=VtCa#iQ4Xmi*V+@Sm{Z$Kj@DrS)Gw*~2fl;cv9zW&cv)7u)dP zCT-&XS3Vkger)~At^ZQoZ2wk}Y+QZhY+R=Vvhie||IK;+C+G3ok>{_zdN#kQ$d-*C%EP6r zY=5=G+4$*s{Pj`F_LrTFY`izmU*EB8|1$KMjlZ7fFT3yA{=dkRXHlMhwEmw>ukT_u zzAum8S$W~Vn@8W8=f5Y9|3IGqJ$d-*Jo?Y(;rsJ&`ZziAo|cF6ZOrk%IxoIto_}{9 zp2)+i^KhMcMx^x9l7~m~@Y=la-Fg0Z<>B^Z8x|+c?2|X+cI-28)^!%JjRCOF;2i~7Q>r}P9M)RrXQ_c%q5x>w?508u)0yFX<*IwGCw6di{{Xr zm{@C)2JdKVxV0&Q`OYS0?K33yRkka2^IFERrLl5pLN-St?ZyPAVOQ4-V95q>K zBx=_bv$H_z$w=aL$g)Ehr!n8^gp`q0_ioR0VoFs;Rvn4#q&By8MB3|@sQ`2=TiROR zVuQG2n-(=W8>wFrxk}bjJxK_eCyF;+?;=G#jnQ`aS~IcW4b51m0rKBK&%t9yk-fHw z**%rpj_a6ebYg1mu~p|xDTijw#zvqiLKl}uU@_);+gg~lt<#zdfrMGF`i|RM8>~~h z*qT}UJm&evUehvO*A#K(TS8jCxh+ZNtZSz3XWWLV+@nOblPesreduaPVS6-(loI%VwAQAnzrLv=Dad?MP0hfocYc& zXBZSCq^cc!RO)C@ocdfW)0~yhVGNr(g-mn0$~JXc9rDilV&*r)UD@@n?JJc#^Gbo7 zbJlP*rk~&Pob`Nt&;#Bl{k?z#-s`Y`*IQSO@AWvGISkEXXpX@=@ARCt?PmKNKQS;o zjyh-k*5{(9*mzN$c{U&)T?=CeiY}y&xfETxr0+K#scL9Bw`4d!ea{zbJKH+Ad#-~$&dZZ7H0o=n}j_*wTE3JcMmA{koL)O39 z`WFGSf@|(Q2Y1%UZMpU8MLnzR%lTe4Q1?_(TC>fW=X-kPojR09u4(3KCT>WrlP2Rg_yi`GG(YG-z^;-Sq}O9 zT)I>q+#`PO$yd?a*+c8J^3_=ex(6-$vFc1ay`7zfeR+D5yppe-^s0=*-W6%XQ~Xu8 z<}(j)EwG(Q{B9H@G3N8rQ)qvhS~{2C`TXAPliqZmU>2LJ=Yj>A$<`h#j?4Gl$D7^K z74qEwS?thL1(Biy;vC=Er^K2Um~q4-}7-%!sBksGuJ^coD=MrtsM6`7|qu2*<$bz)|y-%CsC0wVx> z>dvw8)Wl09VoiLu2hQ<;2EplFXYS^8vtK{Wv}9F&;MzUEfJ3ELDRAVl^R72DUH49 z602-bVih0}?K1(yF19P%Fh^CQxhVBZWu(f)ao*0u|0@OY?TcSS?OquSTE28tmH_N)(m#d&+pLLVCk>;rJ1+d`?@gz{bLo%F!#D_@?8x07I*Q11!79Q)Oeap*w!F3ce#N#$z(hnsyS*=lIVt2t zK4>C0iB4?ww1r?c?m?qJ>*)l`c*@0kI)O5taxtFn^bqD+Om>y^o9(ZIu_AKtYcKq| zKNR1WdfBu=#*7MQo;D$}bdcdD7sCzvo9;Ek*d(Q<_t5~2QQ4scNzZung`l}Kp_PfB? zAB^3{S(Dfw3W9NuEP6$4;=7Z};ioU#%r3pG&~4+cL%YRR5M6y71b_QwltdgTI>1F$A8~&61(xA-5+)V z?%Cr%s*?9Oy1e_wHC~MHbK^?Wfl>%ZuXi5NJ;Kk?T`osG!_e)*+0h*(XUMZBC^=uw zqSJbbc^toC_NQg2iKi+w<`C&)oMAmKtls&vU&!109p z2f_-z2)q>c?ZESZbwGMXB^AJN_y>T9Tznj`68Bd~Tp3XJMF!bYQURO_E(^xfc#%BOSaR%WdMSw zIB22F&nW$80*?ny1WIow0;T_PKy<`=wd)&qqYrlc~J18W2Qr3UH4Zq%o*S*ntR$2dk8~!O9 z{ykQ|Iz}e>`)&9t>z|~(((`lc-)#N0A4Ks#W5b_BScNaL`B`J**S9mY{_ec+H|OEY^7#EU&p&^E&sBNxU6O}4=HXA~ z@jD^Ue^Q>l&dBrk<>6EF)O!LRNty~dK1)=YFj{E12;CYHzSh1vs4n~lBbv2ZMd|riB|)YY>~6>uQ6UM zAaiBsvG?5!=kMLLnqkl3Ne-xzCL_Mxsbk)~tt#HQ$R^oya%>F~&#At#v2Ga3oaE$O z7F*|q(+&fVci#37v-My(TNtt;NsF50rh92vS+92&&Lz`u07n~^zQNljl2yjM`+gy6S=Nxb2sfSSS=@{a9=VEr z_U*o)CXS4lFi1ygsO`oMR^3c2l+g@<#HnLAyMj$ZI+U25oc4M=ob=uuzYWc8xx0nj z&Y$e)8{B>nPxD3<=+5plQJ!SS;$7csi0qak!z-&+Y1MDos&*)%X2qblILc$o9D*N!)0yi>g# zw*6c2u0C(?{P9+14n(y@mKLPqwRRxHB7cuV^6v}){M&cOUcdaFYy4Y)=lOe{Hk4cD z6@-VF`9Cj0?1wOTJr1*sKZjf^P*?=KmWlG7epXNX-8v-})O47y>rxDnd{k78St?gcssM>Vds-xqj5s=Bt$ffi6@(@7eLEHTJ=H$&%|CQfoCJAQB&-7bo6CUDya#I zUw6OIxzuJsqH2RvPpT<)_#^&xHxL^sp5*Utqw?`~p1=D#&uvapSHV!Qwo9S8$vY$w zmLozsiOCcuKMiI4#bErWMiEu;_XS>WlHy>_yoHK zzDV-O*^&PHWF#uBDwS9$}N+?uzGcE9`o5L~0kR~ z@^i-bgd1T*bFw;AuzP4fshWq`xl8;#nn7AJSiKuhYiyim>V@k2Th1IoJM=0xwz-}H z8s*?xa-zEXf3lOYnJR!Uh3XV@m2Z_ZcGo*oXY{yb*|chr;4tC5V)Z^-YP@A*kDSu@ zDHA#}wrXulaX;o0{U*QI4S~!-{M6LHIoAJxn&o6E4hhpDa4kd6cgWK&jBES5KY_sM zJa@$;`2dDThpSvh-@m6AWLGP%nCP11;Qb#i@NfAAEr2u8mfZq;BoqH{QOH2g3AQnG z(Hd)y$@jo$pn7vbax5>DUE63T%c-uW9H@=Tt@B2#tMbH3b0scp{$jM#`+Q*^Xz z789Vh_pUQXhI$wEYwgloo;(1#^0NDR6kab{0l{Wp!!=}Z9P!^&4SdFf$DD;q|O?s=CbS42dckQ zkUDLky00KrG*JC`L2BGU^_GIvsDbJy3Y<2zBgb-0E@!RDzvWUsikPu&AL!KL$5j$yZ`>5Q+rQ;_+6qsqirrjaNl=Pf^4EvB zR=fJ!*o0puF1P1!@hWlD2mKvdrV|-!c-J{1sR&{~C_e$+A7f6z^3Z zEctQbTau{#R`;IB!rpmm@88=W+h35vLLHw$=rgJ1!VE+<7b-ac{{F}ItbSd*I?gz>i(O$#*u0#CnPximh;{QnR@Ha8g!p9Fs>gkisiNn4 zoh)@$noLwj=(A?e$hJkbRpeDZH-i^wF)WjV~f7P6uY&Gb={bfcf8dw&jHp=p6nG%aar^mZ*- z87)!KjbbTL$#e?MJ5vi>&AyVqJa(PzZSV7&Bw{^oUERaXe(NgU-FmU?KbXhS z<=xx96Mu$4C7%Vd4mSHvAj&UU1Z3@~I}@nzvJWA+ z5vXtq>LB;+~Usx`9Ku+TU<9`(1;d)#o}K8(rOfc!s5L^N=EUeK&9swFqgbv z017X$@FeU0Dv=pFpy*~;{A7#&jmYKy98muET6~7Z-#{4oKM$1uRtrCG-S4xw>{E!Y z*us4XE&2z6a=+Zd_gi;0lJdXa!doa5%CF0T%6HaG^_cSlOdXi@O7IB*{juwnjEN^i zg~MYKP|uzGw8rhm_4iu*2<1l4{ru!V%FaiqVU$uC##lL0o zvn~FF#iv^QNsC`(@$U;qM{b_rCl>Ft{v;)5J*`nV^s=j>=RAI*agX$sjbEFGqvIU^ zv-0o{=HYJk+?xU#c0%6G$<|dhEve@a=(QZ)tZ8F`g8A1v7DGC2U4e^tl0v5_j&T^) z%`$1iw56@B-Oc^wo*Z+>ncUeccl62~opOh&+|ej^lByzm4pHniamaJba~Q{%H!Lfi zR?c)9PtLrd4o~J>B%eQTNS68LD`Nuucr-tDz`PCr$I#-{ZZp&2RCBc_X6{EJ-|76= z??uex`1Mo9B@>NJmw6quW zI-pbgc>t(K`I@~SKyhn7hiil+kNm#?)T8}q@}HuBJkq;;HMqV5*|=+;Z2i;fQf5Up zXCc;A(d=c*?E7!i{)UBFwlE7jX?HDm$~kk03t4DC-qk$&tcqE~o#R>(VIfWDtyi#| zl|9iuTsyK+3JCDydAoV`#e78d^joDl+_fX74Z#1Mwj-DFG1en~%Ekbb)FpB_svUXj zd3MKVmcsJ9Y31~=quYSDYnM8$T&~=eQ&E(*wG^0fKtA`TZe{aVo!y83B;Wy%DI`eU z0@DTn>DQTGA&@?(`YrGJ$!eGA(C<(#Y+uM9?j(_ycYjCXQZ)o@epc&8(-j&t*mm zt2fnhu0yA#jteKMn^V`<#Jv+cp*W`hgGHvr{VDyi9UDoA8_2|eAVd566f_*K)+KBH z?mHj~4_3E}E<9Kn0C06^rLu&*=(SwVb4@`wetl=v+8Nwa6m1XnUO5!5sP0@bvnKw# z+W4+;VpVf!^}t5RGinp#kz%~sGA1^zstt3=SVA|`MXv}ZDo1gf&q)88-E^Qry(g&C znVEb`R8Ev0DkpNzz`y1^%EJ@tXN7vra!~R&siN z_YelsiM=8A3b`c5Z*C>ypwXt->j4&K_ymL#p+Gnu zs*LwDacNRfRWPKy9EIA_d6``7vGbJiMZ7Y+)9fyTCf*+&SsBRiNi1p(k6akAsz)2O z@d1-8W%4&r>JzHgX7VZ8Z#*blQ*;!ntHS5+S)@EMGcQneAtAY5uyTSSjFq3|@4gIz z+W5h6qOxePvJfI)QhN`P4pF(j?kiM5f+)ZIJ!gOfhbp<(Q#rTEq`taY<#a%aPR0%K zSbxtSNC{^cHnGs*?|B|X`jC2)3lUdGB0ofK$|AG7`;t2-3{UVCa22O2&OI=hBCmu!0!i|C!Z|S$IFQnazends zRFWi$T8L!3=T+}t7m-(NsLJ27S81W{0(?nXpwkLl&y`T7+lsH@r%&oYP z`iokC*w6|7o)^@hAf;Mn#gb{ccH)!Pp3ylup3YvHE(wCZRSr!o%@&f$Lr%NR^OZn1$Kzwxr zS*9?sI;rj1NuAXQ#s;}qi&pvG*U&<8iKqQr@2SD@7S;|u6*TyJ%o};2d{3IYsf?UE z!6m0z1$Jq4-@@?F)5(n@hz+&)yN^hS*igH_$GpJ{A$-Y^ih`UEB^GUpy%~tkOKKa0 z=VI&MP4F=FZx=7a)W2qz`y+mq(Y0GYIXUIH!}83Dl4dbffnch|W+T zWmZmF|DIj8y^g2-6eRysS#4`|^0Oe8J?Yd(j1-f0>0Cqc9l1#ZXd zFHEx_`s1=9Fwu|7_8pVuYoZ^K_T9dqs4(`%b@z<(Z{f9bv7r;9oSCI(OF`D>DfOsoJDK52 zeZ_>%YmV<=;waU6v`^$C;viv?t*oF8Lr@_C(_+>-f;`FmJ=5_)I)C?h=H(K9_at6O z+eWR1dBfXKf~Iz^H`Lrfd}V9`8%V}^lMWc(Bp>2EoQO;=D)X)b3lCOJHe>f7FXP|u zQRZ{(fa9Ua7#oBRf(bD=*U|T-f`h>fGGiE_j>+P~PPo{v=BzcmToyHn(s1Io94W$s zR~jj*<9EwAL0@Y7I}Q?z-|PiR3=`x^X)p5cMsul$){p)3(9lT~nROVv z62I^ByX9{~Lto~13TujA<@YMTd8{qY=JzV=i&I!vypG?!{8IeRX05T3Ul(+Lq`dr{ zUkP+K^IOMH6BDWL-HZs#JryUR5( zffCdwM5T6?gC%O*O zfQ1u%vR#Z~xEE2y6qn6D{<&uKcz_ zbM4nJ4u}ulTs1w0$!3$82#~prEE6n?!dMkaJs)X{)VBnDD^_-vL>6>h=PNCnHhsp- zSr?aAl=y=4YcuF2zRRk@*Iw=mlw2NAgnHiTJh5tndEEM|MJEHR__=xFDb_tbpPY3s zNJ|!-`U&RA<97j$8tgfKA2zzc!O;zK?s``i{kgPe=5h4)9*=XF_hSmLWQYkm+QgDq zfWlt{o(cQ~kZdj1y$qa>tZgA)`BzwYh@QXjM=k8K@N6KuDbf6p;EPP|2x^i?FmB;V zOrbCbJG++Y1im39D;aPznCqP9L0=T21n+1;t-$}e$C-{(^x7}lLH!r-`;!CXmK8s&r@%_U2oq}+BUbX%o zw*LRHc#FkH6PMOm-8`}1;^lVUISLQ0L(~{-(2YKN=((e{UYHt(w{XyYj;S zEf3$9hyNoFe<=^&nun|YX2DFFob!6E#y;RXT>QzwHH>2N7qxN}Vk{&}by=%kIRs8)$MBc4w@mMr=Pl}1=gWL` zMkXCoG{SOTi<4Ad7`K!^GizmSIC8~u?DhI%oNFm7z1SXu$yu*oxvZtJp?*bUdZ}%= zbvCo+9-yG|(1xbhG>t>vAI%Z!aqH_2SNo|S&5e29={lS0j~>Tw0}M>BQhYM!MOng6L(HjAI)#C zz{Ot)Vsvn4q1+jE8%3J+_Co7Jhd9rNj~QVG=avc%N@Xm;m>c2s`i}coC5DqxC^@kof2HghS5!cwi5L^O|&?WlpQLakH1L-Q5b$PPPd~eAc^Svcs%=Z@ICwvAv zeQ*1LdM@Rs@12wHKH>PgMq2qRfA_Qr$6wz8Jq`S_yv5y5ckiGV>k;_|GwB2q)W-sxl!=z7Dng%!RJj@FJG4}@@qrExCxx!ml z+%hxW)}V@`?6gXE%4=Uhf4ug_;2wI+zkPW=uDx-2@lM+t$0na2?p@AL@PA1keDKVL z0%@J(x4-{i)yMSd6~ldx%+(9#_J9sgCHeYL19VVI3Gn05_h_xlWaEolqs6qD^zq>*mLWb4elb4kd-T@(J{+F{EBjp%DC@D}rd_bR%gqImEIijP zu$Ei&m}VN-MdPTn^&_A4l6U%fyL}`ZZ6H_oHp9>8-ts%v_cGv(^L(;P+)3K9zn6HK zJt$(W&kC&G^`r0Q;5u&Yn!aeR?7 z-jZ^Po@*`oF?+#rzCW|E;(&OvX(Fga3Fa>RJ(@Eg&aRz%S+I(|&Js;Kxhsbq#$mMozB)NP z+4bb-f{Ck7H?yNSUWFrqcxF{uGVj)%IH87}!GS8)JfDyTndT(ssAoks9G^EO^f>c` zdhQ8T>_&RT(&|_A^qP3}W~?TfRMo`)yCzY+*)0Ee;~N~D7myZ`w}NnD!pz0r$a^?; z&lI1(`&q{j(y+hBgiWyVK#P5B zC-|#*VLJCXxP{{z4nrl`JS(c4ZuzYdF*yluBMJ))&nW(F#EVP65ze^SVi2~)KoUaY zOMcD-JswR*#&eP(c9?~~nM50IShE13=rZ}cwPb46bJxi!oLCnEu>Ir&OEjF{IO~_8 zW-ZPuNzqHgiHF4^++Y}PM+8#$4^ow-pqlufSfW5jnKGr}cyQ3jCE1k*)ee^lKS9jo zPx<4L@8!+2a)DHBMshQVM<1DB^m9VAh5at!p=U%wDfA^Zb*_>X+{TM9_PXD{?q7Hd zHS7tlt@0OI>Y;h3CpBD8bH2$0TQi?@1rrZTQ58@6dw0VkoLHmOCMR2R-hIiEEF>#U zNk8t#&gs-8s#`M@)>cN!?B$@*OVZjcRSC(dp}#Su#OYC`nNWp<^7niTS(xkHT~iPU zC+1D5DfnIO)IZcr-LLB5oe)$4Rhm+FQ@!XwpWQp2wa;}*XE?D#3G1!$jSMv$O!tse z?;*&?!ffZ0LN^0`e*0;#k z4VFFAmv5V^+kGF#nnhEpS7 zshn)?RrhtB$C)bH%wRKn}0kxvCbwSDjQ$*j3^{RBpQ=*ccbE)5Dkw-d7x-G`po zk1f=Yzxo#p&LR_fuNe`J?N}_){a1gV9pI5uW3P{lo*GVkPL839eIfr<`%)9R>mYS9 z`+uWjtxsw+ydtcUAL9H$;&PV4Q{zmhHKe;M$G z>QkY?e)Zju=&9@l^ZwMIm6lLq%#y@9&9X0vul=tCNAB0DQyyQtiT6-q-RU5q_}Yyg zc8Z5>@UZb7w%)`3uILgE>jM>vuU{+2_}VVxrzrHHBZ`-BNUU275?{OD3%Jl@v(Llk zd)QtN)3^^dyFE-5gD5JEJe}Dh?_m^09e-0eu1uU3E&l!sirq; z66Z)w;lwDc_gC+WZT&AWhMC`jqHF6O6+VBDwkp>orVsW!%?a}^oI<_dStynEJ|vf_ zxVJrqk-%9-=~W444qjyctCt0wTJua(B(H{1hKv8h{oEg;`(OaN2nL`FUjRiO(A@=K z2Z;o*-vfIA2;hNtDZn!bU(>tQWL57cjlO!fDJeBpSWG8;dq{)lkZIapOglMLs zBJ-XK8*nV8rHbFuTLvv&tBSv2h)gzKTD>n?#6f>$vW7$EUIpWwsk=<-giZeYx6H*# z3|Az@4xbU79_sBV+(85AOU>e#$cRucJyte=BC5gEsmh9{=^gq_meGG&+AviFGouGz6&K4FYoih}+7FMD7kAv}7 ztKwg~i##$W!;D0s#0X03-rB^)gVm2f<{KF4t8MuG+^+AQ`y+`FIeuVd0f&x~Pk|YU zAzvH6em!$NYo9QF_{Km`ZebgEZRA-W1n^|dZhbftqZ<x1u*g8!cd67)N$+7=kduXT*<#`SBIBE`GIvL}>2%y0G`7HY#75Qj{5f~zHa@aw z5_XJJY7!?%D1cN4)je=L9E-Ytz1IGk{&0c+{jaHCA(w#?UWzPY7?R0e*n5ldB#VF4 zUBK+v8h_Q8!Q*u=LFoMasxhPQ(P)-5V-vQfUQ79lCUI#xH+FDp%KxYyv!~U}ylzbH zMb;KMc$e~=MKPA3a~#byB$#8_m3z{pi{_=F>;!0QJlmYP%VZAW6^yf8=zZ*uOPS03 zT=~&n^Gp4;FCzms%l4WQ>8*Pido_C*9JnrW1XD3n#K=3*JoqJE-OGcA`E@UE9)+p8 zBl54!$fEg8l8*K!6zyZ{{`XLp>nRt^P=3p2e(6cdDtB7f15X2E*%Nl$U>@9gLRS^= zvfIxo|N7bF*dX>2sm@X+nIK>u4sCj7cJO{9lm=UG;Zs^EFB&~DcZM~f_=c~LT-rac z(hz%$bwV|xn7fpn?+#@jV??S+)nLj$ciT?9ENj1$e!Xr|EL)c0MCSJA&d-e6mwJ33 ztTVlLDoV!Nsvf>Y^{(0AztE_HWo~PsF3ZtQQt~?{r98OxyyET5{W_UHuW~4RQhMl< zOPK+oU+mZe`q&oJ#V~AFcuf{HLMBR+NZ7n9|B>-$DH~}vLCl-y^vY!aSd*LHTW7N# znCk8Q2g`#dPu05_TzY<2g1o)=*PFl}lo@dA-hc*umE9WPols1rM4`9rUtPKMh%IHA z9ml&F^-Ch&{+xD4SpEMJn16>-Om^LWg4Raj-5dGu{ocF(1$@)~@s;tr@(S@xw?sa@ z-;7y0Q-?{T!_lPG)3>UvP&h%C9lYLz)%YwPKN~c6y%U`kq}@i=8t-q0%>RL8fzn_D zf1t9gczC(?H=tv7po3@F7~*T5LQKs&(EE|`CfL72d2#W%z}2Ip7>T#~=pdu263?E%g^kvo4#tMgd;pu{ z9h<>n^HIb6GTsmNn9Ax^mr2pzPbUer_Ub3R-wi$f9p+}Ev+t&JGeigFxRo!v*gzM8 zS3lzQ{)YH|q^W$@)cQ^pohiVK_pMzZt}zs@#_yA$!+pU1n)Xej+X_fcvP#0Il|k4jmSyVG{`Tta3?FY%tz zba#o@BfW*m`_(2g{{1TGfprurTNQL?=M(R_8ZR63glJ3+P6HPbp3eX9FzK&TvUT3` zHqE4eOXViglIDJ&*KaNzK3?ZEimLTYOFn?mx``R@ZYIwhLSN_`Ufq3`6+E*a zcFlC)y^y$P4H>XjKY!i{tVw~5WLnX{pWtlq!Q&2K8t?f9(#vdIIZX9|Q7W@>Lhz3b z9;I@d7k9x zUx;tg7zVFXNnE4ONYrhoLT#d&^J>{~JIKNi!yq3WMle#cpV~GhO=k>w@_x0Cp1yUb zkJx-t{{709CI}M@z59egVC44AI|6;PPUzKj$)QKF&KLjmi!hDf{WJTu7g8wM`_WOw z?bEVQ0l+Wd1Q*^Vch!0O`+LSvD_!DddpLQeZ%(x!VL_P%F$?w*0g^oy>{6xjm2beU zVrElx60bTLDP1)(Hc4LlL6_XoUHN<3!KlG&4XIzA^uDOCli>k0{JtUD;AsWIFTEMz zkb4OXzK0G|Xh9UT`gX>9!f;7Gpo4JS56<{z%(ZW@>?y;kb5&}TolC}RfA3}$1KM*n z`?JyvYOjA7c4@3Hnh!qjmP&o`CG+=H>Qyn?MO?!g*!L^#2augN_&s_f=)>|3y;^dY zDT)?#M&&N_Z_QASC~#G^@nn*~K5X_K`TI55I3XForMvPm_z#|F%cLY4(3|`%9ia2H z8t?tpyEPfoXUQ?lg4aK+xl;72glwn0AG;h4m-_*;ouqe%EBaujVTx$*j>3e@OiL4X z(IVsDxwnME*hbUi_3}*idNcpyHF-_OYuUA<_9=#eRg2y7g=VcLH(hI=LcycVR~}a9 zomR`Zq)(D$*L{`dGGg{U!PvqO`QE|zg>0qj`z-gEnKs=+>7d=&mYt^Eht+!fv0%wO zI#D!@WS%|q1G#ZK=9P@vqOmQs2Dea??Da30r6lh$48NwFq9&^ez0RM4GWAsN9ka=v z7E=9rW4yzX{-;%q-i2ef=*%WdrP;&$c@w?4C0u}>)rHqR`WK(K)4OnDrnjk#OG*jv zM?s#_jFTGLk(f4fe;Lo!*unhu(5}HF{d4`!G5-7#Q%W*@88?${tY2o2BiT)`m1XGc z`24vi_qF|RG%^CSw<0Qx$*t|wJ+GAzU~F;kN5D& zydvG?tKUe_)3^Fx%!5BQn2ZiL9n;fOZi+~uGk3@SCg;jKT3S{tZ(Pvj)TG+v6 zi)g8Kte3YZPHjFXacXA_G8wcy6j^5{)=@BR*}`FXOk}(nN9@(KH@!8|xdp2fiEQh# zma6t#HkMq%4T8j}ZOzL%6K<=-1fHIdb(Tc?@{`8LLh)?I#>WbzG+T}&yk5ud2}{5V3uaZTa!PLSg>NX4i22!Ic3TevyndVvh#BinaH&@FF!4txUzM5a{?Qq*bc(14(dS@r=8k)TFmJAOQZ{)WDDb@tsTl= z&Ky^epe>!9WO7+++v>!rt>a@CQQao`uqSp)JKNi?q4r5boQH!{k`W<7NvjYMdTDNa zY>pF=n&rfVE#0L#SGuPsvbGd-O=5h^WapsmZJuq2h=Q$^#QcjJF08GsPiE4W)l#*I zCC#+Ua7~G5!Q6U7mA+`fWtl@#MR}PVCYHBjxYZ_j(Z%!A7u2WgYi)%Thbyg%F0QG~ zBtL9}LmpxtB1Ut0a zI11=L7NrlJ*UyCL<{yMk>1RW9V>M{X1?gW{Tn?iDYKZff--}umSj9U>$Hg@FLFN{FYVS#o*ruUJhIYl>a#372tbl*lFP1K=wqdz70&k zzZp0g{8FIOO#)BE|7@VreJ@by3>2?k$eEO?ZXj*8Y9X)@_-=>4%-eY$_#c6azZ1xP(TeW@ z>CaW&zzcvKz*^uqpy-~Bo4x#s-N16_zYhEW{(mVocRs3~26FDH;t7ZAJ}gyMaX#=$ z=pJHzF&nrJsB%gJ#dj8vs;ig|qzWn~0~_!^9Jmnp+C)qDXCOsd@du#7w*eLY-wwY9 zNEWM>0LAyiK#Hp3VxY>q7MKB^1r*&$K*@15Q1v4{zht%I^$C{#1z-mMKLW*XH;^n> z>;fwNX6HX2NERzFbVt^Q1Z+NegrrHI2riAC6?a@ffs^H|Mc0wX~4O_f3m)H5hBPw@;TtY z0xI4uz&hZ^U3fE4a()CTIWKhh*+8;XQ3d=U;V-gIMbcF=wjsV>c6cXH<#Yv*tW;bC z6#aQXwJX_Zk^EzU{8jyxB^mMgCGaxfe*+c&Yd}P=(3wm5>ztna8-a*Wkp?RM`++Io zkH^?@`yNpJay?LTod*0U_$c6f;9nVYh*GfysC<7OsQlgtgrwpVK*^g0O3r0K{wkWB zzwCj^U-zl2fpdVW@7??p)OUpX@&5qD=gUCR-v(5_odLvEOmX1}7k(UY5#dh|S#o~^ zBISD>Q2AL*_#}olLE3HURN!=QLE2fVK6Oq57fgU_g?$RRU={c#;J<(i((X!E0Z#`P zd>?o{@V(%Iw2RV7z*E5mDd*CC$WaL{NPU&=1WpAPJOg|q@Dy-CL@@WgXMlHr(+!Y4X>lf#d3_&E+gUO4If zZoG|O<-%Wg;nL6~e!q3{o$v6Uy6_8J{3$Mfm%8w6j{c(#ztrK)4qxT)We%@$_%#7u zZsob&;nfb`;PA5@{uzgV$l?Ft@EaX|r^El(;oo%l6Au4@!{aV}Z5t}T_qp(XhmUvo zF5#5dsqeJ%{mzAd(ZzpOICT=7pL)^ZH}lexlg>YdKj(0r-xXfYOHr=U;kP+_hQs$c zT;qx8>v_q_>HMtDr}nt^Qcsxf`_FdtH@onsTzHEMU+Tg)l2^rV=Vc~$tqb4j!k@%X z;U6I%a_6}4Elz&=qzV6t38l}u@EI=rA(#HSuDt%ug(sZ+1e^FSdhAun15KHWpLF4O zix79Ri@(@~{{VUyWWuL{gmKw_4&(U<{TGN84xbnae?1cZe1zXM5&SC=d|m|CJet3P zE03f%JA$7Y!Jm!D^V3N9^^x#}k@T*Kg#T9rzbt}Z72&@uf_oAEpNoXw6XDkx3I9zb zeno_yIZjb|wMOtyNAQ1*@OvZ@z95qRvl0C12)--A@2`>Yh6w&fg#NHdxI3e)6_~b` zB_YeY%iC941FI1;yI3vhL_303QLNQgbH+K>fv$s=Vb8EFf~#^U1c)_+)}%rj8cgir zlhL6SDJPj06F5m7W+*Rb{B>F9a${fxio*Joi`d$!D~`)snzAyEYSUq{i$$!ar7cZY z2UO@w2o7o+PC7wtR)JVtaWuy0uNKM*CUgso8#-3BuL`b2cU-lia{&eEqFvLn;>vam zpIRYI0f>pQzih;@mWK^@+1PD^I7rdP(OQx7;oeFhRZAdOU}ra!H>^R}H9eC`lRfO- zmTm8Bb$nVot~slrvkAM<#&ASi%W?y)o(;pOb;-2Wz&5pAJ#taqQqqbBV`+JWpoZLX z)`%!sQxzTAcFWsn;AqUYBZ8KPf>yP>efgD^+$3u=)6hmUQl<-~W&&vz&Lh<3# zOvrP%QinZ@b2jX6yp($L0UF}8ILn# z4XoQ~&5pXZL1#M{SoWAsVX?f4{f&-d9@SGF<+Om?%vi&6n%Gqxtu!mkZCY@>U|JyB zw1RBG&4lV8s5%I$4lXBD2hpp8G^%Gh&eef{(*ilF1JSF|hay=UT&)DMOb=^7DK0-# z;)S9xSW&qdpGY|vzi>Lnqfi3E-u8X|>Y3ALB#bM%FJLq;4Br+w@csnTkGEz2WR)V| zI(RS01vuY^=Dq;02jkxAeSr=aA>j8M^D?G{Bit8wbA2iSpAsk69^{m$WiXovoNy3* zDjkHgt`J+y$5w*4&}kjVII+@C@%eVs_to2W+OcuQ1WdLbNWj7wLCKzg?m06LPkD4C^Q8JsBHE%s5uQC;7Hr$i=OEuNF=)otkK5yVK=A{9%^43}dKaQ*<&o^3&4#;5~ zvcV_ijZO_A%!TDfySNj|o`ViHq-212zYf){O6S*=$Fd)12eB+Y^Mvei$O8vV5Ln%i zSx$PVNR-3NX74P>HMb4Ci%JGdP_1Z7!GC|s`(<+IGFe~Iq)9qoT=|$L80_(RzsHEd z&_(52R8wa2%E{!4iPMS481Izdi69(xvnQ-l`RmGKx#x%3h-fIG$eaKyx7&+4D98o- zufaNlXC3Dex^I&#>=CABo}E1|<6l&gHo3F98_P2$cPa0PNbWM;#pDhZ0VWUWA#{#& z=-r<~UG-(LO}Cn3@9X$o#N`a0*;G9-<*h6kE-F)fpKcZ*?gf4d*J%K`Mf?=r>B4_5Tyb6aNiIC7->jUUVRtPrjX=sS8Hx z%&#!IgA%m!ejm$DL6bwx%s1Bjwzm3}!4IVTHNW3iZBN#7jGtF%%~SitBGvm*jx?{0 z@p9bl(j>9|T7{u+qc$OEPvMk=&Y%>(?cYRio3WcTfwy;gU@|FqiMx|I-tUKBx8|6< z&hRj~dDP5rUQT-dZG4UD}$FctYw6z4spIfqWLb6dsS1bGcz z+NPcJS}h%ZxidrBojTxhK~W`gOrN<)-LACvb585)DrVD%5|lJ&T9ZQ`DoOkCj6Z#Q z+CPD7F#bn*MH^djhjB8BSGHzWx`zU#(c%1C4#F|>3a)OYhc2F!@p3y;zSe_ccG7k< zH(;v!l&w~d@(wZSGPya&Oj7>DAyJc$w0A{GowuC%)8&Z9)NL(XR-(t)PGiXCap@rx z?RZZOp6v2V+Cyc7?{JBw{dFZnN6YVMb624}TA{k7;ELbfVoNp6C+8f(du3=onVXRD zPv2hWx5UgGOEq%7xsFiC`Rk}C8k(<+=Z>oLn=6@jK9l>6p&sO<^qBKv(adH%TzrKQAFTJVgyMY#ZJ}YFC4Z zviq^5Uz^}8>VoPgxIwd1+0FQskLwbGayl*LAC~daYOcEk-1I>acJ>{#RMX&Gs~M`B zM9a!}FXf&Pvy{JZXKLudnGde{Ho1*90sDah=XcZgY&8}7sr>>em^w7`WAE`ThqM08 z+<4uwsZsk=SMNG072kG5YN$U|y(=~I)fIn6@K;gfy~|Fcv3G|0r(7a_7fScfp806* z*p#$jJ!q2hwws2+Ckyv-0{RaGQ(ZUpb^bn|6Bn2ccBJ|oGh~oga%ZKQE-3Lon3%b9 zEy^cp_|qTM_YNUPGdrHSbIqTbc$<$1?yXEztf4*+Jz4(P%O6sm;0`u#KAkWv?FaMM zzl&Hdn7@v2ZbfsXfc{cL9HMvgUGdF^=rk`g?jU?cuen^nSMxUG0{Vy^7STV+FQC7{ zQXf=q(d(*pK(BRZ;{yI8S?aNYO}=+B7KhrUz3AEIM# z)4D)jhl-!p$T)Cw#{&VK7 zWWNa%|Kkq7+{NGL;_G`_;dM@a?Kg`5E|>n9g5&R5@!}Q&eaQD%R zUc+Cv_KUIj!!-QiYWRgCSdZplXDR%}IlS2r`WOv;r-nsrX4fqnd?_2A9j#5l-ju@T7Vbkbp%8|+T5WK5fIN%{@j=tUy{hL-xHosPJR00((!etz&ksgCQ9;m` zJu@KT?s{MLG&WZjvkS2p-9EcYBvyU{eD(g(WqKW+Mt`jwd&|wpB>_>=6Vk8kI}HuHIp> z+$1)3W~aS*^^h-;EQ7~d<`n(Jz#l>QV4u4JkoG^>MZ#duk(~QbW<#bVmgT!{ zE+sUTm~2G_yFrd5<8`v|(OJft$YQhB#;S%%Y-n!z(A?vx*_|XL$77#);IW{nq44SL z+HT5w)$RBcmZ0pnIGb7jtn+h=O|gC*;p=+upN*vY_+D*u=WX|XnY#C}SLgrl*S_#@ zLQ6}pKF{~A6fUH;zkWpT^wFtN4;njJ3wO5ec#hmoeyH^&!BP9Y+^+TeXU~bp*06c= zpuX_e@94XK?-2f6E3*mFRXj3~^m|hzJg|Z1bpHHUt~8myUp_H=c{=Uip&Db2Cza0c zNTs=m2pTL7dE5D_KBaKCQWxcaWW*n2X{@tEs|)UP-)x2rru$9mD!62Sk4c8d0gWq8 z5coB)FBg2fr~UhtJl$;F1g`Y$w9Ky!ZV3ls)%AYOip8pyUA8ikB}S5Lf+JRTq&7E& zZR0eXXKC+eisw%#yUkr&gH|Jf~o!J1Tl zYab7>+_?N!#f!0C*=yP%*ZWGqwe=a?^z(QMM^E+d&`^X}ZpCGfg%1@*Ub9ALbcgRZ zpx(}1AY9N@xTlfZD8xS4i5+V4A;`zb&LhwQXN*~HA3f9-3u#I*K}}=By!jhDFfIQR~zUuROlPMWbtao{rZ%mGpi>YsyYc&b*>5-u+o(3@)qlm(}~Vo4nd@8Ws#5 zaQUX;0t?7F}>bDL6rdPbc;kKVTSHeIU4Y$Ch-{ap4wyvExTzwxi!aVL|vVGTD!I+t&ZfBF>I zuV>CEs2%^R+d9P&Rzg^WWv!7HW!{i|X9Gj|cSot|o{PSn^3f}%XJ$@9b(?=I`##&C ziAm4mw9L%Eun*x)9Xz_fc9Uv#kfRZoBHKGsUKs#0T1T{FO=(>?BZEcTpoo)0k83tVh^?-n9ku7? zGVvS#PN}7P*Um^c{W7)v59p)IZ8ijKJ!L{oQg_hfwB}T(HQU0lwXD5_vcX5qQZP&2 z008-W6WIPXY4^dmfHT; z!;|Bt-{(D=>b-EQIl`0t+0!-Sv>%YlzdkzmSpI=7R(D3_ zQvMCQi06$p6*4$8#CqgMbYzyO_4;Y1?2lwiEY;A{mp^p#W0XkN{eBHZ9m3GV?)OJv zYv@<>hGPbXii5QGcdSDcN^-cFu(K5J)*>Y>nd4=DJVx!RuVmeLm@L#d zU4vFR9;2aOw~;n=GTM5^)_D7t_%#oWU6S8(#FC^}%T)M>CDaQ^JTrK>>X0!~{eU*W z2bQ`Z?^$9WR^y#iXhc@E!iWP~Q46fM-(2bbAF2&7UrNQYA2yO=OC-tU*Powaf`pb7 z_nGHu;<&0jGxOOs)%;s`xZjZ&oWMV*YG&?Vhq04C)OfGi%=Yw|F36d@ooTOh5Y-t| z4l!|r={ert&~V{&@O+KIdS9ONa}^WTK<#;?<^`u;lapT3g$l@S4TRRI%r<7#*2 zXN=7rt`lJQcgeLm}cb*YhE0HMB4vpa3U@-c?1l$#}9T?fryKzY}GI zJ8FLz+fn;4zlX44qR&+`pp+e@(ph_Ra{Yak!xQG$nO3HIu~ALI-InS#Tle(Efn98H zP_>N2e}e*}I_t4x%pfwfCm4D(t$CSpX8tuGOR@Ra4~zHo(Lz;3zCQDAsVpfW+`qB1 z3}~|{?R%!9pNU+^^CROukcGe)a0$4J#?K+q!X2sJx*r-U^rtGh{x_#X#`26{U7v!CjDF0o`RyL95$5V z<|DjkDyb!R^yp3(>S13AOK%c){EsyJ1JA zUZEI{Ve=~g+Tro;^*juCEW<_RPy3}^_qgQHj-e!a`Vhr&@A($(2EY70;yAh}<(|)& zus<7BgGnl{e2gs%8Bj0RM1SDs;W8+cm@T5*giqD}5H*QC9pg;%RUW%Li4;_fnfg!% zw+(y`PPVX20c=^V_7U&-vU%5UFcVgP95OP*#=CuddCtr{Dc*BE&pWzAKFWwhgNtp^ zzkym!NKg%Q5^aSd980=spRQ#;Bw21C1MJt)DK+SB(c{3wX;bsJ`ABvZWJ`|cZk9zX^zXsdp@M;ioZeM5X|(0lGI*W zP?E9-y`xLywj?!w*rI>7fCg?C_#pOumA8o%hs2JQ0;@hXf|>iTKUpCgZAkpn zy6UG;EeR4D|Mag^Cn|WxGeT~u+)Nqq^|B>4n>wo5Wpb~<#@k^Yk!|1(;<$cf{O)-# zadqy85osriU4zCXwMUPp{ca~%U-l?sr)PE>+2XyI8CklWaKoXJE#5nWP?K3|)|Bg! z@$PRRn-Nxpfd9aMs6zP!GzZ%>C}@j3tyqRKE+FO$=Oui&FNtEl`YYwnt^hnJiNrD)gI~WlXY%zpPa<6I9`Z~ zZo^4$nK^hO&qmFzyUzsSbvlY+b3jTUjpS%qHIgHURm2w5h;6p*?Tp``Ey01q_-Eda-4CnMXt-Ug7L77H5&2zi0HgYoGvOca z{s2dFk{*u((|PJzyMr$I5b;QP3ngOP(_!&$olGzpl;?ojfq8A_GOFr$_t)_@Beknu zBYnJkv26}m=_`7Zc3(hU7;e0QO;Un`3xgsjTfy*9VQNh$+GwePI=z7-@HKC#Pz}Ug zqu0xex-pZ8o#q9=*N8t;#{JKhSdwcSIxX1#Q@cTAbEUS`vc zci&>#25X@d3vUnP)E;6$%Y1#KRGFGRXF|;6BoI);&ILr*sK%)CK|PuovXYyMBnL2c zB6+ojsl<~@nu#e5jk&9-UROKu?z5oK;KCbEH=b3nWv1Zmv+X*p6yD`>Z70R6E^GqS`!W(UJ%aqk22x7eU(4c~ zs~C-~ami<5(hl?cn0&5(*+rsp#RfXTmr#Mk4%Hqn}oqv6UJI97wEN+SHC4e~MYIYOzPNb6dF zs3rx~l`8{NZ68w#ywJ=_WOlw@2%D)5^@~2L(i|(c6As%2_Qh8oXXBe@5Een|Vhx)# zg>B|g1MA>!MvtVwpt8L8ga6dnaaH~`)-^L;qIb@I45F_5SpM}Ax9g*YF1sFKB0#qo^uITzo7gt~`Qysj*oes9SJ zbPBfC%T^w*#;OKnUvxB%8tnj8U^e|8bu3(Bm)(SX|rcC z$vU3d1)SY?OZ=|AMwr6a?e7M$B{Lf0+>rriR|{p?qfB+$Nk$EmjMVXIcIguGRSvP% z+gv$Gd0|X6v&V#HkHH{kCN(v^r_VMG=_vQ|VkN|8zs7rxb(KY-bro9S;1{vw`R>26 zG)fce1m4H*c8YY$i$g;j`TddKjK2*Hweh=y->>+c@zT)H27WPyhfnd_!|xAlMMT$W z%G2Isn5W@#Yn}gJ+BB^5r?V!>XX@t>isjv1m{{w~nTSpNTUD6vXa~Niab~rh!NtcTrUhW0j64p!>s~k8Aa9us4&j7)&8NDfjGM=#ohTiiT zU@7m`sRH%_5*JA5LwmQFK|cH ztx`>O+`4&fQv8OWGuzNT_rq%U^rlO=el_qIKI`|-gl{f0O!pNy7Sr91&-(o*k*+o0 zF-)svx?e{dtz*eNhQXyEiB)(;=RTAwe&No!lbIBBzpS;*nH4+!5> z6kj!69Dk#HqN0Cd3%&z49S|hx#W0XwyZoW1ke{I`{G3IDi;BF}LgsV~@)8Qs8qZaO zQx5R_#0C<;>`s*U6J7Xg&uap@!}sRKqdQ!~2BU~6$R#)b8*|)0(fReem-p_k`Mu6B z@C)F(2{*$q}?Dg)Qepz4uib13GGS_J z;eCM!Y;pvvIwiTW-pz}7rI9FGYV39fdtcr|0Xf@g!{p=pyF@NWvCBqQaQiS^p4G4D z+|J1(FpWfVTW&Sn#O$rJ(`&cswo{@XpTXLbSwh#v(?B%7J$J@(cestWK5vw{L3_Yf zo0`i`?{U{)4&7Wtzn8{k77xru`&(#a=3S-v4z?K00g>DhrXYelgKlzV&&Rn*#shj$ z=@xarZV+?Am)p7*a+1)TCJY*~*(mMH&SV1M9;a~O)BBCC<0^vYmT4cw{TJJrGsSg1 z+s)?49AvpCVZ^RgaMhQ>99NjsI5{ZTz{_eFN$Ps3W;rGcsCo$>Ce3hLa^%CL_8=)| zxF&CJeepS7sH66~gQVj)%(31aBIQ(}nIfw_`o3nPgX1lv{l7DGc9VRpJKXeP<{q>y zJr1b31w()_TlNd4MqBlztOElT*f<+uV#L&{qr7^zX&lymfLJghQRtkpyI_@_&sYx( ztKQHBzo_4a5&ZP>jMC|iXZ>KbF^p^~AZiPmNA9O*P2!fUPHAC%4l_aP$~fsdDt97h z26<^RR;-)kri`XB2D31l3!OCglgNaTgA)D`pMUkWRMUf21pkP0N880=ClWax?<$?6 z#g{*1uElh;x3x_=wK>t;c{&>E6U#a$qwQa+`Ik4g$)Exn{&ht~w-yqe9c_)P(Kz4S zl9*-G*+&SCQi>4?>rtMSxN=4N)h*{FmNqVLZfi-L+HraU6>j2$34`?V1b1_=FMtfj zmIHU((-T+9+5korFp+SnQTne`q~WYtzKO=bv_b-V0d1{DFI{tI*qXv2 zX)i`QT4S~qRsDw|weraZgOYAvV$3mIxf<1O7$j(FX~iHx?Ek_o!Xkx!JQ=S@tZc*( z0vbe`v7?ZvxoCdE=!F|k3yC`JDjFBn+kZN~S`X*5*f{N*7#G|#y`WgXd?kSyegVB3 z>iL9p`tWUR>HaOcCmf_d5}jtm0l!7j^h0`fG?xnK^to?bBwgj_1%3gY?$8<+(2a0! z_jqUmdZkfB@9yo2Z%v5K4C^8c_(tv-i#{8oe_GvEE}$Plj<1I3xw~pzK<`kM>rX;- zrOv;=*WpV4T_Q^7a8v&wx^G44MyQ{O%nJfJzZ|6xjW^RnbaSJ0 zq5An)h%RV;h5B~!l%MVp-J6Yv-+YU7PrgOEf4oJyN(S?wTy$E&xS;(wRQbrfMY?Q= zZjp;$D3?$_xIIMoX62`IHGzDZAsaV>d@qFP-gywZDQ6h_6SJP5V)WQo{T8?$y#mJo zR{@``GItNF9tGYBz6khL;7ni>`UXw~c7cy|;lH3Et^@xLu!ZnjfozggtpHN|Rn5S1 z;CT+8;_w&WXY5B*JqG*_!tVo40Dc3=wo%oMK&5+w^S{jb?|!eP`vg$(&Ii^5&jX77 zNTAXknrzd(3%C*deZWrwmraVrZUFx1RPO2{Z!_>3@QZ-r_dei}z&9!_z7_a2@b3YY z&;JIhyguXb3{d4#3l#sef#N?IxDxovDY4jU;8Vcsfj@Qd0pJqwyMUtm7O)xkRiNlS z;8nmb;J*To0)7Gb(#bactqy)2cqjfpImy<`2A~Jt22{KYfpdU!fK1P;ra1Wf1UlEj ze-1njeG=aW^6stp5>Wg)fUHPWjRsx^+`vWtCh~cdgV&xAi!H~0I`HGbH!5s+A5i!m zK!x7~lswNe*%E#?P<%X~=&p45zW^m?1&}JN`UmG@B=2)T#ZLo!fD?e?Gl)_P`TzA@ zHXqLeY4a6714{l4K+#Fhzv%vrM#xfKRSWQHU=6Svc)0W5N+H|?{uy8wa3N6TQx9a! zs+bNG-~AL4O{i)oQ2e(7CHHrMlJ|7rZNOuIl2?VQ{QMo^J_mdiW}^QKFc16oB+HW_;0{@z*~XU z!0Ujg17T4y3fKWYc$CrmXzbxE2EQG=6}SPYa=Hen@>mWeN<{-u^8YU=2|Gjst!kILi6|y43dH`+;Ak-P{Rm z0=57*K=&b_@>2ukui^$e??muAU<-6fpyEA`r~Lnif8&6wfbu^I_-XL5z|R2RpwN~9 zHv<11cp-2ja0*cLUm9=uTmlqc0+c+XfTDW_=JNj)@IS$|jf@CYFPGTy-oXxEy#UP~(gaj!Xh( zh>U0zNe6#E#^!$`@C$@%?xONr1Voey&7W=uuLhEI)oBjC1E~6ueUSCQ9|09lCo)K? zLUu z73cEr6NJ^>rd%^cm=#}7t)N`qhC{q?!2!0IwX5dG`1wR756!>9q!A0ORfTw^9mV=i8KLjpF zS(a+GYazJc0`NZI$>4(YhfG0-gviNEa-v2R48UUI8vWHYe~XNPjEcM?zsqzFnA!1og_NWUq4r-UG_Q534&2@ZdU!!>>>{A7op=kQ?N zBja#$dXxAK4!;ZG2 z(pNaV#^I+r{NEg22R{56Gx#TVsPT2+eK^8i^o=z>d)ZsfFzRuwZ zDpT$zhp%$@Mu$(L(&fJE@Ggfx?C?Dff6C!yG+sH`gOfac4*#daXVA#yO4TU|-{bI8 z9KMl3MeYoT?{xSahwpWGIe9;k->)fixrQOQqQZAoTKs)3{%tNlYhC=ST>J$t{!@-WQB8asn?CF0OE~%F zA-DLm)N9=BE_|0O|93n7Qyl;2T>6V0|I1zYd>3Br(%-$CdxrUHD&I_$n9vj4PjytDtaa zy7V`?@;SosA9VHigvbOn+85h3U^#_kIg)QYjflLlNP4RFaC)Dje!}>g zNci3e|3603KP8gC4@T&vS2E0>Iad+>p-B4Qi-gaNq^AozVSXn^=sy{e=OdBy_eH`h zBI&;oN$>ec`PE0_Yb`k}kJe(txa|Ce@ump={Rsa{BI&<7g5MFLejLnfvC**+%Cbar#m(~e*Ra^U&jcpAw+0}4> z^ns-=F_1kqV_a>na$)w1t)+r1SIe%GV<+2AfnBm<<&pu9=GG+vfnj1bOj_$&4OVK) zw^+{R_T>eUTe9s-mNZbP4YJ(ShS{#bwAjklw&o_xwpmSvMb_7xIX5G{Df6htN^&u* z0`ow-Z6>0XFG#haWx33*1sGHizS;`&a=6l z-S3EB!G2jWDHhza?M>}%!_=XKWa`YZY$`H4dY5C17rRCMpsg0~AA0N*RH=O2n7r2BrDXWb}BuQ*7IvTXO6{CNy%`^>nB%@k2 z7wCT-9xs<*sIOs3>k18KHX6r19A^!2c7zM-rY-bkdM1YBvMmi)wly|g%}JA>l@?R9 ztiaA%m?k8Z20t>{7&JLsI?hCl=vFo4t_>MAv;#(9NYUiiy$!5(-4JV}E0{)fgGpc# zFid5PJvKBp>9k8x*S5qOGmE@c+8lK$@@wqGBwkQxR>WnEtK1u+P^dvW8z#uMXL*qf z7yE$}g_6X4<5k(fcA+bUc1|WO&o}qP{+Mo?Nx}~}0S09qfrKE1*>eMv? z%Oo5eRA>=_?Mp^MZm4)Q5Jvrm$1oFOD$#beC}q)GZJ4-7qL$#55)HQk)dz2tC~xy( ziF)cK5cP9IeAL_Zr>J+KL7M=RH&+XqiCDeJq4KefG|FVyBxLwi7&J)JR7Z}Y)*20Q z4R%GO)+lXg*1}s6PjA|3W}sT$v+{GnUBD0iWFE`uST zFc-_akV8Wi&7|=R6;Fs&sDoNg!xdwwTx&4T#SJ20T4)pU2=s%$|E$EYtDZh>>e(~i zKV#~&MB>b;)dWnNs?h4GQ_q@?V({r_RTCmtq#r!!J}t|e+BL~3s0trRPxwZCI41bv z*e;LF5PlH1i*+fvK1UPaEDvfQNqZB8W0pEJ)q!uGD5g2u&E& zEM(r>p@>dDEJxno#bNy5PRADZ*D$x_?iVIeCZJ5I{H3CxOAy}5S*>?phL8hxd48p}^; zAM2~@y<5^G{TucGyxJ$z{tfa-p|{N?_dsm6z0vTn(OdRwLe2e|L8FQ-?HPK%_Q|Ao z!ydw_ch`CUwU-AjrtSkMwo#N2Tz*J;KSVpksFm|cR0Oj`k)4w4dcZ8)=PK`!$K>ta zBldi}uj_^OF1W4(#d{=yIAq(acPH}?>;aACJ~ePVfSZ(O5cJR7Q$SKJ*R)V)N?LjE|*+%M#1QrK{SLn%@M+_>~Y2hy7?C-4G3ufTn?3p_SSFUA7-FN zF*q+AyL$KFStC&5ePWnw1QK)OVZ>X$!!?VpY}ASG_w&j^N=g%M(7s-#_fAu_y+@u* zYj-;2hW6;%{89+Hb;O14;9*hlP#-*`f`{3`!;IizYVa^Act`{f<-tQ)@K9nO##9Qr zE|&80p$-S8{`QaMNVc5;jjP>f4Lu<}GPu%jGS3PpwU+M^@bb!i zjkk3V029O`d85o!7o@ckPTA9|i?39h?wRqwAx8f9#HR+;>gJ(PZGV+f0+UoqO>B!u zeUWA+zlP4fl>fah5b_h;-bwjehxwsG&fb)gV!r%qqvPGp$l{pyJd(TCQIiOI5Ywaj zE${T?$1;a)72}L&xY2z~qP7?`xFx;E1}bRp;SLcLS+<(o25Ruk7&h={327B^aMO#f zv7(Uj!2b|t86z81CSfE;6PML&hW3EmM_oxfCfHgC7Yr)mZ9({--6J0Ey1C^#8Xv5t zEen(nSYJG2M&;Dt0@S?duHvqg?|0#w8ilE7Uxk>Q-0zYd&iKG-+&c{AZv?LDpv5)) z5IP5*&g)%{dd%8=mhUPlOWm)^Mo`ZHSL_oloz%epK$Sc$ZxtG~jVmjPz+ zhPLNkGTK%ye<=0p;}DI;pTvycn&(sb?fX-cAH~))Mg1G)i#y}~iTSM=Wh#4Ys&{KW zPo`7#=Zz=+=62HM4^>Z@Hs#Ei{!g8PrFwIpXywvY?*F)zDduYlH-Ss!mIqU~bGQ`r zcBmIFznW#|IxBxH_!oepzY)lJq^dKW|4Bg6O#mwXQ;g=!?Puu@E`L=Y z=AY=#2Qp+-=p0u9d@2x;DkcL@0s&CSvsCq%FMCBjRdoj}fgRc!?-y>9{`skj4(t5CP)ZF_}aoFg%lfTiGq zlxOKah>iglJQ`g5n8z2LD@=+ z%H1WLj4USea(xb$j#{}#9j@~Ta=RVA&*6V_c*1>;9gZyG*X8iv5=ZAEZgJ^X^L!%V zn_M`k2^ViU^;Lzha{NCh93q_ukdtNvh1a|I>fhoKxN~?2@W>Z)s7JAz2pwzXb)S<4E&Zdj(tu4pQl zpKD^tpB;=Q)`PH0*TKS=5wXCfc(bD5U6f_Bl2ROPIPnnz!wa_8n$#Pbu8cKYtCbi% z1&d$7CXu9XFn4|nSym=kxO1e_91K>$s@W6JK2U=ZV=0>&?C*t^xC)6H;evDxa$uUq z+m*CS)_5I|f_#JZqiHj=9OT@g){my0J=KvHtsix26S1&pL>nAw-AH3(EWr<_b))CZ z)5!mBW^k6%_$?RU>h}6EEExAz*NvoJR!;m(T$nIUYq0MU2;8C8c{V#fdt8JBSgvUSBu& z<_lVf_M>&^bhHl5X4;L`A*+1o*2M<9!zv$YLHW=!ln>=lKD2f-iic(pisB)oYRK!I z1cu_FggpIOk~!@kkwT@=RuwVU#Ktf+--S4--kvf;%V&huHng+9_F;X=_Sg35V|A-! z9(pvtpU>wnnFxo^fk&!o;$}WLhMqeKpX4J;R#q|4PQS$D#(b~*Y)^9BSSJ7Z*A9!{pmzfr zPI?d5OO~u{Fj>Re+9ZnU>k332arG1Ts4Pt1zy{Hzfxo;d`&V}*PjU&YY&FbJC}NHR z1gUAb$ntZx$_H7=8kW~6GQt`gniQg*WrNb=UdWlHL=}Xp`P|w)xiVHroHiP(<;y0M zUzdpGb_ZEV3{D}BQ)9VDF!wg2#AL_x?g#X|?Kb{NhsV6B1kVPMt`(zn;i>KaJ9_XI zW6g;y_?BP)yo6{5R@0scVm*#Egf=xU`vEP(?DN#JVgr}qtMABX`5nP`rM^us;5W$c z+k`#BZw|k8;A;I>@|(slSih5s2~@eMdmB}5KjI09zGs>#x!7e@2Q`75rsQl9BHq2P@%y0<=M%0TEcELt78!T&3LsG0SP2Z#! zbZk|AmBn}YCDps*cfQzJhV3CNmGouN?U5=^4(&4QVg)s3#j(nRSlDPvG5*M)7G~9k z9xp^vPVHC-jOtma#EgB&Wl8h*j|(yL}r$0MN2W9Tr+4$-s>+it-xITVtr+?~AW2;z z2+LBn3Zh&gs3;vkUR75J()mhLKz&yT^1dle0879H;aU2xiUfn;eYYEb&6{VFh}>+R zWjA`ZdrxavRQNS6e1QvJ>cTg>@C?GqO?KhsE*!LI-aaH8{yQDNgbP0jD0j4rzt@FR zM&=!A0{QpV2)-zS&x_!niQv~q@P{M#vIwqY)yhM`**$nOFDf!L9n7xHcD@Y`&YXnL z!i7)KHMO^2-P%&b#rhN`yy2LdrMsE&K@L+!4m)Zp>kg(^c?xXJJh`*8t>J1^!f;B; ztN}URmNay1%z6Z;#6sCCKFtx%vYnfnV~*w!T6nT;(=MD%Go&Fun~r>k=gR*ld&$$z zcH5^#^I3BWt-19oPEpxe?MU<4jjHg3t?@(cgD!RLzRxw109XIj&jrWc>U{RI^bNUy z-z55x`oMwn**CYB9Pp`DT-!&kpcI&5w6Fxi-288{ntBZ9zW9pM%bipCg=g zm{^L!SVI|w=f{c{{1_|EJQ?t|T<}iUj-2u$b zbl=>y`rRfwk$Cm)mP{3%lLJh4LdeIGybV6Wac}` zp<^m*d;Xle#O;9jb>HlM#MCzyO$x#UyNWV5nexyKw|18zrt;^aO~p z>$OIM);S3q${PNW<74$J+E=ZvQk;X%n@%SzJa4+wQ1dUC=S0@qMW5jp%y)LsIE)ME zM_9*R6QX~wBQNlG^P`*S|C;Aq>)>fXzI&@GfD8o{6^De&V0d~{ zB=4|yF>m?1l}8JzBdd$k3#*L7)1$(A-_&5S4|vG+zNs7-iZn$H}$ z9Ml~*O85jn+@a=&!FbWaC`!Oiy3?w_ePo@wlC)he&FbO$py&( zLwv`l-g#*pf>mq_|1?XAx;`842dIlZ=r)uWE|WEW5KFQBtu2YxcWYd0{pu&?*PfVn$afj_en z??Dr2PD9wE8od0MqJ}lu5L%9v8dEo?H0o@VL&r%oEr+WnC;fG-wt&txOHSwrem`e7 zl0(N1mb!To6AH|s?oPS2m0{K?7U=xzONQ!83i@-UmG_On@VU<0>=?R)l^wHyfkJ%j ztsV-|jHRqTNqI@Oct)OY1S8%Q53odHCQ z(y2gPsp#a-oXGgg6IWUW5oLXaAoHeDHF5gw6@tv)O8bD!&#n-pkD7HTc$sx5=6OZy zP~xA0j;?Lip_G0Cd0a@X)v z_>T=ny21&Uo*B9K@l&|=edX@vr*Kt069E$k$l)t&Hu zvk2|M{ZLG9o)ywc)g_GpF1RLrLGAnnlGb?`S%&9OLBhp8Hicq8lZf$B9Gi7L1^L#q z&Ghi}s!&RWc$T_=nh3(&I@Q}cw?C~gTPd1{nF;UmmaE#ct;|hB8?e#!D%J6A{9+0H z`+xVm>}~Bw2iF;j?=x_7GTYFRZC@S~$^XyGgYKAZ=Q6ij%{*{_{{O4(W9C%ddXX#Y zHSpcc^(KP6Lp9B z9?+yjuFw1@zvNS_Z)WmR0%Q)c)CCzJdCU3jB3$p-UA!ozV-C8)_dqkx`YFEVevZ_Tz61?W4U*^L;Bkkt_9WK*LbfP9>hG6nN@6?rb_r5 zPwnf*wHiD5SLQ7AVa!jqDR*IlQb*A9$U22viOx-At$mCdFTwXlaEa!ji!d^vBgwIa z%R6%&9qlW!7!=@SlF^wEo5yApxL)_IjcsmmGq&*3Od_XSf*2)eK7+lbma7`uP|&|( zStHf}R$zgEohCw|izTrLU~aR+W(f;098EsGz+c2%*Vf5osrX;so^@*eugtZ!Wve*8 z%pb>?I};qs(lSq?IoFcNwkH}BqG+zt?LHlGZq;$KDOfwmwKXq4ElZl6?QPeX6V|IR z*MJRy1H*LBJrYFUk=g~N&}r_2#^x=kKPR!WrFBKK^MQ3o+v-@dNje2cdU-1ugI>3m zvE87Ab1Rx!Y{UgiTY_lX*0YqMM4B73jR}>xB^OglgOanU>r}Xrhnt1NHW?0J-Q3!2 zimuT_r@UGc^_SKzAoj9lC?uF-BXAwuoDZ*0&Y$lxVKNu;zicG`Y17VDt~wZ2T3j7l zhE0ts=_RdK>9o1*Kqz5TsHV~oA~|0iZB%!Z-36rc~ zB-o}UyN10KUYHCNC2+Ad!@;@Ab}k$*u-XbtpCUe|2b+UpGA$xefAOUYoHWG&mofnl z0xm7|TMGXwYlK5Rl#9a{_)tw;x!M-2?J5OJD2yIxds#*!&YJScb=Wp}@%#m``SUY{ zR&5J2+-Gy@&0JzoX@xs1MbKz6ea;zY*xJj~B=^-EgQ>P@A(F0LUE{UouAa?7r4VNhH`t7=B@rfg?oDeZ&1 z_^r!w%My*tFoTkfC6{wk#P;XV_}RfdezK}Q)*i?et7~l2$c%rsrHyH|8*oicpv45+ zHZAm~C2Fd4;}wbd^HZd42D7VMhRf&T3uE(5Jrn4<3PsNildBSwFjQj?zG6U!XSLJG zwx(CCW)e@vu3|zzJiN!|Qk<$db#l`pis&dm&ircsASg0;1g{_lp#x$BWYPm8fr5Uh z0ZCaj;pR@vQfkF^*8-jCPz6f1>P*`;26*IayPipMxSWRDW)69V2Npxt+Od=*>!U>* zwAGeGBRhq(2UFtC)Q@d1bCco9=+wSpu`uHAh!T@J8na8!PiWBRMYN*zs-@Y^^C$Bf zCx7i%Ek_>+)_GR^KkR*bd{ou7{|p2O3Ynm&@ev&~C*%h4p4VpLXAUXqtmBm>2@B#cs8UcCSTft6xWHnn1UW$Dx@S6ABOm<$SaDRHug zs#}**=WY%V){H$(snJnA*-9M-8uaO<^Dt{w-Q>Dz`m_pf>9pz_xgf;S5GjRwjWjhn zSYCuN$zF$2R~SbyO!Menr~|8YC{;tHRQ{1nw&Zj=Dib55o>@4UF0NUEVG}DyJpr-} z)`sU|PWEzKo42gmT5wtktF6IG3kzS{13Hp5zFM2AHO)|~B-9R9 znW?3R8_n>E^1tSPOW=P?;Qvzz=<}4XI-fgVr>Bc^EkE4!xmMmW{Be&)`#T!Fq40CB z!(U4}y)^!&)3JXBy7@d?Bm5NpmjS*akaBZNfd2vzyCk{y11<%A3n2Z^1;oBf?hL^0 zfF*z+l{*5k8{j#DWBZFHcP2a`OjZS;7tjEl16Tq$8?Xql60iWUC!iPb2EZJ^S%Bo< z!P!h!CLqofvluDqbRx2^0e%R0E#Lt_hTjJ`6L2@+HGt$V!Wm#zGa%BOMZxpwfExg( z0j>wU3UD1D&i%6P11tr+2XH)K6X2DA4S+ttdcX?6TEMA*3jr?!oDDbya3)|mU#lQ;y z2LlcQ90ceEya+G{@It_Bz=437faoJxj0`^|H+%u$hc2ZbNS(9Nejo4wfO`SGfV%FJRh_k}14S;B?S?dA8!WHkZi05$+(YgNf1 z;~ZI?*W#QxYa#6W1I`A-mTlHdz*7M$0J8xNK=g&I5(99H^_uvxbncz1F{%gU%Blsr49}&DoaLT{XJS+HL z1b;>F^D`{>w*;rY0h<35e3sxJ2!6NVp9!w+5@!IUmFfMPxRdXc_}>L*xf1V(!Jp=A z!7mn^cYM;lRB)C%@jAh&Z-DrHf?px{LxQtj=)PU>D+S*t_}2vgSnw*rdtz{>SuFS% z!NY z(3~N7iQt@H>3*Hy)Td7TCc%dbzE<$Dg8xo%zu?_4SkaUVUL^R{f|m(iDfrg}r+f$F zyHW5P1^D8^RB3)Lc#+^61fL=}<;|F$YQeV& z-YEEUg8y9bR|S7k@IMH?SMWaz{(<0s6Z{kzUpob_5ZsM^r^;XOlLU_meyZRP2!4*> zzY=_);H`oW6a06Aj}bgm#^(~ja|I6wK2q?j1P=&)9dSJRJn{;>k`HGg3m0ZP9^Nl= zkDOP+Nx9RF<~BTZ&k=XbnacfqI>LMx58X?|{bJ%EGJ%dT596WxLUG3$i}SQ?s?u<* z`BL2L(s1EwR!Z>oVYlXVRyz-AmLirV$Kt|2lk|gQTy@B&lnU^z(&n44TdEnS;oZSd zof5TTf^qD7Xv#_Z)C4H|QY9ItPwK%q0~s{zt5z)>7UC98w0a7}r*raW9z9g2q^3MlQy!@)kJ6M!Y09HCV$7sr9H03dx@)%8djHXSbwI<#E7z?ec$}OeXv;pwT#&YkaUYQ092~lX|7mTbYd1H1ymJUL@i2v6(vn1 zXg*wk;H{A&{JZ_;K1+kc^}bn2)_lD~aYq}N?N<4Okuo$~Mm@#uZNiL|8A`-YDD zfLJOjd$bFs zUk&A>_Ak(clsq7tlo$R`ZE7C@QDpVyA1rh`WxL|KO`B(k!`&-(bBNf){H8PMwMnv zuyku#t1^d_zjd((y-P@?m0m*YWuubX*O~y-Dz3{*VQ_jMw(fe7fX+)uR4}Mx*C`V( z!kD$3xACMoY1Ga`auJytebU}RgqBHW?tj(1#&Nu+R%GQ+75{VQwSrN@k20^-)Q+~N zwIj-dWB)pK052XGw%;OWhfuc3zkTxBEPgbu$9>YHIo^5gM$5acS79CcCTZa?ph27z zsI27Sf6^vhZjNIZ4aOE_MuHB0M>Su?C(H4SMo)&^UuWL9&%!v4HcxiK9pj^#FB>g? z_B_e-@L_n)m3%)@!>M9gMGRZbxS#&>M0i}`n_ICDZD}Dd+@t2RNM|B+c3Tf<_)V~u z3KM3lvbREYoMbtX0yK_406kwjv~HmdZX>dlMv&gJqE;|lYBA2aXe-+!O)hvCPNe_4vFtn^5m{{8UZwLC@@=>kdl zo>Htp7_n^;sr2$d*Kw6_0QBO4VgK37LOP1^%D&-jhJn$zo_Emql{wydC#EJDoa+d^ z29L-99x?A6Tc3}nvsdEpko{~yT|!=?m>0o7dJOsRS{cwZz1>)JbH1p>IT_9mk1$8l zOa0!{dUj{Cz+pCE;v&7HnXj4`H(*guQ)>ZNHp)%aB?dgw1^I>IqyY1ugJ(9}asKOS zz(kS*OZcn-pg!RlU( z&>46UT2EW_Hd?^6mEFtOMM(Tfyf$p++~V7!T%#f73m0z?8fJVUKwI>B{4<#EY0LU) zYB&s-Ul@06!^$S} zXGSB35>TlGV_iAoHy@*IfR{pac1LkF1ufM~B7PI}Ozfl@%8}5iWPLOvK~WRop>0VO zMC9{cx4qMGn^MSx!jkAcjeS7Yw>l#ac{K+z<=fz&fY6VMpizU z@I>q2Y~?BrRsuv3pYaPLUcNpUFMCi0LlQmFGvNzLqA~;KTkU^_FZ1`zlV{D2p!tbE zrm_R|K~1L0Zdv30@OWm+7x^+FSqqN}#K!1?!L19Y1tM*b%74bHXWX>X=eD;yx|f+B zFboOfq5@DLsbE=Q!XHyL0e=Z2uGVAW%Z&I+l>OV1`S58-UmsrrYL$@9gfEitFaJYF z5C5V?nU^tGsE_YacSkQFWLV3y0CX0$ZCCye?r?h=C!=>E9}Q5z+7vK%SVgJYqo*;B zjub1uH_>92-y1p9({tC)p?R}?1#DT6;bC1Bq7-1aa5fUxqpj>gmT>#yP|2xW{IMbh z+i2~25~C0IFRbPjzE3$J6$-|3{KcQ!LP|x^HznQDaXe9;iQ+;E!|XKjL8rkO8&%qF z?_>%U36?@IR()S6t8kYQdyG9vsq3VIsUb5Ota5`> zw!yEvaVtpcqSr6;Y~1BDf9Lz`51`=pl>Oy5?v8GSyCeySIx}341`w`eGYBtk!g0Z#qA3g&^ zF33XX@OlfVwuY-;tRf68W{HO8`|uqTnvLs@?)dz-NWg8^Tkhwr3c~&5RTH2+EOO|K zRhP%Y>my%|T{Sw=d6~4dRfWFzckjg~h2W9H6FhfOQ)RGfSFnn^ZS}=v=Ep(v?T#w( zVpv*hp;;FSb$6qODvi2LNFOEaWLwW_o9ZZbD<>oW;LnUIRM6)#s+$k`>^}D_+6)7fXct4bqceln$Hprc2&CqRUeD`G^1+d<3^P# zNW=ZQ;eN?*;|8ccs{-*pyNpGtxA8G=G0waAX_S=-COSUo*l?YaiC2h$gZT@#kqxTehsxu%7ex+cw83J&GD5OP`W z^3^T}yxBF0_Tj}YUw8pTR%%^St3s|R%WiV{tE*fCM-*P?8(-=#n=sJ`Oqv`lpE9-L z%B!YLpK*_D0-~8@_2p{mr+`at$mPKJQZdFNwO4 zym^QfDXb$zDsj!WvRN2ju3nH};z)CNxq5*Z0r3BE<~-z>`=9*gt;h2{Jdfdd70)Ml z`k_%4;F*GFV)=B~SZ2obQvK?>rYvbc9`a-~JJ77I@mcSe0r!dhhkW;2_K)HnvTgVW zzaQwAi9P+4iamL-O2wXj%EkUczKcEmREYgPzKcEmTr2kHU^=>1?CHl4`m?xXtc%I=&hqD83=PYl=MFS1f9}20u$-q_uP&BVg}evxexMOyydfS@t%R=~l)mkC?| zSO`2QIQg~celg%BfVqGfp!*EUo#F2Wya@IUfN;vaOz=wpF96<-`eZnM^TR6lw}3c{ z$^W)MPIwG|9Uy+W)IpX9NPUzAu&2H?hVKaoqxi-dFZUIhpWT2Mzf$;gu}D{Zy4bH& ze7fY%T@Qa}0j>kY9)#l4#rLY>(*-TXr+YeJ1Kh!5r1*4EcZxsuRKSI>KLv0$AU<&w zpKdlF+n5K?0K~azRtaEVK&1U2;?E_$^X1%Z0O)vuUnu*V1A)H_oco)vOM7{rI0`HpV)-zxYcf;S5OxZrWYHw*rM1m7z7 z1A^;&o7M}i`7M7V_;cc)Yi-8=lHl6~e?{=;1;1Fz^LK(53jVg>#e%;lc&XqY3LX^v zkl@ndJ6cTF_?ylMEzx{VjLm zqM5YVRk@l=e;e`*nt}@5F-~F}((DV$<`jjoJ-H?`?kb{P}I;Gw5?X${t&)=F0okUe7?kS-q~j>aP>b&|f$B&G3Ws z$G7?a`e=qrK~haT(~(I}bPUF;H&{DMNNxSeDybg-P9K%nzvnkU@S7j2VlrE>^BbO) zEc~;bh3|>(K+;eFp6F(#G5V(8{OIdyAN;aL@ZbeE^; z4j{A--HPq2mG>u9*@e#bJYK%>V9T|hHQ2G=9Uq@@u;nKn|F$PsGLe<*60wyJh6Wq) z{x1M`1$w{g^E^I1ucz4>c`@_gwrf5956urFJ2MV$L!j0~3rqPNZ1Q*>55BO`eD>wP zME=yR_cn7ky|fg8t`Wlu5;=(VHpZ6k4&%bx9Y*@DRZ8=yU_&**ZiW_24Y#L~|12wV z+4e;ETqDu!FaB^j+F>GHd_wA3R)CSsayRtwWgSQp#itbr; zZ^u{_EZST@92U4pEix9R<#~K^&x0-5prmuC0-1_X13t^F?I8j zy}_qs>zL0Y^x+PL9lj52J_W8*l+oW`X>zahAH;*5I%UXPri}KVrq`eTZ^NVgU&yvX zqy4Ax@!f&J@ML`F)B^Saq#O)_ESUtD3A_Xlts?()asM3gqtE42o(N0({O8})!bjFB#KA=jE zxHkYIX*UoeDeAijL%ibu!yKZ%V=zwN;DtNl%W47ScZ;4Eh5%=o>UoFh;JS7b>}Vdr z!*wkAQfUHs=&tK+EpfOH5_dSItZVNQcgoMuoR5cov{{B1Cw_ezp3WbbzK&&Ea)y`H z-HJK50CWksK&-W3=q4y(a8=eWTTEsATJ}RNHn~WxhN66t|ERAF-88RezE+!Wv5Z(Z zTBa@~^`h3X&ULIVt(dIUtd*4Hiqc6lY0D7A9IK~)pqEe(1&N7%h%mKjB*e%8KX)lTJ_5=`9J^ex~J5|4VW;itxwg7ih*N22F$d$G#Uf zIoOn&FI4?jY?I)t)?+1XurTW+Ar&Y`(&K3sixho-A>Fm1w;UpageTwIe5 zAs>@!IA1ZB|5=f=SiC*a`w+Ky@ogEZ67{C1@f&zip_3fo2oM?DJ(P`!IShUC;8M2; z5x+WCni*}r`IJcK{h{HJ&b8s;zAdbsj&WG3EMy0)4-wZ_7k_%E6U` z9j8V*e-zI2ZDEV==;_;XF`!~Pw=PB6?%PsEm-l^JCJ^rTZ7~Sn@@?Tb+VQGy%Ot|* z=il=XX18bYyoTp(JjDNu=L0+k@vwe)pP?!iRTgH;CPo+C6~2*ckDS-yb z%SA?8*Y@SVeVXrSoW4GpD4x{z1zAcp*f-`&2fgLEaQeBNpd-AXZjj6t~=d zrmw9mb1f_Y)!^l8?d58}7ugF`&F}`g&nVgg$AnS*^6h5^;wvqN2L@LCM2H!KcQP0X z`}SElrpCtuh6i74CHmEV68FGc%1$u?PeqhpOMW5+eml_uF=|wm)IJ5G2)LgfR!sn+>Fp)%nH-leO0cVe0-BB ze{H3G*h|~*L=y~}KP@7em`aUj$djk%4z|`T{IKErUJ|uWj z_ueh$lX@Q;WkAoJ++R0hYZ-?w7Q?-kUObK0zztki zlj1=yB3Ch~S{p>q)_4H!8C8F}Q7|i(3(~G!keiswbSPAK(BdNKl1Hz8sQb_F&A-r@lHrx-TwHe(X=hDJ36;O0^Yeu!^q_kq+Q=ER=AN?HTU@Y86 zUkxa&K6*dwF(~;WD_z}vo_l+FqN`zJv|(`rqX#*ojT0t@iZZZ`s4s9GU;B0RZjb(s zocW&OjNLvq=`NM<#3ocDZn&0)V3pYunec4an#z(8IDFWSKnQf{?G@z>-<%FIxaZJ_ zse96$1pfm*cOX?Sqk9j=+4a}(*y~E(F{C_G%l8>rL!PR0YA<9$J=BU2bCB|get}DU zXw}ZhNeNp-dqRC>7VfzTRqnDBm)lDtE`@?vomx|VBGg~Td0hY4rq%%@1$S$rPjjcG z<<9nnX29Estf@44!;w!m2Ems0xv=6{x5V!@Vx_o%s36vzJf1h<-b%G-w#!!MSBk$; zjl6vyAgIc?!*K6R?DI8j;VPMHP9`82=jXmF=a? zEP+%t0Dh^44XZgs+Q3Kl2uC^TrBZe1n}y8*^ZB4z-Bd1HXL@`Cv!?F(jblK)*+Ptg4r)HuSh@Ppo-2+=K1|*x7DCWU%h*|` zf3Z?hd?0kO5xdUX){hnFW|~|dVp8E9Vb%iLUi+_Gab(jw8K+PsK>l(Ah%qBAwmX)NbBDtUuLW@(6j%8{h+GP z2E*Nw_#-+dhbqrTqg%@#GyR^8_1%5FU&2QA>z>C;OVF>m)Oy(yB~ciyU@7HLeD1cpTph<9&60E`rC?UADWZOl)e$D50Hd!nQ%fs-NU`^{TXHfdug z3hiHzm-50eP3|iJ3Eb-^ttxm zvf0P`KCW87%y+4+-?Oo#d+(j7PJVY3KN~t@K9;D_H&I2Xt#K6p@I+rw6?UujO*ubN zTGFw|YKmRe*T1Hbw|62=wsW`cfnCMb{b=o+_K{BaO_ebf{rkXA zs6~I{h!%Y{NhtEc`2Qt+T!4uCr>$=UpV@|EAWyVV*{j|ii_nw)Xg#v0OD9)-@0W-z zP&G0y(0$`NzM2YjTq>>d_(|2z$J&A<^i16T0FboSq6RVNie}~9 z;~|IUaD3#{yoOD@ve+1GqI&M#9*D0Rq-qUYT3AvRc{aWxNA_qw^_4sly=6-_cnN^s zo@eyIW)S%7hX>551x8h?QPa6# z{`~nAb5VX01Ke#sb5&kD`+-Di*Pb;As(sw{7nrAiBEG|xAOYfg9a|!sSwx=T=ZyOM zpCvHfPTB4=Cwe1^ZmT@LwuyOMg>L0v$0?D-h}-(ojv{$m`4_BuiJAO<;Il)~W}o_U z@q4B=mw|v}!52FtIQV6|I~%B@{NK@w>ho~IH zaROJp95*3asY4oYUr6Xu@4y;p;Fp9ho&&x8yv-Mi@T(T#rVO28>*|AHCnde&Qf-w7 zWUs3L&Mayol9uJjXlhzq%c?@vAs226nNwF)Q-gvXSjERRaPd4>h*v?l2F`QMUA#!W zlBo=L|5&9))&G_AYalgo1X0{hz?+PaKo%md2ViCJ&H~y}Uq1=ulM?R)5vp~{vsIe| z=Z*DFUlu}%Ass_OA%x3Y2F|0}f9vfeO-`Z8#J(Puosf|;cE4Il1pEIpz1+g ztf5?~Q-5lb8cN+eXyClTx}2%%e=#nS!37Q>DCSp}9oW}(IX&T?1$F6z7M;`tr^dT_L*(f-o-LP(d#%9`#P`lZqSMK1>F-j7H7yEC0` z8b1jAKkx8g!;J?TO}7jAfG^;z>GO0<8SUSp2PzM7Yk&5!wDu>#m@j_oX@3jE-j3gq zuaLu^=C82*rSZj(F6BKm-RHP|pwaQmJU2yM?{+#I<;5-iJ)XK>GIrBF*`kfV}_@V) zUkgZoHvuk&{Zhb1fKvs}0z_HlX8?|ZzmL$Ni0=pN4g3wj8-VWyoDH}Q@aupkAmh0W za3uWI0?q(_Js{ot34Hxj#V?S*4v_x83kX?>+3tWFQVFNAv$ka!Cq)3FAS;f4y_ z;j!X*67UkZKLW`3P6wO=e;;B&Sq{FdcEG8?-vXrj9zdpNCm_@FBp~VD1BkYoUn_7S z;4t`~4pD8x zcrom+0A#&WUoYWManAu94EI0xQFnaiuLm3i_Z5K5*Vh3rg8L1CEUzm8F9bdb5J7Xt z0lEfb#)Y0L}!Q57+~+7?5-a0D?6p*CV(a5aWLCVMKz%^xOl0^hbTvkO#_r5ikd^ z84zP(?h}Il9FYFL4~Q@;4p!?fK10}fYSi~f_VsCH1`F->A-&m$nyFz zAi7lU4*<~>a#sQ_h5dZMYXNTnWW7xXTnv07Aj6FZM3c`Q3)l~EBp{k*ZU;Iy!@mH? z@Xr8xU{ARhhNpZC!&8n1O(%Di*p~q=fc@u~PYAycNPjUv)+6aU^xj{AVhlAeINnglz$uo zyZ{h!-9R`9IEhSTmH~$XCtt_};DiH#uLmpxPM8P09?%b*5cyU2Y?K1$K8zRmAi(j! z37H>e(g&RIT;RKr&Jy5+%-1@=D}WO+fAxSUGo=R-O-Pl?IN&TFBr(eico}d)n5^Nn z1Z`~s#PMuGr=wB&{o#JIg}Rh}f8Z<+nuQYnd^AED&cUSj4iZE29l_U09BT#7Lno!# zKpf9Q7#wJx5d39{zeVtlGcEUL1$Sfcpm{~`vju-k@U0Slzu>dP{jY+T2)%=X50Us2 zf?p;$@2z3_W(eL-@G%npEWs$#NbTxk+@$h?uP{*A$WIo8qoip_|Fl1 zq~L>zBmLvV|8T(#!N&^TU2wnP6F4xy1O@+r;4=h&M(`U1Um^H>!9SAxEfxGMalc9M zS0%nxg4YU8eru-pn}UB^@E-`yahUF!pY_MY@o4_hhXtRBNtWgr!5ajBS?~>lza#iw z!9Nr{6O%SgZw@N3D-t|M@Y#Y77Q9LDae{9Ue7fNK1fMN#ex?J-XQow!S56N z9>F&VzDaQMsGo;6q4{wy22C^v+cW`j;?JbHV@;IezBkSP-ZXc1BPTtcKsoWgY4~5$ z@O#tnxoPzLY3`qvc#WKD45@2B~vo70{92Tr^x&0UF{f|J}KW*S#-L0G^L!fVe5Wn1-(E+gzY?_2$Ds~%2-@IKO|(VD?gW4atjUg&HX>BQ9%XuDBp!`9qfIGQ5 z6gS`@zN|Lj#ZFyIO6ieMH66ruo@#PBDkVpZP2f6-CV9JrSRCUX41L3aeGP_v<;F2? zwy-biIP!{%d;Wi6|GJlAR9h74Uql-{u3A#Ke@uU%^Dbg@~I)mrx1dDn;)aCyCi z3DrwU=(Ip=Ii&_FvA>Sv3tdk($a?c6Nem-m7Vm4rzD3|JDIo4`M$I|iAiZDEz;Ut(qY~*R7w(+dP!O& zHJK;vRMXXsI%&PUKKUMUyeG>v=`IPBI_lcqNe_i!cM1AF@%uUoi;If7(BoZKiyNG^ zZds81r{&A}kw??4Cn3S{ZOQLTezPfayz)^65 z>p-0r%O>^zE9IGVx^yt4OIhI~l9G%RCm=r~EAY_J4;Sl+i*LzU)$6vA#ml|7=NqwZ zIHV5EHj3+MnNwWrz5P@pW@H-XNrqVg2K6FWct=O6VeamDdS$T@8=p!45Q>2Rvu^7F z|104i-Y4OK0?7JISGWf_a?RZVvn11qRY03&b4Ls~d<9Gp2JwK|+lZC#HB4aTyA9YT znN7(;2Jv%B&5*P8Dr6|M0>{BP5Gpi#`+bCtol}SAv_;FKiJ8 znDdLPa*z_QzxY<~?PnR_r$zFRqWYXztyimFg+C)+ip(p&XDPq^18rzdNb5{_DSWd7 z>>v;tfaFjvD%^;n7EB+AT$$s^?(XU54w&bnggY)WVy7}Cr#Vvsi7M6x)RIC{OnKan z{G>B$SbQIbc}N}VE2h$iSW3|S-uPp_D2X4)p7)5=c{?)k2iDrqXqy)i?9XiMM)B{% zVa4)+%$6b1sIX~BXayd_O0276Dw4U0rO&iZRKCse$Q5{b5el^oE@xFa0W+&(pycUv zrU21OgGtR)PZ7hjPUozD&_C|;ysh+1qt9C`jC)=w=XtM*z3tC&-n1BQ`kd#*bbno( zAKmZp|3bQdIX~);VnDIx{}g|OR|xzA#$)1-3G`aybM9#Z-vvFouLHz4*bRhe*-9T3 zI*q!o6+@=lU&A=A_Sewn)czWxRQqcPpY;I3@%vqmxBT9r+;s^a8b(JMH*F>nhuchX zKaV)v*NC5`;?8|n8tfS>cU}J15{FxZxZ|uwxmO_#G>v%ZzE|93g{$U0=X=dkoQCW5 zuX4p&U~V-uYFnQI%4&J_l4Unl&%K#9lsN6x1THIl%%>KuG)p0uX6vMw<|I@mmt9*q zW$N@9)5`pgwb2Rdml>ng%cR~?wNif? z*Ym$r3qJFXPd<8l8of@?RWy#6|Brn?l_7LW1ai<~li>F?=^bsp&VeH*4etAvSpMw! znpxz-@T5g}qDD^*({MMHLo5+f9V9o*?U2I2^w&=@phIr!uqyi0$;FBhXFSS$6(7QQ z@s~ax6~G?-J0E94%*!}0Ao8R7HS(A>5;*&{E=T6u*^fEyaj$ANAWaq?`q75lZ%$mg z55CmV{sgHa&&sl@w9kCY3p-Nuf zLUX+B|3lelCOs6dYc}@1ZzO>u+W)cd6VPOiJ5@-_! z2IlPm_CdK8Ick5xzUFwi7oG2Ny^lzp>)(rE&xhgJ9%V}%Z^v(Rf6~%QIYF}wGAu6y zpl^swssU?Nhkj+2?d&)y;BGVAWjpC1c3B?8^H^=FlUXwHSYFi6vvdV*;UYl^=Tbha zMR@{e=L8C;d~Z3dpv8f^h^H$A-#plR)P z{FgN*%FRzbQ7U*e;_+HoL70$9gRTM7k}loMku%Z>fvQ8OYA}O`A*A=1!>g5mSX5ad zX^m7b172DKeA|ud`5s?Oq1h)(KuF7sBeq)@O+0#=0`c1cY;NH-^}txYmVg$t0ePZ4 zyj&fnLsN7I{#Qpypeai2)2kJgrf92rC#j}r8~&37nE()st!2?@x)8xsiI!-B@yB+; zwKd9rRh|Ht9RTJ8BK+?u>ZlmVPZ?Ej2IBs6+z=Wu#!=1bsta&! zgb{x#msO2crTmtg?{#FAn}3FHczvrpOYO>B!bEz3lP_83R78I^a;WQCm9P@!>;F@Pjzbw;U)4n7qFM-g4VXiS0c&tc)rz;4O8vCKvE>P867JIbO z8Z|G=^TqDZTgPr_zOHHp@_3QYdw}a7D%k>e{GCgg>RL?- zZUM6mouK|w4B1rKECp*xW^P6L6I=KP&2vHXkctsa`2x;K5$d3=#9!{ zIc-{_bpYKsn|vZep=V>99;;-Hc-89v-PmMaZb~ zkm=S@CIcN=YyS`p!L9)G3zlqqUz8(CB?uXLpkc^4+J)HuHv~ZWf#`?KuV>@V$e|wL^I8sMeo65*r&M%T zqYs9|_G?sD`sQNru?3tt4(gI`{4M(dhEULND1wd_YeeJcu&aG7-7FbaCC%6VJcgZQ z&?Y)Zo@U#3g>FYVk%&sZVMe`phZP-_71U5#wT_KK;uHR4fL{u5WD zM4)yOQy~dbFkTappx8UpsX|9;AB|KA?N(L!5Uzx{hrcNVJrR*+Y~yUVlX)I5;yufV zH|DZLtyq{wl!>JL_d)kZNQrWeuayRd-89UV*klWsdzC+QquSuu$LJhhko4}XP#wk& zFd3<^YSbraJQx{}|ieic& zSAUJ_D=vl&T&TgIw&&QD8Ii-?Jkbauwz{)B7`xFccMn0OXQ^jna9GCprn~Y(NCam> z)zPpV6A{Ni;+a6??-}9OBpTnAOwj76wy1UYH~o?Uk-{**6VvQg!<^|cGY~K9fu`4S zMda|gp6GQLU#-yCgA8~J_xQH(19$cH{W6>GKTT0fY{L~g*AocH@bbVIY;ZbCM@I zhFC1lRCqQ*vsMpJbSFZZFSYy)JJmZew_~PP$@Oe}Wr2zf-ur58{1eIPPrT4}<-(S8XM zvvG&1hEBnKW=qh@A?_5S-yjxM0I_HT{>>=+Vod#m z$Uf^$(eT0n_iEAIZ${4n07YgKaY54!UQh@JJsY=K73)KtU<_$7qd9O2wEV>jY)_!2 zV^EoA<8y(QzZC%Dj-FpK@*-c$U$cS#p+(WpY56JXXU0@C-Bt3fD9!8h7RJ>4jJKJ7 zb6#EvzfRy8c#(Nq9u7dR&#Qpi8(Q6#XZW!o^qbT33jAg;ZxCL*F_j?GpOd6*Jg zqcGf!xDY7>NTE2C9;E)r)dR}^N~&|KtLC6ct(191uni@>6cTv4I8kpk^T08LG(gO7 zVYSy{Ao{nYBT1fhkFs3ior4ON_)#^KGo-%N>g7lgTf_4Fnt65qOj>3vT?A#XOQkAD zU8+mLYO54m1vA5(xop7{z2r^1Y>;){W%IqbgJ3~uq4#p{@KK|@*UhO4g&|)F%W(s5 z3C}voYEhuLbeS$p*7-uD-FA{fR&7B$aG&iBEGs>uo6@c zONxeSAw}szluSHopsu>~C`ez<&0ks#dC(ebG_t#PGVeM$lIF1Lx(ruixYUU2&5qt@%@EU5O*38S4Z4e22gvZd@VwxsAV zT$h&aXGwKv;j(!u`Z-lq)wLm39Xfj;MA6h6!{Ej9F0NTrjiCpkr;y-9KTA#53N@~H z=cq={7I;bRoVq&PDh+Agx|*d`)kp-SwV6St1WbNv$R#1^*Q)y>wq%h*1%p5~JhI66-KXJ39yLuBU)eI#JF+J2|%7&dFAt zY%ggIKo47b1Wk_ZqY(PI$M#WOk12Lajxl<7IY1u~kdvx4+8>|)g5mYJKChm4=>1bK zI#Mnsj(%hC0tYVi_bA|{fVF^yfI+|k@ZS?~H1K`+$ibOk{&xYr zu)h-!XY;vXK*qZW5Jx$=;{chyK7gdZANju=@H>E5=jDC_knxNI^Z{Nh@QX}KPVPfM z@SNxV3J^zIxjzNOQBv;xfH+FaT?9z_1|Z9W@@R}d9}q`Sxn~06+avc=Y@FcRC-(p# zJ{5C+4>$(?D5u77KL%v_ZWr7SI2QN-z{}vJKOpJ$1*BZu7uc)7`BUzGK-&KS5a*-0 zuL9!eEcY2e(%%3``rih`4pM#tAj`83FdP1+0W#nDfQ;uIv?tQr3y7-D{S{yqU?U)^ zEcY5f(whWGIzB*DUG6YIR820gltxkKo(#w$egcVNKE4M?`Y}M#zXcFQlUoPK`kn`< z>KPCpY`K>M(q91}vYdMnAd;ASE+9zfQVxaXPI(rV+kXHuA1ej-1C{{K5&J*!D-ie_ zfUNH)0ZE_oP9T~4ARxTvt^uUKIzW{!K$R{){Brx??+Uno?pEi;x$gjirz8K@fNYm0 zAloJH{bIOLfH1kk09kHl1F{}IgC)yj72pWqUk7A;l>w@H0?fzxb^{>#u)05B2=EHv z7X$YKULxn;D2J?DK$klw8QE}v`G(*Z2)rwP4R1fL=JTY?t}zF+XG1*aSb^Y;tE4+=g~=qCj4 zP6h!O@=efxt>FCxpCR~Jg2x2EK=6+Rrz||fKPvbr!QT}8a>09Y-v?%*;OBFr0j5Im z0pfnG;6cIX3VsNK0?i`9PZc~Q_!Plc3jVHy|EAz~2>va>Hwb>8;MYldek^$T8CHA` z30^7gj|je6@TUZSM{wS6$nsbz;a?QIzu>P6{u}YXk2pG%K8H6DE%`B?wW4=@4e#W8 zD#0L1!~Q|{PIPV>%Bj%3R@{N6@N<-kd$zbAfIIzYQ;!!X{);pmeJ#bkF%5q{4gYo; zo|lHRnw;^S1jLDdn&y5^n){42_l0Tr*fjq;(%ieHx$jGJ7Z#SeR3^kvkxFbHh+Ud+ zMXI!m;u=!{z=>V6RD!5w>Bv-B7?GQyOh|ntmdGk9@h@^OLW~<0;vlQk<(2AU5DOEh zT6~77)jQe!;ety;^sRIbI+fw2%u<>x4Zq+aXHzKxIlS#o`AABXD5;!E$&*w3he4gW z9F@lIlTw07mN=_K((qBl<$5}Swv2}0TJAwmEwqp>nxN$n3bp^EOEuU65Kid~NrWbA zi<119T&K&Hk4Q?jXo9wU%5a^zq@0D0eS}Tf4y7rN z&^aEVJ&)80OUlcPPT{@M_p?~{t$39w967vTOwovU!)mAkJhhr&@^%3(k_4Xl_BL5%eBz)+1GCF2^` zIeg}dUPjfn@vAdjGyEyB+tnf;B#vneV4EmA7d1A9W_kCEn{xS2*pgxpl&ZV*+Pt22=3<|7l$wB_67 znGA{qwy@ZmdNo|`3Z0CUAX`XM_>EcHUB2<9{;~-ZjliVI!SX3nE3Uk1+VmM$Uo-RC zuUWM(%f2J-b<2bEIe7Gb!2ruUK5|6Qm*Dj0cli79G5jrd_{n5h}A!G zD+N;i8YcHu%YW`e0`CzxLZEyGfXwX!6UlXebjv|L%r_%OTNCMV%{LkPq^RfB=*9jf3q$?WGe7#zv6}gqOTvgAH}}C6pkO zeh@MgS(SKred^8%4oUT~~zp#^o|M!~}H8z8~r z1D_&UY<*w$_s9vV)FoNkEiiTy!brXxZ$&3&oXmqcA#y-AXvEoy#hH; zgVEw|3_1aY(HvSBh^_E~8OY`uiLJ_E!JJ+mUrIqg27qRJvkZb_%^|~xmF>h!0N0>G z#1NtsyF!p>EZZ40ZyW^aHuXkU)AHCV@L=y}IYfJdeXPSPw7}ex$nH4Bh^ZzQh~4f@ z@cNDfL;zRrX2d;IU%+)gMr_t5FnGsS?o>8~dl+g4V&8-LluQJ^mi=IGI@Pa~?GJLW z+vyfybF7=;9k|Gibz-niViS=w6lK{?+MrdhTlHZ>bOI!|UI=e+)H z2IM?Hur8E~96EP1>rLHi-gQ9V;0{i~;u(*Z8hl5DFYM8P7mAHqR} z1G|sYmDS;CjKLLL#YXfX%J{#?vXxP8E*%7ZMJ~;LFW(vKZ5kN}+GMz6Gj_~3E1;mC*`EQq(F}M-bw;*P_S6&Y z$9lru2dd85NSyVwGKckqh6C;rt3FUP)FFIS276p-3!br81Ll9>qGF-CwFD_wVmL~u zaWgPGzV}#0JIbT`Lj!z~#JOQy$6E@G#^or*8OYf*^t{R5Cs_Pog0m8dUW-K5!+W=I zCB6ILoxZRXMJZmO8MA@Hi4Hx9#+mV^x@No5EAwYkSktQeh)GxN#{*7*J^fz_ z$b8(3OfsIOfY|!ZM;=r;;Y_s&z6*XZiRC3%yPOnzF8akvQBpff$V!&w21Pg$T@kJapeD?jhoE zCx<5u>yqx-vOc?;INYhPkmh8()4fF8?}wdoN1|!CpGx;yao-3#y8lVs)&4Tv?-Tb1 zxWm~tDBBc#d>TG84WFNeb4}!=_i!3sk%qUX;j+%Bz8$^n6{{+T4ju^UYS+qYs9JI0 z+IN>Sij=)ma*SQjUsyeSPK^#-B@&M63!O+;ap=EkE7))&S;sj4% z%aIVy$dX?Yjx-|=Nqd!!Br1_7Ep+@z8#`WFIfO4||L=spLxx-1f%s-g-T$NfW#s~} zqtwIAB9Je zTV7mK7jkx(^!CAF{Y1Xod7et6zuPsAxs3Cf+7G4s@$MJjC4;r5*Ng;_&WV1v-y?LI z8I}fgn72;+VZJ@;cRSY+{4VbV{Lu1e@9&Z%ABN{QJL#RMQD1FWPg6p;xa&;Kx?8c3 z!1qGoE_|Sb1}9a+6kr7l*$oJbnQs{8%SP-s$}&I*Cd;O&?siN@hUdqcma43{;*~b708{|K=Jt)h*iR0B6KqEpANLC z`c|v+{&@%1NSj{*|E2@vbeakBxj{v5}qMtmJ0+VKs9C~vhtizcu1wV++Abtjf&YTXHX zN31*FML4cIbw6Xj;JQwm2E1_Hw_faK5Xbut@$g%5r(O=4L3rq{%UP`>5q`J0FA{gz zhju+j9PWeg&;;;^SB3MO$cc|l!}a2c<6-3-=&{7jGfS6sp;N+|K^)%nl1wk%)RN4( z7_3vCL25A>WVPx=%a%(o#}U6}>5N{jqK=3&xwc9pp6*@KPg{ANxZbzXWAtuu%KAd{ z57<-4KRbUksM<=-9~$Qvz(=b0xaW^?Y4kosBTzI>aNoB?=xDeBbkukcVx)(@v{1Y# zK)W0~JbyqxQhY{5fbe(3{6W8@zf^a?;;Po>0}N`mU=;2V*_F}J zJ@UuT)vd6Qku*OupSABdgRkQq?{qoZ-}f@!fv1mY&*$DYp%)POvA;)$0Oz<+0!YI= zI>!Z;5&P{-I>PY0D5V^fqEaWL%KWOOp~YG&s@?ulzbsVyKB4c5(e~+kO8Ztl51M0^ zLl3Oo#+lB4ww>3K2u!VHR^$I@JHOZ>XVVk(gx5(060k(zI;4+na~~k8>8S0T{fhp) z@Wi?8SnV9nCv4cxvGbUCwm#QzABI@ii-kB|9$x$+cH(gwTzt6hqYmtg@5T|VGRNDl zb-CH?T2kf(L{{u}Oq}glmk+DW*^aT-quQ|nsEnoVOPY?%5xOCzHCD|B(P*P11BoLacLZl|m(m)A-r&*7SgAI0pw%yQ7@s2bPplw%vs@vi58INb72 zdic2xT#h-O@gFfBA6pNRrqf>%@bE~BuKp)&r>U%j90atmX;WFri|sUqbLG+UE&-b{ zShGDhU?Fi%(wqJERs19yIM~AslJqrSYSEiL$!bGKn=kfFcDa6yaJ#RDJOCDE&VF<& z?D;T>EAdEC;_dj2{k`!eu8G%Q0&KKOES8@MEruDRwz5rU!0wMci<0ekP9dJ=Oo^@?4eRTUX#cztV6 z9E#$ zOb09)$&?<5U!5=pzmXCN&%Baaop_sU(EKEn*-mC+ko0Wn9%+6j(uo`esxlgb?tO`U z$U$)M$H{c^a3Nm46AD=bKXk*en7*UfP=*f1HZ!>mn-gk4>g8+eg_g+XwjNvd<*^l++;Q*+Vvpv1C|R`C zMNzv`AhrsO1~?n<$F>Y#WN1f0cp6=>P|4xJ^e3QM*xaz$%{+x}22D@nw-`@k^8t*1 zE>F{1{M(0$=5{Nq*ro6^vRejXP@xoSqF;xmkN42Kb>%yYOILQ3zwmfp1Ua4`3aLJtf7S z2;r!ng-3o090x)=eTz9hE~}5Lh_DYp5dvwEO`Rg z0kzKW>5@ljhYJ}v7GCeP%jFIh+EGK1E7T8T{iAs=qowJ9xX>C~Mn#VE?-V6K?JF^4 zc+PWO4V?l@<>C9k>v6{6eE)aFmrhs5sUh9@p6>78h3j~AoWH@w+fI4-{_lF6aX8=q zUGb&U)p2S_cfP0l`*-0wUL9uwai4*D=fn4Z*W--C`Tp;UFP*NAQ$xD*J>B2G3)k`L zIQ2@JTrr6Nmd~;KI4@!!UClvPW01!@*w@#3=T2C=!JyNz42}((25=w_R~eC8p_Bjm z)eW5CfM6=<*Vr8H=WDx@6A-1wI!0icxHJ&oI+I?km7=X6NCwVU>L@*30&#lLTmR4= z1r9{D1@Bz2lxD&YX6suy38yT;MDIP7zNfozHe?v@5iVYF8FYlpAaTLjNm@MWOCHoP zuco=EPdB)f9N|(zYSt-2>Rs}>8uSOvAf<)*i$MITJXLDu%ALN}UM^oN=5^EqxDy-m z)}uH}R-BC@#S5&=#=K3cgl)7LZ{_BLc^d#3;#EL2H91tl4BCL|Eqrr>+bnxE7|$n_ zj#DvX^$NsSx$*51@RVW2x3byXYi>tgJdM0*cy%v+s(g&MV0?wUqbC-gSiPc($pw$k zneYcsa!D05KTvfWh~J)wHgDqkG4w>xT-h8edv(1#bgE7dBW){tl>p~Dg}XXH4czc8 zKE@+7$A&wwMAA(M8mY_~)`u598v1EM%vk#s_;YxTCH;Y*#3Jli{BkX5 z*u)DlT_LSjmu$<{M+uU9N?U{pQ~M#dN=KDpm73TiZ;_04iEXw%I1-`$_R802i|B=~ z5!>9UVoh_WC5^CGT5>bssl@FR7}Og$sN?n&d|tI>S5MX(N<(E_1%^!uHv?`9h_F$%9^tQz~?G_p(SWjsNxCRGv)*iIgSP7=6W_zOzT+P<( z%(P2?*xoTgUD`r#Dqq+L>r~XiFT0sdn#b=WoB{Rq0GKnZFE^A-A{#xfudnT!Y(?B# zFMRWeu4Wy-$Hp45JK0*1OibZ>LciDW%UGnGDSRdqNj;1AnnHf2B-KtYO8()qb_J+=g96mpM1~y7M-i1_L zz@sYCHQ){e3<&ACpmAw! zF(476gdG)3Ljv8}4UvH2MuF@>eQ)vYn!Y8 zw!-cmm~-tDjpHpASZNryBCCsh7I5v-kr)o*baW7en+SgLYr6DW@GC{RF*UU;lAn`_@d9p7sDTP$L)wE+WaE^2U^gJLQ~+6DpvV;9d0%b zoit5@Cevjl?bwc0kM3n77`UZx5$51pe7L&7Y2JXS{4J|9dNC&5*z-Pb?3jYbD5Aum zf^QQ?4d8UDyZK8x#qMRO@!Oh)F<9?F%j7iGlA6&0*lRpp@u8V2>=bu%It@errCnWG zea?pl5B3S;Jm+2ezEnYz`64W;Xl_8t<{{0eRQwa%MWNX69A#_sXbeL7VoS3S2ZyZQ zfMLFdjX4=qbvOS}M3scQ=}!oH(1eb*CBzP2d^xmrA`wJmG8w-B&T7=7t(nxx(Bx&_ zEvE=D*xh_N0&rZ7A2CW~47Qq0O!I@&DoGSd@QQQc+^T~#XIWQaMR zD)n2m_zm5N-6q0N{6n>oZmrP zmCmnm@@?iUfxj`wl+Jv(vC^P)_$U^0_&AnRK9c1$TTZo+r=lJQS~ja2rR8yk*sb(p zn|O|$7#Lr$WfMc0hX-roz0PZ>S!GpVa~Mo?^eJXx$R9WR9dx&sbBfMN=$Jyr zmpWJcS~{r8KcbK0`gD==-$2I%=QWBShe)Kp%s{%#Bd%4koa%`GgwJ3cI@OtydJ|LI z8KB-!7dIC}8%t4r=&GvEdIVP0=MkLPv*oSK~JC%y`xxdblp~vA^ZIw5Onft0RN*=cV5AkDXh z8i|IdkfAOVCs2{q6N=P`PeYwW)ESYJ{ToWA`KC^r7Ay&j=@~iJbSt+f^Fw=FN!H zq|*>zcaRj4wq*FWux7^Jm}Rck`n->&k{?+y%ZZ9CV9E zZSi>Hq$Fp%*0_b8JCI}d!1cE7t9EqJtV&)ed%F2HO<=ZlmrAu?538Q?%eI@}>Z!%a za&qt}ROg7Dv3Z@NFukgH=v$-6V2xuG13O1SKiKMu_x{!>`1n#$yo0;cA5F;!{Ztff z@KbNSa?ht0M|_U*?$S@%e3ioD&MBDZNW2n$y0utfSFar#>@Z$-cF={A(3K=JM>sRLspXQal@cM<(1RQH}DZu8vXQ;=_du}$o;s0RNP zIQgUZ@~z2A0S|2YGnzOz#>CTj2xMn32~`!n2rqm>vWbkOHym9eI`e&ckli+wZ>Lf6 zFeKr-3X?kEmF$FqUtavZT^LM1W$-_e8H(?~Ip1;ET;d(4H|`zZUOhaFZ{lB}K3R9k zZ=hj+^z%K0_hR&~$RoQi=>E+Dm@J?^&=n8a$XTcq(i;i$Qpl$d*{$NB*;U~YG(5sl zTNy8`aV3t&V-g?MdmAGY8Rkq!>TYgPRY1QkX=ED{^L`Jh6>&z&+_@f3#%- z>W+E4H7lEqf!s*}k8yS*g0V-a8A|&PB}MlKbK{b}sUx$qjJ>k(0-IBQYn;_tN0qqH zw~1fcpfxx$OKHWP;6xLZv@I8#op}dalF7JfKoE~Bahw(5lw{LFAJw#|lI7qI_a5t4 zh*6=%&vE3(HWNapYzEO#*;1R~#8WAG(M6>CWr;O1#Rp-uvvlv7x^L5D{EuJDD=0;i z9L!6mP(Y>WNhQ@jNg5OAH%9rXTSB*8(U-(q#eb~bTeT3zTgChpE*s``4EYG7Q26}| zzc`$F;qtA)?~FaTSMaO+q@%<8ua1sV{0`tp9rL^UQ|vYI8TJ^1TNQrKeb~|QD&$e0 zV{Y_|iK_0VI!yFGIC^-7#{lo&tBl(Fc`@`wd=$lY3}=9s5`oInj4s$9~;I;)8cnpVe?xX_aAX% zKfGqRo0q~>J`uz(!Fl7>4;uHQC#6!w~>QZ8JEY-f%=`**4Xlk zD;b7uYVM|^;E<}*++FEh)*6hJj~0{7or)`h&6!k#>In1_a@u78chjTr>J*QjQPqWW zb648ox=xzm(#}r7PEL_YiBbB(qHeenBlJ0MHMHY8BixLxbB-{(Sk;G9p}Hon@q5?y+k*3y`vimbe*r5CZji|>!v~vtA=pyh4SP;?zuu2J z)hDNMYkTAVUJK3wsYiEA+B^`5zJcdcXv}BzM;ZS>%cVJK!ImpJ8u$0Edy74xbF|lf zZ)5~Ezznn;pB^0Z>4IGKy!b}lR$r=i2G6b|-Rloshj&(QxX*bl!Be^g$9xjj`NKC$ zGtjTc*FmTf{VLe<=!>Y){JyC_M4=W`>d&O<;okb=1>YO+fsb5t=bEY4QS}|Rt&uNV zJlYz~X!Ev4H4rRUE7?XOV)>wgdk*ng9{~f=7Xs1O{LwG{u`^>!7~$HC@W8!GcHk@{ z?6Fep>1$JqVB3~3sSHGt7=$hI25HUo@QEp!^w*l&{L7wQTM(Y9bqm7NQ*=26-q)7K zfhZlM0A~$P@eSA&>D91hJKqq)Py1s}aa7D7`<)tUUi=I{5d=ZXghe57Xt>rkgtKBd z(eAxl8?Z8Je@CRZzws%x`XM|uB}t5fGfDPfb&?G@GfDQ9B;8GgsANb_CwnU+N=Yv* zJWb~)Eqq=|^fVaJ^W|MfkC0tN|1RpbL?6U-@aQX&k8bX!7vQDihOmixdMwi)<#k}m zq?pfZ+S&Z(Wc>cvt-52JEH3NrnO0JS&mws7Vl}|tT3=&kQFwq=gHX@;nbz92HF8=} z^f5Iy2l^}1)N3WV4I;gZqPlC#dgfTfs}~VBJpCeV4lnY@o@Vi?klb`O_B8DjahrTk z1bq@rz-*V-@l6i!l9jIcu!C=}uR<`VBa7d1lMeVI%L$>!=$q;YB%Y8P45#P; zVV|yjsm5BXw!r|ThO*SG@m}H2_0UiFLz6grtpk%|N0=es9RmYjdO7W(*uRrenmOLgz-}fFS=wv{bgqlsK=V6PR_6rF$Du9 z)AVj$ry7HO#l=OF3vE_d21|}?3g~L7&6lt(P%Sby8~a;fFPm#Cd%Hvlb_}|-q_T2; zuJ^hDRTYa|u<-(4Fi;qnb`j5!sR`2pQzpBLF$@^+1z{B?^7y7t^Rr9?a1Z+Mf5KE> zC@+NGU14BSQOPuQs`vGAO`aAExn@jZkfAPg^3byz?<;hTFT-{=Wpn0WD;scptBs9Z z=#owF75l~qf=r!Rca=<=GPOt-j$98{(F|WGFu6#I8)EVF$&-p)!IJ6Y5&4v27y570 z=T|PQ)%$v3nO1n-{D|4!NRpaZ6Pb@~h^ivkNGFWFrm(Y41vaUwswu-}Iv3W>!@d4kGbqJS4dYouU(0oq?OMtn~zd*l~h(CL$XJi%ZELV>g&DOHVoSko$eh_ z?((JXnM6AC%8E0w(~{E%yN{JuR>4zWLEH+w8+d(+CQl1Y@J%b~+9@?n6*E@{;u7f* zV!JWepGns{$4*YwmCVk(`f9z05;hyFtT+k#cu5r6qQXFlZ+x%_bnw2t0TkMH8+;Aa4J7(R>%nt$#zI2Pi!4_!4LZ?W&i!{|A9^LWj} z_!<3W#t@@#^WW~ui~|1+EZL!xfQYs>fXD07paWllX?ehO`R7ac^8*Qd&+*Vk#Mga45F z_t^CJ^Id_5$(LilE_MBF`hCoOZuGmTFJIgAH|W@t@jL8cxt)eMO?gC}`f@#}H_fJZ zz?n}8M|-cg>D4&nbJSPrKWx+QRKFbhwBrq%ewj0Vo4x7j$$Wk0)Dxb`B|}}V8^B{z z4MbazHyd~fD4u5keUNj3*h?nwK)&ApsTK$u^Ns*ATsOf_hbTUryg2Y;gntEyDTbal zU$&&VW1+i1s0G=NWo`vn{~8Azugd;BOA_UdYD-Plo)( z=`I&m&gK0Y*dOvD;EBKzpci-~km>aXA}gM^^VEKEo~MC7hx-EH9l%3@j{xt*1(^c8 z6*vw0QQ-N&3gE+VzZ7^O+&w)G>ct8Bl0zQCxbtrHR}0e=JcYk^CFHNXi7cQ)`w$UT6|fnN^L{vQL!!~YrJ&2axIurKfy zU?#90$of7JcnjolKn%fojs@Z?P~Hc)F?qkN1yXOZ;DtcyPX$tcC=i_dd0(LNQtufc z{Wk%RhyQvY_3i*JhX3_I>XiZ?g5Cwd0{EXI?uP(bt{we#IVOOV-x2wFAjAJs-0v0l zCE|X$xL+*p=ZO1>;(oNae|?gU=MCTz#Q!>Q9PHQz#4{{!8SvM@8-WPo87%V2K;DPl zMg9r`O!mA3r2bAIp3$D)i@X)c`}b!e-vvZaPekNu;0cf~5xE4&cHwA|4+owFc_SiW z{7(SSgnXOGD}iGme}+hykB@<)AwL5A56JU@S-|swi;=Z)z=t7sAdwp&?*_6x+z1>A zoCs9)0m$oi6!2cSlk}VJj{;!)u_1jzIb9I5sT^gIis{3H-f zzULtz^&bG{LH?=u-vT@hGWVBb`3?c{`ko^G#{$uWdbs~x2II%b7WEQ9#{V|(RLFl8 z_qD+L;l3EicoqO}gFF=YOW*)tF7!_TJ_y+jL=)%v=5P$KLcSTud>;n974qAM>2_@u zknzqp#kNbQ^Fb!v7M8s_MBDh$`qA0c3d`C&+zPDZk%G;~xbd6}(&U zM!_l|%jbuysi^~s7juT57GONjs>#ZvVknObRdcoIEpt z*8x$+dkNAU_f`0~>&s0<*QnaJ|xb({;C z$ntGRxy^x0WI3+^qVCKjvb<4Nu1d&6UPnK$0x}Urkm&`MLnh+L?1^&EMBL`^P=?}= z(b{FC$m>wpJc>nssTN%qQASy`57Q2pi~NSjSBkt#5oFA!(+MlZxH`m z#D5S9i^sjRX`Ogt(@E<|I@;~J5l z%hhs}GSdHC;=5JkPeuNz$X|;5fXKX=cswF=v2RQ5pZSB6C6n<yMdX1Z z|BW*2Unk}Dp2#1F{F%rHMDEd3$M>L=Utf_Q5xJkpkBQ9Z1=GJ+@-tB6QjyOP8Jl3L zLp^7p-%sQM@%M`y5cyD%&lmY!Nsm*onV$#pbbQ=Do9R!H{9Z3|5gHpF&7wasU(0ui z|A7%&UL*c_r)!zdN5+5Z5G}tZ`Wd4ChRBm8{&z*bROF9Dt`PYPk*^S$4=2X|E3wBz z8TK!b_y>xd5cv#|2Z_wZU<`k^*cTN4CnW#VMSfl6nIcCe{2Y;EVo$Be^Thuek-Lfi z5|Qs0|Cq=Dk#85dUi9x3dAOv{bqUPhXpw&_@|_}Y5cy(}w^By_J~&O6|108OD*k^H zxl-hJM7~nw4@9mL`E!x475N*H7mIudA0n_XDsq;{D@EqM@$}y=`Ryd(YJI_ZQhO@>wF+ zip&LpOmB_Ivqau5@&b|fh=YorK_U+kd4|Z7L|!iPr6R8r8GUTEZ=m6u+=^#4_YoW-&u3I^b``8+yhF~ywYU3! z48bl>cIdz4kP}GDuD{nI|H&ao9r6N4eCWHU#CNGfzTF`Q9QJbj*>2Bhha7i=U*NFk zK8O4_hyDOZe9t>%-e&gn*-y30mpSy$aQJh7cf0-shy0L3p6UpHvcvy#hg|NE+3&Td zSL?8kEO>VR{*L_p$>HDZkk>op2OaVkj`&tP{8^XbWF2=nNpM z%k3NB;2U*CRb^eN`o67+cd;*JMP+$S1?bilA-lDGrip;e=;l0yy1jNzU42PqczP`- z7fissgK(wUT1UJJW#&Pbo;q9!CT&RUjzHQ6DVA5)iiYfhuI#L>Ev*OlJT^r);=K9u z!kX^76ruEfpW<6zUqxEm`Iu;6?c|QBEy=L;VGzz&mzB>=I$>KM?i`WUFvsg&y^D(20p#LfZVt_0%p>eBEvwUzl@ z#UzPYN<+I+lH?ZFaHfV$1LYO2sd6DmwW?V4^_VweYLUGxzDHgx3x+u?K;^8isjI9g z3ztd3bK6&>f>f((t~NyrH55t(Cvk`x@4l3pYrkXbMQLt0%*xN2#tLb3wVjq$)XYaZ zywh#ExB=!_+g#b>F0HMrS$K^JZ)+y%jgN|{qQ(_0JsoA3KiZs_4ep1UUF?VEOR{C* znrfpp$})xbti&(r^{#^r@OL%;aLExkxb2x<9ne$YE0UcsiArs=KZN zJHgFEB)Z0$=xx)iDkc6A#-x!}LdLj}#_Ul;4jvEdzqVq8Dfp2l$`QsclfG*3jJheD z5&6c&STM?pz+BXkrbtH^<3<>lQ6~5><1);I8g4Q$Y_w#cx(s)MtsV_C8pDk>!%cL< zjS<7mb;Y}*&gpO~0V~TU_(&6cgo$~iQI^0)VVH@3n2CRwiEa33+jezbw>fIV6}c7d z=kqI*lH68F2gkjf^iZ`wDas9ybVxp{ZEiKmCLrnRxWSVi>WP~ats237z_2etYCTmA zR%d73W+mO(A|@rPjbgizbhes~q?1((l1|1R+YOlX>~vcty-Ya!oz>Y_)%&Eg?G8>l zb`cZqE&BgE`!wW_95Y()>yWZfLv2m%uG2C&@TvDVJk|3RndQ@$Va zFfxWSIHbgH80z@G`!v*gwLarxl%sQ9uAOxHf%`O=c*ttaqk%6ZwnNOdT)u0chAb0a z0(x`wz6x0w?>gR!C3*5)`!r-BJP&>^;^7^rvp($6 zptkqESu?yn!A&6ijaxHpl<~WnNs@$kaLEI)6aBGAYcYt-)dso#nA%zbA+l^C%sL4M zVrT~XZ;-PrpY!U3&(nTFZVN9g;>!YY zqh3vu7-v{-;mW06JsQq*Ma-hL)O8MtJiD$AZw0}M%x6;7u_WYBO{=D;Dup@sDA=Ty zWA07*aRfv&Zel%%gWxxO9=Lo_u)UM?z92*V!EC!0qiu5SiQ&2f17)_p_L4moqp%5M z#r3kaxU?xGw#zo~V(a_|qRUz#g`!*50ieAbz*)Gejs#*`8c;}YmdbB)cm!*aTaW;NlP5!yQ#Mj7GL= z0^7sI942b<*M6k=YZW^l_hYd0*Mgfyjp3@rPSabZnuoz^Z)Gc9fV^S9c%vEXtj6{u ze#}ADvQZIONUWT`hMPaYXtX-&gi$DEC)YIc!b^N_!&xl|4L)5e4r~eT3 zf_R5wO6j5i-A&}L?OZwy@fYE4@!DqFmQl(*#RrddPucvF_m$qdQuCYs?=soy1$=DV zJMq$TwO8~j64PF4Bc?4j#I%#J6m$k^gQ;42-E4lVS$l=`n>l*v+R@0bur}xwUqY)J zPDh*bo?kQds@fZSbPr=p64&md2s+Rd;#xZLu&oL8rM3=#1~o5i*9*_vxuNIYVC?>O zgmX8Qq4+@`KqiI63@pKmOaK=yy?9wdU^i4dSOi**9EC;f+qt|v_Y-A((yY+-W@Pgt zchlVn5@(ZPiz40x#|iGu>1Qm5G6ao_2Ye6Bx_1VstnuK!E}yXO^fP7C+M|MbYD zKuci`Xg8H5iNeNxeIvse%H4bsZcPcvdvF8)C9p@v*WDtAi#vM?8~87Av@H!TFRZ|o zW8MN|o~vVK!)UM@cfbKF`~qKKtI>UA8jo5|9nVD)i8H_p>fib{Np8;x=Duw*FDs*^ znQ=ESM}p*S_y}#Clx}Fu=k6tJPg$<{!7+O`K*tp>3*_z%qB)0;+2$NJZk0;>!qlK2#l#-b;F+K;!1+C_7geot?K-IZ!XA^p*<$CwU};n%Fje zS|%)O>3dWbpgeuCKW%%*u2AgsK+7hQjp+y)zXmnsHHZS&BHg{DFTUDi_4bM$q>gOd zKMtEc^_rX_F>biC+qDM`ap@pS)~KVWfe z-Ol(XxQAlnLM^{#l4wA&eqUnuin1%oKhcck@K}iHV0JH8ckC zVQ|vskQsj*fCm8b+LS*RMzYAxPyMMgW5Jb=&J144P|A=TR1tG9UI~2D34z=k?33O z>9;k{lJs#pBY9e!JoU?|HgFZLI2v^!=VSD!-&QHdcwF?og6kKicbgrCg6F)@lOPa_KV&daGM{U!UZlx|{ zMao2mPGuMy0Nf5Oj9i5>1Vm@DtYdf3oln8kY@}$On=EkT#1$V!S=}Qgkgdzq#ocux zZ^^c$+hGK&Zu}P9)T+J|EvH#nhTTBak!9h=4a7F8SS`4UsLdg(xmDB4%QV%MU<*4ex`H*#Ktdr!|CX=73Y&6XYM=nqdYf%iE zBTe1Fp|z?QCeu=K#1-M>V8t*1ezr@&yZ3N7g<=Dd{dP%zyI?D^t!SeL^^C*Ah^6ey zU-}OK8b+*<2W|UwP^O1kVb(^hk>8+-!&ETNOu#bvcEzx{7J;xp9;`Z{R;-ZUSQrc8 zUBY^Lk;z7}uFXK1*yz^u4s`MHEIC!W@{OSJ2ZC|;YZei%fiaxL}pKq~8lo{^zAw;_0yP&^+ z11CY^Vv`_qd;Q_;t3;KOzvHDi=hmV$H_+dwE)F;|cR=#p6zqXM6863WL%R3sL;Pd5 zEl7Zl{V7{)FVx4`i;99^r7-7fxu7=KE4ZOW3pz?7b`mVMeo`# z5^0F7fMwm{AL0K~$STSiMe~_G3RN_|jr7z596C&vc8W80{|2+VJ}{;TkMQ3@SB&y+ zFpHwK*ZuH9FYFNT@X=;>^IA9v>*qmI#??p445(9X@bP(qrimfhydBhLdPb^ss0`mm ziiw$8O!IBTMMlL{W+eRDHQl!n1?x(T(V|z2M(Jc2o*wbAqLDJdw~;;NNMEg6pv6$y zyK?!1x$p5lYW_W5*5c>E47xfNN)u(VT4tlUS8c_|=s1T=Cc7ckn3KYfw>exuPQq`l%>ZeQOk>O%z=aW71DW;ULD;ZLP^js6m;K+sTBY z1{F9VdyK-Uoky^`1#61bv+!9cXl=ur*$a$_HLSEn%mcT>%{IT zR&l?Yw9VbbsrSadlpqhm!|_a5O{dsWwpnYtg@=Kogrh0l!eC?4jdfzIG-+wZ1qMhl z#D9X&YeA!UFG^p6LgLb7n{qr1Ek{ooxr)Axr^sqNMOGOb@vK;l2V7(rE{8l>!>6#X z@{M6Q)Ooi`Sh~jyhah+h2j@<*bmbu*Q}0Ick5P0_@|N@GZuO`AH9RrU63$860@IRL zBoJMy-{@PzrvzFaQ?D-|Pc*&2Kumd$-Ho6Dz?;}~{f?3eT| zYW|12sW)SYsU9IWnCRzTdJ_o$;tZo6@J(;xjGZFgekG37uG>>wLF4$I3DDdFF{&Z{ zMh;d7+Lp4z$D+e2hYom(jep$DO*k>Ej+=1~!MXX5sinBG>OC3*KIh90sgZ%W5oaMj z==h`CY?+LlZBsuwm0VLr!?a)w1M`rp%TqK5ng^0^{I-!d$-TO1Q=9O_%a)(@cB~m7 z*W2RtZ5oZ(6Zc!X$w&(5ag*f%A}5^{MSC2duP&n+rj<=xe47|T@j|Zp6g-Wy_jGi; zkKaUSegka5ERw5PKEKlXwO6e0(Gy;mOXqFry_1Zm33U?Oa?t1K@R~dBIps@dJbkW z9g0ye3jF@G4g(d~$tJlmmL6~HieRqx-~@9ZX44ye$@dMzGiTb2t~o{uuDRU3OE?Uk5%!wyvf?;H{}beCY@sr67GH@P2)a2@PIo9%MJuz(jB`*D zd~+A+mm}4GbwaG)cvP)9A@MIlTw{THPRE#ynK(`wTCKZCFv=Cbr20#%?n%_^sB^PRWSkVxZjBSKz%F)F?B*QT*A$!N6`27|WDuA2}6NWr^b){>HN}KJ)mnD*=jmfQ~L88T;r;2d|{9 zrU-&9)!6t!C7Qp}y*}t^-HdJsa)MGYG{o3t03?;&&@^O4-oR!XZ1bhNW!-n7RmqzU zTPUh0*Aa*)aj31m&2J6F`d~A%Pho~h8-|u=t8jNO(}+8>`gsQO;{15VLDEdrp!jt_JeuRf+a2*qNvckb_%p$ z$#>A7aYj%l`ZLn&v1a`E$9$7yf#%OL;*W*zu(jjSfcrw7{J8&2`h0HwUmT|VP5Nv+ zdHlOPXgLU5h#$J7>WG?%4gZvlSF6gV$8&WUJsYnV*Y=qBK47nahtcbT&+0jN8~rPl zvQ57WeyGoE`W&uOhlyWA=IeOm#l*`|3Uzd$S7_6F*r{jBSCvigi0_dvI}h5g*q`HJ z(s%HH(cTwr@!z48ZThzBVCO+&S*yduYvaeV^Pq8kPl}$1rvVF*7gJ8^ivj&id=5S_ z>W6LmXE@_^Twmtv0h@j)vLjzVLos;8i?UV+(+n zVXEC2AeL5oP6g&d&H@eszI~$N|Hyj?coO8JfZ&D5d;SD9!7pz!5ZxBfqd)}lM1c$7 z9}@rZz~ONB0=fXV?I27@FMD7dBhrAz?92xIsU@fo#h&u170#-vF0Ynw_oCLfI@>}Ss zVpf^wDInUEysLoyAQuAh&fz&4i2k5w$FVxySAclw^t=E>=f(4L;1pmO7(w`f!0Um> z0EfW65ED}`f;<*@2IRpap9DM|^5G(90P!B`c`sY*zX3!Y^ZZfdR^Ta+ZvbA1a+n1y zMvyVUFmT7wieJI=3=l83p6h^f;C?!AHn1D;LWKJ}GE00JNc$fKvOIqUWWGv)iy)5! zUI4w`Khm3z7FQkn!CJr2n&0P*K37Wq6N>)k^9 zqkcUQZGvY6koi8~*5$DecrxVOK;CDYfy^g)dio=dC_E9`fs`>jq>x zwLt1$1gwMp*+8cE5=IHA_X}V(aH7b^io6*QEc)LHtOW*u#{;>^Bi)Yz;+FQL0U7^x zjA!t^o+@}cknV>8%i$i+(BT__Gaz3D#I5To6}gvSy14f^MC&caNC3-sKJW^Jn+3ca z$k{0KfTscH0{a7TOM8w3GF|QxPyu%iK_bdLelw%~8ejxiF7Ca7*FsJMvcBw0*Yc}C z+!~&TMZO=%`a`}D>XS!=^=-1qML<+J&xs-*1!Vo&gMJ|O-v^>9d44Z)D-c!0^9zyh z1oC=K6q(NsTw2dtz)FPQ3dE)JJPO1m@^H%}mP?T!_Z?wA-$>Kt!RIK7(6beYBJn&T z?pzOxta^S1go&QTf+K*X2tN>520R)#6G$G>S-?Fm#dDMQv>@sXhjvqVgC;{p9#y-< z4;hyrORInv1NjC0QeXpc6fj%-v&5exu=IBUM+0{u9yGa%HwaB=W-Dak2H?@abwK1- z@dlv^D&8PewJv#s7~d@DGd@3%@e~NcPsKL`$oK{U86R|9jF0)@rGXz0Tq14%K4d$D|rV~czwn~_QD-U<`*n9q-73r4v^Pp)ydlB6p^z;_ECoZ zQVGCstcth7s~x6_yjbLmMP4bg;r+QyrO4Yv?v8vg z{XdG_N90#U?nfEr_p0RgB$3U&DT)^e{vV2e0sRqQlZ5w+e4WU}l%apwu`YF7A^wk_ zq~&_?{{WSpN3;0P7yp$aAMh$~*IlCjiNyC?k+-38^LR$|Kldup^#_r+NPOJnf%b$> z)c&7{|2v}prO20xes?r_)Srom6py1sZV`KPDI@wGPUE(VgxlZJe z$k`%aAo5Ehmx}zB#5Y&ufcRe}@-&gJ6?u%vjUtZ|d4oFBG{a9zG1eM&zSK zZWnoo$ZR}$oFnoek&8tx7MYW`7~fivuM>HP$SXx==a9!kA`cRIo5;l?zaesi$o~>~ zoyZw%1d-kjkv$@_6Uzh7ZpC|I)^o9KBX`6qsZZn5Amev;Po?hScntdn3&q|Mkl}3| zVTa6qfZe~`A=A(9|ByqT0#CdDHMq8Rne&hBGUuGwW%3c)W~LJ;%|0@-{tVX*CF?C=<_)b73)~!(4XS) z-{kN=)#1P2A^*u?e}9L3yW{%wcgRf+`FTh9=??#^9O-j5jy-=7hy6lPP+r~@uL;M7 zMZw8y@}sbo7}^axGfBCPKm~*k|8HO^VKJp}fOJ6%0#j||At@{)c9x9Vs4~=S z2auMi0LeEfYK|vs{np{OG zSX>}VN?Fq{%GQE@AyhDo5QcCe-*7SH8>$71b|c@Im89q}2Im_~^Np!O38L(6?~10<7;3Jb z#mzEwlqnCBgvi#_G(jwC6tH*{`AcVmEvXVrB`WvMs-3L#6*cyA;mc5A?0gx@!BJW5 z;kc6oO}g4D zWzx|eZL%WKAIHi0XAIRm6JB-X4<9;Y)aYTOhYa(2M-0h_+t4BO$R9Ff#jWUkI81^w_~*8#dqz4ZG{+U zf}X`oQHpc^@EXN2Wqz;u!G}x*ik;Z7%r$#D9x#A{09%5NpcGMm)ZTjX8>W!cIBCt?pa#66=rpv#7v< za##3dPVhb<5PK|VA^kA({w`{|6tk#xWF<1?R3>^o zjn4v{k>zgUJD5LO)XroYkPK(j9>>Hew8bcz>nMNS`yjrXM5u!Fc z5Di=2RWZyCfRv(f19zTx-EfgVx@bGoqnH|NAle$DRU4tFB72E;nh8r>K^2TuV(Zbr zV-a`|yO!^Uw=4QACaz*P^Tc2T2~SC?!wqxctN^0S8OPY~96QpQdGnk!XwI>3^mgpT z-Q0+X<1u^c5|P9r0T4}Mww%Mf_KvLhN(2hVM&Lg#!=iRy$5AxvIwXSAM19gcdv3Pc za+8c2H;1+h5w&(?VN=%OLRf&$CY(zcjP4bC;FpaR$m&XAlJ66*pek6EW5>5G#>S-M zZvwHN!Pr{X&-|UL+u&lx1YB*_Xas&8|9uUMyspRqQw74unSANliyc|m0$Z;yN*t5)LQ*dAVhg7# zZKxTGqVH#vvGqA{#excMMXMID>%}6x6}UY(4Pz0Y_Fo;0?(z>VYLA?xN(*ZqR>Rj9 zy>ks9MYCThy14<4q3DCF0MJ}cO+6=)ZKs(&AAL3uTjU^73A7buFi~Gy5y7SQt?jgF zw>717@du;PDEgz1ufw_n5a&px!L{)7hHTlwxtjkrlL{&d$E7)uM`zl`q|&?*DF#~x z(8vULEl(v=QFYhiQ+Wy(U-PM~!&&f$^QpvCa+s6YPi$hcZOV~nq3HK!RJmg<>{hwK zg!U|34&$SdP2R@3slXZ`yJlaoq_8Z~;)i`7wQilrRJx2UJ^n1_^?zrg8S#6*k6Knd z@_p0_;*-Bc&D}HvzLML9_{k8^E>tNtCPl-9<{^^fZ@IS><+wRb)jmCKl#_FHljSb_ z6#9Xdo7+)hHUcJ9?7X)k$4eW8+Q9n@i~U%E#h+%dcIggCQZ5VX;T~xV3y@PxA^mS3+6*8dl%P+1DB52Y*p8HYyZ* zkPUhuc3*Ln@$5uqQ8zZfz_t|g=ye0R#nr$@mMsovXh+*3Cs|J@Q!c9EjjzV__D3&k z&)>;DLgS+CF89g;<+f-8+*?Dj!W=w;;2DfQgXKaQNL=<_cdzf$+r55x_Lxtwf~Do$ zv_LeNla1ZYLA8Sa>5&V4+X{2MX^H71!1w@_QxWBLa_N`bLtm0L1p&!$l=&4W9jf(WUDLosrtJ}vfPtV1I<3Ma$PIe*? z;zFDK-6Lmqk)&@k>aHu4yDb>~m%2Qmw9f-=$Rb?zeG!U&lR#7b0uZz8{bMfM?p8D= zFxDTttTo&}8LO%f!L)78OyIe`A$V5x_Q>J+J9(u|{}|6KObEwAAgYQHU|mDGZm1^M zoj&>>?9}J)R8N{gwmXfL0{vd}AFyz^f%O3E!@@b%+AuyAIb zLgl)E#PM`I)!~RLsWoD~tjeiuP4qK9rjMwcv7SKI5FE*P)muR)2AXWtT|9M*V!v(Y z849Y+Mn9t#T=j@#nLd;+`dqvb6BPn2KjUNBZ|G;Xuz!$3Kl5Dt66pD(&E!uAv@8=A z8m@wm2k}V@_r#T$wPGzs_q8ZGk;Z)$?#7!C(xe!Fs5k0gY!nu4Sll#N+HO-{@+#ht zu}T+97q_dk%~>#}TV1BFVGHj*biTM18k%d>kB37bc9&|_Ta#-vr9f4=A(L3aSQvYR ziyqz0x4~Lz>)B?+$HO4s;sb9m=H}1w;%J%5=?i?ybj=;J_`qb8FxJ8=ttV<#ao@EN zfaR3gd?dFh&KY9^Xj|xNH{}on#eEEN0wjy3Pm@rXXO=~WLG#_suR%xb#`GaH1^=-zq{=qUX$)!0s zosm2(PM-SZRP03$gD&poC3r)Z`U{pBhE>-XmyhQ{Jc9*W%C#A+8M@{*y&)E>bYO?WKjdrN`a&#AY0UV)%7fP2iq)gpDf2qR>N+k4ib=9Xt}+X z`4CXmGVUt$U9~KW%~ad6?P#VrcEdaK01Q*tt7r{V=tNXwir_0|KsSY0WR>Kq!F52n zC`&unqhb_dC!4ycL?pJdSE2}HU0UnJsI^3^v~E|WX{77SP*Ivy0vOh zEt2co*3^@6_Xa^*n(C)8`_X4rLNFKpC(vJ>o9DtjG@UdGJrwY_CflH&@QTF>GW=2H zZVIRAR=Ar7AA1G;5JmE#TsJ(Q!Es#$%&iXR(#h*ZC zQOmgllHst)s5`>{WXUw&)M?=A@sDx4o4mA4ano^NaPc`Mfs2dWO%>V|v^|&OO!3#) zpY3Gp;l^m-W##^DX@SP)zHm2ekz8AGT82uDH zf*Ww=@@?j&iyRvN6QrB^^t4g)fZA}uhX3yVsM;1Q&qNfQsk^urPn!Ym%_TSWfcL7gQ*i)LgO-y|{$3#D7F3y*L?}{n3Tp9E{8=(|~ z^s_qtu!ZmWa$AQ%ai@&Qpg!jkZxl%nU#pDu*{#9Ro^*-Wm9)lY*$@^oq#JO;` z8<-NN4{v5|oq2}thn3L(0llbO&>Tx7n859d7r^#F%sltmBji2!Jef|*{ z#mYLAX)4k@(~V7e+*^exW-_d*508J{sXnY$SLq&jh*e5n;gB0CZ(BxgjI_iIli%;n ztmAGP&yMngv(a7C2 zs%(W|GL;+m9TPrI^)dS4`OmwwF#793G0UIKK20|xG%0+Jb}yZ{r=ugWAo)zMyORAw zeY1h9r;=7LK9E3w@cAh|h*I?i79ZgBOLy}Zko~bI`0Y#O`=CQIMP%}oZkDdc2+6yw z5FaxZKbMWzYy&<>{7ZP-s)cXkXgEY(Nq~Y@jX#kW;)~R_Bk^e0ehito%bt&9xD5Ek z`I=-8sxP5xt>c%%FBudc3U%@caN>&{$;j}f+7%yck1Xj|KtH$LFU5X#;#Bi0gN!PB z{^(0$iVFP-uIubo_kGmS@icztLJET4XDeNShv1t29KW-`@AC!?E^0mczqtg&yDl9fPVp=i=P^uC2cp@fA?^( zvu>JueMaNf_Qw6a76jbu{b_PO7U$jMJRj%X!EzWr10i~ZbKUE=Htx%d9II<^$^4XJ3C^A@oaTMS(zNT!#Xkhz+E8vLLmB@Kl-IVc4lk|J9nD(ho5zvtUv4)wJqV0 zR|d{(tUpwCvi`6ZX=T;gl%YU1>kpNktUnkjz#W#xS63aT0B8RW>klK}`(3O*7$jtB zd@ShH8tkb(0U=4O!&gu{u@1hrf%S*UI9Y$#*F>x=8XYUEkfG{1IO`9iaj(Yzuvi@*S72%mlPjtuNzI%Q5#(llQpS#z$HtzF=KQw(<4ptBJKgk6V zEJpYGY27<;%X$~|1-I!d^@o6sH1f|x`nL4$7-~Mjx<$yV)%bz;2lLESH$2UEHy23c zzmsPs5;7b!#ot0LgSYox{P5tlJ?@KkAqiKaZwl#*od@P1Br=JeY*+N{uSfaY6pKA$ zYf}U{Jloc&Is)4oRZje|+c+R?JsBLW04tOX-~Fw|(CmkXv&yvXG*3KqN09_KoHK>aw^fT{{t$QKBD zCr+IbIuqJ99bEV+Wc!&^6ZS^tS1zo@L~2wc8tWw0QHd1!wLWX@k9x>* zNTivj_*j0_#F5x5Y|GTq%~fPhe?&CtTW0)-X)`HP{w95XMC9>ZygEy?8Xk(7SxdW3 z=-X5HOgO!@5I=MW)xkAv>M(i^o)qeH7OBzad!{;!eiu9}57_j3IOBKl%P@Y<$};g^ zsUpWe6Mq*xJL#~&=%4M>xAD=OX47K_Mja+z5p#gkYP}m#B1Z1`P!y;hf~jHXAW#L<+IOZ+{EW7f0cimey4bC z>0fWtyU3ZoP0!A&Gu^2tb~0T%uMS6U)nV)uk@dsQtJCTFIO-qcoTl#7J6~KJRBY{H@{=Fj=Z%N)Az)Hxc0a^bK z;1!hleGka{=vTngfg^wmfq6id-vJB*^FDYGNcW!uk)-D*K>A+?Y=nCya4;|vNWGro z|7WzDH$c7$NO$rG8{8C=$g_bPe!A$ZY41 z1uh5f#TW(s{|sCT+yF#V<@qge9^`sp3^)hK`X3az0Eni~Lp$YZ>1?2tn z7m@z}#I5UDC-MWpY{*fO7Xf*{kY|G7i-D|9-}KP(R$vt6@oOM%A;fGn^76!{)t3*==YUkh9Y*$?D(A#ckZgv%3opvWt_>++lrWO+>n zRzPpO;20pUhZl${<6*y${-1W!$o2e`-vm;RygH~Vp7rAX8^P7$zZi%r;<-}fsX$y} z&q&}+2!93;m(a5(P4gkefwY@zOz8htAWZk%C-PlDTq4g3Ad1%045WSy5Ji^9L3Qer zAE^fNH!l5r`4~7K^1HxV;5Oh=;1xia;3)?ph-W&m6o|URwM=7I!|_TK*(xA(6<<;n zumSQ!AcxfH&#%n%&j8Y&kxc^bLOdq{w*$SvR>2KGJen0>60U>dOG1;T_A^+)~>9g-B#3{)oA7 zF9u!)nK%^kAmF8tiGv~ULt$M4nRo_dUjK_B6HkXszJ-e*6Jbkc18@dpB5cZ>0lW}0 z5%oQD5by%XMAZ9CUJP7=nM7RA%pGZp&u}IY^*?hRumt`@WI|ns%OUf6ltG>WoC=wE z667Jk^C1(xka>NIAro0%J5UZ&AQR1Xm<)L>WR~ATU&_nArny~nO@*|kcl`l z$xT9j8*>bx48>w(p2s+m+fUK*4AEbrMOPVRiBJwLD-!Jk;k;$XR^nNSy<05|~GQavWKPO~pdtMj0@lY+lFY?ckM;>gi7+*t< zmK9$T!apba{LIJrjsfyGLF7C8XnCl}eQ{g z$X=0aM9vj?p~%BUUM%uiBHtu(fylRs++E~*C?h{nDWA0>KQHonk^d}m8)f8YrIgRh zBF_@}FCs4$`7M#}7WsXV?-TiBk#7_E3(BzP=Td%$p^>D#|72Z$Ih2w9T?4h8C;l7z zYxx}UPZNK?$cDe?e9@oc)%x>9&XMrfi~Oae&zVn5uXdo;|Ec(U#GVb}|Iq;Lzg6V9 zBEKN=b?S@9_$y`3Wa#s58#x%nOKIacDkSmZX5%SATpjIR*+V!8fx zB3~)`ijN8LT`h7G{nN3oc#tkn!_Tx^H6ni?a=XZ1 ziM&tbKDZB?E2(8wadF4`o}u_ zcRIq8@6;ZCr9=N)`KZ)4AWf(9f5%5feus((I8w@CLuqwcE!ZByv&C*O3>}QDYC+vR za{n;Y!qV{7^J^9yoLUIcd<(G^SUUI_a6afxQlqeO1=ZJAkvU>MzDJeLubF>2J|134 zRtjBuG&2k;qUy48aF}R*pxRQQF-bZkX-vdTQ#4gomd$4YsBpX{rIq#NWwn*1l{J@( zYk9SuPmFeUyySJ2xU7J( z>eA|p5h(Kd`eb}|hOPPGs_N44HMNz)97>28kyO-G*5eYRu7_)?Os%c23fI&dLMy|P z#R>qHEL9o)TMSi>nxqJ5l$(>wM-sCeV92PH6?Tt$I;%6f*GG6BTffz~~jhPcpCM{*M ziB~acrB;c$^4f4|*h%BsiZ^lA!Kv2-AhSV$GwyEFxO1(@}x(~os@L8ZlcZnE0|VPLxN7AIQsP;%Q-69FNKSn3mKSusK!uT|8P` z{l{aw^wha{YL)``UT|{$lVr* z-IFr|%4B~yRXK)Y%Q)QXi`~2dkfQI;eKs)W&7gbAr@`nRPA#A5D|KwoNGdHK7QV*j z%qW5#?JA0|bZW7)b1)s!z48^9Lxv|1K@>H0fH!Jv92WRC?Z*G0JGh%168_kPAyAHt zCdq-H)C5Oh*#n$?Sx@sK_|NiX)Sby$$?vPkm19$D^!sh8jPMI`4VTQkL0*CiqPjZo>zdM!*o|nCCf;UZD9-UASE%A3nXaI(jzXYNOLb1q< zR7x$Zee`X_S1{HAchi?VQ5!R>2tm6f6F=byJ_#<|`3qIrirN9zdJ9Anh!xEM!BL8F zfoLe(x2;I53q*?we9`HCFf*}YB$=78Kt`p86=GNv6VAl425Y)$0_!Nofv%tjQp0Z6 zs05pFCn4c4L(x5w=^cu@X_!42EE!D$fkOlb5hYjJkVKzQbkU$d^s><~ZHTO#=)B2i ziGT42{AAG7ikbGgYO#wuw}oro-MM#gJ(D~4vIci<^%{3>WSu*A5tdT4aEW^` zs+R5hqiXfNKYGUyIQnDwDv3e_`9-v7k6)7;;B=S2rHD)`JKBm~r`0HA7N@^udb`eP z>`?5lxhK*a%R6Y$C70=Ct5!Q8Y<9TKv5+e|eFJ7GM;AR8h)tYdV!xUqn% zJIsm`6~>;$*NwajgoZEn5pygV9CnFeMtfL4Y)H ztN@x{^=)CHp#rXPujE2de+L+4FzdT_q#AiyCsi~UtKJ@nz8F3d#go06A+V`?D7ssj zq}+G~KnewC<;G>V9QO&tt_A@O`0Jv7M;aS^9T&_+dlusMtkId-`Plq@dOONc%{C8= z`Aewf#x(beg{(|tUWr`mU;Jg77n2>X;!-kLuUjLPz>|ZJAVRN7%wrmX=o|jrPocEh z&?=zGT(_+$o7dVE=y)y^oel0BWEl(8{n0dBMs-W`&f_)A-TxHyT;Zt@@?TA4=~7Me z>NM(#xu9*N+M{|hs)TLt`RLX_G*kAx{e5^UtB=Za^kroxtVt$Sv>JtuD)(&u?|GFy z$xFB3FjhoX0%X(ORE70+zHJk|Si`j&t)6|;S>6H{lPh-K5Pz&>v_JO+fA^9>sHgfe;+Zf}J)i~`?T(BL zw$u-jN{^s}z(*$~=C}bQm#TqIr2C^2hTvL(O2?Y?FY98?;&gkIJ{vp|FSX&ZsFo#a zmKspJUR_z|T2pRwH@;{EIkebp#LY6 zxLrjHIc0j@)s|06(Lro(%Le@!IBTzG%}cbf(|MyvDC>`oCnHJWRa)MwK&`Lk{9H>5~ya z9Y(KudcZyH)|0eq1=!=g14T?cM2-M)cuIjM!@mSb{Ru!Xa5%6(klevJ zz+Xcd{rS8rfhgm=Vj%U;5*c|>@>=MlNM{mJWNKamT32r zGl^)7)qE4opO{HwId7pI@#0-=CK2VP=9l2rM9pjH1Gxe2_;xjuh*y$K+J$*bGl`h5 zl<5WH{bME(_GkVl%7x!0`TdT^lOmh2is@*PZIwo@n>Q1V7bxXBmTAGzk`o39P99-|NHpy7+~TT z|NG!Z|L4U&%fv7KA-L0@Yz90o5&yN~e~kEZKNubX@ox}+M$7Q#*hPKlu95N>CjQN$ z@TK^-i~nZvKN0cr;QT4|ol)Zd5N@{UU3C!b@=qKx=SSK7Z*_#{yehkYt;2tg!yj{o zQuG%)E#Jw^}Vd=;0hjOdUt83)lb8^84?W!7sMM zJdDidoj+-YQUAW*IN}p{*zsU|jB+0yc1!5+1IH0fJco$^ZFmUV4>8wr`YwL|?RaSO zXi)#bvyXi95t4zaw+1B+vVEe&_t=H@_q;-F;rq>v{hF(@ws>?>XOdzkkp7e2;bUz|r`UDKQT*8|~n^ zkjY%(r3jC8!Ki%6y|}mHUU?Qp!kUb=hR>J0f^Yq>mJF&{zXOiRXzOKnGYTg1xYD=% ze*Q>d`AMn#T@xuf_Ov~{W#fEG-N_m?KXD47&KE+B2FS)}fH(6EreaBZw zYyO_~%)t4sbp)U8@7e&6L64WwqhArd=Zm1e8qnh|rleD?C*Pl{*fI1oyHOsvmUKEF zj&|@|>uK;z_wg?Gfw}_IW~HCNe84_{0g*&)eRuU@QVKT&B`v+t`;uQBoD~R}Wf@ne z@$P-#-F*1oq{QkQkn|yd*d04v*QY$oSqA?b)PgePu!} zKc8KYo;BHyUh5LR8b@|zNzrf z@y}5nSOj{@@Qw7<%3aJ-5p$9Ydq%LJsSJr}LDdWh?BTk78^hx6}-?SkV5ecR> zI!=12=`0|)fnElY#{8;vBlwwU?FMvFz`GvSgQ1!h>Noj8fuOV%r6x%J=aa$#aCf zS^Xv2@N{D#xrrAo8d1H{SZLbN)U%tBTj!;~rs3x{a zd(9>70m_L!h4Pof6QmhMYdMbT%upzYsP_S z?jA+zKX7tdI{$r*jM9aa=YHF0Fm4uuzRc7go^ zf#nX54TXa`ArmVnDUR_o@a?Xi80V$dUa?3et+*)$T`?49g&HwOG9ey8x8!B0A! zuI2Z8G@YG;H~(x#uNl1F#33l!4z-p!DP8!YmO-3xRPKpxaYrD1I*PrXSBErhqmoRd zxkD#qCZP#sol5_b?`BwrT*xO)*;fFzU1Q{6HI&)Y6HE%rX~{#`Q-Xx_c#}gkwUi&; zO8XS2#}|0zliRKZ6^c8Vy7Wbl)JrdWeM^1GvOi}cq2K!~?7}@Bmz~~R5h**kv`XEF zbcAPTvQ&R=q4_j@awHw>xnEDF#dC0(%Kw1{7R#N(Ivj2+ep4P(g+~may)3nXrqM<{ z_M3}wEO;Krb5OLku`or^eDY<&;-QqLNba@jXwP$C96=u!z4u9LUy)z0;u6W2 z)Q+E3CZk)jW78)*ozC@*OXr_Jk!JK>E!!Fkm(noAVWS~r$Me0J?{wi)x4!kcQ5pW(C*pqwIw6W~?t}nlg)f+rcfR;|4xru&CdMyVp z(@|a7K||U*rwg50nDzO9n9-WF`YJd9e1d>7A0;D68fJBNvFgXGQ@W9!$zIAtHY&{Xn` z`7@3b6er}B^68(P4BRKo>oNg_Vy^G_eS||XuNN}>ZSFJWIBI%Bk!)p$85yiShGcms zVYw&5k1}|wpEw0pQ{T@U9~3=W+qP?deMEoicALUvhO0(rQeq2bQjulBY0CAj()(oG zbBBf)Sq8^8tUFM4%4A+v(K+$FRQ^AB1;m}?+hv+jp6eoLNEL4zXNyPLJ2{888v){s z_ArFgFz?nNMjbI>tkamKxr0^oK1PXwUzviR$=}E$suOfEny?8>UGsZbt)ErNb6VXG z$~CvMvav9UuSnwYNWBi+*S-afT8TnK_vH;|92x{Uv|SD^fs@zIs^El_gVJXQSNZj5 zCTdS*eBv=PF1D>7%i;aiO@-~+n=wsg+Wgu#!VYf!LD%nNia&EfC^VK&Cep-XTwsh0 zx`CC9Xb|?Mj0W^BmP-#Lwnb>vY--ALvft(eH=C1eZDRfSaX&KZ!=~SIUg}}9#e><8 zny?+{cg`KE%TA=r&8D`ivlG%o{fYInD*$Bu%Wm+S@=}^pVfDbfl}#trLFq1`-7v~g z{LIQGO6pBCSM-gWLGyZfKyM3NL!*eyy0-0OmqyTUgyO3Ot6P?= zBTlWbR;<3cW#x*c(2J^=xSyWmnyQSosf{EXrqC&} z^Ehdm-_f#~=XWk` zCwR}LCb_zGjhNkzv}EC>VgZNDHHjOMcf3?7YU`l&_#ZZ*Evs*A!_olH%Ct39i>aoU z=%AXMcar(mY-eW8DnFH_wiZ7+vC;EpiuU}v^J?F6qG|4G>}1BZWH0tfouz+~S!-ya zt1~r?=3M;JFm3~IRP&L}>E8!Sx!JpED;%eeFOzHH54Cp^ASga4PskK-MWWy|mAT zz^%aRfcFFc0(cEj^m;w=9MJ>Q;5wg&M_=>r@b?6N1e}8VSAbW6-v^uwem8I~_*&rE z;5S(JCgA(P-w%{~El}=yg+>1L^a{(d*iV6Se+EcfimeB#-l9OI>p0+9*uTz#M(O=0 zAbp``1F#Xe0;uqsfoDSZ4qz4V&^XWjSHLsCpSE}}Fb@8YK+&xSrtsedJRLj(d@pc0 zQ0ZC>RJ*tesPxnW86RTPt@~7<+Qq5BMYvZ1-wpoiSg)SG2UIvaf$zfpZ-Juw3~(ZN zmvvtYWT7AX5YV&>YyV#0JF%Dk6xsiV{;2SDA5`|=0xG-*f$snpdqi|M0!7yh5XKvT{@j-X*fR}>{66Az9@G@{g%!FBF zPE1^9{=(vJzG)TC@0(Q~#Y&48ES|OaBNo5I;yW#VkHw#|xY~und&c6QwfK)M{w0h5 z)Z&tN68$R{mjtiyS1rEH;$vtuGJO_bZSfyiyxrn^EqS z*J$zC)_sA+e`DQmu=r~0zRcnUo4z#`|Gafq|5y0mw)kBZf70UXEqwR-6td62MVu}K|)5l41`~5@e71g9!qR{yUgO97H_cl2Q1!b@$cC3pKtM9 z7Qf!&Z?W`CEq>6tue7*3m+utL&z*zcZt=worZSQ*l>0i18+|z7TP-gAT5{iS@$Xo? zia}cDIg8J*xaKL*FShufDGSMExpVzx!uic$u$8HzY*c0&EWKnf<$k|)*UMFM-)h|- z#}CfFNr&(~A-p++=R^3%Lb$>XhJR)VS1||O7lH)wL@L|W}EMBmvRGFesG&sqT?W>WT3T73QR&sMk&II&ZQ-Zvd-aRcF0)S;1#Wn!uV!4-r44r zjI(aJrFk_BqL!6hHAW4>YRSAcv@L7NuFPD6O7KQ$Z8v%vR<(5A)PW6jnU2-1tDFV} zcU@f(xIoKOS`zCDC&IWG%kU-LNVBo_Z@kwzS+6=L16JpxzDifw-6deIvRiqvi`|F2 zZG5Er5|nzU-3f-;gfdnRZbOzvAq&<=??}F>wjpUdncP znC>oImo8JgDE+JO{(bGz4Q?0rbXPjumG(mR?_%pxx-EDAYQKNIo4ePZqu+K7sg>xX zwL8D1d-NWC2Yo^8R8QK{i_&GP&gI3W#pT4+u1l;-eL%#|3q9O&N^Qzs@AflPah$j{ zD~^%wEov1jF`1DTykd5IK`}C&#*-iO7 zDxDAmr~EH*plWKyyo&hBq37%qM7p?FZ@(42sqx5#JI9kl7=^sFJeg=19{3E}v6 zvCIKFj~QvtZp_i{J!xHLjN{LZz(<5n;`8&WExFHk3-A#$0lM?Ube2CT|6d5uv8VNn zi{FMfge`4i=I?+kNsXRV;aZ2Xr?2^(b?>lH>rJ`O1=7Z9t^i_UDhJy8%#A>r#3DiZ zlG$(5?#zChQZ)BYXtUyl31=Rk+mDkUOVP*wZ7Ks_; zgVr|eVfG5ZSO!LBr==*fJiGd);B+(^P5C@AZANLDh#zg9nC8UM%jMB;Y3W$Kk^?b+ zj`;7+4+m&NGH!lw_tAD%_k_`CdXK8_~uy~z@bKPaP3r}u<s`#;8YkRg!kzHon_06NcUKP?nvRi9H2W=KD177`C!cU%n0ez9Y;rZqbnf z?f~79()VD1?nvdLJ-$odk-~dDKzF2kRMV%97T#oN_;2)B6Rgo=&3tL}Skt$R9&6f$ z(PK@Tj2>&&X-1DV=LbfwIAyd*^N{Ar#X!xIf|@610LOs~YF?}Ya$d1Wkn@QN`>8G3 z>mtGTfcFAv+lvG#E2CGObB9IugEMDMXa|z#MS{%phVRXK&G5aW;Bo9>L7I6O*5!n6 z5s&8GP1wtb@1c403kHiszQniY*%PLeFS70`XBjhZW7p%MkuK}L*1G=#_6q-#)?N4gl)jDDUE`YET|4@vaNJa$GL(UF zckSmn;kc`OWke?b&O9j`_g-spiE!MfTl@sR<*xdaIhUW@&oCJ6OE~VTUzs95xoe#z zBmMSrpT|#T0YAB4Z7{;K?wf%!v-!#W3WL#Bth-z1IF)~JG1g>ZLTPGV+iWnHEG10p z04?@$lmoJb4Pa$%Sr{ZGx2*5xlnQ!o!phwOu`7m;yHGmUKv}}%Rtj@P(9O$(zY1~L z2w8Nl2wIrTge}4p*_9!RY>>jsSb)OITiBvAV39RB3|M%X3|g3c1}#ihWsyvI8^u~x z>9Okns=Kh(F00D+)63Bi>aUR$?nvvTjcQYIxqAC(*G4^?^1lmh`|On;jKdkz%syIc z6PY)=k2Y5cpm*U-WDw;42cCew5C? zir9UkFneO6FgIR-wDKn^Q7l6Wbo-OE05qVpjU(=C2DZSzr4@lro#B%D4c*?KdS@ReD)D9UcGf?&e>{hCy}+>otYyX|8Bi;x^UcG zxwTmLO6&g$@PK#8RFvU%Po8Q@%nF{o_ z9tgqA0VO&Uh_Ta{-Mpe*SLV&<8hr*Qha=wW9);gJtquoc%I1ewWve5z%D>zlo*z_Z zW(qyxIA|1rrVr`!44uIO=>k%02f{%3}>G99AxE@rz^F zeEI)Sd5p}DAEi7lcI^0aK8tA|oDDdA<^EbC+)gyF%~RpT`C-&f+*;aLg#L6{yxlek zhr4!SyX~7^M65p!*Osk;V5qkOyP|-?^ofd33o9t<M>p|B!uyyl<>mwu!!m_YOt4H2CiA=Mf;2lPPj8+%ol`lx=KZMZ{dx8hzfW z#$RyWapmaGJC<)e89K)Q8jYLep(YL_A7;EKZxbXJpz*#QD5Lxa$7}i5{$`;ZG1`}j z#+f)DLEH|ffuHbT_hQDT{Ey==s@=#q+_ito+L$*xPQGCa&xNPP2!CLtbu>(5B+I?v>0jmNQ7)V* z)?KnML1UBaTOCdRh1<_}Ssz+Is}F1>ec`Y~aIh91 zet*p!8rvB)$_BRDCGOxHZbpsq2{=0A#O?X$mbd2q^nonh`UF%_riON9f0HUUJyrLN z^kCY1R_XkciS2NRxbpNHqT3qn9z*=nZ^?!B{mPDi_c7luJ)GtOTmGen{40(5U$OWe ztV>rs`M4Oj<^tNoOYzc>|3%)rUB$wdH7^P!xjt&h1FAgxlIS1q)V;9nswGkniHS0i zH*PCf)0?|uQ~H~@hy59D-)-e;p!7OsPVhG@?(DF)A^%JE5-ww27@2h7mX>!Lez0^w zUWzciJbEDqLgfUH)%c9SJ#-t7NvqVI`QxWe?e|N!-w)Ouv{&EJonY?0D|6iAH<1l~ zdG_3SDJ}$sFK^5?qlUYs5#e^n|8a9=DMr(C%$R`P(ata3IN;9%q5a1p8r8|n1G|9i z8)~)yi6HiQU?uy70+8(1bOGs~v0E&@%Hrbp(Fbeh0Oc_9wFcC;h>LGh2j{kmF1#aqZUP z;tk96@ss=U7Ju5}uAF`(oUzD_PcK=#*V6wDxb`bR0XyS{_CnP82cFtY?~Yw5hT8QCZEPK@K=dE72LQ;#5q<%zr4ebLGl zT&8L+vkIJW1|QuC%EN`l*35p%30!%TGV21<%_M(gg`O;Q5;RVtCa{Sr`O$g-bIj|6 zk@r(8macBTWyR_Xrn#j;c%7^=)=UtI>(Bqy`>A8vKTMleJJSBrhyku{yKzlsh2FL4 z>}+4*mCXOc<>D5ICcpmq^=SL5OKNSwlUKr@kw;ZC($LJ>_XYR zr(V8C%I3MLzfVa?6^-tBuG`CdUv8H|L_0_?pkP!}ut0IUzrsn4`EQ7hjUkT-pg3Mh z@)dUY+5oJI`+UB0?sKGB%} z%34x4tI+)wEpGG42UEqI)VrkeCiP&R8u?@wpOYcML8|e!#_gHmK9;)=-9%6H^}MKD zDNsd>vVb04o{^WA?3xdK7aIyqU)XO_S$I@y5SEYS`bA`E-1862BUnQV3q0|-w*Do z+iKL6VV6NoNsly^H5H1J1&kJ}?=|K>QH>7xan&TFuz)Sc@7Z2#EY)CBexHdLr9VQY1YKi89*#D@N$lU9WlXF`NX#a~SN|%m)qY zHPZ8Fq#l|n-$V7^=BE7b8Vai(wCVCST1XvDULl!>RUY0?jijPYJ4y*`pc&_Pm=vN~ zM4CAC5;Ph^GPh_K)}R7fK&qZ+Kex+}*cmyLVvMl>c*T3c5jz3n5Ty$>^L{R82HvI@ZAD#9h}*>P6~x7q9TP ztMCS5IO8HE6>sA+oqN1p-6u1TulRa>p^QJdwXaJfMg=j96qbBHt8%DVuo((=nJAbk zJm6JA)5d`x6OPs85lF^BhU_uy_TozBZrEy?R#UGnlA+95ltu3-QF=KXoHmNHZD#%5 zIWw{nf#-o#kR8)3WMPVJ;9VqLm_POv7d)FPmDH9DYTmC+5Uxj})w>^4sFdSpK2O1~hGK$gg@Z;lE(8ALp7WVB7CcIbC znD?F=N$2-A=6{jOo8rUU>r_i5dS5Tnvbm?nG{Q-M)qpSetV_D$iz!kAJAr3VG!D~W zQx%`xgfDt#W5Ki{I0c)dJp%;Qm>={W)`)gXVY|_Z@|I}#g?yt8igHt}HLSmUY~Q%C zkw>%yaKpFddcYt#J0HhcjM#d|uZk?h$#QMZ5#tqd+Ij($QQR3)@r!nMtOX1iPDhzG+OG;YFEw zdGLLsg%a&vjcPMPsCk>LncnPG4GmKbX#IVs^LO1T71ZoT@`@z429CUOw8>C6)CiU; zcule3HO!&@lo=-RKa{HIOI`Bg=)D&bp`QM*%}y;=%}is4OL*e(b0`80J~XB7fB6$H zyXXe3-wM2HHbZ%1;i0tzo;{)K(ONTxeDJPE)nj%MK$ZtXNT^8x)e}jb+hh94jzjU( zl<#CuqK7i#4_t|x88Rp&@L*96oP!%#tS1V1TbavD-z^b2B|MGi^4`l>ljp{~qmF)2 za_9S!6)z9`La`T2U2NhJ8;M`_~jmIEt9XgEv=$0KRGbNc!M!&wJJfkXB7>aKE=e;aN8p?@@F!30r92q>{E11Fe zjZ!KarLXAk-W(k7y!j&JU`9-@L3sn=z`NdH(0F_Xv6uzcPCghVN>!FQx6}xX2El00 z7oky%U0coiICFyES}9RA+QhoPMAs{n1iGwLTV@p-?dg|4)H@bd!7Y6m#H~SdhZti! z|C5z&zqcsGEmHT)@Z!&zwP+;T^L~g2{!Za}vzqC0UWu8!G~^Gthn#p!?FR2THJ>)+ z^;APY_-x5K|I*;2FkT1WNtQRJ+(Idd&DYCp1~;M`%;qF>#;n4>nB}?S`zjM!u2T?0 zgJUUiznAPH!P#Xlld9QtVVhQU<*Vy-e~&C>0-t@k$#ka*n_5;yrg%&qyq1f0&7L1C z(1ACo)0DSvPaN#4$Qb=)bM4CCg;4T7xRBhrwICNxhIkO}_KibtAK0RBMqBt3oT|U# zNZEH;RaRJ>n~ewh$1u^J4=eEeONGyveT%EcKphTT3`G*{@k>^&=v*F8&6kcUZRO*c zEO#1LN~6=H&PyjPM>mKEBeUktnUkC~pT=`uEx$VK^-nZtE4d+(;yLI`y}zC&qIn9h zW|ntH(x}=RW)r`;oVxo#W z>y{;GnL<_9QdCqy;vPykBGK@diOR|C^)oUSZ(X^jvu)|faYkBo!vOxd_l{8mYP+P~ z3cY0h+eC2`7a6LlaRNncShnrNNczUrysd1sBAEw_MC6nq)ht=F^j0dyJ#OR&zynCj zGAD)-vW&Nt*4#qwm)u$&Cqfx06*CIQ&Wktj_(Ob!iF9dv@=ZJqz8WQGH^$Gp;F2kk z>#n=5CXq!S6RB&333jO$MU5T~E!k1kVQo{o9&4)J6p^Rq3q4vTMO$9+PMQ%CI=MY}Y8jkgPcjIJPt(BfkVZ4iRhD1n)6L6`zxVi}|I*aYaKD)I zf`0>^%{jr}0xtl+61w!Lo~KM?4Mp7uW}11Y8BA-fM0Eviyz3flBXt zfGV#Fi%Tz&%Ijx9mDdwMScS1q0!5z(vX6*e0aQ871Xh7RJq{ir_*a1m;KzYi0FSfy z&uM$YzXq(~e;$bJMNK!5)qHFv@OoFd2Y->LjsfSB0b{Fw}%0!~35 zL=b#J9C)sk4>M_;!nb)Z+aX|B%J^Sp0q(t<3Wlf49YdZt^;zf&JU~$L)zue+qvHp`5f6A86 z9E(3_@#`#plI8y|wz$))w8G*)vEg+H=jYA~v{jZo(%+lXqOXuQoyWG@@YI}x@=CwQ zLhdQ+UXQ!i$u@Az4&P0-2Op3O9C5og0>E!BFHS>~2& zUMYncRNgY8l9m!_Q0|+Omms_^`uO5QC#4h>RiTsEi%4JmY~*_ zl0^Cu<63!T&T(mF@~hKAQQO!oD>naN_N-6b>4BQ0Jr96#_Rv3XTfc%ZUUWm&8OAk&cTpYZvlGotZ@N`gB`m(uIpE$nanMD4&%Det_m|!|?O7zdJ{1ab~=+EHw zdfLgz>Wo;Z(Jgy(JC95AnoqiLugQtepf?F}sU3Wuf>q;7=lb1+#6zU6;`gaMmlQ9r zHsp0Lc2$KGY8P%-a7U|GY^X&u5v?FH7#pzN66`Sttzw z*=dig@F{Hrw<^+9?zM`{>HHm&*rrG_95DRGP<8hjf4j!+n?ADBP3GSYZGJ7J04ewZePnEU1@z1fqK)f^X6cuDgSjfss5g&WX5Zdzv1u< zFNypYC*zXnyGOl>C&li$To9A)zsIyQJ~@fg@mab*>A4h>6FCpnIWku59&vKHg^Mj* zXrUPmp-Wl3-ohCc)>=5(!nlPK1)K7#+7tO3YV!}wCpH~krSr+Ez+LrWAO+E1G&jQmK$^Np^e+RPtc`ru-BANo_tk?t*Wly#7&lck{`~&}ME# zB0?u)8YviXs{F$x`;v}Foyw0DajQG3EZfqJXI<<18X_%zCuA(;jU+=r!+(PA zz*~b&UF5*n>5SMVDRXgC;eDZ?(s>5b3zcSbghfz=qUywrPXoW=buVrzbPfEB56^QX zZyMadZ0OW^bs5FJfpyeR)4}Io%Y&zJCJXxpPP#Cznm)a^vCz4&a5ZlnifzGt=i8sM zeZtRp;kK$&@!H9$;??oS{2L}Yo=8;Y41?rmL^74;tD!IhA%v~!74*UW{4Absyv(D4 ziJRf%+r!*kWSaox#xxk^VI|e5BQgoREV(zU>ngb?;=Yn$|>3f%N7;ACqbx6t$}?5iwZ=|L@a z7^R-5{KySEISSF%lWlS5nw2-VHG2!n$y4ImJ#%KUY)uD;XP5CiF~Zd{w&h5;E?W~O zxOCD|kH%~_Bf6W$Axf6FIP?yO4V*wYUg=cqGN*W8*!>F);aW$z^9++}(YkXFePcw| zz|YaCT8$ZjZY2(m?nvQ%IzV@%@E!}$9Vxt*19X;sHex=4`iPVUV_ZJ$y>xibk)S@J zA6hcMTta&FM8A|4>+;>9)+^(}4ZUZf^89pwezbfkTuJu1a33=5DG+Yxyh-8yIzVr? z8KrdKE+e{Am_S{)N20s@P0}rW6LiYYy#cztN{oyvr>k?v-|L^AdFhnQhfC)skGe!} z^$?y!0n#&T4zqbWm!pDLEPM%AkNs|-&Kv#-I18xvDn$25AjMUqcPnJCcPp*{E&}Sj zXugHBfpy>)051o|flTPJ6M>vx&D1z2`mX?WZuBW2Ns9FV8Qp7cv+k>bqHhB#ybl6J z-vA`2*rhQ0I)d0Ci3_-@=Q4iuXUMlk>2D8mM$h z-~ahQtpo`&_9Y;svCjkfADhP?o!{tuMdyKWp!^*NWDi&KGcq*`_$=@W;H^Npe+;N_ zKMGX1(&wabB@%_#nE1`||8s~Lp=-VYRQ^8))cIP`;&%fft+@jzx}`wHr_o;VQ5P~b zy##tP=SPCjPuKuF30#o!ov<8uHn`v<@Oof1xZqjfl7BxFT<{EV-OZg0F8Dt1ULa%f zB0{K>knwe(|XoC^PcTKq)e zGyum}IK|?JPVoGnYjK@x%jld{^qVZM`qz0&wQ)ti7;ZXm*<=0BvF_A~F)OWmmvwKm z?v$Z1cU$*O)_px;EBsTimw7AsQTUsvG#Q4gA9GwxZC5ah~A-4{0psnt&RV43JCMOb)RSB|2=k!f46Z(2Hd*Gt^40m z7jl2r)>q2r&oF54qp@1pt0*|FhQpSJwRw>psuAf6}_|w(jR!_q{fL&E5R> z%~_*+Bn7ld%VqY$LmJ|c*ZCI3PE){uXl-v-@xhW!5`gf9xwCqnp7Lh0Wg z!ganJjPHk`@Wbb4{}FOu7{ad(;afxauS4;j9>TSL!i#SZXbVi%KvUJ5VcfQxQwtYp1J0J6dU?ZWUt8iHa_7^ajd0K#!G`B9lsrkliO9zqh zY-R>^zWxgjE83?i<>j>d2(;u8Tmubt1XtSzM|N?gQgU@gZYyZGgI`C(om_QHAKmF9 z<7BI+Sw}mq&E^HyW@l%cTgk;f*I-X(-34!Va%oh=xNO*6y(M)gs?&m(z+E(@s7;E3 zjnzv*Swh2!lH>ob`{No~ns4mvZ2AA&J?Uu|&6plHrtG}Wl*j7K%2lJCf3hq%rt`jq ztYc()?PTe2Eu-~QcrtJHyl=Mk;KI}WNW*44#`8WG&PToIBjZ^w2MyDGnK{~dpZ1S3 z8_nNHWG&$tD>A7i9m_mgZOJHn_8$?w2PwFjh3{s{NXtR(&175|$v=A><0kuKF=eMp zFh5a0`D5`vi(l5A#m3@4?E=(yA8gA1wkeu?)pDF4QLQ;XC!FXzJynx!dw3Fi9M62W zaMUu+y(7LYQXhUt+`Yby!+xcfAl_1XP5WO5&q#EAAd-0xEJ`AATx70Kzbnyi6n+d& zNED6-p9rpoW0;>oZIWp4$zCF^XW2O$*A;e|`1r8T%)0}>ezUIDYoU?BZw>S4*?+#o zPc1&Ga`D0{KB}VfzPSu$SegUM)v&Tn_7M3pWG#~WcNWGgMN83p>REW0~tyc z3)=W99e3?i=#9m%SFI;$XG75L5v=tH@K|p=eqJep?m%81-SISe@1=v}Q& zM;rdgrBT3-3uDbyngX#)Ur-}=jNDB@&JKFCQQ@Z19;l<;M9bOMyp*Z0;sg&B69IXMST- zM1SI1VRtTXxk=AGe-xoN3H^s0v^vakA7ZkZuF+NLy|X@rt=yzeT}@civEt(`=B`29 zcs0+68&Nh`SDt}aV$9L>2GvlN#yCD=NN-Rzj*a{r9}%9CXB>Utz2i)PZty7K>OEG* zq?vCA!au1w0Z4tu4l}SZc*I@-%6&HweoV~+7XPS)%|Q9nzE1vT1LaS0)bjThApD#f z$x9P-O#3(ZI5m=Uq-<*5Z{e9h_WU*P0pcY#7AU&IcFAw4OhH&bvj6Te_cq-&RD}<{J2ID&`gu~k`bN_P) zw_6NPKvD}Cx914RS03%TIkQviZ0TIdx>&bwniWoSh8O3jHLv0kl$IOa9x1rxG9C1(^@Z6zESJ;1D$bYH4%+lMGz_28i zoC2wot5x`IaSa=}OBOF3+fDzflb=&JP2x*MB3x zScLu@qI1ji+D7Scw>Gog=uNL*AFV78Z>t6uSsmm0)rIpnHeI*bbb6tivCw@Qc(nEF zLhFB{^)-=nDQ}w?OpmmFl|0)F=oT`V>KrV%epT7(r=dh^bS(>x)tEJw^sv5>C~U7J zq#QTvtIT37(SNrrkOe>&`*t1Zu!6a@?uEhe7PU${JmSml7DZ-`!E!TB%rxW zceo<^?#ES##$oU*>vubYd1SB(edOv0J$kNX z)G2|r&E2vz?)|0D!uE+Hk;>ANy3Y~S2yKE64MF~*%g80Mh|k2*#rw3(Oc#5!%xo$? zq{U_8akI934~|+&;;1Dij#^PB9@m1hY3%K+2qz}`W@|RRRL@3zgC2QL6y7N%H&$;%BL9R-HA`t-F_!w3 zo-BkYxskdMMc_#@oZ!C(XBVJ_qN4BKZ5RDg=94bmXG+pbgt--O(=nE<1EC^`G<#x& zyOKSi;|DE6xoCf>YKj}qW)+&s|EnLH@j*}nFVUVG^A9OWUe2*Z>5yr3(Vq9<3TCQ5 z+N1SK*JY8+N$LD^sPY*2N22D_E|yK2JiS1flZ+0YXwN#8l9%qF^LXQ&T@`d9-V|G? z%B~rN`9$`EUKWcFtyN(a@9PCLQmKH4)!D2d602phXRPIWyzbvaf*zn~_lMPKqzfq8 zJ%>+QqE7aPijhbWLY^P6<%5d^o=`jTidVl#AlgR4_AT12qby~YI-GJK(Kl{9syB90 z4mKA?&xuJj3AxyO6eczm+9=-N`Fd1)UA=lzI1)&62^uJx!fM)Oda4Pn?im-JCx8cS_gPhe&AdFiMW5@?jI=c8!JGpE5S(2`dGpEzd9Wo?h0(V;UeNH0qvL zL{x|-RAlk0R`UnmQlLOg>;8-qkKzsrzW{|fQgkhn4gpQ}7Aao!n*A`Duu$t~+jW$d zk1~OghL;{Url3r~eY)mfh@_10VMBf&`Vut0goO`X;S`d)68RqWfkgfRHGcJ!SGl2& zz8c(Y+bblWsyk@EQF@g1WH41n*+89}qGi>Ms)F78!IP=lWAXP__@frG(NzAl>J&1) zl?ra~y;6)tS=-KywR0DFHCvb!Wz9Qlv;%Erle1Y*Esi@cHx>!@+q6b z(Q>1PqJ67vE2ZhBjAJk_kA|WAe<0>-YvFNqUenE-Y?u_OZPRdS1b%flv~IWF@0^}M zC|GqMZCfuo21-gL9W|-U%@~(?VL**NRk1TYr7!z59+BNHo;E>Gf>_^=C_)p2@x&+* z?bc=@6wsc56R}jgtLRHaw=`Tdgr1|!*{w%{Z;Xrn<^8h4#~B{&hoe1r zV`J!Zhpx$fLSJKYhvL}|L}0V;_oxz?GmI*utFzZ*F$cXYS7)!$*O=UE@yxq&hZ5OY zpjV=&>B{US`Z7VBpUU;Uo-Tf9tR1b8q_xvoI^SJwx{^0bcrtqLXrgkR1%2L2e*+47 z#2PB88Hs%O8Y!d*ZTN$G{rU5eRI}`ZN#~u@X&4C$u0^wP3g7L9RbPa(=e6 zyV4bJZ&}fC-e`o# z6%q2Q3wbGwykYzT{(G5C?;Bw z47>qj!u*wLY$c1}_$9~D@{Mu)604toDwYlW9Nlg+(qQ4}Lh@;%*WT9A|0W!6NKWo^ zm1fO6GjHL?fm7J#w*%o<#Qv5I2y!tqKLI4oHOqnUER39%@X6qkWBL<|cgDJ!{lND^ z|6L$ysp$ot0sID#5jgf$;F;i`1x^MQfeL3G@LXUPNSVbX$Hh`Vb|a9zerz!i{!Z+} zK)P|P9ti&=Cj9^`m}74RDqQIaPGTDnGeDZr#5HH0iLg2RI4$ zCBU=E$1EUwikUS)mCIScaabJ>WQ`X)C}OKzKPdrvg>Z;;%6^8$KKH82K#v zp^?vG0-O-XJt&`b3-O6B=JvsNSp26HlFZ%0`8`b`$cWu8dgJoqH;zh^*=6zZ7MFaA+}~~Sf3x_N7MFaC+}BwA*A{=whX1O?@3roK zw)n#q*D;CwPqzE^sKtM2-6e-7_tz|bhQ&{`^ygSSW^uIx(brjAvaiBlw&`gQPJ?iK zf;kr7W$8&?8J|&disD1ITlaa^-HoTs*8P6#uJ)iXoOuUG5D(wi{~Clr_h&-*&Ja$Y zDWj*)mEi|Mcv}d6G=!_&2IE)z4dP*a0F^if-J>D=S0VrRgz!&=aIKGm;k`eEi_aT$ zKR1NG7@|KbRuN*+ehXjCNXZ}|)4rs`i2(VMHQsv3 zu~*B5Xsk4nw?fhaDblQ!P1w@` z>~I&@>zo+Kv|8un;wfEecQKW2-#f{W3j=)MVfj#ABle#AG4Y3|*G)Szf4CJ*WdRQH ze^(E@)>$&WwzD~0*7`978uMo58#XXW%ee6NGybyv(&XGF;LPxMfXd$$a^aZWHJ;|# zbUOcGcr^a-CY!D!H=Loe>E3nFnAUy^}^&X;dckovI> z)SA-#0LNt9j#^iff6RSN$u{KwsJ*J)e5Z@IRC04`JhuB4GB|vJYbStv`!&55IUpCy zYDP$+zOi8V1L?x?seE$(`Z4R0`+E0{U;h^s>z>~;P`P7W)6aT;as2u##;n`XJ20m5 z`E^Y{@7;IY`o9>v?)lz#sOo z?#Ijhl}PWpKrdh0MTkKrk&n&C3?NRbyDH&bmObBjxB;6Qk6N+W?F=G>LM%9NSN zedLPuC#_2j^@+XEJ4U=oo;>|E*)`8FdAArxN}6HnnPdfb_I_E;zqSbujW~VJ^4t;3 zBJa*;D*tr;J6@UOcbc?_m--%4GQ9QrC+o!hN$+NGU9W$y&kx#G)8xi{)2=4&2cwqR zUPylZ>f$FZgs%f5{`Ov*dpM6&pJCwKN5Sg(DfmPv)!&*qhg+=3Qmn0LEM&JPqTB6# z=)}6&ya6yCIgS1?JPn&3dOG`a71kLd=h7>RX&X`_mKwq}9;Co+^c%-fLXu{NV?rFTLW4uD`iIl71}G_5L5d_>BiD(iKlg`z<2{ zRm%U|Tt}pJyUMvrKce1XRj^$1_ik%Z3OPXRL-}IVUalB7W7jDrDwccfX z#uqN0&xYqXi`Q)DPR#8<{wLY%%4@61fxSNJq9{L^$9dmlN?8@&1CzEpwN&Q#H30ek78 z61VYE_^_(ggu)2|DsY=f&4OL&{D&&j`3b24CmeHlkT;sTtZ85NBnBDk)4aHAyj(r| z+B53Us-9HAJTa-&`$uqZn%{D@h-Dlf#okM-#!7nx$3M~f)fh)NyQHUbB@T{G@(so~ zx{!Q~_%dJM=ji|1qb|iC;>(EssQ~>)!t^8Dk9<8q|GO~#272P$crVR{eR<7?f&8x#--I>&%(q+n{}|`tPXgf!%-jML-CqIE1ZIKk z$7@yqW3xFbcj0Pp~8w2~r*tHUgPs7YVXNGWXP2GMRg7Y~2kXgrYTk z5Ru0DQwc7}5^Ta>QXWdH>o=bg&d;s?He39DB9r;HaLU}R=Tz>(_gnWJ(1@3l#a`xQ zpxMV;J_=4{`}~KnkbAH7uX2+ADI&z|vF=sYzxXh6Kh@GNvEiG=GW6a2& zH^lbt%&b|nI&N)e9~|7b2ky$4-Kq&?)lCX$c}pkS{Mh!yXVzrfISYs&qqK@E z5yO&zXP&n6JeTjdXU%GEYG7OJ*#<5vnTNesExph>nPZ-r^(Yj6PKQ=QXT~Zl2+os^pTh(&o ziq^gz7>h{!>C`c6F!RB zsGS$4%8qjmXUsQ4C3Au?ZbF^s#)>&&9!>8DV`#F3s zXR$FA577C13VrJ*|IF#8?f}PR+=AR~zgd*C{eC@sS780|+^$$`4zXuu7QzqM!_u6c z0MZ0~`xT+2Sh5Rrzd_=GFqZ$FGYiwX5nH3g#|E4VpJ<@!%C&WZe$Ei8^ji+V#oqSJqYN?j715P(Yzdd+G@#M*km%Mh%{M@1Q zZ=Q>+fK6ZY+lRH=ll;S#RgbbZLx!w3)6k$@b+$KE!5#+E1>WWM^qxDC@7WxvB{h-S<+p-St&(MU=y&v zyLux)hEMV6Wm0@^@IKA=y1;jr|J_inGX%rvX?GvX^#SK+v4sl-#R{6|K2q+Z-hIq) zAGPjdvOe$>w{T*mhgbcj2P@UE%QwEM;sbjSSK6*K!8(5v?6@vT$V!75ScwJQTNe{gKytcteipO|09mmj}x%qCI8b zx&8cd8$`kw10;zw<@r>;xK7~=_3Ghlcwo+BUQTP}l<(O9Xe@qBF>O~oPLhkp`YzYD zUVvp(Fqtr^7>wGa8B9Ei+$X9hB7655Y2k^tE(KZmiZbok3p`gx1SRZxFhufNu%Y_+%4qjt zQzs8BR4`t-IZkALr~mbU(vt7_7yi-&B=m?cwT7+sGhJw`uC&ETeMQJY{((yU?K#=x zW}B=i#RJ4+m@y?*2exq>iHx@k1Btga9qpM;9vX|=HYoPuHqoNXPXW1?rfdO|e`RCf zDOIhzokp`U4Xfvchn427`V;MW07Y#BU*?ZXbMd}Cc(pBumj}zM*-y$pFz)$v)((&8 zA;n0lVx=p5^u;P82OTi++8OUC==XwQJ+-4{sRQ3ucJVWI&mH#(vHxNp0n|d0` z?TV`9%-hf@SE;}&cBd*1rYfEpgwgKVRZp}~C%%o~d#P)|T?T&I z%nFV9Pgk!4ht0pZA>UZNkdJx#NagRX))u*efVFi?K^V8NO0dwQFbU9l)mon$I%L=%Bp$F?N zKEuLV3n$AVI7d$O@G9$GX>h0clSQH#4ffDoLUW`Wu2QXg?>hWTR+6{WQP3K#DB0LP z)4zJWZdTO5MUBVyT2}>^%I#!j^H3#KQMgaNWvk|3p7*?DXXiUp#m8bIGJUh)jkgs$ z889}g=2#GxZXN_?Nrt2iaxe5O6ex}xqb^psZ=JA;J*kSlshNtT15UPCA(qcxp1}9O z1yqFX{n76KN&ZuLnEubDez-sL?yHK8msKRzzjNIOhx#fwV%fowLSJfVS9Y+mIQ@dA z{4b@{^oRTHq?9@Bs^YyD{*ZjEKegl|#gl~i;85nZbj8y)rp(8f7nSP9{5~c_MOH1v zt`)rDd+%EmL}LAdh!;qD=t;$_KzJAP@Zfw`S{$>m+BRj@Sb?yrSB4bwS^{p$zvAR) zab(`Vs`%K2rXq?Db!n6@m}$vBPORW9;fLhT3#VpQU98mc-W|Y1VXioA>vCvd6%&xK z*6JtBv)5L{Tn8;(G4*efwykQ<@ZK3$&}ydfV3fIo#(h$^+8@o^k`|tu3VU+CCbd>L z4*i>iJfSB2j8eQPq07lmfusKx82h|9&s;4>j^hkJb(31hzRB?IdBJ~|I)b2RNBrEl zClShr5*$~Gc^Yd?e94L%M=j?O3hcc2{FV-K9Z#c@GCp_NGFVdaMx zbLRqQS~)O3{E&R==_h-9@z-gX)vyNs6L<#v?N@+ojcc9&o(gl|4`E>QHpA>K*A9{^cF#lFQKhEgM63J;{_7K>j3WY1S~h~)@_X6!|v=>8cf z`!4{`1il{#KfY$Vg}-Oq62E>Mkn@0=dx4Z|%{4&zyA&w;sTPh0P62<7NOZn103;}* z2Tpx4_eZT2Bi998lqI z074qO2Z)K?!5@Xw0EBl@(*=aZvPe+p4fB9h{USlC)SNFc=PinZN5TJ|#OQor5kxZo zY;ni8dC20QvV50q7B5)(CoO)j#lLUy-4_3m#b34fPc6R6hWGEn`8mGRsiZ~e(YtRl z;{8vcz#ZRbo$M%pjr?S^xjP;AddpYRS&7^$@F#PJb#J%s@+Nm@&a>`S)}6Xg`T9mf zeh|Mjgm;ASGYKz9ulfz*SBB_+7jhpT^8clfyVhR8@Nyyi@eqDP2wxJ4|C$iq8^T`< z`F}m+{oF*O7`)A`Cw?xN zW;pJKnJ&EUq7v>4`IYhGk9OBOcrN13Or(KmguCN9I~b-+%;o@=HrLWeJ!Tm(6@eS$ z?pOuJZ0mAQOw!0Hnv4eKcUwdqXuKGS@m_ugGuk1*NIrf3{z#7Y0Kq#HF-hv=0z79o zomqD!z7&^#8f6Ge_N8MD8-F)ivuBb~6O zldE)Ml}?!QVw;5{xAF6=eu9>cn>af2BCHFXgV3Y?EAIx?T~K@RMRA$o=N?Ls6QvyK zykny}YTWC}%=JgSXCK#M2-9mjx5HUenDY)hT+`-JU6?VX=1+5Tx!j|3i7^?VgvZEsr(JFOJ9X|zss>J#nkr&^qe3VQfqf0b0iMGSgRZdbaGy>87^Q` z#cv>oG37W`SM-g$EOJ%x6PIyu+qX<3a5yHN`+fzk=fb?m_PTvrigO5f(K;MJT4@hL zXqz=Hb3xU`P4J!&+C=x}ggMUWH|29gxiq~l^R&m7)^Uwv2*d0>P5V)?i4lwx6Wp=8 z2NbB=^?5f-b*3?1rx_>lh>IF{UGLz@_B|I9yYstK)qrZOl&7vLrQ18)8>@_N8J{~e zGdoUi^^8;@cl~-3bchOWLVj*zDi3FD!Db^3d;9&N=S#TQtsA5#`SP%(x^gdAq?{Dv zi+N9q5n;Rjq`B5_E{{tFLBf?hRpM=VDGB!2mN->Z&HU2TKy*uTC$ElpGGxhJ@bB^q zHbl4lD3O0Ik>8che-EC2Dlf*~g75L?P;|?)iTn?B@IveQju_=T_E*8)>rL+%j00at z@A&m(;LE8UzpI7iH*XzwgC+AYOJuw>gI;CyB+K&Lmt&^2MeeexVQs-*iR zdk#i>#O;IgV~F%_(WS!O1?>9{aCQ9QdSXv(J(Is)`Fhk!!mCP`Puwozu5#k;-t73k z9=Z6j`1G}l8QB#sxJ&e7k3=u#ndD|47$p8mU*SX3sZd1Svdgj#@ z_L`;a+;0kuv2xpDzPzkU^}@lykBk~yV*5_l81`{3Y|h_j2Zq zT7g_fyKiIX*I0O{9WpoG`GcHh95-g^xX&vqy{pPV>fIIKTtw{(W}*$X-#}d*$h)!8 zc?g!K8y8(%c;G0fY<#p4jF9GjmIE3?A7L9#k9*0BGLSm#oZvVoJqJi&I6gz+;xh>> z^Yf63($AySW#Cb`G^!C~du`OWZ*T`$FGROA#(KAF!J;E}0kx(337hfm&i_LP|c`{SIZKnB4G4+_V=I-1K<~@RUf{ zR^jWt8Kt7UD;2iTNARU3gZuXM7f<5zZp)dtcUF5R;x#kLe)hXPJ5>_M3_Sh4y#RP z^|}NC45lDB!6qt2ZIyYXyy3v<^k6DiclJeOdS3AE4@A2^`zQP{vzxijOzz%vS4gs& z^SXvNRQa9=&3bw@2!2!EVNO@RU?>7Ug>NQ0}#-El%_t1L>Ph5BJar!_eV*SZuyLV@zEaGy1nwc3t zQyD# zB6?r%_92LMkg|^@>9V1xqualmd+j54o{@X)+&ib`UOO=Z;af77L!CXZe%)(bKdWe{ z+>x0&2*LH))9MfQS7hJW7rCCq)qlHU@SWs3%QOb{3G1q`tQ#5}Q+IIvwI=V+WIsPR zmYDi9zPqW>W;!#46)VS7epPbr?Nv>MQ)ktitsf9`a=2gKO*DSJX6QnE8;w>$^wpnM z(O+*4G}n*q?zI&c?OtXIl`1)Mbws9X9C!<99#%Bb?!xel z`t2c68_4tbAyi+X;gsiQzG+LQ{`>1EYDqCLC7<1*_!@0KD{rMt@*?Uue@ z#Fk9d2_r8z++~WkIvX zVY5P&QWPGC4CdBPk+;$*6@#+aRA`#q)U!K-Qpu(nO@$<)T0Uc;JkNut`H3;*MI~yD z6DpB)8m~r)Ke>VAl3SMv9rRE`2ebs}jc%#btav;Uy<-M{$1KjQzneKU^IN1Y22mh3 z=yzhbz&%ZI<@XO(BFV9?k}wdfnm{0#lkxs`vk168`wMUKO{||VxR-e~RhXqgmOFyH zG+dQQH5RU}EOheZuynC$xn@>tezW>5ViSRif?0Rle6VKjOzzclbAD6^#d=+J<{{DngKl#1> zh6^@ZV1M$2-Jd8ra|1IlG<(l}mJPvXptWOScsw*0nc*{u$LadLH=1~?+FIJV!8O+f zn4ZRN1U{>G*>`xta&OdUxsd$mUJXL@v7o$CPL?wLxqbF4oJ{jHc2Z*`oI~X2|I_tx z_1Bae0V%Un#@Fozyn4wWGLurR;f1#Nl<&L`k}T2XP3k-!$(NZZbBj-^owoMB^NTpfUBq$f#FdM1yj9bQSWje9?F_;% z{dm|+(HW5zNwCa3b5iG-Q>8y-mG`-N4R1SnpRIxK)vcc0(iJzhb!KX^9V?tqPf^Is zNu5(awx%5rF}@-wTH$(8rX$-HF`-A+w6}Z=1R@lM8I5!LQ-e5SH;m&{mJTf1ah?ew-wX4KYRa>;hU} zf=M*%x|M6SrLDDGwO((p?d4j<6cK~i1T9r+t)*%eEmdN?7OfXSE%|@H^PJf|`((pQ z+h70x-rxWE?Cd#b=FFKhFV8&l%yVWYg+(=KYFRN3X!3zfF$I`eQe9Q<6!)aFol*vj zOJG^U!(2Vt4Gl#ozwcPPo--YGyb7kJ-_dK@z`jCrx-(Dl?RE1du`l9hH7j?Oo8Psr znR+~;`1$?GTuJoUjsPq7H+(GdvV1N(Bz`J!^oxHPb&V)+;WqY-)_Z^J<^=Z=2PjxHMmxfWp2JCa=CYx<-gR; zujJ};YwO*7u66I*U>tP~?1x$azXteqz?rZsnkq0Ga0dK`0+R0}z$*X;0-ggqq&G0e zBL9B?UJ3tu0byU1Q4L7`#enk>el_4c(Bp(2DsUj+74Yv3h+8D%UECm~e+zgP=%<8U z2j~O625=6-BY-eP%eY0tD*O#cJG<3PU#NV(5RcncuqJOoHNcS`t;fK0bU z!V3XeZqotDcP1d^oD4|5_h8h;a&H4Vi12R!&Ia8eFeGrPz!L%IL;iCZ z9Wb3A3XBN6LEu#aCks3ma319T7b08;*CfaIGBh_|wg z(*ViWNBq0ejQv{1hk)e&H6X*c1G4^}1f+i72Be&O0V)4Rp@V?rTLQQc;a39o13em$ za!vg06mqXqR3C{;a6UZ1R z^e8}7O-4V!Lh$V$;K=_oAc{JpHz4Ia0p%&@dw>`aXRZchzGnl@1e`1|3y}4jBJ^j- zBm>YZ;y)7*MW2x;^iV+bk(p-#<|4nx0Wu$-raJlH zzJtuiPC)9#b9SlMRzT{-eIM!n6F|!SH=((2D*5gOB;QIvrc(>Zbcz63ezO2^WlR8M zx@Q5h{7wO6y8QwDfPcaBhw}ahkn(uGHvL~0$n&)szD2^H5dVh&sn_>}z7_B?@ZAVV zJ!%1&PB|duT@6S%mjg1LfcWPDQqDy}bAK`N`2fjxy!d0sb;HN~UMcUt0m=7AK=N_l z*UJEZ4#@O312W&=14L8J_!q$0pzjd4O5k+@rvkEFW&-kl84if1oWb+CNqYg&L^Hm` zToCDffM{YFy8(GW?gT^?XS@Q)eq${lBYwoexNU?pK0G zapqU}LzXk%2PDn&m!U!i_bnm)1N?zCBP?_+AYLjmW&;Kg&hw9XzpVzOJ_`UTe-_{j z(6sYq_y|C@7oKa3$7;r0{7nNr9WWm-2ax4_8ekqE_u-t1c$_MrKO?dH|0l(PzXzmT z?oUEJt_H*}gZq#$-?Rs1`sV{O-WzD7)N2PI{aXMR06r)%EN~HE0r()>#Di=D@r*J0 zqmFrH@ci!KFy|#iQJ8bQF9baW^aY@~K0F&V;l-f$K#wV)2{D#PYXLkDG$CZCaY|w| zXu?sT7XwZPO^ANY?1yp*=+U4jf@WsNfF{fW&3ugnO_&M#F~A9+33EWN0vrdLa4cv) z;CRr47lHNxo)4OE1n7Tdrl7mE+j>msb4~>VuJu9>6S_s{>%=Z=3u)-~{Zkx%?jKBf zwG#eEp>GoUW1*Xb{#@wWM1Ggh8G{^osc4jxcc#$C3ytNV<{B*YVv)yvjmh6E@-7hi zJ3@~Y`g=l86ndS|+$WjwzZ80=&?%DMJfV*jn#%#nKS1a*p-&K+_bJ0q6MCi4nL^hK zeX-DCp`D3okLO;Y^CbLxq*30tp6ulRDG4u>@XbQc6S`gKpwK&nZWfyRNmIW+3jLnY zL!~@Bg&rsLXF^{l^k0Ookn$RdPKEMnh5j08^aa+AuT1DEywPyoF7#fZk+lSS^8ScR zoAt*ey+1+rnP6HZ?Ja`#!tiYpe~-jpPeHi8A@LUscIXC)|9-kdpDppzC4N2PQGOHR z@p@9?H{1B|V>tJt<&`ht99;4m2FGxWnay>!gzpgjY0uB_eNunrlKxsr|Gy+Y_g&(( zOyZ9g`R7Rd#m70}Z%KHIga;)2e97N2B7cvBbNvC+|GA_;Q^IQ`{r3^9iQu3G|hD>n*N%L|A(&dd{=lc)VGfRV;8@+eO?m6VFN{VHC1+-oY*eF z-OROXDsdJ-{ERc0_{J^Vlbi0lOzVwAy*NM{)mK(8)zTeaq!B;2Tia@v)D|zN{d!y- z6Cv4Z1f59tXh~KNlyu)==x^HFNGG8-Zqj-=Gm42B;!1+$*b@pcSbaUWUN%{*#i4s; zH-w5SV>DM1Q0Hzd8}b5|<~T35`EFOF|2Fu}C4h+nz8;e#HS7K`2;T>x?#2#xGf{e8* zL99oX^@we`on;q?jImpITbAytN1SBrY7@(!72CAirk`ckr)0&_z1Zf<#*S~}?aCSZ zw_r66l`pBNkVs>!;4xP47%O;;)pm?kcT6lpHq9|i({v;HhDp+r%y$8taDxvMM;2i@ zmoS&AwJ`~Gq;q1by~he<=s8)Vj%t7MF=Iw!Ee)^k>uHvUDuWeEZVVo3e{w!6*TQ*x z{B!oAGPFbX_}}6R!Mn3rS7V>ON4l=YigC+>f4vPOM7fN~b~0-Iv&M}XeR1~K?9pR= zzKcd@!Otm(tkI*#j~fRnOSV@_EElfa#(_U2*Y~u}=znW@WL-R38cIStSrV!$tt?X; z%_UoRMT2|YKKKsN)8)f>kXMZ~1WViYA;Cwy?rMU_vGUene3!}ux~;n^TUJz#kx>}~ zJ&>Qcj%$j@*=0iU-VQ||%ENPu`vc;2VVMLOKs^V+`7r*+Jga9k-s2WP245@Y!0}>y zI_g7zys91bWk0dwv_7POeMXrmS2Xp8;RB9KY@cFs+lE;<=R5iya?v6poC`~-iTt*F zTe>GSm|wrUnNB(OHE~-dfBPLgfQi?&W^IsTcm)G~d_;FX@q4qxI;VY_c|{Vv@V(yo zc;4mHAJKV|D)-1Yu_G&CKkFE9hqsudVXHDQ5Ppzp`n#s3a$oXAPQtlY&NFA#9SlTn zh1wUxY5`lqt$;b#zM#*ab4KV>Igl~XH7nKM-eA?{JQ3_6AjRZ@bLr-C?}soHzW8nu z`)+le!-mO9`K~G7t;mSU++0?kocBe(O>kD;bcZXh zpYUZMzo>`IUn3mz$(fG;qODE39}x4nnU@QVIWW$<+WmwxFqg{t)Jd&?Xy1zn`yt9& zz&@Y}(RR)Lz-VD+e_-6BW7wghH0K|5d>KYN{iqzPEq<~0LNn;7tgNUD7U^SJ^xL4s$CjkQ z+G@KSs}m*BPZ*0!ON;RJA8)Qocm)n@sSOrYaY3u&FWj|d%d1zEb&ufqC-OSu)%f@{ zQL}FTR*`N2DoqncZHpvF!RlH)T5<)E{ivV!W5?z=%Zd}9_Y`f8`0MF;&;I*po^QKw z^YF6IBTN6a&$j>-Q1a&BX2W;kqkg{45jkt5akfHFdQE|1_q^KA#h&tZD#BzV%Z ze!lU6M2CKc-z3=&9ra}_(XO1Aivv{T0Y?Ql562&$a$E8I!qaEG-#H+~A2HKze&@*4 zJiBblJPdIba0tf*n5QJ3M%bb={xpfNVU0b|aPGuJ=UHj3h;7W|&oMlWs7qIHa6#l^ zYn_HI46$UGtFw%#_|r=*UB(Wkw6L=~uNFow85)Q@IkXiy3`CyWk!qI-nl*gU&<>bY z8e!)A;HG-Rb|={akq1mHtZvXsibw1m*vZ>%_$W1a zDpr>wWM6QY)}Zs$Kx8`1aQ!Lf#0A(-&Ixo)PtAJMY}7hP85!DjW@gva&Ry1;kcU6O z!VsHU9i(k!ULZ0V)}zRfW9Diz#(@jYr@)S~IfH^;Ird~v8@g2(1*i=o~nfgeXLO|oxIdBb4^rK4$#hK zSRgWFs8tpIusp@6WDwgXObRFZBVU81<;S^QuQ%*Z33YTHgLTWH?T+pXbFWR%ABE&Y zg8t~WJFTWR4_Jw53Ws6Daok5_3eth;Vk=J^c1$8k?1qtW1eTq9k%mtVcaC_xvjpwR zTuH_qc?huM4&3(6W%-003aH0BQh(&L&B0`L%)Ak}> zAJBwkZ3X0bk`NuT8IPh3n(-*dr#0|LUzji+MUf_qN7F(3z=!d0+D}n#9FHym&FdFJ zzW_g8yGg^@=i|ph^F5Lm>y6>rP?Faha2!v*YAAdwMi|GFsS?g{D8qSg@cIHc!&^k& zqwr(+LnahuEb(_q_$Knhb;6(5T@udk#=IVp@Cpg9mhff?N3e-+nDNK&QB0rT!FW|m z{0k)h9ErbJ;U-*2vQ@gM8r54ghJ-^ae`3eR`Nf5{c@{@ym! z6+YHQKkuUL*xZf_^*4c%5nAu)iNsn(L}C9y*(V;Qp}^JK&O1no=hZcNGFEuzm#>dAXVJSf^Eqr3sd<>7A#pw8pJww=f*Jd+!3jLb2LQ} z%DNUWiSfKhs?tL8{mx7nrqq*1HBx(s%`jX?JKs8PY_?3#Cd@C^RMeDJR#e4jpp(rn zu44z}W2(;lb2jN7E_?1ytMFLbzJEzKc*OII4@$pi<*mWP=RBs}ZGQ34=T2BTcZ%MN z@Q~A&bjLBT!|m%d+`O&C=Q;L39`m*h4@o>|J0ECjJ6p?EQlsSk^#9AadK{JrsqPx)>gae4`mk1ln7%ehwQ7zZg8z zAL&PkSCoDQk=#{W2ls<5ft;P*A8hsg0&8X7ER4+JqOV(z3*>BBpK@ET=AF$Dc;%e> zKcx7h&O4m*dWa?9*rsWKU9XRoT;Wgb5T1e%p?Rly*;C_lzPNEw)aQZ759*;>K?H9Y z&f6W99R(&D&k)Yc>mA5>A$W3b+nqPE*!_`gb3UfYA+|{Awh{@44D81`B#OjrW_&Jl zvOlM92%F`9ljY!#%t&?0DAM3?a^xQz+}4ngh|$@3rFBpKiUF?aK8&jXmviC*HFkzM)?QBHw1PERtghI@<#{ ztCkWnX_7bVrFhC`_{+k`#W;$C)z|op5itq>PC{7nXNE&&V+#&2_y)yxaxZY4A-My4 zQsWKK)FrpFdco`hMJcoz2X`!l8+-&qnJo-rkl7d9WTmEqd$)wb@E;q9)-#1OGOK; zPwPCJFRcmF>$2BYjOTOAMnHhGVAkZ_X?F?lhMbzfG(U@?`%Jxv!aJZ-fD*4n9t>Dvtz|EEurc!Le)cS6AFm8^Z07r;2XNC?c%>9t?k`xS$1Wkk&n8|eU|qJ zY7ocEIC-0Bt5{CG&Fwmctvn|X337uCtoO5vhl9i7^%2^cv@Xs=Bg+f#Nm87g-xwGx zw$HEa@?E=i8b&`8e8VbBeZz;4aK*n5Bw42uRQw#ro6E{o z>vSGKfR%fju*Kf%U2>_%cE!*4O>ekADSc<#Rl4F3Yd<7z$aI??yLY5c#J>)a!IWsFuO^KULl|SHJpi;H{us-c zc>r|!#!egW|BHO^$9N{~3S^q^@wBhzb*<3v3SB0&9j8?a{egrBNkg}b0eRgc;m4V0 zk;n6G3BN=5Y4=LIT{}+Wl4{aE6b3Kaosxb`Xx^KA@3;4R2)eROEED-H5}pnoUiV8l z*ER5>H{;vuY6+hr;lD!|!>@x(UYysUe7~fB5&04R2MHf3;ar!&D_7!kT>&r7n=t-f zk^d?D7=ML?Z;|j;3I7*_OAw=behEU;?tP;}uJHeG#b4&4OI-Y%7t`|p)kVMSia*sw z<6cUL&vRe3yc1kB_o&q2Ly>|vYe zs-?kY4pZ>PqB=aY68V;es&E2kk6d~uYQDYlM2N~V8dzBcL>vPBCTxE79C>wo;aYz6^EE8j9f0i!5GF|cD`Lmj#(0} z!_BV@k_a4E@Y;!I9UqOmpdW)U*5D&3cF~V|??pJqIp#V40wDNe_FxzfaZF_6^E<{- zU$M77dDV8lSo$OU{(|@PRViJ^NV~5HnyN}^*boG>oM~&_ribkrHEjsL;N`K z5bt0G;Xhz|Y`!(+?`UHvNwF*2$Q;^DaJaSXMw6goysb zpAr>ZF8+#jRd=sN-Mwb!-j(lZ=00{nQgBuiHX~f%-LS3Uz^Krk&RN`TvvVf?dw1sN zw&kac0!QaW(gitxSTV}GVH&m|`~{8-4gIO}EHL1UOa?%&QH)5I0h*<)wiG4#vm0K|Ad^DRJBZN{%8{6#>tnhdrghW{84 zEiB_fp=G?7!Pdg?5FoCMx%i`<+c-e9`AK*;GIng>G5YxcG5$B>e%xzmH-hH4-{!ks zXpZN2HN!EyOXxL1_l6&@wQvmYEA%>{j}!Vap}7v1*LpbeA1^e=?HuRZ{)EYJoNTXB z(g+_d{0l&g<2wRIK1o(HnXv*V zz0FujjgG49(i{U5&MVPFAeBV?+1$e;+S>73Gk$BuZ;kjbR_0=;e_TiVeWC|@@KqO$ z&MB^|%8ETf-Oo>!9ovY<$3OF~?$8d|<3HPlzU=eU*2Vu0V1sH>}~PzCc(TrRN{BR*V*TSt+db5Sz8%DUxCoWgLI14jx|*w^{saIyd1X&b%q zN&HL4BoME~(mz_--Y+t}aKzv9ev5~gl}C{^m{giYkE0xKS~+7F7uUs@q|%qD8}q`s z^wm{$oaJ$@qN2Rq`MH+DGm{T6UQ!k{kjJvxg#xlcCS3ly%S&9(kj{=C7oL^os*!RO zvKu(uc-SZM_KJS>kVpM$Fi}FAkDkWEK0LrCGqp1@XM_lPJnVxv9n0!$I6HO+dc>C* z4`Z!B!$+_d#WDla9-gC;n|=7>=OgU%h))hr^9hVkInKVq{>ano@8W>Da8K5&`B|;G zoG)^|PC0g$Pk^)^4`_yW%O39rFUF2M8-+VrhA^^h?}8oX)O)%Y;Q6X(r7nRlhe_Qu3O6PsIhe#oS<-sCr+F_J#_v(4WFeLUEi5}^#!8!b9v z#un39YNi`|Kyp6A8tVM1eP@_AC)a$F5XGEif`9A8ztC3x8dOB-X;#h>z^eDcXY?)Z6uJhFE-Z#{~0@u#Mq%L zonmJBVK-T7kjTIzJq}(T8in0{87S7QOCu4g*l?hC=!}L{{XD@jP95O94z`ZY%Y^Kl z+;E^*Xry7eD#pTozH?}KWQwmm+;B7GI6CkxF}Lm56s-JN2TxvlFKHf8!qQVV%jO31 zNBlUcCQ^eaktyTC4Xc2lGFUYxoCiroo?(SLWVGPenJpY5`&S>}>x=hJz7G{dpP>YP zn~eN)mGSuD8e|wJemkk)Bnm_Fy6?xeC`xnkSoiZ2V2!=rbg1o33vh@tBzSTgCSyKeI-5uMhjZXr z$WvLK^#j9Jz=e@VTft;M#5+bYV*C-!>)k*1In(USIoaMjUnOhw*=EE=!#FOXVbHTr zTT>W-4dWg_kEgBaenQaS1YEcfRYQ-B2a!3u6d(}UOck6e3U4i++MYLY;6if_S{ioh zHj2VR!h~Z_YpdLV-u~$P-hIkZ(%*x~OIhUKCW5Qs`MxOfe*xu>7W6)OGvC@V{edEv z9?S^K4Y%jxp))YI?GARvDILdQ<{*GGC?e*m(r(5;*dUyRRuKL(4%DG8=yF)J@h-;* zL6_5Yd1#_P{C$V}4?MpcY-avzJ(^)|q;J=@hW*E^I0ucKJa~55E~DcfFi0EdxP!NJ zbl}4TC4E-=Q?_;O!l@NQ`*E_1(-o6aJjZxiFsb1A8ApuXyluJRSwlq601k<_V)G-n z4r%M1(!##0!%H0+ZpQv|-o{Kc23VgAVe};N+M1R?KUUgeLTGb8kF&4mUz7L?(G>hv1aRfwgUcHRq}YI$Dx*#~*UHnrfNAl3JL~g@&Gc1 z4_dIR3$DS??N79B0S& z@IDfUR;c|<>XEbzf-TgJ&EWMRmK%&$c(e+mw>63mp6VKt|BMVbx6ME@%9_pw2HYs0oaoyD}d zS=d8~bzaXxuy;))TaqY9d0&z!NclHb1jbGALi`RzNAo=B5KYPG`y%Q;*l^$&@10+< zvZBXajtu!r1~mIqwsgHKDzeo@)=+Asp5`Ckt6IGyOkuS(-NZsf3tL6V(yTFvdAhMU z2XvK30w~XD8Hn)xOZndv!aw3H2k_Jbx!xeQv`4bEImKoRm3J2Jw2lSLScFyB?C3;o zBI~J{KeB3-|AH1%nyVodAMLwtgSWTfo%Z@b0I_kQm&uKzIdL>Aj*f_z#WO1>nhzUIu|pFXC23C%`A{Mvji`%yu9; zdmKubJ;COOR3a3L`t`8$KQ6beaj5D2x#nvC$~nw(4yWJ-(<8b4JZvtt`$&#QAN?4v zKN2|yZVT`*+*IH#JiG++@L>!DHo>nEj?eO}R_wfgVdTyo$V0eq3*WW<4bQFN-4!|+ zSTiy6B51B)-*g;UVCnpdy*n_K{P zi3~Y z$uk8nKK%1e-y05X=bK)%*|dsqb1GAfUa{SdJ26P=*RUV23_K^>UvlksvmVpi$h#ph z;s=x*2%E$L?RTy%1!`IvNWBeNw{-(CPP2YtVZFQ+h_Or@Vng zcbY^c#ZWaqZSCaCT4|v7on#J#4e&SY?^8R+AN_hS!>nP^0w@})XRZ64O@KWTehT@hiCR`pVp^qUg6Z{d8uvF1`aB3 zpO%*EDUaO47cB()@PHar9-cPDWH7vCOGi3<;ijG8SfR!YkC`Pbr=;QUMkhljqU?9E z><`$o_o3`}73Ay>rr~Yaw9jw@n@mCYr>sl+$;-?mKqn8}JP)<=EL?~^T{*tI)MH-( z?8^bi{v7NxyZ>)o&$2&sF7}uI@JpqiYE&8E={0Mm4pU17x2JWsk~AuzVOSJD254Vz2pt;p_F}xL!avm3Y9U$fWp^qcymw>}TKLdC^;6p;M0UQDP zYCy`FA@F>_i$LFwc7>!eivb}rlc#DSDB~PJ+~%1bcyLpn{{lQ0ko#^DE(Dy2@XG{p zKha_EzYcBb9Kaa@zeIZ?{f@v#0U7T;fkl9nHw$nq{L#EPXFq8dAgV5H8z8D8tyN$P zAc`<;Js?yx`z#}Avz`}8rZvMKS6V&(&_vP}15%D3kaDI7TeBE*%}hfD~t z*I=P-e@r`4hTkJRSwfpBbwpylrlBF&?>)06{PA>0VzJQnLr_rYg~%+gJB9vI_`fIg zZLDBiKNNbnDPfQ2385DY%|mo)?_j@&y(sjX68~31?-KfVLjO_dcZJ>~G}|%deJJ!N zLhlv&fY5zTaP&)Ip`#-0_o?HA&X(_0Lxo-}be7P~LgxzIBJ?#v?-9C2=s_nr>D3E8 zMd)t|y-etT7kaJG#_k*XwF>Dk7raudIw$fy)IhpX-Z18g)zpf&IY75)NMuM*w%1y zuH{%R@%4teOGCxAc5QZDU8P;*T!alOmsD1lTo3bTd>4oL4s3smN|s$;xsQK!A<4hf=648i``fwxVE6AKPcx5e^^N%X}jrIdBg$| zavAfLti<8em6vak9y~;aKm6*(qDzP3^bE`?O4sCU|bRs@InH()+#S-Edj& zExQKw+u=;03XdN#{fN5ZvR?izyVCvrwn1EP_zrS>`@q-d_#Ok_;l}r>zWy!mjrJRv z$ATf-ucU6-1#_I)DT(SJVMon$rbUfX9gS2(3L+Ddfo!W1QnV^T5BgFiXh&bF1f408 zDj_G#=CLt#!uy;1HkYS3ITpf9nKjSqwPnws=IOniAZ!F+7;PBgpypYJpEX^t?3cZ>)>6(x$L}ykV66U;Ox8yX>%pvt3-h1yHeO< z^B6)i{(Xw?Q0Z<`e1}SRx8gfgx&zR-t$uiybgm@%;73Bshj+Xl`8cMveA9a1TMQoD zPv+bqyqctCgT^b=B0`K&)6xO)inNFjI;F8M!u#VQLcW)_0^(L(M9BA0_T{*j%|2I* zS_2wWCgweo@1cIssh|n@-suDE1DX*1LmJoZ^1aFSA6f7}6Mpvq^5Qt2`#|~FVclnjrJ^!18?~wSHOZYZGUVnyT{2GaW7HRNe zPRd*xNh55(#4jcdobLm?_#VOVwGzJ;ehj}r!nq!S;jI$hAmOyX;KlbOhVPN^#F1TW z=*f}Z*fH^;DCzOz5@`%oITAEubm32+!5^c|fKrcbjfYObcqB=pvdoM$bSiEy6DyI+ z=$7b(#Fn^Z84crHaV1@TMo*VtEYbLCx4)ykeKpo2;#DSYNd14yxTlBp2TOyMYV&op zmuRK670e8g2*?1=W_3F zZ}qxX!prfH(wCM^|HIjXw@5y@-jUZf$Ya^B$K)sGzk3{~@*J}Yg!_D$cf|uuk5lnn zwNFP#J=99-$6>Qcf<5_?}nM_Ia|C%g+7&#JyT_P^wgM@_>%G1&KtlL zs)VR)aAYUrm`#ou;FtoADakl8$uS%pesK87aS~JUnpDEr^s4E_&~cr|u1^795U0n- z_qVkfziZmE+~(=a?wWQy!0~rYO9!C+Kp+ewyRRF?<8}qGMu$&pXkf>^$OWtre9R5_ zOi9Eo9KZ*k)=>Y>aH2NomBq*H_lAviq$P|%g)Jq648YTG< zey}}%w}}+JW%p*@AJRO6CwVtutOr|YY!W=sDY4F}k^J4A^9=`#Ky$;t)jKd5@4S>R zd*hP@?whSoZMvoYn0Li%FM-IlXw~e@J-JV&_lJ(386AiHuW#95f>9yU0$nczR=2OE zu!#>dt=bFr%ys>`%U#C7AW1Kc^@at6sXc_?^=5=WMC%>^#OKZUvq~ zfyWzxkj0LogUZHw4Bb4iPx%#Cy%XBTJqjb|VITBXuyTuardJTTevs;j+RR}kX7SK4 zH0=P)XH5>yW`Y?y2Oo$+H-n*}eM)C)Ai8NN8%rS4IFz|E=4G%p>Q#I3M%HSe_kAWs z@xLk66FkEosU1|1^YJZx{o!A8i*jcAc``H8Z=yv5hWgtI@AUdBe&>jCl!uuO_C1`2 z9rVzs!_#11myZTM4H+_9%k_(8tROr#H*)8G2o6v4#WJPZl(h~-3p960v~IXH3~Sz! z)!O)C=(Jdiuxnzl)tx<6MsFE!p38EtV|PMRt9-I8u$6ZV$}%*A)_)C~oqK9%)|&+> zT~71rf+?AaBR4}};)CX9c-wh8#-2Xycd+_+p#{Wy2h$FyLcII)m$dn#1M1rvUtz}u zBlcI=aq+U7DTMEC--Fs#BwtRmTAhB;m`8R)ZK&C&o(JF1s_7Y{Qz%CYelsfz>T&sx za|{meztdp`Wtx3BLUt@{VY6XJsvhuh^^;*H(Sx~>JN8C68VO#N^(OYoya4ypet7sJ zmpHwSrQ7@LG}*-t2@@Y=l$(De8ltQj1B>U{O;obwwi~fT<2Mu!ZeT8@4=_)PK*_<) zso?5LHD1LTeh zx6O{;JhGQ4h*rqb+v>D5?lJj2q&PF0Hxg^K^4ABtP`74gqCKCJO(;U#Em(|G5O%D% z11WE_eMCa&uRj#!^Vhfa>Fp^fxn+Anq-+Q8SL!+=a>;(X0VtLdq7MkcR@Gz_B2hw$ z&j><_oLjQ~v%=%{NAfqhx@3DdFx%l@;7OH>4M)RY*;^X9&ZDxQ!d5a6#`w-LAdIzQ z-I3ur_ggMXY0uwba>}KH-bQXG@XR&vFzX=B24yz>I1Px5FO0HIj=YU2@P{2g{@E~1 zkcmwj&8=vI))PB-X6?&*)shUR@ls&*UpV{az4P0K_fI1G=Y=_c@!rmzy==RR-jafP zqbcfg_-=$ln`lQxqaHrS_N?)gF+}n<@o-$o2;t;~5B!m9QHiKF$0!m-)zoTq^ycmC z;I8F(Y_?+Q-6&TEe{Oae{lw&~16^XPf5aA~8BFtT$jj+!*x%pV#M=ONoZi7`do8+n zjHVkHY966iw4%p2-v9aU*v1ec6-t?wAbGmma9+{kZ+ITd6>eGY45|v{W&ky zW#W18e!+-8VgHc9S^MzvQHUjR{i(*U8on49?AttGw7;tjyO8+1UJ31L>oXcEVJFn+ z6?j7Z+-@C;L53s=pRV+VTUtD!(+YBK*~ZL=PBh1Qgug^-b-ZTwA-SbBt|3Mh>@4*N z)@d@fHqGKuJ#dJ3m{;Y_ofVjM*#zGeb$G?ZR++`u`)cv^ta`bxu8ezKVk=Bf?GhX> zg==d5Wr10~Iaf?A2u$mkJ8%2n zhv3um*?i?OmzAgN?eu*1gKj=$zo+N3F$e5iR-Ta5Z#SIP?>O;~&b z3l(4e5u{HWI4hU)!sfF2s(Nfxe3+|GFI$g2m<| z^$_V6D88%Qe5$^=r=^v5sQhw?){*eNaD;pxDZU#Hq2Eb;;_2q~z;_}1FHwBm`Uh8g zB!8vipXipG%uZSHUyr&nmu){T`9l%7UGeu+u5&SeHV1Z;7XvN^90qt9>?uzaxO;#@ zzX6z!@EZXA2oC@*1DywmSK5r@gzgK7xx$RyXlP{!e-3a7;CBES?+(C4peq1N0IvZo z1Smav`cr{=lU;uKxfaKeY zLSXoFfDFGK@G^wg0iuX9uK}D3_!nfB{M(pmz<&qCx5~^b0U7TDwDl_hw*$@sTqkq{ zun=?+Ab!i|J1~Rxh@`pCEPfeh;}74`%(+46>N5W1w7=!FlO(-U;46Uh!S{1O{4!eb zhk55r_EqHjS3q1D-vXq(5x*2dVXu{J#F9yUjd=Vku3(`0+KLIr1@u2zgc`j(e zVW4-RJja11MEgry4|pMH!V5t2TgKU-3C{w(7|;ir@J!JB{yYdY;i;h00Y`!+%mlp$ z^?*+j<~#I>pj$y-0-6wgq4^GtF^u^RjVb-4-=T4foA1#55bi^~Ge8rf{iprxSo|R` zk0X=3ej&8|p79Q8l%@S1@xFxrSorr!_)0VeUc9f#|8=1~xZg?NDs-yQ-w`^UG}?y! zK7qDjz7roX(mb9o5q2ire&I)-W5VA@`S3a!_cglALbU?=6g~H|aEF9yXi#+j~Bk|Wt{1NbH_-^EjSEt0E zgT}+_Z8(M(O8k`)e~-i;54{+Ey2Q_w_}Ma0WxHeeTI7q@`4XNk;RrI}CJ=w`usq;) zNcruR@N!B2Zb?5~@;3qkDF1N@|5pjmmhh`2e;@tY8VSE$ z!q-bU$KI4bOv2|&_+km~lJGYq{B;Q*F6Hw*%SAuz(r<+;{F^R){?ip+?4lc8^fDJ+?V=+t`UDrvcL`lS-*knGosO8tmscz; zf(dlVvNBj@JEk?*JzH;{T~Y~)?4mfku*LSdG?C1yS>1V*y*?*LBr0~W!6H?1J2NIY zmkY+MtBQgvs;XBCkKTV>bDGrXu>>akFn<+x`c&Z9GDVhDmK9fptcgAuto^o=&$t$e z{qjhgkZBD_d?X` zVU`bDc@tSUj2{VFS=2;;UEncRH{wB-I%D7%+Rd-(8Hwhu+E-elg^WcF}v)aVfOp*jL zj=6tIa27e+y>mYl)tU3pO-Q_M$jsao#hGKbL`?|iFIs<|ZGe>vNjIu3q3!tcx~dwO z#{|pcOE?@!&avw?%mG?+eBXa2osfi-Tunt4vWqSIYeGw|FT>K7a@wo`U?LQ4yF6IN zmc=wz71dP-t3x-LQ}&8+?{e+Pa@?X&6F-r+q`0mOHg$GAP`PP@s&bc?UQ`!a-mTga zys0a0Yt_5OjrQCfT0F$ni^T)jPsJ$;cY3ZwKk1SZJy}_aKGHF{Je|cZNj-I+lE|RD zmBbL;Yb1u~z9BJ0cMpjnv3?+lccPcQ?_IvJ8@nfedv7O(>)SgqMBm|wA#(dBddBY4 zL~ngJCWa*3kcmMFw_jpV!tKF3@DRcAAlD5P4`4%cnswaIG(~=5D6`K#Qxeyw;Q5|>T?)r0YvDXT{{8P+r_+PIYE5-zaV_d0 zX2APTY_IzFSkGn4qbRtHrs5pz{QvEwvN*GNmCKO#pSYcj$>wr3xem8qb`SSW$&JPO zuKB07^Zt9>H)hOMSAu1de48@$JQ+3w|n*J95) zK74#|xG)#(;hbsF4}=g50|x&!S$Me6HtcI%@#VT8*s8QNR!*sTw`-OR&#@NGv*!r`NQ%%@|cI81UQ zFT=ls?}wOM17B=?ZmW;TKK~|#3W`*+`KDp>$Cc!ZO|rs|0-;6 z7k;V+|FB&Y`wl<$D5ni8joMDC&u!TBTUxXA3LV#$0)x(d9rs{5&mWF1V5G>I`H{!X zCV1HWcQJjUjfNfM9FT?4M}Es`u-r(af&TFQ%iv98pIXd9!cK^7#M&zP;om#~{@CT# zPhsJ=kOFp%q-2P2cH3(j2MSv@t^;7%Ae=G_qffS{BdI`SlYul)acnxXy3FpIS+DLP zJMGqCM>fA8{8TmtMWT$2y(M26j@Z2Xk;rIF{rDTU9P~FF=(A$B7{#`m_(;x)mu*bb zj9+2+{fHqp84xsSs$ngdL= zb7KYan}xkCQ#`5u@XJodu}U`_9gai;*swU9zb4@ZT%SO#O`xphmUFAFO9*St!nTMu zf&9l3!nPHNX{|luD+JrKE7m;6Li|~*_F>5f8?eWua-OAv4jz4qC2mV7+{6$|MNCGT zUc515^??h%-__;4ho5yf=POAyT8* zZj?NUH<9Iox-p&5n2qY;rd3G6+V)1DB894Ei#Pc(H}jP2S1L+ly0G1-oBTjf)=CjjU=`MnuOvOE`?wG z7WOtp;VrT2Ta0?%#$PcHv3sz-C6`)bQ)v8y)zOm-Y_)}vr(5B#YL&jI8+%~5$;GMe za+E9toY-h6k0I7`v7QY5%@9`@zGpj)0FRuL-Qr9xW4dJ{@9QAX_)6b_I-!?8r3)vU z!>H9XCF|97yis@y7j#`ryKkKGVVjwBEKrg0v6ZVM6&aKp6}=e0Gc)c9wvV9U@XI_w z?h{HI5c7ToMya;9lU8ZOIghrE8R(5!-_A3~ANjVaO&dWt3sDdqKK9!-0BPCsF9`3& zruTD9lV~>0IUMyd-%fS5H!Vc{v$5L0i55ho6i-Pwy~W<2jVPc_FkzTrG!Z*(Gd5~QIkUa^!};|bv)qr3s<*+! zwi%sieHIR@XwA=h(IiSm+ME0~LG1qx6zS5(rW7{0L+Q~IO=uo(gjtTxXf=~0L~bwJ z%|x0g+leC5pzX9ikW zIi8yI0l7cxy?uZu_nEUA_rew*OU{g%jl9&~Whj z+k6cNC$2mv;C*;+?Xb?%SGQe*{=4Dei7V5={7LNzov96N_ca{sRhx><;|E;n?|L5Q z*S-8*+q_LTfV1-ajVtspWCQCL%~=-jT8U^5D6f;V6nql;*wXERi{c8a1vK`(bKQ=<;(X*cSJ>s)J_HJlq|63TjvlT4)k$d)& zGYT^&4(uGM;U*(B+#U$OV11YXl)W|{p!HgTF zBILnphrSP?y_<|WxrvzEn1oGlj{<{L7s@@1zn)~p3fpo>B-E1~bs1s(#J}@W`+^a5 zRtH7y=j%&u_`X*Lv3l(Tw4Xox3bGW}=1dU~dwgQSrR2Bc{LfgU=7l1+z0XkGIXok% z<9Sm@uCa6OW|)k5I^MuvF7}|u=@s6_3z0H5srEJ=hp0T!qL=s1S@7%rI=1RRbFra% z_@##T4mNzzD>MZs?>vV#-?fo{x!%0r;G7+Rzhu1_d1@7spVGL`@6F$`nZa0*WU|xL zx+<4<_-d$twi7Y0ngSO^NX^?Y174kH82*TQ4B5koHuGMv zPb&1z6Z3b3PR6QG?Dfu9T(x%55fMx3RkQ}w<^rVLh5|bK6E==x@sy}xF=DHF0EmWc z^LiP3t&Bd!5XqS=_=r49KXjbl#%+jV0wIaH!ueY^wAK3!b~**oAMa(_;kSj)>9_Hy z_!|bc2_ss2z%2%~gG~D|S#tViyGSYa9O&9=70mfQ74|kQL5UmH*tl>@vk2xOq}|NE z_@ne<%Uuk=K)CT0v$Dr*fJT-sThvVx*2uf9mR5b0Ug*BHU`YN8sAw z%$x-dUTe$8;TF+CJQbY6X?P*sSs2H;3+@bl(9BB=sYiXh&DVWCt%ejv9m2#3L@srp ztkZ38e4Do#ulOoHv)g!FvOOk?pI5Lb(!RNw*RmZ2B?o6l`#hKRW}soy&zYvj+xTZP zn#GV!eiT^`>bN@qi1R zXxUDBcqO&tGc*fw*wOu}^m}C8!lh9i6 z;rP_BKjl#OFZH zJE0Gt8W$g%{qmib!!eB6HDAxEH6s^h_1#}ohlHuL!bq7XP}1Js^f>MYM)XHb1O7d; zEqPsiAo4rB)D5z)W!n*CpWtO^L73h$?0CbT({SLI-g|xvIjaw>MI`S%e=_*p#2d4~ zy!t?tcvCL$K;-^yCP{fP*kzEpn_v^{>9`%~c$*gCzcBnkZhPbJIbFv$Cq5~oPdx#R zjfM`%3>Y$E^1@0vcIDUbu-u6ko!C)Fcwu9_Nw*=h-g|DqScZ%_-aENU#6B>i19zOS z;)r+00yO zE+28Hdhg^yB*@+ggJS4+yFX<|*DlLvA17Rf->r1`T)b| z<}(73Gq8%$8PJ5AI5xqp+Pt509L^iVbL=!_Q6JAX$76w`Ud(XT1LSUEFv@uch>gS} z&r*m}zuX|{ysZXfAst0HPcpqfxH>fJ{LpgTKE;@?79UjvW@)C%)*r2 z{;)H*;=Dw1Oy%eVb!66s&*dB{>uBXq!6*jnB0n|hD}C(43J)oyjMz-i8(x9?Qz;y4 z_2vx~FOm_H$&L>6jcA6gDA67YIuYNjBdQ4VYhg1J zgiZA&5yrQlL}6Rw!cN!1xQSW(77Ac+*G)6pnI2P*S+9ouy}ftvB&t{h)5<$oyK#op z?hNf@=(>~=vQ}23IBz(+dpe!h##k!B@{sNUB*D&WVk{M4`86y~-P(3uHHlqfC^lfm zy?8P_Y)k2!e3H`}_grlqAHzRt<7<4E#Krtu6PD->geFenvTLnf&J~k)r57Mr~@rq}b zk1xlEtw40)P;5u}jt-YD%xDz=5Awn;#vfgUV{uF&Imuvr()6OY@m#QA)`Bd75pM^g zw_@)RC%fVAb6AR%@aW{izeDB>$$surlmhZHhrv1bGwO5HI5>NO~`T z(`XS-bGOtaijH*%epVX>1Z>yX3&?VI7|rBex5Kn3B!(7gPVW@|Un&3h75;|8Uk0w4 zpY--pU3^@B;3&I^?LEI~x3}qJPDMDQ^5GXcdcn)qo%5VZoNQ!qh?vtMrt@j( z9y&%TO?YaT^*>eN$0@vv2}$n$tnd#M{-(lTQTSGcKdtcpQ1}lN{!NA7sc=rkSRJYr zUZU`;6h2eomnwX$!p~Fq=?eEMytl$XKM>cUQ{nF@{MQO^SNJmu|4)TKtnhCuJfiU1 z6kezBr3$}U;WY{`Rrmsh7btv+!pA9mxWb1hJYC^^6uuwJlWiS+r0`t|e@)@r6uwE} z>lOZp!q+PNZiUw?JgD$x3SX%3ISS8Hc(%eXRJc#!Cn-Et;a}lIL!0-#3g4~poeJNs z@K%LCsqk@1{&0m4QFyw-`zUO^%CWWt8_#+BmtMI!OUa#<=!g=w1sE-%|Jv zg}ZJbFID&gg%>D%io(Y!e7M4gC_G)^eH6YQGsCuRf28nT z3V%)E+Z4V@;p-L78D}eVt-|kCc)h}d3SXx1g$kde@H~ZQEBr!*`xJhX!c!Ig)!w+C zdlkN0;X4(+UE!??e^TL(Df|J2uTglT!dEH0QsIjgK40N}gZc!iOk4UEzHczW=}DdH+b^yA=MK!nY}Wlfu_4{1Jt(RruWsuUB|b;mZ`hP~meF zo~Q6^gv;mrzvK;df? z-l*_Z3a?c7VujCFxL@IyD15ZShbnxK!Urhaqwvo@ROO@aw-mlZ;V&q>Md6Pte4WDY zQ+Tt&Z&rAX!b=stK;Z=npQ7+_3LmcUAqr1dcpruD?}+F9BZco$_-hK^rtnP)U$5{- z6uwsBcPqSJ;X#EjQ}{xK&rx`u!m|~Ap~8I%KS|-K3jb0$HbD>jXa*?vxZnh)ZfXM_ch%$kN@0>UX;HG|oa!@J6vpvAPCQrq52yf+Nvk@H{oUrVGA>7&1NjB^lr*!7EH$4fxSX?$J8l{gme4-^u zECtIZ5+D@&@tfIgF?`|d@B3)5_{b44q8bjQcpG^;V$p@S@fY#7tSZRbK*`tZN5Qlv z>%Fe7AO7L+Zsq%3UG;ESaAEi-NW6PNKM1!`{3)vq_piMB!Bmze(YD2!5~fdr;w4?$N>@LBin+`V@ZV}vda4X<$hx-QH(dzJz;{Psmdlc>oxXo}c z!MzUm9^5}l2b<2vNb?K0zWB0o0^AvJ=fjPMn+i7z?i#pqxLPlR>-3#|1+>hWkz&#K5GTa+*@56lxcMz^WMxUp^oeeh< zZUWqNxVdnP;I<--!@29gw*u~VxNpFH7w%EGC*U^2y#)6<+O5UxLFvrd6K8*U`r1i0yNf2}V6r{m3qZj0cqgIfW2JKQ(mz6Cq?j{)C?`%vh8fW0ttod!1;?p(MraFgL?z+DNq1g=WxwZDh%c<#N# z=PTTMa38~c0oNDL>p8#$Y zoV0aq%I{T$zpd~O6~0gKUg(dkj5LK?zoUhNA>&-QF>vFd-(d`;ddA_??j)C=g9=P>2P!57QtNy zw*u~VxNpFH7w%EGC*U^2y#)6<+FMz}V(SK;1<`w(s)+*YL7@>W;Z3vfH&zK=ZT{0991%AgAF zCb&D`?uC00?niJN;GTzj8SV|Z_u)Q;I|$eRZ9MPb&W0NaHvw)s++4UtaM!`DfV&;; z8*tx+`xestTiv6O^90;xxR>BwhkFn1W4JHi`l3HS0qzXA^WkXb%~P0QzFkP;Cmgti zm2UaY8)&poJ?yc!(z@9n&BsAdSgQ1rT@J$KF*o{FA9xHU7ffA!;HQA0!MW|QLIrz! zYZtE00$6>YhZ8pTbWUA;;3;yPMhfO(p)9aou2}JEJuzl;WLE^W_sx#8&|p0Aj2Il1 z;wT>AsvFULr%?d97epV~%Dn*m4Vw(a8?Vhw;m+U)o?2q^8Q$XP790g_CkL=>#UIY! z8IZLOorTD^Jz~VNh6WafFBvL1=p2f8I7BahXJ-$YxY(Tu=kOL|f}UV_4nC}?!yXO= zkxXX8S(?Cu$jr1yLBwaRv1r3)54nL~+^`p?<-B9EWez#vc@_4g5No@~bx~%CN`9+% zME-iXb#QCo>ah^J2K5H8*a33@VAf2am!>!tVOW=Pxzz{jQ0#IQn;tCo=frB%8hxAN zd9a#Fj4qKM=V%z~;dOb$&Ba@2eikd2LRc6V?g*Vg^J4hB&5PNt!=J1^@b74Iw_zze z?dWmZk~I%E1=K>r`Occ?>MLPJN(1=Q@O`QTelRIbG%%kMizp4V^CGKnH>*)GB5yf| z!mS0V^<);V-ReEl^C${*3*1X^|Eb)sfnx&9xi8f*NOCsWpK&e@7XOdQi&Urk+tIdZ z?*Ca{_)o^%`#qDbK)4<2AZ{H{kb;w@3P*eu+SNJP1n_7n-lbe6abct%mV5<=H5@o6 zgxwtSx3x_f|(4Ew~c!V$1IFT}x1S-1t0o#17b-C$9VIdup} zG*P`moa*MR+`)pI=(r&~x@g23P}R`|r%(;>r))*_=KQ(#oz6338ZyC#oO5_SVEzth zm149CgwJ%AZY<2b)>*z$S5{e85*&ryv?_hoRla%i3Ve0gN~=?>yC^_*cS5yUSLv=wYR9jsg)I2@MnN@uh%+r*jMi<|*;!&q%{M5Wyjg06MGVqZyR z1te;veZgv<-Tv0J7DuJpvg^>gkUy%KBvxstj4@59DxxK2JPWC=Vkz6mk{el2p{nb# zsc%(6n#@@>n$(Tmi;Ou#vvC?nJljs@RAKu{(Nd~V=VtF>-`T_JaNNc`NBPp)YHVIA zx;xuyQc`J%hXEU%nbTPL*=WT}a1%(hLy2semt zWkqnAss&G=Dp*!qRa|K}ovke8{wS*|sSYs|>Gi1BbnGMh*T%g-n>JGA0~eO;RNI#R)gZI>Z+bq zNJxLoMdJ^tf0FRS#CPf6U4Tpf?hHkV`nwtOr=gJXXRBe>6$J&c@^=T$oi@(Yk*yzh z_}DyDVt!tJLLs=Bl2vpvo@AQlA5ztX&}6zMF!ZQw0#{Gkc4JDWZoF-EFVoy#bPAQK`hj!0_75ucV#MRxXO_Y*IjSYl)(^7 zyaxu=dG*L~I2k?m-%8P#j2`lu=U18>g6HsZ617QQYzb15vbePAf#>jYRJ*jT#x^I^ zPQ2gmq3{()kA>pmNup|kntXs?Hm#5k5U_S{h>S1cW3$J}Gv3t)B$2@iOh_lGoJ5wS zViH-BN^wVY2EXk$BYthz`t9%n`nmkG5@bTL1fkl;Mu!Sh5E|T(5 zp77Z^OZK?#L7aYITkVoabJcGT!dzTEX_nAbdJxsUB_!1fIkh9B9?HMRGIO=_p32Ns zoypjGtkG^6O(HBwnI+TgNJMonGq|FYTh1G)19vu70rW=)@6G;i9x zD@_ZVGjFCdmbM+1eayuIl6F?HP+JL7S&1@T?JL&3#A3S>z_ohom zH=ZPN5;Qy#U6S+x-E?)`{;_ad0?;F|wb=mMDR$F5Nvhp=RAnWVV-vBdCuH3Q+L#G} zwp=7%Nd=H6i3SOBY$8^Gq0Jk+!T84+pm^V4yg3f(?#r9q`sOc~Gkfm*cxNzfbWyiR z_IBwppl5+&%rh&Q&_G^(u6>{-)dnxIh-Z5ktFOs2-*1x!bh~#MO~%kVr`=@>Q&RCd ztfv%MS%*!5Og*I#3+o{TXRvd)B-D_|T}W*7v1yzh6FHK6sApNSL=Kk|XE3XC!Um?= zNWxgk-S}*vj-RwT<3qOYN~-a6(vp~tdm{guYjTV73T58Q+)lQgcMp#FByE;+r#bgQ zw;L#S6Lbr)I(G|5(AS0de%(VGC8^ zdxJ9}uT$1vVRW&XgU-w(HFM2x3a;XCvgCYGFkb*zYGpor5SpfD^UG_imnV&wygD!m zzJy;59O21%Jej;44$Oc%UqwuvVMd+Pz`?Rr!LvM9SBK1J03OfA%H?;4+4Fp*)%c3R zN&mV~4Zm3VP=qVS9u@Z(&sDi|X9Z?mHi3~R_@-Skw_x_1`9&aR=3nirsPp0DMK!18 z@%h5}K<0~mAsgwN4@Gcj+6tByjym)GKaHIWd=%B$hc_rF2nZ@F*0n*5iW zK>~zZKtzQ#CJUtGMlMRMd@Uj<3My?;QE8!;Dk>^gZ0QfIR8eWgieG6lkI*s4DJ!_CMB$` z?M=yGE9_()KXTGmZwWhobZO;4FI#7TXkok;9jx{4kBL(!=`)&1lbaixXLI_Gvpfn( zOL|>nmHqHsdTouJJZh~aWUaHRS~&vzVII>>=`rVo+<7`bMwQ9dl%(K9UywFK*ddjz zRjq9;It^$i@Twb|`Juno^d`27q1E`QXMsu0T02+6>64mtexffmn1h3~a3{;^?c5eW z6WEdrQ^0<$D-892-J-wGj;Wn;QY;*7*ngFsshd%&b9Be7*~!SmF}dBZE%95j{oyCa zf74PYQ6)3k1(m_?KaOj%bAkV9CscQI8kquTaQ={UJsR6lGbv#v6>nrFO&#P>=ixXq zYHC}mI8|E{$?af(<2iFTys@6swPVT4&PSMXR0OA%%Ezbkn{!NxEtjNMjxD#tFF1u5 zc4bGQ<-OHO>%Bl)Jug;i?-}$4))+Qo?_Fn zLFL20xM^OTGJ~zq4^5_*5APB4&!urXZHPUY)fVfRV_RC8R?_)NBZ3|LmS@WLl#d(H z)=>Q)HzXKUsXKF*GBVEI@!&Vi{YTm@6Ju#}`=s^hdBTbJaThDQW$D@c|1p1AU=RN; zNmjF@cb`RFN_+W#v4rxQ>h?SEuHIexJz`gH{DKpfbX(f>p5yO5j%t3ptts`nHDU0G zv}^r8!vA6alT^*MJ7R&~rqz2TrCvBLS5NENIRBPXZz9|1Kf-=H8Ryy53H$$|?YI7i zr_{6GuJIpXyHcxHmr~Ea8MKvkQtw+S^)A!;oz>fvQg3LqUP^r4OR2|Cumq1tzZM_+ zsheG5k--pLy!_s1zzk$=>72EXMthbR>5Du$?#2B4!6T%_y+Xg&tV4q8SD=^*5bY3 z>o5&+XUq7ZOJlKD;eNOk?uM_x9q?ti75)@%gj?V`_!3+Ve*%}o7vW;K8P0>7;2g+J z5aUVsV>lIVgca~dumt`P=D`=>Ajq5%kHhC-U-$#q6+Qj_LwXhLRgAH&3tcPW=4i>@LFcW?S4uG|= zADjid!jB8!m**VexkO z2&{(>!z%a?oD40`%Aw_1F|<7MpygQxv^?t%Ezf#E%d<3Sd3K12&GKwNv^?7lEzfqq zx8PRz3%C)!3D?2xa5a1bE{B$9i=pM&JZO0~2U?ybq2<|BXn9rvEze4zk2K;4qqJP*#T&IwijBS?Sz(R+o0vyW@ve~9$KEQftF`0pyk<8Xn8gt zTAsB*%d=W&c{UANo=t$3XJydxtO!00GvPWo06qo#!6#vNXnA(zq9D%>Ld&y#(DG~- zv^?7mEzh>V2Dky%!?myuu7tDUGWZp^5L%wKL(8*zXn9rzEzc%H%d>K5c~%T9&pc>( zmH{o#`a{dJUeNL^4O*TZ8WiN&erS2N8(N<2fR<-lq2<{|XnD2{TArmr2QAMALCdo^v^?tzEzi2bH{jt5gFHI`e}?ac z+u%<4I@|^=&o)ELv-QyOYz?$LTLCT4mO{(3`OxyL4O*VnLd&yh(B`uV(DJMdTAmd_ z%d<>qc{TuAp7n#4XWgOY*^vu^JUa+2&-Ovfvt7{gY&*0(+X5}mHbBd>wb1fxCA2(S z1})DPLd&yuXn9r-pMX_xEu0J=hvm@ntQcCJdC>AK16rQ-hn8o(pygQ_v^+a>evoJT zVJ*HJ&VoDOOt=+31~A~4zxT=Ld&zM(B`uWXn9rw zEzk0x<=G%;c@~E&U|;wk>*0NH4ZIhw zfcL`zs!D(% zyP?Hz2ekNYg%-b!(BiiaTKrZ+i{El+@mmZne)FKsLvvsgOhTK7rb3&CDxl3nC9n?W zL7RsL!LPtLw0Wp6oCUkWnegzJxi<+s0B69xFbQ|U8n_Ks!_DwUxE@x)HSh+w0w&;6 zI33Q1(_kCC9@fI^;52wGoB*f7GI$Lvf>U57yc!OGlVLwN33i8-@W?r_*hF{`PJsL1 zc(@CWgWKU)xCK_g4R8!x3oULdp~Y<(w74yV7Poe2ajS6Hn+z>(<Y&9nj*o6(-kBPzU7^M8@YzA!4nT|BUTAT9 z8`|fwSKw&;d1#-*?$+}8a1_g1;Be|y!*YBI90^CmtKd*A&(ZP=w7fsG_WtpufP3Hw zJ_mkP-T+Uh-H*@W_l&9cYj{2WHY}svXXQ`I?~~sxZ<5cJp9Ooc{;81PN+|9Q?ep`8 z{e$uEHPY@*SPIv{E8)Y?;;;;s;0xg}cq<$VTi_M&E3g<&hZc{q@Nzs`JRR~I3z^;F zWi0Ok3*q52W3d9b9}amT!Ya_)oQbqn59Q`7B=~R*S_jkLCF=2c8XcVL$n& zXT)OJ_K!>f78?Y2LHi!$1!&(ptc4bz@4zg|Z-usB+n~i^ z3Y-FmLw>9^GYk#zzoU@;8Z*d+V@t2RNfz+M|mH47s!+xKioH{ z_W?Yc`maHY-=p$7;QtYdGHByH4%+u5pY~yWs}Ff(-V6uQUKKnSmO-mGNE`qye*NJ9 z%DY1Q-s!oMgYTW5fS2R9!D5(%_C3y-(6;kX@1XxbL)+dx(8j+L4#U?#rtZwUp>4-- zbJ!hP{m*;FVoa6sccA$;$dnY{1TVqwgiI0fufoB26J$z=*Fp~6_%-G%zY20F#V>=T zcziI-VtG$!?S9&m{loIV!8raiXyqH=weV3`1|NZ>X1p5m^Cy`VFbAFvZU6Rwq+tBW zNo*9$-+|WtPDo0{pO>$Lq)hxi`C`bfjX&HY7Gqb%=R-mruQ0NHnV2aK5c`XtbZ0&4 z{S}@J--Y8D&o0;#e-)ktpM?B6P39f2H=F{;QLhA^hMxjYf&V&@?SQ|Bw*5~-i{om@ zu8rRdZM*J-?5cQDJ_Qoe_-JVH$Q4hA7gFD@rnKYuC3rsm1hjS^frKu;3|@t|iPKbG z0SQrj7~}_PG6zE&*DKw4or4cS8_!*kki>6+wqJ%qi(gmBrp0%34eD)y3@QEtXyvQn z#c&Di4%?y4|1~PVMjQ`qyq7_S5YK{kJiK*$a6D{+1^66j?N-A=I7vQIyc}BmGvFBd zIR}n{ePAW*3Wres;c>hkR;|P2f{2Oi@h!2B*#f|6Uec)ekBlA=5KQo@saN`mD zCCCO$H-3&k2>(sF@l(7B{u4JI#CZ=9>qdQJ*R)vgbl3$qrr~T$?0DRG9R51|i1m$! zSbr7#5H~Wf_nr$s#*P27_Thfq$fI{U|9pZQ592>Sk$>omxygU*GiTd=mk9hH@>c8KapRq`ZdG+>aj8M{w0B5ull8`Un9RpUMH`Tx61#`!Df$n^7pO^e3AV9 zse#`Y)|Wpdw+|2YcvL<|>pvwwUA{s7(~&{_7vBkgYxBZmEW!L zJ||xz-z0xg{;K>#`CIaHrw8%-t^Aa01AkBM$^R}NCI47nE$_mc3)>%yF^0P(<{bk9A$cyCH$*+{(DjzNXv3!#J zxAJN7&*d}Z1IGmYHOjA&&y^?T^W}@=cgdfUe^b6g{)qe|`5JlOilD!z<(JBTD4!^Q zN!}{A&rKH3`{i%TpOgPizC-?={E+;B{LHaI{~yUOliTMsYk!LT#NL75B=0MKNPd=l zvwWcZw#uOWO!*V?0{PqW68T~IXnFdiVExJR5%Pq*PF^ctCU23yAfG4SBfmr5P4oFO zd8Yhf`6Ri0uC;jFB7a7{O1@FPRsOR4-Lb*=-;jSKx6jMgUe9qsxqXf{&yfE~euex4 z`3Cu6`LE<%P7c=pm;5Ao|M5Zlr^%;G2s|!tm7g#FnqDunFlW(|Bgdr_1Na=gV)AuaPg1Z<8;P|4qJJezLab+wvUwWAgju&&q!+-ze{S zb+A1z%QNKL<)!jp%WshHmCuv^RsN9tkbIN;bNOz0_ddb?`%HeS{7Z^=TwW}{Kt5gW z$@ge`hR8pYm&(tX7;N7d`IYj?@)`2!^2PF*@~7lY^0(ye@(<;=${*HWu{C)YG@(<*Hl7AvUN$>BD?;Gr& zOXa=gW8`PbYvt$4m&z}Zub1b`EA@V8n0&E(lsWIeF4yOWX)1qOwEgYu8$v*g`R z3D&<)ezyE2d7k_O`Dpo>vx4@nm5-D!>gs>55PO{E_PF*$obf$4Bk(=P2jx51ulCq} zLQwv?#`~GdGZ?2m-dFhtDt}ewmWTFuPUWjq&aSfWHQeKFm5)^U^Ie1TeH!1*8sAGA zU(aqqdE(TdiS;V)Gc$1enQLo5UF8p`{LfmyMCJ3;{+CrgQsrl={9_tEDn^o8 z{$iy3w~_MGBID~5ssE=)`L@XTe-|m=5b?Q@`VU6>|6asLkx!}PKPBROBI7HJtp8!8 z{@jR9jMTU9NmKi?A7)SW2@!uFvVE%}>)ZE>sq0@HS>KE7&#{sEg^}^T9@*YOk@A}& z>mMH}|DVYA)4}d|IUbjEHAMw%@)yPTjtHBYr3{{+lBEdr2gI_ea*Z##7s$8Sx7v>o19vABv3k zwTKUijPJgP^WF4O{o7p0f9}CK#-p6?@{jU6BHPm(aW4{&XCvb)h?Kt&DSt8ITO#e> z9?6ebqO`5KE>Tm}d~4+;E8yR}Tq~eaptLoa4 zDHTdbbd&|X`Q4YdChM(re^mYsV@zQnte~{x3PgW}6!%9JT)SD>R$tGUIwE%!SO2+? zm5#8nmDok4M~x_0;_vWqf2K4aE;{NGws7ImmyN{|wGGMEL{n>HkQnqnwyplgWOHS3 z!Dq5YS9~cUs_XrWy8Ond`$e^8G$+|RAeK;I-H+k*xNgS&TaJRpIKq&_%8DNlar(ncV6c z!x<`g7G2MlCP=Ge)@;#@bYlrJod~wHHfz%&O(lqK zm#CiW4g?)OcFnCN^Uj#zyUfDKdhTULvBBQOWz2(@IxbbgIV|^@9 z)m)t$K996pUz5k>$#hrh-(kbjWF%|(_ni&<85`acRR`y>%Olf%EWy#lcKLl(6HG3` ztd1qPEVH_asi!*FFU-m%R#3%tlf#oUs<>{RRf1zEIEpLUTJ0)Oe^0P8)ZmRAefhbG znq+lj4P{~0@ETLnP|a;;Qxc2$_CFSn4)MaqPn z(oL|`UVW^N+lUfwQrl3YqxfdK!?Ly@C0T>3JyTza2PbEJQMFEsESO(dV0qqIVVLTj zmIYU@`q|xCxe~myBA3&h6{ep9%UBnFcrUQwZ*WoKo% zWkqh8=bq)bXSwcKo_m%bKI2-gpyg~X)(@Y#dR|98*RR*nvRfmoV*~|ZD_I?DxKVj- zES{^E?Mky!ZN+QQ-P0aD5cGJ_=kP1+I?**GGZtqcH3v zC+s38>>(%YASY};Cv4uOPEOc(PS|!%*mQ2#a&FjiZrEUM*kEqhU~V|v+_1siu)*B0 z!Mw0Rmw)b{aL0t(rEZV99qRUHUf8nRn{H>ied%_k+mmiby8YO(8?(X<^RmJ%^RmKC z^RmKi^RmK?^V}@vxjD{rbEemEq@)}?u8)q{!5!~j#}v>pWq9Fsx-4@^=5oxXn9DGi zLN0?`0=fKghfrbIh3B%yb7|wbym3kEa@M7+%S4xmZsKqUv^$>N;p`@?!Z5alVU`qy zS>iFr>ri&D1)iH%JU6|2ZhH6JtmkEi?Rsu%Z&TQFGnN?hbR>3B)b3fuOw!p1#!P+O$D`*CNUvjdcgLpZ z4o=SPY!%$Uv2Sqo&SBCeJ5w%jmOgMAOCN-0}u2I|NT*< ngf{K(b=`M(iG=@^maCOWOe(uZ=lb2klqb>lDEfLzaqRyA57%v0 diff --git a/Dependencies/libimobiledevice b/Dependencies/libimobiledevice index b314f04b..7a8e432e 160000 --- a/Dependencies/libimobiledevice +++ b/Dependencies/libimobiledevice @@ -1 +1 @@ -Subproject commit b314f04bd791b263cf43fadc6ac0756e67ab4ed0 +Subproject commit 7a8e432e9b492bd3e800861f435d1bbe751076b0 diff --git a/Dependencies/libplist b/Dependencies/libplist index c3af4495..17546f53 160000 --- a/Dependencies/libplist +++ b/Dependencies/libplist @@ -1 +1 @@ -Subproject commit c3af449543795ad4d3ab178120ff69e90fdd2cc8 +Subproject commit 17546f53ac1377b0d4f45a800aaec7366ba5b6a0 diff --git a/Dependencies/libusbmuxd b/Dependencies/libusbmuxd index 6426362e..8b82ef16 160000 --- a/Dependencies/libusbmuxd +++ b/Dependencies/libusbmuxd @@ -1 +1 @@ -Subproject commit 6426362e5cbad7284368b7fe70363f6b3251f94c +Subproject commit 8b82ef166eb2ac12bc5228cf06a883ec86d520ca diff --git a/Dependencies/minimuxer b/Dependencies/minimuxer new file mode 160000 index 00000000..bc6988e0 --- /dev/null +++ b/Dependencies/minimuxer @@ -0,0 +1 @@ +Subproject commit bc6988e0986f138bcf04dcf762744e7186f5e0c7 diff --git a/Dependencies/minimuxer.xcodeproj/project.pbxproj b/Dependencies/minimuxer.xcodeproj/project.pbxproj deleted file mode 100644 index 062d1729..00000000 --- a/Dependencies/minimuxer.xcodeproj/project.pbxproj +++ /dev/null @@ -1,283 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 53; - objects = { - -/* Begin PBXBuildFile section */ - 9987603329A454B500818586 /* minimuxer.h in Sources */ = {isa = PBXBuildFile; fileRef = 9987603229A454B500818586 /* minimuxer.h */; }; -/* End PBXBuildFile section */ - -/* Begin PBXBuildRule section */ - CA6012A875F9AC6C1400ACA8 /* PBXBuildRule */ = { - isa = PBXBuildRule; - compilerSpec = com.apple.compilers.proxy.script; - filePatterns = "*/minimuxer.h"; - fileType = pattern.proxy; - inputFiles = ( - ); - isEditable = 0; - name = "Cargo project build"; - outputFiles = ( - "$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)", - ); - script = "# generated with cargo-xcode 1.5.0\n# modified to use prebuilt binaries\n\nset -eu;\n\nBUILT_SRC=\"./minimuxer/$LIB_FILE_NAME.a\"\nln -f -- \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\" || cp \"$BUILT_SRC\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\necho \"$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\n#DEP_FILE_SRC=\"minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\n#if [ -f \"$DEP_FILE_SRC\" ]; then\n# DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n# cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n# echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\n#fi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\n#FILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\n#touch \"$FILE_LIST\"\n#if ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n# echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\n#fi\n"; - }; -/* End PBXBuildRule section */ - -/* Begin PBXFileReference section */ - 9987603229A454B500818586 /* minimuxer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = minimuxer.h; path = minimuxer/minimuxer.h; sourceTree = ""; }; - ADDEDBA66A6E1 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; - CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminimuxer_static.a; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXGroup section */ - ADDEDBA66A6E2 /* Required for static linking */ = { - isa = PBXGroup; - children = ( - ADDEDBA66A6E1 /* libresolv.tbd */, - ); - name = "Required for static linking"; - sourceTree = ""; - }; - CA6012A875F922869D176AE5 /* Products */ = { - isa = PBXGroup; - children = ( - CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */, - ); - name = Products; - sourceTree = ""; - }; - CA6012A875F998AF0B5890DB /* Frameworks */ = { - isa = PBXGroup; - children = ( - ADDEDBA66A6E2 /* Required for static linking */, - ); - name = Frameworks; - sourceTree = ""; - }; - CA6012A875F9D65BC3C892A8 = { - isa = PBXGroup; - children = ( - 9987603229A454B500818586 /* minimuxer.h */, - CA6012A875F922869D176AE5 /* Products */, - CA6012A875F998AF0B5890DB /* Frameworks */, - ); - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - CA609C732349A560B9642892 /* minimuxer-staticlib */ = { - isa = PBXNativeTarget; - buildConfigurationList = CA600589A243A560B9642892 /* Build configuration list for PBXNativeTarget "minimuxer-staticlib" */; - buildPhases = ( - 9987603629A4611D00818586 /* ShellScript */, - CA600F638141A560B9642892 /* Sources */, - CA6012A875F9AF6EBB7F357C /* Universal Binary lipo */, - ); - buildRules = ( - CA6012A875F9AC6C1400ACA8 /* PBXBuildRule */, - ); - dependencies = ( - ); - name = "minimuxer-staticlib"; - productName = libminimuxer_static.a; - productReference = CA609C732349C7AAD9FA67C4 /* libminimuxer_static.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - CA6012A875F9E04653AD465F /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - TargetAttributes = { - CA609C732349A560B9642892 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = CA6012A875F980E02D6C7F57 /* Build configuration list for PBXProject "minimuxer" */; - compatibilityVersion = "Xcode 11.4"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = CA6012A875F9D65BC3C892A8; - productRefGroup = CA6012A875F922869D176AE5 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - CA609C732349A560B9642892 /* minimuxer-staticlib */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXShellScriptBuildPhase section */ - 9987603629A4611D00818586 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ./minimuxer/minimuxer.h, - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "bash ./fetch-prebuilt.sh minimuxer\n"; - }; - CA6012A875F9AF6EBB7F357C /* Universal Binary lipo */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(DERIVED_FILE_DIR)/$(ARCHS)-$(EXECUTABLE_NAME).xcfilelist", - ); - name = "Universal Binary lipo"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# generated with cargo-xcode 1.5.0\n\n#set -eux; cat \"$DERIVED_FILE_DIR/$ARCHS-$EXECUTABLE_NAME.xcfilelist\" | tr '\\n' '\\0' | xargs -0 lipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n#if [ ${LD_DYLIB_INSTALL_NAME:+1} ]; then\n# install_name_tool -id \"$LD_DYLIB_INSTALL_NAME\" \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n#fi\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CA600F638141A560B9642892 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9987603329A454B500818586 /* minimuxer.h in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - CA6008D36272A560B9642892 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = libminimuxer.d; - CARGO_XCODE_CARGO_FILE_NAME = libminimuxer.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - LIB_FILE_NAME = ""; - "LIB_FILE_NAME[sdk=iphoneos*]" = libminimuxer; - "LIB_FILE_NAME[sdk=iphonesimulator*]" = "libminimuxer-sim"; - PRODUCT_NAME = minimuxer_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Debug; - }; - CA602DE9FCEDA560B9642892 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CARGO_XCODE_CARGO_DEP_FILE_NAME = libminimuxer.d; - CARGO_XCODE_CARGO_FILE_NAME = libminimuxer.a; - INSTALL_GROUP = ""; - INSTALL_MODE_FLAG = ""; - INSTALL_OWNER = ""; - LIB_FILE_NAME = ""; - "LIB_FILE_NAME[sdk=iphoneos*]" = libminimuxer; - "LIB_FILE_NAME[sdk=iphonesimulator*]" = "libminimuxer-sim"; - PRODUCT_NAME = minimuxer_static; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; - }; - name = Release; - }; - CA60A20F8EA6228BE02872F8 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; - CARGO_XCODE_BUILD_MODE = debug; - CARGO_XCODE_FEATURES = ""; - "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; - "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; - "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; - "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; - CURRENT_PROJECT_VERSION = 0.1; - MARKETING_VERSION = 0.1.0; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = minimuxer; - SDKROOT = macosx; - SUPPORTS_MACCATALYST = YES; - }; - name = Debug; - }; - CA60A20F8EA63CC16B37690B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; - CARGO_XCODE_BUILD_MODE = release; - CARGO_XCODE_FEATURES = ""; - "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; - "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; - "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; - "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; - "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; - "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*][arch=x86_64*]" = ios; - "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; - CURRENT_PROJECT_VERSION = 0.1; - MARKETING_VERSION = 0.1.0; - PRODUCT_NAME = minimuxer; - SDKROOT = macosx; - SUPPORTS_MACCATALYST = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - CA600589A243A560B9642892 /* Build configuration list for PBXNativeTarget "minimuxer-staticlib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA602DE9FCEDA560B9642892 /* Release */, - CA6008D36272A560B9642892 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CA6012A875F980E02D6C7F57 /* Build configuration list for PBXProject "minimuxer" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CA60A20F8EA63CC16B37690B /* Release */, - CA60A20F8EA6228BE02872F8 /* Debug */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = CA6012A875F9E04653AD465F /* Project object */; -} diff --git a/Dependencies/minimuxer/.gitkeep b/Dependencies/minimuxer/.gitkeep deleted file mode 100644 index d338f61d..00000000 --- a/Dependencies/minimuxer/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -Use ../fetch-prebuilt.sh to fetch prebuilt Rust dependencies \ No newline at end of file diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 00000000..2a6c92f0 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,104 @@ +{ + "pins" : [ + { + "identity" : "altsign", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SideStore/AltSign.git", + "state" : { + "branch" : "master", + "revision" : "7e0e7edcf8fbc44ac1e35da3e9030a297aa18b84" + } + }, + { + "identity" : "appcenter-sdk-apple", + "kind" : "remoteSourceControl", + "location" : "https://github.com/microsoft/appcenter-sdk-apple", + "state" : { + "revision" : "b2dc99cfedead0bad4e6573d86c5228c89cff332", + "version" : "4.4.3" + } + }, + { + "identity" : "down", + "kind" : "remoteSourceControl", + "location" : "https://github.com/johnxnguyen/Down.git", + "state" : { + "branch" : "master", + "revision" : "e754ab1c80920dd51a8e08290c912ac1c2ac8b58" + } + }, + { + "identity" : "keychainaccess", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kishikawakatsumi/KeychainAccess", + "state" : { + "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7", + "version" : "4.2.2" + } + }, + { + "identity" : "launchatlogin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sindresorhus/LaunchAtLogin", + "state" : { + "revision" : "e8171b3e38a2816f579f58f3dac1522aa39efe41", + "version" : "4.2.0" + } + }, + { + "identity" : "nuke", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kean/Nuke", + "state" : { + "revision" : "9318d02a8a6d20af56505c9673261c1fd3b3aebe", + "version" : "7.6.3" + } + }, + { + "identity" : "openssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/OpenSSL.git", + "state" : { + "revision" : "87f41bf9488e7dd2b0de2ab97cb3eafc7304e0e6", + "version" : "1.1.2000" + } + }, + { + "identity" : "plcrashreporter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/microsoft/PLCrashReporter.git", + "state" : { + "revision" : "81cdec2b3827feb03286cb297f4c501a8eb98df1", + "version" : "1.10.2" + } + }, + { + "identity" : "roxas", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JoeMatt/Roxas", + "state" : { + "revision" : "17338c09ec0ffeea4c68135f17c1f801a3d6d10d", + "version" : "1.2.2" + } + }, + { + "identity" : "semanticversion", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SwiftPackageIndex/SemanticVersion", + "state" : { + "revision" : "fc670910dc0903cc269b3d0b776cda5703979c4e", + "version" : "0.3.5" + } + }, + { + "identity" : "sidekit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SideStore/SideKit.git", + "state" : { + "branch" : "main", + "revision" : "7ea34a09b52c104077dea8e0b90f8dc55d43b36b" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 00000000..32edc337 --- /dev/null +++ b/Package.swift @@ -0,0 +1,289 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import Foundation +import os.log +import PackageDescription + +let env: [String: Bool] = [ + "USE_CARGO": false, + "USE_CXX_INTEROP": false, + "USE_CXX_MODULES": false, + "INHIBIT_UPSTREAM_WARNINGS": false, + "STATIC_LIBRARY": false, +] + +let USE_CARGO = envBool("USE_CARGO") +let USE_CXX_INTEROP = envBool("USE_CXX_INTEROP") +let USE_CXX_MODULES = envBool("USE_CXX_MODULES") +let INHIBIT_UPSTREAM_WARNINGS = envBool("INHIBIT_UPSTREAM_WARNINGS") +let STATIC_LIBRARY = envBool("STATIC_LIBRARY") + +// let dependencies_cargo: [Package.Dependency] = { +// USE_CARGO ? [ +// // CargoPlugin +// .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.0.3"), +// .package(url: "https://github.com/apple/swift-package-manager.git", branch: "release/5.7"), +// .package(url: "https://github.com/apple/swift-tools-support-core.git", branch: "release/5.7"), +// ] : [] +// }() + +// let cargo_targets: [Target] = [ +// .executableTarget( +// name: "Cargo", +// dependencies: [ +// .product(name: "ArgumentParser", package: "swift-argument-parser"), +// .product(name: "SwiftPM-auto", package: "swift-package-manager"), +// .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core") +// ] +// ), +// +// .testTarget( +// name: "CargoTests", +// dependencies: ["Cargo"], +// exclude: [ +// "swiftlint", +// "xcframework" +// ] +// ), +// +// .plugin( +// name: "CargoPlugin", +// capability: .buildTool(), +// dependencies: [ +// "Cargo" +// ] +// ), +// +// .plugin( +// name: "CargoPlugin-Generate", +// capability: .command( +// intent: .custom( +// verb: "generate-code-from-rust", +// description: "Creates .c code from your `rust` code" +// ), +// permissions: [ +// .writeToPackageDirectory(reason: "This command generates source code") +// ] +// ), +// dependencies: ["Cargo"] +// ) +// ] + +let dependencies: [Package.Dependency] = [ + .package(url: "https://github.com/JoeMatt/Roxas", from: "1.2.2"), + .package(url: "https://github.com/johnxnguyen/Down", branch: "master"), + .package(url: "https://github.com/kean/Nuke", from: "7.0.0"), + .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.0"), +// .package(url: "https://github.com/krzyzanowskim/OpenSSL", from: "1.1.180"), + .package(url: "https://github.com/microsoft/appcenter-sdk-apple", from: "4.2.0"), + .package(url: "https://github.com/SideStore/AltSign", branch: "master"), + .package(url: "https://github.com/SideStore/SideKit", branch: "main"), + .package(url: "https://github.com/sindresorhus/LaunchAtLogin", from: "4.1.0"), + .package(url: "https://github.com/SwiftPackageIndex/SemanticVersion", from: "0.3.5"), +] // + dependencies_cargo + +let package = Package( + name: "SideStoreCore", + defaultLocalization: "en", + platforms: [ + .iOS(.v12), +// .tvOS(.v12), +// .macOS(.v12), + ], + + products: [ + .executable( + name: "SideStore", + targets: ["SideStore"]), + + .executable( + name: "SideWidget", + targets: ["SideWidget"]), + + .executable( + name: "SideDaemon", + targets: ["SideDaemon"]), + + .library(name: "EmotionalDamage", targets: ["EmotionalDamage"]), + .library(name: "MiniMuxerSwift", targets: ["MiniMuxerSwift"]), + .library(name: "SideStoreCore", targets: ["SideStoreCore"]), + ], + + dependencies: dependencies, + targets: [ + + // MARK: - SideStore + .executableTarget( + name: "SideStore", + dependencies: [ + "EmotionalDamage", + "MiniMuxerSwift", + "SideStoreCore", + "Shared", + .product(name: "Down", package: "Down"), + .product(name: "AltSign", package: "AltSign"), + .product(name: "Nuke", package: "Nuke"), + .product(name: "Roxas", package: "Roxas"), + .product(name: "RoxasUI", package: "Roxas"), + .product(name: "AppCenterAnalytics", package: "appcenter-sdk-apple"), + .product(name: "AppCenterCrashes", package: "appcenter-sdk-apple") + ], + linkerSettings: [ + .linkedFramework("UIKit"), + .linkedFramework("Avfoundation"), + .linkedFramework("Combine"), + .linkedFramework("AppleArchive"), + .linkedFramework("Network"), + .linkedFramework("CoreData"), + .linkedFramework("UniformTypeIdentifiers"), + .linkedFramework("QuickLook", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("AuthenticationServices", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("SafariServices", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("Intents", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("IntentsUI", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("MessageUI", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("ARKit", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("CoreHaptics", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("AudioToolbox", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("WidgetKit", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("UserNotifications", .when(platforms: [.iOS, .macCatalyst])), + .linkedFramework("MobileCoreServices", .when(platforms: [.iOS, .macCatalyst])), + ] + ), + + // MARK: - SideWidget + .executableTarget( + name: "SideWidget" + ), + + // MARK: - EmotionalDamage + + .target( + name: "EmotionalDamage", + dependencies: ["em_proxy"] + ), + + .binaryTarget( + name: "em_proxy", + path: "Dependencies/em_proxy/em_proxy.xcframework.zip" + ), + + .testTarget( + name: "EmotionalDamageTests", + dependencies: ["EmotionalDamage"] + ), + + // MARK: - MiniMuxer + + .target( + name: "MiniMuxerSwift", + dependencies: ["minimuxer"], + cSettings: [ +// .headerSearchPath("Dependencies/minimuxer/include"), + ], + cxxSettings: [ + ], + swiftSettings: [ + ], + linkerSettings: [ + ] + ), + + .binaryTarget( + name: "minimuxer", + path: "Dependencies/minimuxer/minimuxer.xcframework.zip" + ), + + .testTarget( + name: "MiniMuxerTests", + dependencies: ["MiniMuxerSwift"] + ), + + // MARK: - Shared + + .target( + name: "Shared", + dependencies: ["SideKit"] + ), + + .testTarget( + name: "SharedTests", + dependencies: ["Shared"] + ), + + // MARK: - SideBackup + + .executableTarget( + name: "SideBackup", + dependencies: [] + ), + + // MARK: - SideDaemon + + .executableTarget( + name: "SideDaemon", + dependencies: [ + "Shared", + .product(name: "AltSign", package: "AltSign"), + .product(name: "LaunchAtLogin", package: "LaunchAtLogin"), + ] + ), + + .testTarget( + name: "SideDaemonTests", + dependencies: ["SideDaemon"] + ), + + // MARK: - SideStoreCore + + .target( + name: "SideStoreCore", + dependencies: [ + "Shared", + .product(name: "Roxas", package: "Roxas"), + .product(name: "AltSign", package: "AltSign"), + .product(name: "KeychainAccess", package: "KeychainAccess"), + .product(name: "SemanticVersion", package: "SemanticVersion"), + ], + swiftSettings: [ + .unsafeFlags([ +// "--xcconfig-overrides", "AltStoreCore.xconfig" + ]) + ] + ), + + .testTarget( + name: "SideStoreCoreTests", + dependencies: ["SideStoreCore"] + ), + + // MARK: - libfragmentzip + .target( + name: "libfragmentzip", + dependencies: [], + sources: [ + "libfragmentzip-source/libfragmentzip/libfragmentzip.c" + ], + cSettings: [ + .headerSearchPath("libfragmentzip-source/libfragmentzip/include") + ] + ), + + .testTarget( + name: "libfragmentzipTests", + dependencies: ["libfragmentzip"] + ), + ], + swiftLanguageVersions: [.v5], + cLanguageStandard: .c2x, + cxxLanguageStandard: .cxx20 +) + +// MARK: - Helpers + +func envBool(_ key: String) -> Bool { + guard let value = ProcessInfo.processInfo.environment[key] else { return env[key, default: true] } + let trueValues = ["1", "on", "true", "yes"] + return trueValues.contains(value.lowercased()) +} diff --git a/Plugins/CargoPlugin-Generate/Plugin.swift b/Plugins/CargoPlugin-Generate/Plugin.swift new file mode 100644 index 00000000..d5abc454 --- /dev/null +++ b/Plugins/CargoPlugin-Generate/Plugin.swift @@ -0,0 +1,70 @@ +import Foundation +import PackagePlugin + +@main +struct CargoPlugin: CommandPlugin { + func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { + guard let sourceTarget = target as? SourceModuleTarget else { + return [] + } + return createBuildCommands( + inputFiles: sourceTarget.sourceFiles(withSuffix: "toml").map(\.path), + packageDirectory: context.package.directory, + workingDirectory: context.pluginWorkDirectory, + tool: try context.tool(named: "cargo") + ) + } + + private func createBuildCommands( + inputFiles: [Path], + packageDirectory: Path, + workingDirectory: Path, + tool: PluginContext.Tool + ) -> [Command] { + if inputFiles.isEmpty { + // Don't lint anything if there are no Swift source files in this target + return [] + } + + var arguments = [ + "build", "\(workingDirectory)" + ] + + // Manually look for configuration files, to avoid issues when the plugin does not execute our tool from the + // package source directory. + if let configuration = packageDirectory.firstConfigurationFileInParentDirectories() { + arguments.append(contentsOf: ["--config", "\(configuration.string)"]) + } + arguments += inputFiles.map(\.string) + + // We are not producing output files and this is needed only to not include cache files into bundle + let outputFilesDirectory = workingDirectory.appending("Output") + + return [ + .prebuildCommand( + displayName: "Cargo", + executable: tool.path, + arguments: arguments, + outputFilesDirectory: outputFilesDirectory + ) + ] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftLintPlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let inputFilePaths = target.inputFiles + .filter { $0.type == .source && $0.path.extension == "swift" } + .map(\.path) + return createBuildCommands( + inputFiles: inputFilePaths, + packageDirectory: context.xcodeProject.directory, + workingDirectory: context.pluginWorkDirectory, + tool: try context.tool(named: "swiftlint") + ) + } +} +#endif diff --git a/Plugins/CargoPlugin/Plugin.swift b/Plugins/CargoPlugin/Plugin.swift new file mode 100644 index 00000000..9d622d8d --- /dev/null +++ b/Plugins/CargoPlugin/Plugin.swift @@ -0,0 +1,70 @@ +import Foundation +import PackagePlugin + +@main +struct CargoPlugin: BuildToolPlugin { + func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { + guard let sourceTarget = target as? SourceModuleTarget else { + return [] + } + return createBuildCommands( + inputFiles: sourceTarget.sourceFiles(withSuffix: "toml").map(\.path), + packageDirectory: context.package.directory, + workingDirectory: context.pluginWorkDirectory, + tool: try context.tool(named: "cargo") + ) + } + + private func createBuildCommands( + inputFiles: [Path], + packageDirectory: Path, + workingDirectory: Path, + tool: PluginContext.Tool + ) -> [Command] { + if inputFiles.isEmpty { + // Don't lint anything if there are no Swift source files in this target + return [] + } + + var arguments = [ + "build", "\(workingDirectory)" + ] + + // Manually look for configuration files, to avoid issues when the plugin does not execute our tool from the + // package source directory. + if let configuration = packageDirectory.firstConfigurationFileInParentDirectories() { + arguments.append(contentsOf: ["--config", "\(configuration.string)"]) + } + arguments += inputFiles.map(\.string) + + // We are not producing output files and this is needed only to not include cache files into bundle + let outputFilesDirectory = workingDirectory.appending("Output") + + return [ + .prebuildCommand( + displayName: "Cargo", + executable: tool.path, + arguments: arguments, + outputFilesDirectory: outputFilesDirectory + ) + ] + } +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension SwiftLintPlugin: XcodeBuildToolPlugin { + func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] { + let inputFilePaths = target.inputFiles + .filter { $0.type == .source && $0.path.extension == "swift" } + .map(\.path) + return createBuildCommands( + inputFiles: inputFilePaths, + packageDirectory: context.xcodeProject.directory, + workingDirectory: context.pluginWorkDirectory, + tool: try context.tool(named: "swiftlint") + ) + } +} +#endif diff --git a/Shared/ALTConstants.h b/Shared/ALTConstants.h deleted file mode 100644 index 26a94759..00000000 --- a/Shared/ALTConstants.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// ALTConstants.h -// AltKit -// -// Created by Riley Testut on 5/30/19. -// Copyright © 2019 Riley Testut. All rights reserved. -// - -#import - -extern uint16_t ALTDeviceListeningSocket; diff --git a/Shared/ALTConstants.m b/Shared/ALTConstants.m deleted file mode 100644 index d7c4efc2..00000000 --- a/Shared/ALTConstants.m +++ /dev/null @@ -1,11 +0,0 @@ -// -// ALTConstants.m -// AltKit -// -// Created by Riley Testut on 1/10/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -#import - -uint16_t ALTDeviceListeningSocket = 28151; diff --git a/Shared/Categories/CFNotificationName+AltStore.h b/Shared/Categories/CFNotificationName+AltStore.h deleted file mode 100644 index 01c2a336..00000000 --- a/Shared/Categories/CFNotificationName+AltStore.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// CFNotificationName+AltStore.h -// AltKit -// -// Created by Riley Testut on 1/10/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -extern CFNotificationName const ALTWiredServerConnectionAvailableRequest NS_SWIFT_NAME(wiredServerConnectionAvailableRequest); -extern CFNotificationName const ALTWiredServerConnectionAvailableResponse NS_SWIFT_NAME(wiredServerConnectionAvailableResponse); -extern CFNotificationName const ALTWiredServerConnectionStartRequest NS_SWIFT_NAME(wiredServerConnectionStartRequest); - -NS_ASSUME_NONNULL_END diff --git a/Shared/Categories/CFNotificationName+AltStore.m b/Shared/Categories/CFNotificationName+AltStore.m deleted file mode 100644 index ac0eb5d1..00000000 --- a/Shared/Categories/CFNotificationName+AltStore.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// CFNotificationName+AltStore.m -// AltKit -// -// Created by Riley Testut on 1/10/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -#import "CFNotificationName+AltStore.h" - -CFNotificationName const ALTWiredServerConnectionAvailableRequest = CFSTR("io.altstore.Request.WiredServerConnectionAvailable"); -CFNotificationName const ALTWiredServerConnectionAvailableResponse = CFSTR("io.altstore.Response.WiredServerConnectionAvailable"); -CFNotificationName const ALTWiredServerConnectionStartRequest = CFSTR("io.altstore.Request.WiredServerConnectionStart"); diff --git a/Shared/Extensions/NSError+AltStore.swift b/Shared/Extensions/NSError+AltStore.swift deleted file mode 100644 index 55288d49..00000000 --- a/Shared/Extensions/NSError+AltStore.swift +++ /dev/null @@ -1,143 +0,0 @@ -// -// NSError+AltStore.swift -// AltStore -// -// Created by Riley Testut on 3/11/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -import Foundation - -extension NSError -{ - @objc(alt_localizedFailure) - var localizedFailure: String? { - let localizedFailure = (self.userInfo[NSLocalizedFailureErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSLocalizedFailureErrorKey) as? String) - return localizedFailure - } - - @objc(alt_localizedDebugDescription) - var localizedDebugDescription: String? { - let debugDescription = (self.userInfo[NSDebugDescriptionErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSDebugDescriptionErrorKey) as? String) - return debugDescription - } - - @objc(alt_errorWithLocalizedFailure:) - func withLocalizedFailure(_ failure: String) -> NSError - { - var userInfo = self.userInfo - userInfo[NSLocalizedFailureErrorKey] = failure - - if let failureReason = self.localizedFailureReason - { - userInfo[NSLocalizedFailureReasonErrorKey] = failureReason - } - else if self.localizedFailure == nil && self.localizedFailureReason == nil && self.localizedDescription.contains(self.localizedErrorCode) - { - // Default localizedDescription, so replace with just the localized error code portion. - userInfo[NSLocalizedFailureReasonErrorKey] = "(\(self.localizedErrorCode).)" - } - else - { - userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedDescription - } - - if let localizedDescription = NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSLocalizedDescriptionKey) as? String - { - userInfo[NSLocalizedDescriptionKey] = localizedDescription - } - - // Don't accidentally remove localizedDescription from dictionary - // userInfo[NSLocalizedDescriptionKey] = NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSLocalizedDescriptionKey) as? String - - if let recoverySuggestion = self.localizedRecoverySuggestion - { - userInfo[NSLocalizedRecoverySuggestionErrorKey] = recoverySuggestion - } - - let error = NSError(domain: self.domain, code: self.code, userInfo: userInfo) - return error - } - - func sanitizedForCoreData() -> NSError - { - var userInfo = self.userInfo - userInfo[NSLocalizedFailureErrorKey] = self.localizedFailure - userInfo[NSLocalizedDescriptionKey] = self.localizedDescription - userInfo[NSLocalizedFailureReasonErrorKey] = self.localizedFailureReason - userInfo[NSLocalizedRecoverySuggestionErrorKey] = self.localizedRecoverySuggestion - - // Remove userInfo values that don't conform to NSSecureEncoding. - userInfo = userInfo.filter { (key, value) in - return (value as AnyObject) is NSSecureCoding - } - - // Sanitize underlying errors. - if let underlyingError = userInfo[NSUnderlyingErrorKey] as? Error - { - let sanitizedError = (underlyingError as NSError).sanitizedForCoreData() - userInfo[NSUnderlyingErrorKey] = sanitizedError - } - - if #available(iOS 14.5, macOS 11.3, *), let underlyingErrors = userInfo[NSMultipleUnderlyingErrorsKey] as? [Error] - { - let sanitizedErrors = underlyingErrors.map { ($0 as NSError).sanitizedForCoreData() } - userInfo[NSMultipleUnderlyingErrorsKey] = sanitizedErrors - } - - let error = NSError(domain: self.domain, code: self.code, userInfo: userInfo) - return error - } -} - -extension Error -{ - var underlyingError: Error? { - let underlyingError = (self as NSError).userInfo[NSUnderlyingErrorKey] as? Error - return underlyingError - } - - var localizedErrorCode: String { - let localizedErrorCode = String(format: NSLocalizedString("%@ error %@", comment: ""), (self as NSError).domain, (self as NSError).code as NSNumber) - return localizedErrorCode - } -} - -protocol ALTLocalizedError: LocalizedError, CustomNSError -{ - var failure: String? { get } - - var underlyingError: Error? { get } -} - -extension ALTLocalizedError -{ - var errorUserInfo: [String : Any] { - let userInfo = ([ - NSLocalizedDescriptionKey: self.errorDescription, - NSLocalizedFailureReasonErrorKey: self.failureReason, - NSLocalizedFailureErrorKey: self.failure, - NSUnderlyingErrorKey: self.underlyingError - ] as [String: Any?]).compactMapValues { $0 } - return userInfo - } - - var underlyingError: Error? { - // Error's default implementation calls errorUserInfo, - // but ALTLocalizedError.errorUserInfo calls underlyingError. - // Return nil to prevent infinite recursion. - return nil - } - - var errorDescription: String? { - guard let errorFailure = self.failure else { return (self.underlyingError as NSError?)?.localizedDescription } - guard let failureReason = self.failureReason else { return errorFailure } - - let errorDescription = errorFailure + " " + failureReason - return errorDescription - } - - var failureReason: String? { (self.underlyingError as NSError?)?.localizedDescription } - var recoverySuggestion: String? { (self.underlyingError as NSError?)?.localizedRecoverySuggestion } - var helpAnchor: String? { (self.underlyingError as NSError?)?.helpAnchor } -} diff --git a/Shared/XPC/AltXPCProtocol.h b/Shared/XPC/AltXPCProtocol.h deleted file mode 100644 index 629e1f42..00000000 --- a/Shared/XPC/AltXPCProtocol.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// AltXPCProtocol.h -// AltXPC -// -// Created by Riley Testut on 12/2/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -#import - -@class ALTAnisetteData; - -@protocol AltXPCProtocol - -- (void)ping:(void (^_Nonnull)(void))completionHandler; -- (void)requestAnisetteDataWithCompletionHandler:(void (^_Nonnull)(ALTAnisetteData *_Nullable anisetteData, NSError *_Nullable error))completionHandler; - -@end diff --git a/Sources/AltBackup/ViewController.swift b/Sources/AltBackup/ViewController.swift deleted file mode 100644 index 17a819a5..00000000 --- a/Sources/AltBackup/ViewController.swift +++ /dev/null @@ -1,206 +0,0 @@ -// -// ViewController.swift -// AltBackup -// -// Created by Riley Testut on 5/11/20. -// Copyright © 2020 Riley Testut. All rights reserved. -// - -import UIKit - -extension Bundle -{ - var appName: String? { - let appName = - Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? - Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as? String - return appName - } -} - -extension ViewController -{ - enum BackupOperation - { - case backup - case restore - } -} - -class ViewController: UIViewController -{ - private let backupController = BackupController() - - private var currentOperation: BackupOperation? { - didSet { - DispatchQueue.main.async { - self.update() - } - } - } - - private var textLabel: UILabel! - private var detailTextLabel: UILabel! - private var activityIndicatorView: UIActivityIndicatorView! - - override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent - } - - override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) - { - super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - - NotificationCenter.default.addObserver(self, selector: #selector(ViewController.backup), name: AppDelegate.startBackupNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(ViewController.restore), name: AppDelegate.startRestoreNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil) - } - - required init?(coder: NSCoder) { - fatalError() - } - - override func viewDidLoad() - { - super.viewDidLoad() - - self.view.backgroundColor = .altstoreBackground - - self.textLabel = UILabel(frame: .zero) - self.textLabel.font = UIFont.preferredFont(forTextStyle: .title2) - self.textLabel.textColor = .altstoreText - self.textLabel.textAlignment = .center - self.textLabel.numberOfLines = 0 - - self.detailTextLabel = UILabel(frame: .zero) - self.detailTextLabel.font = UIFont.preferredFont(forTextStyle: .body) - self.detailTextLabel.textColor = .altstoreText - self.detailTextLabel.textAlignment = .center - self.detailTextLabel.numberOfLines = 0 - - self.activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge) - self.activityIndicatorView.color = .altstoreText - self.activityIndicatorView.startAnimating() - - #if DEBUG - let button1 = UIButton(type: .system) - button1.setTitle("Backup", for: .normal) - button1.setTitleColor(.white, for: .normal) - button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered) - - let button2 = UIButton(type: .system) - button2.setTitle("Restore", for: .normal) - button2.setTitleColor(.white, for: .normal) - button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered) - - let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!, button1, button2] - #else - let arrangedSubviews = [self.textLabel!, self.detailTextLabel!, self.activityIndicatorView!] - #endif - - let stackView = UIStackView(arrangedSubviews: arrangedSubviews) - stackView.translatesAutoresizingMaskIntoConstraints = false - stackView.spacing = 22 - stackView.axis = .vertical - stackView.alignment = .center - self.view.addSubview(stackView) - - NSLayoutConstraint.activate([stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), - stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor), - stackView.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: self.view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1.0), - self.view.safeAreaLayoutGuide.trailingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: stackView.trailingAnchor, multiplier: 1.0)]) - - self.update() - } -} - -private extension ViewController -{ - @objc func backup() - { - self.currentOperation = .backup - - self.backupController.performBackup { (result) in - let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "") - - let title = String(format: NSLocalizedString("%@ could not be backed up.", comment: ""), appName) - self.process(result, errorTitle: title) - } - } - - @objc func restore() - { - self.currentOperation = .restore - - self.backupController.restoreBackup { (result) in - let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "") - - let title = String(format: NSLocalizedString("%@ could not be restored.", comment: ""), appName) - self.process(result, errorTitle: title) - } - } - - func update() - { - switch self.currentOperation - { - case .backup: - self.textLabel.text = NSLocalizedString("Backing up app data…", comment: "") - self.detailTextLabel.isHidden = true - self.activityIndicatorView.startAnimating() - - case .restore: - self.textLabel.text = NSLocalizedString("Restoring app data…", comment: "") - self.detailTextLabel.isHidden = true - self.activityIndicatorView.startAnimating() - - case .none: - self.textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""), - Bundle.main.appName ?? NSLocalizedString("App", comment: "")) - - self.detailTextLabel.text = String(format: NSLocalizedString("Refresh %@ in SideStore to continue using it.", comment: ""), - Bundle.main.appName ?? NSLocalizedString("this app", comment: "")) - - self.detailTextLabel.isHidden = false - self.activityIndicatorView.stopAnimating() - } - } -} - -private extension ViewController -{ - func process(_ result: Result, errorTitle: String) - { - DispatchQueue.main.async { - switch result - { - case .success: break - case .failure(let error as NSError): - let message: String - - if let sourceDescription = error.sourceDescription - { - message = error.localizedDescription + "\n\n" + sourceDescription - } - else - { - message = error.localizedDescription - } - - let alertController = UIAlertController(title: errorTitle, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - self.present(alertController, animated: true, completion: nil) - } - - NotificationCenter.default.post(name: AppDelegate.operationDidFinishNotification, object: nil, userInfo: [AppDelegate.operationResultKey: result]) - } - } - - @objc func didEnterBackground(_ notification: Notification) - { - // Reset UI once we've left app (but not before). - self.currentOperation = nil - } -} diff --git a/AltStore/Operations/Patch App/ALTAppPatcher.h b/Sources/AltPatcher/ALTAppPatcher.h similarity index 100% rename from AltStore/Operations/Patch App/ALTAppPatcher.h rename to Sources/AltPatcher/ALTAppPatcher.h diff --git a/AltStore/Operations/Patch App/ALTAppPatcher.m b/Sources/AltPatcher/ALTAppPatcher.m similarity index 100% rename from AltStore/Operations/Patch App/ALTAppPatcher.m rename to Sources/AltPatcher/ALTAppPatcher.m diff --git a/Sources/AltPatcher/include/ALTAppPatcher/ALTAppPatcher.h b/Sources/AltPatcher/include/ALTAppPatcher/ALTAppPatcher.h new file mode 100644 index 00000000..5bcb2d22 --- /dev/null +++ b/Sources/AltPatcher/include/ALTAppPatcher/ALTAppPatcher.h @@ -0,0 +1,19 @@ +// +// ALTAppPatcher.h +// ALTAppPatcher +// +// Created by Joseph Mattiello on 03/01/23. +// Copyright © 2023 Provenance Emu. All rights reserved. +// + +#import + +//! Project version number for ALTAppPatcher. +FOUNDATION_EXPORT double ALTAppPatcherVersionNumber; + +//! Project version string for ALTAppPatcher. +FOUNDATION_EXPORT const unsigned char ALTAppPatcherVersionString[]; + + +# pragma mark - ALTAppPatcher +#import diff --git a/Sources/AltPatcher/include/ALTAppPatcher/_ALTAppPatcher.h b/Sources/AltPatcher/include/ALTAppPatcher/_ALTAppPatcher.h new file mode 120000 index 00000000..123fa68a --- /dev/null +++ b/Sources/AltPatcher/include/ALTAppPatcher/_ALTAppPatcher.h @@ -0,0 +1 @@ +../../ALTAppPatcher.h \ No newline at end of file diff --git a/Sources/Cargo/Commands/Build.swift b/Sources/Cargo/Commands/Build.swift new file mode 100644 index 00000000..dffffb36 --- /dev/null +++ b/Sources/Cargo/Commands/Build.swift @@ -0,0 +1,61 @@ +import ArgumentParser +import SwiftLintFramework + +extension SwiftLint { + struct Build: AsyncParsableCommand { + static let configuration = CommandConfiguration(abstract: "Print lint warnings and errors") + + @OptionGroup + var common: LintOrAnalyzeArguments + @Option(help: pathOptionDescription(for: .build)) + var path: String? + @Flag(help: quietOptionDescription(for: .build)) + var quiet = false + @Option(help: "The directory of the cache used when linting.") + var cachePath: String? + @Flag(help: "Ignore cache when linting.") + var noCache = false + @Flag(help: "Run all rules, even opt-in and disabled ones, ignoring `only_rules`.") + var enableAllRules = false + @Argument(help: pathsArgumentDescription(for: .build)) + var paths = [String]() + + func run() async throws { + let allPaths: [String] + if let path { + queuedPrintError(""" + warning: The --path option is deprecated. Pass the path(s) to lint last to the swiftlint command. + """) + allPaths = [path] + paths + } else if !paths.isEmpty { + allPaths = paths + } else { + allPaths = [""] // Lint files in current working directory if no paths were specified. + } + let options = LintOrAnalyzeOptions( + mode: .build, + paths: allPaths, + configurationFiles: common.config, + strict: common.leniency == .strict, + lenient: common.leniency == .lenient, + forceExclude: common.forceExclude, + useExcludingByPrefix: common.useAlternativeExcluding, + useScriptInputFiles: common.useScriptInputFiles, + benchmark: common.benchmark, + reporter: common.reporter, + quiet: quiet, + output: common.output, + progress: common.progress, + cachePath: cachePath, + ignoreCache: noCache, + enableAllRules: enableAllRules, + autocorrect: common.fix, + format: common.format, + compilerLogPath: nil, + compileCommands: nil, + inProcessSourcekit: common.inProcessSourcekit + ) + try await LintOrAnalyzeCommand.run(options) + } + } +} diff --git a/Sources/Cargo/Commands/Cargo.swift b/Sources/Cargo/Commands/Cargo.swift new file mode 100644 index 00000000..beb94c1d --- /dev/null +++ b/Sources/Cargo/Commands/Cargo.swift @@ -0,0 +1,22 @@ +import ArgumentParser +import Foundation + +@main +struct Cargo: AsyncParsableCommand { + static let configuration: CommandConfiguration = { + if let directory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] { + FileManager.default.changeCurrentDirectoryPath(directory) + } + + return CommandConfiguration( + commandName: "cargo", + abstract: "A tool to build `rust` projects with `cargo`.", + version: Version.value, + subcommands: [ + Build.self, + Version.self + ], + defaultSubcommand: Build.self + ) + }() +} diff --git a/Sources/Cargo/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift b/Sources/Cargo/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift new file mode 100644 index 00000000..192bf689 --- /dev/null +++ b/Sources/Cargo/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift @@ -0,0 +1,20 @@ +extension RulesFilter.ExcludingOptions { + static func excludingOptions(byCommandLineOptions rulesFilterOptions: RulesFilterOptions) -> Self { + var excludingOptions: Self = [] + + switch rulesFilterOptions.ruleEnablement { + case .enabled: + excludingOptions.insert(.disabled) + case .disabled: + excludingOptions.insert(.enabled) + case .none: + break + } + + if rulesFilterOptions.correctable { + excludingOptions.insert(.uncorrectable) + } + + return excludingOptions + } +} diff --git a/Sources/Cargo/Commands/Common/RulesFilterOptions.swift b/Sources/Cargo/Commands/Common/RulesFilterOptions.swift new file mode 100644 index 00000000..0a409fb6 --- /dev/null +++ b/Sources/Cargo/Commands/Common/RulesFilterOptions.swift @@ -0,0 +1,20 @@ +import ArgumentParser + +enum RuleEnablementOptions: String, EnumerableFlag { + case enabled, disabled + + static func name(for value: RuleEnablementOptions) -> NameSpecification { + return .shortAndLong + } + + static func help(for value: RuleEnablementOptions) -> ArgumentHelp? { + return "Only show \(value.rawValue) rules" + } +} + +struct RulesFilterOptions: ParsableArguments { + @Flag(exclusivity: .exclusive) + var ruleEnablement: RuleEnablementOptions? + @Flag(name: .shortAndLong, help: "Only display correctable rules") + var correctable = false +} diff --git a/Sources/Cargo/Commands/Version.swift b/Sources/Cargo/Commands/Version.swift new file mode 100644 index 00000000..d9edd205 --- /dev/null +++ b/Sources/Cargo/Commands/Version.swift @@ -0,0 +1,23 @@ +import ArgumentParser +import SwiftLintFramework + +extension Cargo { + struct Version: ParsableCommand { + @Flag(help: "Display full version info") + var verbose = false + + static let configuration = CommandConfiguration(abstract: "Display the current version of Cargo") + + static var value: String { "TODO" } + + func run() throws { + if verbose, let buildID = ExecutableInfo.buildID { + print("Version:", Self.value) + print("Build ID:", buildID) + } else { + print(Self.value) + } + ExitHelper.successfullyExit() + } + } +} diff --git a/Sources/Cargo/swiftlint/Commands/Analyze.swift b/Sources/Cargo/swiftlint/Commands/Analyze.swift new file mode 100644 index 00000000..88df6a72 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Analyze.swift @@ -0,0 +1,61 @@ +import ArgumentParser +import SwiftLintFramework + +extension SwiftLint { + struct Analyze: AsyncParsableCommand { + static let configuration = CommandConfiguration(abstract: "Run analysis rules") + + @OptionGroup + var common: LintOrAnalyzeArguments + @Option(help: pathOptionDescription(for: .analyze)) + var path: String? + @Flag(help: quietOptionDescription(for: .analyze)) + var quiet = false + @Option(help: "The path of the full xcodebuild log to use when running AnalyzerRules.") + var compilerLogPath: String? + @Option(help: "The path of a compilation database to use when running AnalyzerRules.") + var compileCommands: String? + @Argument(help: pathsArgumentDescription(for: .analyze)) + var paths = [String]() + + func run() async throws { + let allPaths: [String] + if let path { + queuedPrintError(""" + warning: The --path option is deprecated. Pass the path(s) to analyze last to the swiftlint command. + """) + allPaths = [path] + paths + } else if !paths.isEmpty { + allPaths = paths + } else { + allPaths = [""] // Analyze files in current working directory if no paths were specified. + } + let options = LintOrAnalyzeOptions( + mode: .analyze, + paths: allPaths, + useSTDIN: false, + configurationFiles: common.config, + strict: common.leniency == .strict, + lenient: common.leniency == .lenient, + forceExclude: common.forceExclude, + useExcludingByPrefix: common.useAlternativeExcluding, + useScriptInputFiles: common.useScriptInputFiles, + benchmark: common.benchmark, + reporter: common.reporter, + quiet: quiet, + output: common.output, + progress: common.progress, + cachePath: nil, + ignoreCache: true, + enableAllRules: false, + autocorrect: common.fix, + format: common.format, + compilerLogPath: compilerLogPath, + compileCommands: compileCommands, + inProcessSourcekit: common.inProcessSourcekit + ) + + try await LintOrAnalyzeCommand.run(options) + } + } +} diff --git a/Sources/Cargo/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift b/Sources/Cargo/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift new file mode 100644 index 00000000..192bf689 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift @@ -0,0 +1,20 @@ +extension RulesFilter.ExcludingOptions { + static func excludingOptions(byCommandLineOptions rulesFilterOptions: RulesFilterOptions) -> Self { + var excludingOptions: Self = [] + + switch rulesFilterOptions.ruleEnablement { + case .enabled: + excludingOptions.insert(.disabled) + case .disabled: + excludingOptions.insert(.enabled) + case .none: + break + } + + if rulesFilterOptions.correctable { + excludingOptions.insert(.uncorrectable) + } + + return excludingOptions + } +} diff --git a/Sources/Cargo/swiftlint/Commands/Common/RulesFilterOptions.swift b/Sources/Cargo/swiftlint/Commands/Common/RulesFilterOptions.swift new file mode 100644 index 00000000..0a409fb6 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Common/RulesFilterOptions.swift @@ -0,0 +1,20 @@ +import ArgumentParser + +enum RuleEnablementOptions: String, EnumerableFlag { + case enabled, disabled + + static func name(for value: RuleEnablementOptions) -> NameSpecification { + return .shortAndLong + } + + static func help(for value: RuleEnablementOptions) -> ArgumentHelp? { + return "Only show \(value.rawValue) rules" + } +} + +struct RulesFilterOptions: ParsableArguments { + @Flag(exclusivity: .exclusive) + var ruleEnablement: RuleEnablementOptions? + @Flag(name: .shortAndLong, help: "Only display correctable rules") + var correctable = false +} diff --git a/Sources/Cargo/swiftlint/Commands/Docs.swift b/Sources/Cargo/swiftlint/Commands/Docs.swift new file mode 100644 index 00000000..2e35fe85 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Docs.swift @@ -0,0 +1,43 @@ +import ArgumentParser +import Foundation +import SwiftLintFramework + +extension SwiftLint { + struct Docs: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Open SwiftLint documentation website in the default web browser" + ) + + @Argument(help: "The identifier of the rule to open the documentation for") + var ruleID: String? + + func run() throws { + var subPage = "" + if let ruleID { + if primaryRuleList.list[ruleID] == nil { + queuedPrintError("There is no rule named '\(ruleID)'. Opening rule directory instead.") + subPage = "rule-directory.html" + } else { + subPage = ruleID + ".html" + } + } + open(URL(string: "https://realm.github.io/SwiftLint/\(subPage)")!) + ExitHelper.successfullyExit() + } + } +} + +private func open(_ url: URL) { + let process = Process() +#if os(Linux) + process.executableURL = URL(fileURLWithPath: "/usr/bin/env", isDirectory: false) + let command = "xdg-open" + process.arguments = [command, url.absoluteString] + try? process.run() +#else + process.launchPath = "/usr/bin/env" + let command = "open" + process.arguments = [command, url.absoluteString] + process.launch() +#endif +} diff --git a/Sources/Cargo/swiftlint/Commands/GenerateDocs.swift b/Sources/Cargo/swiftlint/Commands/GenerateDocs.swift new file mode 100644 index 00000000..fc448fc5 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/GenerateDocs.swift @@ -0,0 +1,28 @@ +import ArgumentParser +import Foundation +import SwiftLintFramework + +extension SwiftLint { + struct GenerateDocs: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Generates markdown documentation for selected group of rules" + ) + + @Option(help: "The directory where the documentation should be saved") + var path = "rule_docs" + @Option(help: "The path to a SwiftLint configuration file") + var config: String? + @OptionGroup + var rulesFilterOptions: RulesFilterOptions + + func run() throws { + let configuration = Configuration(configurationFiles: [config].compactMap({ $0 })) + let rulesFilter = RulesFilter(enabledRules: configuration.rules) + let rules = rulesFilter.getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions)) + + try RuleListDocumentation(rules) + .write(to: URL(fileURLWithPath: path, isDirectory: true)) + ExitHelper.successfullyExit() + } + } +} diff --git a/Sources/Cargo/swiftlint/Commands/Lint.swift b/Sources/Cargo/swiftlint/Commands/Lint.swift new file mode 100644 index 00000000..c38a379d --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Lint.swift @@ -0,0 +1,64 @@ +import ArgumentParser +import SwiftLintFramework + +extension SwiftLint { + struct Lint: AsyncParsableCommand { + static let configuration = CommandConfiguration(abstract: "Print lint warnings and errors") + + @OptionGroup + var common: LintOrAnalyzeArguments + @Option(help: pathOptionDescription(for: .lint)) + var path: String? + @Flag(help: "Lint standard input.") + var useSTDIN = false + @Flag(help: quietOptionDescription(for: .lint)) + var quiet = false + @Option(help: "The directory of the cache used when linting.") + var cachePath: String? + @Flag(help: "Ignore cache when linting.") + var noCache = false + @Flag(help: "Run all rules, even opt-in and disabled ones, ignoring `only_rules`.") + var enableAllRules = false + @Argument(help: pathsArgumentDescription(for: .lint)) + var paths = [String]() + + func run() async throws { + let allPaths: [String] + if let path { + queuedPrintError(""" + warning: The --path option is deprecated. Pass the path(s) to lint last to the swiftlint command. + """) + allPaths = [path] + paths + } else if !paths.isEmpty { + allPaths = paths + } else { + allPaths = [""] // Lint files in current working directory if no paths were specified. + } + let options = LintOrAnalyzeOptions( + mode: .lint, + paths: allPaths, + useSTDIN: useSTDIN, + configurationFiles: common.config, + strict: common.leniency == .strict, + lenient: common.leniency == .lenient, + forceExclude: common.forceExclude, + useExcludingByPrefix: common.useAlternativeExcluding, + useScriptInputFiles: common.useScriptInputFiles, + benchmark: common.benchmark, + reporter: common.reporter, + quiet: quiet, + output: common.output, + progress: common.progress, + cachePath: cachePath, + ignoreCache: noCache, + enableAllRules: enableAllRules, + autocorrect: common.fix, + format: common.format, + compilerLogPath: nil, + compileCommands: nil, + inProcessSourcekit: common.inProcessSourcekit + ) + try await LintOrAnalyzeCommand.run(options) + } + } +} diff --git a/Sources/Cargo/swiftlint/Commands/Rules.swift b/Sources/Cargo/swiftlint/Commands/Rules.swift new file mode 100644 index 00000000..d3c4efd9 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Rules.swift @@ -0,0 +1,123 @@ +import ArgumentParser +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#else +#error("Unsupported platform") +#endif +import Foundation +@_spi(TestHelper) +import SwiftLintFramework +import SwiftyTextTable + +extension SwiftLint { + struct Rules: ParsableCommand { + static let configuration = CommandConfiguration(abstract: "Display the list of rules and their identifiers") + + @Option(help: "The path to a SwiftLint configuration file") + var config: String? + @OptionGroup + var rulesFilterOptions: RulesFilterOptions + @Flag(name: .shortAndLong, help: "Display full configuration details") + var verbose = false + @Argument(help: "The rule identifier to display description for") + var ruleID: String? + + func run() throws { + if let ruleID { + guard let rule = primaryRuleList.list[ruleID] else { + throw SwiftLintError.usageError(description: "No rule with identifier: \(ruleID)") + } + + rule.description.printDescription() + return + } + + let configuration = Configuration(configurationFiles: [config].compactMap({ $0 })) + let rulesFilter = RulesFilter(enabledRules: configuration.rules) + let rules = rulesFilter.getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions)) + let table = TextTable(ruleList: rules, configuration: configuration, verbose: verbose) + print(table.render()) + ExitHelper.successfullyExit() + } + } +} + +private extension RuleDescription { + func printDescription() { + print("\(consoleDescription)") + + guard !triggeringExamples.isEmpty else { return } + + func indent(_ string: String) -> String { + return string.components(separatedBy: "\n") + .map { " \($0)" } + .joined(separator: "\n") + } + print("\nTriggering Examples (violation is marked with '↓'):") + for (index, example) in triggeringExamples.enumerated() { + print("\nExample #\(index + 1)\n\n\(indent(example.code))") + } + } +} + +// MARK: - SwiftyTextTable + +private extension TextTable { + init(ruleList: RuleList, configuration: Configuration, verbose: Bool) { + let columns = [ + TextTableColumn(header: "identifier"), + TextTableColumn(header: "opt-in"), + TextTableColumn(header: "correctable"), + TextTableColumn(header: "enabled in your config"), + TextTableColumn(header: "kind"), + TextTableColumn(header: "analyzer"), + TextTableColumn(header: "uses sourcekit"), + TextTableColumn(header: "configuration") + ] + self.init(columns: columns) + let sortedRules = ruleList.list.sorted { $0.0 < $1.0 } + func truncate(_ string: String) -> String { + let stringWithNoNewlines = string.replacingOccurrences(of: "\n", with: "\\n") + let minWidth = "configuration".count - "...".count + let configurationStartColumn = 140 + let maxWidth = verbose ? Int.max : Terminal.currentWidth() + let truncatedEndIndex = stringWithNoNewlines.index( + stringWithNoNewlines.startIndex, + offsetBy: max(minWidth, maxWidth - configurationStartColumn), + limitedBy: stringWithNoNewlines.endIndex + ) + if let truncatedEndIndex { + return stringWithNoNewlines[.. Int { + var size = winsize() +#if os(Linux) + _ = ioctl(CInt(STDOUT_FILENO), UInt(TIOCGWINSZ), &size) +#else + _ = ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) +#endif + return Int(size.ws_col) + } +} diff --git a/Sources/Cargo/swiftlint/Commands/SwiftLint.swift b/Sources/Cargo/swiftlint/Commands/SwiftLint.swift new file mode 100644 index 00000000..c6730790 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/SwiftLint.swift @@ -0,0 +1,26 @@ +import ArgumentParser +import Foundation + +@main +struct SwiftLint: AsyncParsableCommand { + static let configuration: CommandConfiguration = { + if let directory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] { + FileManager.default.changeCurrentDirectoryPath(directory) + } + + return CommandConfiguration( + commandName: "swiftlint", + abstract: "A tool to enforce Swift style and conventions.", + version: Version.value, + subcommands: [ + Analyze.self, + Docs.self, + GenerateDocs.self, + Lint.self, + Rules.self, + Version.self + ], + defaultSubcommand: Lint.self + ) + }() +} diff --git a/Sources/Cargo/swiftlint/Commands/Version.swift b/Sources/Cargo/swiftlint/Commands/Version.swift new file mode 100644 index 00000000..8cbcb082 --- /dev/null +++ b/Sources/Cargo/swiftlint/Commands/Version.swift @@ -0,0 +1,23 @@ +import ArgumentParser +import SwiftLintFramework + +extension SwiftLint { + struct Version: ParsableCommand { + @Flag(help: "Display full version info") + var verbose = false + + static let configuration = CommandConfiguration(abstract: "Display the current version of SwiftLint") + + static var value: String { SwiftLintFramework.Version.current.value } + + func run() throws { + if verbose, let buildID = ExecutableInfo.buildID { + print("Version:", Self.value) + print("Build ID:", buildID) + } else { + print(Self.value) + } + ExitHelper.successfullyExit() + } + } +} diff --git a/Sources/Cargo/swiftlint/Extensions/Configuration+CommandLine.swift b/Sources/Cargo/swiftlint/Extensions/Configuration+CommandLine.swift new file mode 100644 index 00000000..fb003e16 --- /dev/null +++ b/Sources/Cargo/swiftlint/Extensions/Configuration+CommandLine.swift @@ -0,0 +1,283 @@ +import CollectionConcurrencyKit +import Foundation +import SourceKittenFramework +import SwiftLintFramework + +private actor CounterActor { + private var count = 0 + + func next() -> Int { + count += 1 + return count + } +} + +private func scriptInputFiles() throws -> [SwiftLintFile] { + let inputFileKey = "SCRIPT_INPUT_FILE_COUNT" + guard let countString = ProcessInfo.processInfo.environment[inputFileKey] else { + throw SwiftLintError.usageError(description: "\(inputFileKey) variable not set") + } + + guard let count = Int(countString) else { + throw SwiftLintError.usageError(description: "\(inputFileKey) did not specify a number") + } + + return (0..(block: () -> T) -> T { return block() } +#endif + +extension Configuration { + func visitLintableFiles(with visitor: LintableFilesVisitor, storage: RuleStorage) async throws -> [SwiftLintFile] { + let files = try await Signposts.record(name: "Configuration.VisitLintableFiles.GetFiles") { + try await getFiles(with: visitor) + } + let groupedFiles = try Signposts.record(name: "Configuration.VisitLintableFiles.GroupFiles") { + try groupFiles(files, visitor: visitor) + } + let lintersForFile = Signposts.record(name: "Configuration.VisitLintableFiles.LintersForFile") { + groupedFiles.map { file in + linters(for: [file.key: file.value], visitor: visitor) + } + } + let duplicateFileNames = Signposts.record(name: "Configuration.VisitLintableFiles.DuplicateFileNames") { + lintersForFile.map(\.duplicateFileNames) + } + let collected = await Signposts.record(name: "Configuration.VisitLintableFiles.Collect") { + await zip(lintersForFile, duplicateFileNames).asyncMap { linters, duplicateFileNames in + await collect(linters: linters, visitor: visitor, storage: storage, + duplicateFileNames: duplicateFileNames) + } + } + let result = await Signposts.record(name: "Configuration.VisitLintableFiles.Visit") { + await collected.asyncMap { linters, duplicateFileNames in + await visit(linters: linters, visitor: visitor, duplicateFileNames: duplicateFileNames) + } + } + return result.flatMap { $0 } + } + + private func groupFiles(_ files: [SwiftLintFile], visitor: LintableFilesVisitor) throws + -> [Configuration: [SwiftLintFile]] { + if files.isEmpty && !visitor.allowZeroLintableFiles { + throw SwiftLintError.usageError( + description: "No lintable files found at paths: '\(visitor.paths.joined(separator: ", "))'" + ) + } + + var groupedFiles = [Configuration: [SwiftLintFile]]() + for file in files { + let fileConfiguration = configuration(for: file) + let fileConfigurationRootPath = fileConfiguration.rootDirectory.bridge() + + // Files whose configuration specifies they should be excluded will be skipped + let shouldSkip = fileConfiguration.excludedPaths.contains { excludedRelativePath in + let excludedPath = fileConfigurationRootPath.appendingPathComponent(excludedRelativePath) + let filePathComponents = file.path?.bridge().pathComponents ?? [] + let excludedPathComponents = excludedPath.bridge().pathComponents + return filePathComponents.starts(with: excludedPathComponents) + } + + if !shouldSkip { + groupedFiles[fileConfiguration, default: []].append(file) + } + } + + return groupedFiles + } + + private func outputFilename(for path: String, duplicateFileNames: Set) -> String { + let basename = path.bridge().lastPathComponent + if !duplicateFileNames.contains(basename) { + return basename + } + + var pathComponents = path.bridge().pathComponents + for component in rootDirectory.bridge().pathComponents where pathComponents.first == component { + pathComponents.removeFirst() + } + + return pathComponents.joined(separator: "/") + } + + private func linters(for filesPerConfiguration: [Configuration: [SwiftLintFile]], + visitor: LintableFilesVisitor) -> [Linter] { + let fileCount = filesPerConfiguration.reduce(0) { $0 + $1.value.count } + + var linters = [Linter]() + linters.reserveCapacity(fileCount) + for (config, files) in filesPerConfiguration { + let newConfig: Configuration + if visitor.cache != nil { + newConfig = config.withPrecomputedCacheDescription() + } else { + newConfig = config + } + linters += files.map { visitor.linter(forFile: $0, configuration: newConfig) } + } + return linters + } + + private func collect(linters: [Linter], + visitor: LintableFilesVisitor, + storage: RuleStorage, + duplicateFileNames: Set) async -> ([CollectedLinter], Set) { + let counter = CounterActor() + let total = linters.filter(\.isCollecting).count + let progress = ProgressBar(count: total) + if visitor.showProgressBar && total > 0 { + await progress.initialize() + } + let collect = { (linter: Linter) -> CollectedLinter? in + let skipFile = visitor.shouldSkipFile(atPath: linter.file.path) + if !visitor.quiet && linter.isCollecting { + if visitor.showProgressBar { + await progress.printNext() + } else if let filePath = linter.file.path { + let outputFilename = self.outputFilename(for: filePath, duplicateFileNames: duplicateFileNames) + let collected = await counter.next() + if skipFile { + queuedPrintError(""" + Skipping '\(outputFilename)' (\(collected)/\(total)) \ + because its compiler arguments could not be found + """) + } else { + queuedPrintError("Collecting '\(outputFilename)' (\(collected)/\(total))") + } + } + } + + guard !skipFile else { + return nil + } + + return autoreleasepool { + linter.collect(into: storage) + } + } + + let collectedLinters = await visitor.parallel ? + linters.concurrentCompactMap(collect) : + linters.asyncCompactMap(collect) + return (collectedLinters, duplicateFileNames) + } + + private func visit(linters: [CollectedLinter], + visitor: LintableFilesVisitor, + duplicateFileNames: Set) async -> [SwiftLintFile] { + let counter = CounterActor() + let progress = ProgressBar(count: linters.count) + if visitor.showProgressBar { + await progress.initialize() + } + let visit = { (linter: CollectedLinter) -> SwiftLintFile in + if !visitor.quiet { + if visitor.showProgressBar { + await progress.printNext() + } else if let filePath = linter.file.path { + let outputFilename = self.outputFilename(for: filePath, duplicateFileNames: duplicateFileNames) + let visited = await counter.next() + queuedPrintError("\(visitor.action) '\(outputFilename)' (\(visited)/\(linters.count))") + } + } + + await Signposts.record(name: "Configuration.Visit", span: .file(linter.file.path ?? "")) { + await visitor.block(linter) + } + return linter.file + } + return await visitor.parallel ? + linters.concurrentMap(visit) : + linters.asyncMap(visit) + } + + fileprivate func getFiles(with visitor: LintableFilesVisitor) async throws -> [SwiftLintFile] { + if visitor.useSTDIN { + let stdinData = FileHandle.standardInput.readDataToEndOfFile() + if let stdinString = String(data: stdinData, encoding: .utf8) { + return [SwiftLintFile(contents: stdinString)] + } + throw SwiftLintError.usageError(description: "stdin isn't a UTF8-encoded string") + } else if visitor.useScriptInputFiles { + let files = try scriptInputFiles() + guard visitor.forceExclude else { + return files + } + + let scriptInputPaths = files.compactMap { $0.path } + let filesToLint = visitor.useExcludingByPrefix ? + filterExcludedPathsByPrefix(in: scriptInputPaths) : + filterExcludedPaths(in: scriptInputPaths) + return filesToLint.map(SwiftLintFile.init(pathDeferringReading:)) + } + if !visitor.quiet { + let filesInfo: String + if visitor.paths.isEmpty || visitor.paths == [""] { + filesInfo = "in current working directory" + } else { + filesInfo = "at paths \(visitor.paths.joined(separator: ", "))" + } + + queuedPrintError("\(visitor.action) Swift files \(filesInfo)") + } + return visitor.paths.flatMap { + self.lintableFiles(inPath: $0, forceExclude: visitor.forceExclude, + excludeByPrefix: visitor.useExcludingByPrefix) + } + } + + func visitLintableFiles(options: LintOrAnalyzeOptions, cache: LinterCache? = nil, storage: RuleStorage, + visitorBlock: @escaping (CollectedLinter) async -> Void) async throws -> [SwiftLintFile] { + let visitor = try LintableFilesVisitor.create(options, cache: cache, + allowZeroLintableFiles: allowZeroLintableFiles, + block: visitorBlock) + return try await visitLintableFiles(with: visitor, storage: storage) + } + + // MARK: LintOrAnalyze Command + + init(options: LintOrAnalyzeOptions) { + self.init( + configurationFiles: options.configurationFiles, + enableAllRules: options.enableAllRules, + cachePath: options.cachePath + ) + } +} + +private struct DuplicateCollector { + var all = Set() + var duplicates = Set() +} + +private extension Collection where Element == Linter { + var duplicateFileNames: Set { + let collector = reduce(into: DuplicateCollector()) { result, linter in + if let filename = linter.file.path?.bridge().lastPathComponent { + if result.all.contains(filename) { + result.duplicates.insert(filename) + } + + result.all.insert(filename) + } + } + return collector.duplicates + } +} diff --git a/Sources/Cargo/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift b/Sources/Cargo/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift new file mode 100644 index 00000000..c7e25c06 --- /dev/null +++ b/Sources/Cargo/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift @@ -0,0 +1,28 @@ +import Foundation + +extension ProcessInfo { + var isLikelyXcodeCloudEnvironment: Bool { + // https://developer.apple.com/documentation/xcode/environment-variable-reference + let requiredKeys: Set = [ + "CI", + "CI_BUILD_ID", + "CI_BUILD_NUMBER", + "CI_BUNDLE_ID", + "CI_COMMIT", + "CI_DERIVED_DATA_PATH", + "CI_PRODUCT", + "CI_PRODUCT_ID", + "CI_PRODUCT_PLATFORM", + "CI_PROJECT_FILE_PATH", + "CI_START_CONDITION", + "CI_TEAM_ID", + "CI_WORKFLOW", + "CI_WORKSPACE", + "CI_XCODE_PROJECT", + "CI_XCODE_SCHEME", + "CI_XCODEBUILD_ACTION" + ] + + return requiredKeys.isSubset(of: environment.keys) + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/Benchmark.swift b/Sources/Cargo/swiftlint/Helpers/Benchmark.swift new file mode 100644 index 00000000..ef1c48ad --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/Benchmark.swift @@ -0,0 +1,52 @@ +import Foundation +import SwiftLintFramework + +struct BenchmarkEntry { + let id: String + let time: Double +} + +struct Benchmark { + private let name: String + private var entries = [BenchmarkEntry]() + + init(name: String) { + self.name = name + } + + mutating func record(id: String, time: Double) { + guard id != "custom_rules" else { return } + entries.append(BenchmarkEntry(id: id, time: time)) + } + + mutating func record(file: SwiftLintFile, from start: Date) { + record(id: file.path ?? "", time: -start.timeIntervalSinceNow) + } + + func save() { + // Decomposed to improve compile times + let entriesDict: [String: Double] = entries.reduce(into: [String: Double]()) { accu, idAndTime in + accu[idAndTime.id] = (accu[idAndTime.id] ?? 0) + idAndTime.time + } + let entriesKeyValues: [(String, Double)] = entriesDict.sorted { $0.1 < $1.1 } + let lines: [String] = entriesKeyValues.map { id, time -> String in + return "\(numberFormatter.string(from: NSNumber(value: time))!): \(id)" + } + let string: String = lines.joined(separator: "\n") + "\n" + let url = URL(fileURLWithPath: "benchmark_\(name)_\(timestamp).txt", isDirectory: false) + try? string.data(using: .utf8)?.write(to: url, options: [.atomic]) + } +} + +private let numberFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.minimumFractionDigits = 3 + return formatter +}() + +private let timestamp: String = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy_MM_dd_HH_mm_ss" + return formatter.string(from: Date()) +}() diff --git a/Sources/Cargo/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Sources/Cargo/swiftlint/Helpers/CompilerArgumentsExtractor.swift new file mode 100644 index 00000000..aee4f80c --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/CompilerArgumentsExtractor.swift @@ -0,0 +1,108 @@ +import Foundation + +struct CompilerArgumentsExtractor { + static func allCompilerInvocations(compilerLogs: String) -> [[String]] { + var compilerInvocations = [[String]]() + compilerLogs.enumerateLines { line, _ in + if let swiftcIndex = line.range(of: "swiftc ")?.upperBound, line.contains(" -module-name ") { + let invocation = parseCLIArguments(String(line[swiftcIndex...])) + .expandingResponseFiles + .filteringCompilerArguments + compilerInvocations.append(invocation) + } + } + return compilerInvocations + } +} + +// MARK: - Private + +private func parseCLIArguments(_ string: String) -> [String] { + let escapedSpacePlaceholder = "\u{0}" + let scanner = Scanner(string: string) + var str = "" + var didStart = false + while let result = scanner.scanUpToString("\"") { + if didStart { + str += result.replacingOccurrences(of: " ", with: escapedSpacePlaceholder) + str += " " + } else { + str += result + } + _ = scanner.scanString("\"") + didStart.toggle() + } + return str.trimmingCharacters(in: .whitespaces) + .replacingOccurrences(of: "\\ ", with: escapedSpacePlaceholder) + .components(separatedBy: " ") + .map { $0.replacingOccurrences(of: escapedSpacePlaceholder, with: " ") } +} + +/** + Partially filters compiler arguments from `xcodebuild` to something that SourceKit/Clang will accept. + + - parameter args: Compiler arguments, as parsed from `xcodebuild`. + + - returns: A tuple of partially filtered compiler arguments in `.0`, and whether or not there are + more flags to remove in `.1`. + */ +private func partiallyFilter(arguments args: [String]) -> ([String], Bool) { + guard let indexOfFlagToRemove = args.firstIndex(of: "-output-file-map") else { + return (args, false) + } + var args = args + args.remove(at: args.index(after: indexOfFlagToRemove)) + args.remove(at: indexOfFlagToRemove) + return (args, true) +} + +extension Array where Element == String { + /// Return the full list of compiler arguments, replacing any response files with their contents. + fileprivate var expandingResponseFiles: [String] { + return flatMap { arg -> [String] in + guard arg.starts(with: "@") else { + return [arg] + } + let responseFile = String(arg.dropFirst()) + return (try? String(contentsOf: URL(fileURLWithPath: responseFile, isDirectory: false))).flatMap { + $0.trimmingCharacters(in: .newlines) + .components(separatedBy: "\n") + .expandingResponseFiles + } ?? [arg] + } + } + + /// Returns filtered compiler arguments from `xcodebuild` to something that SourceKit/Clang will accept. + var filteringCompilerArguments: [String] { + var args = self + if args.first == "swiftc" { + args.removeFirst() + } + + // https://github.com/realm/SwiftLint/issues/3365 + args = args.map { $0.replacingOccurrences(of: "\\=", with: "=") } + args = args.map { $0.replacingOccurrences(of: "\\ ", with: " ") } + args.append(contentsOf: ["-D", "DEBUG"]) + var shouldContinueToFilterArguments = true + while shouldContinueToFilterArguments { + (args, shouldContinueToFilterArguments) = partiallyFilter(arguments: args) + } + + return args.filter { + ![ + "-parseable-output", + "-incremental", + "-serialize-diagnostics", + "-emit-dependencies", + "-use-frontend-parseable-output" + ].contains($0) + }.map { + if $0 == "-O" { + return "-Onone" + } else if $0 == "-DNDEBUG=1" { + return "-DDEBUG=1" + } + return $0 + } + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/ExitHelper.swift b/Sources/Cargo/swiftlint/Helpers/ExitHelper.swift new file mode 100644 index 00000000..cd20c6a7 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/ExitHelper.swift @@ -0,0 +1,12 @@ +#if os(Linux) +import Glibc +#endif + +enum ExitHelper { + static func successfullyExit() { +#if os(Linux) + // Workaround for https://github.com/apple/swift/issues/59961 + Glibc.exit(0) +#endif + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeArguments.swift new file mode 100644 index 00000000..8edc1ad8 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -0,0 +1,63 @@ +import ArgumentParser + +enum LeniencyOptions: String, EnumerableFlag { + case strict, lenient + + static func help(for value: LeniencyOptions) -> ArgumentHelp? { + switch value { + case .strict: + return "Upgrades warnings to serious violations (errors)." + case .lenient: + return "Downgrades serious violations to warnings, warning threshold is disabled." + } + } +} + +// MARK: - Common Arguments + +struct LintOrAnalyzeArguments: ParsableArguments { + @Option(help: "The path to one or more SwiftLint configuration files, evaluated as a parent-child hierarchy.") + var config = [String]() + @Flag(name: [.long, .customLong("autocorrect")], help: "Correct violations whenever possible.") + var fix = false + @Flag(help: """ + Should reformat the Swift files using the same mechanism used by Xcode (via SourceKit). + Only applied with `--fix`/`--autocorrect`. + """) + var format = false + @Flag(help: "Use an alternative algorithm to exclude paths for `excluded`, which may be faster in some cases.") + var useAlternativeExcluding = false + @Flag(help: "Read SCRIPT_INPUT_FILE* environment variables as files.") + var useScriptInputFiles = false + @Flag(exclusivity: .exclusive) + var leniency: LeniencyOptions? + @Flag(help: "Exclude files in config `excluded` even if their paths are explicitly specified.") + var forceExclude = false + @Flag(help: "Save benchmarks to `benchmark_files.txt` and `benchmark_rules.txt`.") + var benchmark = false + @Option(help: "The reporter used to log errors and warnings.") + var reporter: String? + @Flag(help: "Use the in-process version of SourceKit.") + var inProcessSourcekit = false + @Option(help: "The file where violations should be saved. Prints to stdout by default.") + var output: String? + @Flag(help: "Show a live-updating progress bar instead of each file being processed.") + var progress = false +} + +// MARK: - Common Argument Help + +// It'd be great to be able to parameterize an `@OptionGroup` so we could move these options into +// `LintOrAnalyzeArguments`. + +func pathOptionDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { + ArgumentHelp(visibility: .hidden) +} + +func pathsArgumentDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { + "List of paths to the files or directories to \(mode.imperative)." +} + +func quietOptionDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { + "Don't print status logs like '\(mode.verb.capitalized) ' & 'Done \(mode.verb)'." +} diff --git a/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeCommand.swift new file mode 100644 index 00000000..5cd992a0 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -0,0 +1,342 @@ +import Dispatch +import Foundation +@_spi(TestHelper) +import SwiftLintFramework + +enum LintOrAnalyzeMode { + case lint, analyze + + var imperative: String { + switch self { + case .lint: + return "lint" + case .analyze: + return "analyze" + } + } + + var verb: String { + switch self { + case .lint: + return "linting" + case .analyze: + return "analyzing" + } + } +} + +struct LintOrAnalyzeCommand { + static func run(_ options: LintOrAnalyzeOptions) async throws { + if options.inProcessSourcekit { + queuedPrintError( + """ + warning: The --in-process-sourcekit option is deprecated. \ + SwiftLint now always uses an in-process SourceKit. + """ + ) + } + try await Signposts.record(name: "LintOrAnalyzeCommand.run") { + try await options.autocorrect ? autocorrect(options) : lintOrAnalyze(options) + } + ExitHelper.successfullyExit() + } + + private static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws { + let builder = LintOrAnalyzeResultBuilder(options) + let files = try await collectViolations(builder: builder) + try Signposts.record(name: "LintOrAnalyzeCommand.PostProcessViolations") { + try postProcessViolations(files: files, builder: builder) + } + } + + private static func collectViolations(builder: LintOrAnalyzeResultBuilder) async throws -> [SwiftLintFile] { + let options = builder.options + let visitorMutationQueue = DispatchQueue(label: "io.realm.swiftlint.lintVisitorMutation") + return try await builder.configuration.visitLintableFiles(options: options, cache: builder.cache, + storage: builder.storage) { linter in + let currentViolations: [StyleViolation] + if options.benchmark { + CustomRuleTimer.shared.activate() + let start = Date() + let (violationsBeforeLeniency, currentRuleTimes) = linter + .styleViolationsAndRuleTimes(using: builder.storage) + currentViolations = applyLeniency(options: options, violations: violationsBeforeLeniency) + visitorMutationQueue.sync { + builder.fileBenchmark.record(file: linter.file, from: start) + currentRuleTimes.forEach { builder.ruleBenchmark.record(id: $0, time: $1) } + builder.violations += currentViolations + } + } else { + currentViolations = applyLeniency(options: options, + violations: linter.styleViolations(using: builder.storage)) + visitorMutationQueue.sync { + builder.violations += currentViolations + } + } + linter.file.invalidateCache() + builder.report(violations: currentViolations, realtimeCondition: true) + } + } + + private static func postProcessViolations(files: [SwiftLintFile], builder: LintOrAnalyzeResultBuilder) throws { + let options = builder.options + let configuration = builder.configuration + if isWarningThresholdBroken(configuration: configuration, violations: builder.violations) + && !options.lenient { + builder.violations.append( + createThresholdViolation(threshold: configuration.warningThreshold!) + ) + builder.report(violations: [builder.violations.last!], realtimeCondition: true) + } + builder.report(violations: builder.violations, realtimeCondition: false) + let numberOfSeriousViolations = builder.violations.filter({ $0.severity == .error }).count + if !options.quiet { + printStatus(violations: builder.violations, files: files, serious: numberOfSeriousViolations, + verb: options.verb) + } + if options.benchmark { + builder.fileBenchmark.save() + for (id, time) in CustomRuleTimer.shared.dump() { + builder.ruleBenchmark.record(id: id, time: time) + } + builder.ruleBenchmark.save() + if !options.quiet, let memoryUsage = memoryUsage() { + queuedPrintError(memoryUsage) + } + } + try builder.cache?.save() + guard numberOfSeriousViolations == 0 else { exit(2) } + } + + private static func printStatus(violations: [StyleViolation], files: [SwiftLintFile], serious: Int, verb: String) { + let pluralSuffix = { (collection: [Any]) -> String in + return collection.count != 1 ? "s" : "" + } + queuedPrintError( + "Done \(verb)! Found \(violations.count) violation\(pluralSuffix(violations)), " + + "\(serious) serious in \(files.count) file\(pluralSuffix(files))." + ) + } + + private static func isWarningThresholdBroken(configuration: Configuration, + violations: [StyleViolation]) -> Bool { + guard let warningThreshold = configuration.warningThreshold else { return false } + let numberOfWarningViolations = violations.filter({ $0.severity == .warning }).count + return numberOfWarningViolations >= warningThreshold + } + + private static func createThresholdViolation(threshold: Int) -> StyleViolation { + let description = RuleDescription( + identifier: "warning_threshold", + name: "Warning Threshold", + description: "Number of warnings thrown is above the threshold", + kind: .lint + ) + return StyleViolation( + ruleDescription: description, + severity: .error, + location: Location(file: "", line: 0, character: 0), + reason: "Number of warnings exceeded threshold of \(threshold).") + } + + private static func applyLeniency(options: LintOrAnalyzeOptions, violations: [StyleViolation]) -> [StyleViolation] { + switch (options.lenient, options.strict) { + case (false, false): + return violations + + case (true, false): + return violations.map { + if $0.severity == .error { + return $0.with(severity: .warning) + } else { + return $0 + } + } + + case (false, true): + return violations.map { + if $0.severity == .warning { + return $0.with(severity: .error) + } else { + return $0 + } + } + + case (true, true): + queuedFatalError("Invalid command line options: 'lenient' and 'strict' are mutually exclusive.") + } + } + + private static func autocorrect(_ options: LintOrAnalyzeOptions) async throws { + let storage = RuleStorage() + let configuration = Configuration(options: options) + let correctionsBuilder = CorrectionsBuilder() + let files = try await configuration + .visitLintableFiles(options: options, cache: nil, storage: storage) { linter in + if options.format { + switch configuration.indentation { + case .tabs: + linter.format(useTabs: true, indentWidth: 4) + case .spaces(let count): + linter.format(useTabs: false, indentWidth: count) + } + } + + let corrections = linter.correct(using: storage) + if !corrections.isEmpty && !options.quiet { + if options.useSTDIN { + queuedPrint(linter.file.contents) + } else { + if options.progress { + await correctionsBuilder.append(corrections) + } else { + let correctionLogs = corrections.map(\.consoleDescription) + queuedPrint(correctionLogs.joined(separator: "\n")) + } + } + } + } + + if !options.quiet { + if options.progress { + let corrections = await correctionsBuilder.corrections + if !corrections.isEmpty { + let correctionLogs = corrections.map(\.consoleDescription) + options.writeToOutput(correctionLogs.joined(separator: "\n")) + } + } + + let pluralSuffix = { (collection: [Any]) -> String in + return collection.count != 1 ? "s" : "" + } + queuedPrintError("Done correcting \(files.count) file\(pluralSuffix(files))!") + } + } +} + +struct LintOrAnalyzeOptions { + let mode: LintOrAnalyzeMode + let paths: [String] + let useSTDIN: Bool + let configurationFiles: [String] + let strict: Bool + let lenient: Bool + let forceExclude: Bool + let useExcludingByPrefix: Bool + let useScriptInputFiles: Bool + let benchmark: Bool + let reporter: String? + let quiet: Bool + let output: String? + let progress: Bool + let cachePath: String? + let ignoreCache: Bool + let enableAllRules: Bool + let autocorrect: Bool + let format: Bool + let compilerLogPath: String? + let compileCommands: String? + let inProcessSourcekit: Bool + + var verb: String { + if autocorrect { + return "correcting" + } else { + return mode.verb + } + } +} + +private class LintOrAnalyzeResultBuilder { + var fileBenchmark = Benchmark(name: "files") + var ruleBenchmark = Benchmark(name: "rules") + var violations = [StyleViolation]() + let storage = RuleStorage() + let configuration: Configuration + let reporter: Reporter.Type + let cache: LinterCache? + let options: LintOrAnalyzeOptions + + init(_ options: LintOrAnalyzeOptions) { + let config = Signposts.record(name: "LintOrAnalyzeCommand.ParseConfiguration") { + Configuration(options: options) + } + configuration = config + reporter = reporterFrom(identifier: options.reporter ?? config.reporter) + if options.ignoreCache || ProcessInfo.processInfo.isLikelyXcodeCloudEnvironment { + cache = nil + } else { + cache = LinterCache(configuration: config) + } + self.options = options + + if let outFile = options.output { + do { + try Data().write(to: URL(fileURLWithPath: outFile)) + } catch { + queuedPrintError("Could not write to file at path \(outFile)") + } + } + } + + func report(violations: [StyleViolation], realtimeCondition: Bool) { + if (reporter.isRealtime && (!options.progress || options.output != nil)) == realtimeCondition { + let report = reporter.generateReport(violations) + if !report.isEmpty { + options.writeToOutput(report) + } + } + } +} + +private extension LintOrAnalyzeOptions { + func writeToOutput(_ string: String) { + guard let outFile = output else { + queuedPrint(string) + return + } + + do { + let outFileURL = URL(fileURLWithPath: outFile) + let fileUpdater = try FileHandle(forUpdating: outFileURL) + fileUpdater.seekToEndOfFile() + fileUpdater.write(Data((string + "\n").utf8)) + fileUpdater.closeFile() + } catch { + queuedPrintError("Could not write to file at path \(outFile)") + } + } +} + +private actor CorrectionsBuilder { + private(set) var corrections: [Correction] = [] + + func append(_ corrections: [Correction]) { + self.corrections.append(contentsOf: corrections) + } +} + +private func memoryUsage() -> String? { +#if os(Linux) + return nil +#else + var info = mach_task_basic_info() + let basicInfoCount = MemoryLayout.stride / MemoryLayout.stride + var count = mach_msg_type_number_t(basicInfoCount) + + let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) { + $0.withMemoryRebound(to: integer_t.self, capacity: basicInfoCount) { + task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count) + } + } + + if kerr == KERN_SUCCESS { + let bytes = Measurement(value: Double(info.resident_size), unit: .bytes) + let formatted = ByteCountFormatter().string(from: bytes) + return "Memory used: \(formatted)" + } else { + let errorMessage = String(cString: mach_error_string(kerr), encoding: .ascii) + return "Error with task_info(): \(errorMessage ?? "unknown")" + } +#endif +} diff --git a/Sources/Cargo/swiftlint/Helpers/LintableFilesVisitor.swift b/Sources/Cargo/swiftlint/Helpers/LintableFilesVisitor.swift new file mode 100644 index 00000000..1d92cf17 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/LintableFilesVisitor.swift @@ -0,0 +1,253 @@ +import Foundation +import SourceKittenFramework +import SwiftLintFramework + +typealias File = String +typealias Arguments = [String] + +class CompilerInvocations { + static func buildLog(compilerInvocations: [[String]]) -> CompilerInvocations { + return ArrayCompilerInvocations(invocations: compilerInvocations) + } + + static func compilationDatabase(compileCommands: [File: Arguments]) -> CompilerInvocations { + return CompilationDatabaseInvocations(compileCommands: compileCommands) + } + + /// Default implementation + func arguments(forFile path: String?) -> Arguments { [] } + + // MARK: - Private + + private class ArrayCompilerInvocations: CompilerInvocations { + private let invocationsByArgument: [String: [Arguments]] + + init(invocations: [Arguments]) { + // Store invocations by the path, so next when we'll be asked for arguments, + // we'll be able to return them faster + self.invocationsByArgument = invocations.reduce(into: [:]) { result, arguments in + arguments.forEach { result[$0, default: []].append(arguments) } + } + } + + override func arguments(forFile path: String?) -> Arguments { + return path.flatMap { path in + return invocationsByArgument[path]?.first + } ?? [] + } + } + + private class CompilationDatabaseInvocations: CompilerInvocations { + private let compileCommands: [File: Arguments] + + init(compileCommands: [File: Arguments]) { + self.compileCommands = compileCommands + } + + override func arguments(forFile path: String?) -> Arguments { + return path.flatMap { path in + return compileCommands[path] ?? + compileCommands[path.path(relativeTo: FileManager.default.currentDirectoryPath)] + } ?? [] + } + } +} + +enum LintOrAnalyzeModeWithCompilerArguments { + case lint + case analyze(allCompilerInvocations: CompilerInvocations) +} + +private func resolveParamsFiles(args: [String]) -> [String] { + return args.reduce(into: []) { (allArgs: inout [String], arg: String) -> Void in + if arg.hasPrefix("@"), let contents = try? String(contentsOfFile: String(arg.dropFirst())) { + allArgs.append(contentsOf: resolveParamsFiles(args: contents.split(separator: "\n").map(String.init))) + } else { + allArgs.append(arg) + } + } +} + +struct LintableFilesVisitor { + let paths: [String] + let action: String + let useSTDIN: Bool + let quiet: Bool + let showProgressBar: Bool + let useScriptInputFiles: Bool + let forceExclude: Bool + let useExcludingByPrefix: Bool + let cache: LinterCache? + let parallel: Bool + let allowZeroLintableFiles: Bool + let mode: LintOrAnalyzeModeWithCompilerArguments + let block: (CollectedLinter) async -> Void + + private init(paths: [String], action: String, useSTDIN: Bool, quiet: Bool, showProgressBar: Bool, + useScriptInputFiles: Bool, forceExclude: Bool, useExcludingByPrefix: Bool, + cache: LinterCache?, compilerInvocations: CompilerInvocations?, + allowZeroLintableFiles: Bool, block: @escaping (CollectedLinter) async -> Void) { + self.paths = resolveParamsFiles(args: paths) + self.action = action + self.useSTDIN = useSTDIN + self.quiet = quiet + self.showProgressBar = showProgressBar + self.useScriptInputFiles = useScriptInputFiles + self.forceExclude = forceExclude + self.useExcludingByPrefix = useExcludingByPrefix + self.cache = cache + if let compilerInvocations { + self.mode = .analyze(allCompilerInvocations: compilerInvocations) + // SourceKit had some changes in 5.6 that makes it ~100x more expensive + // to process files concurrently. By processing files serially, it's + // only 2x slower than before. + self.parallel = SwiftVersion.current < .fiveDotSix + } else { + self.mode = .lint + self.parallel = true + } + self.block = block + self.allowZeroLintableFiles = allowZeroLintableFiles + } + + static func create(_ options: LintOrAnalyzeOptions, + cache: LinterCache?, + allowZeroLintableFiles: Bool, + block: @escaping (CollectedLinter) async -> Void) + throws -> LintableFilesVisitor { + try Signposts.record(name: "LintableFilesVisitor.Create") { + let compilerInvocations: CompilerInvocations? + if options.mode == .lint { + compilerInvocations = nil + } else { + compilerInvocations = try loadCompilerInvocations(options) + } + + return LintableFilesVisitor( + paths: options.paths, action: options.verb.bridge().capitalized, + useSTDIN: options.useSTDIN, quiet: options.quiet, + showProgressBar: options.progress, + useScriptInputFiles: options.useScriptInputFiles, + forceExclude: options.forceExclude, + useExcludingByPrefix: options.useExcludingByPrefix, + cache: cache, + compilerInvocations: compilerInvocations, + allowZeroLintableFiles: allowZeroLintableFiles, block: block + ) + } + } + + func shouldSkipFile(atPath path: String?) -> Bool { + switch self.mode { + case .lint: + return false + case let .analyze(compilerInvocations): + let compilerArguments = compilerInvocations.arguments(forFile: path) + return compilerArguments.isEmpty + } + } + + func linter(forFile file: SwiftLintFile, configuration: Configuration) -> Linter { + switch self.mode { + case .lint: + return Linter(file: file, configuration: configuration, cache: cache) + case let .analyze(compilerInvocations): + let compilerArguments = compilerInvocations.arguments(forFile: file.path) + return Linter(file: file, configuration: configuration, compilerArguments: compilerArguments) + } + } + + private static func loadCompilerInvocations(_ options: LintOrAnalyzeOptions) throws -> CompilerInvocations { + if let path = options.compilerLogPath { + guard let compilerInvocations = self.loadLogCompilerInvocations(path) else { + throw SwiftLintError.usageError(description: "Could not read compiler log at path: '\(path)'") + } + + return .buildLog(compilerInvocations: compilerInvocations) + } else if let path = options.compileCommands { + do { + return .compilationDatabase(compileCommands: try self.loadCompileCommands(path)) + } catch { + throw SwiftLintError.usageError( + description: "Could not read compilation database at path: '\(path)' \(error.localizedDescription)" + ) + } + } + + throw SwiftLintError.usageError(description: "Could not read compiler invocations") + } + + private static func loadLogCompilerInvocations(_ path: String) -> [[String]]? { + if let data = FileManager.default.contents(atPath: path), + let logContents = String(data: data, encoding: .utf8) { + if logContents.isEmpty { + return nil + } + + return CompilerArgumentsExtractor.allCompilerInvocations(compilerLogs: logContents) + } + + return nil + } + + private static func loadCompileCommands(_ path: String) throws -> [File: Arguments] { + guard let fileContents = FileManager.default.contents(atPath: path) else { + throw CompileCommandsLoadError.nonExistentFile(path) + } + + if path.hasSuffix(".yaml") || path.hasSuffix(".yml") { + // Assume this is a SwiftPM yaml file + return try SwiftPMCompilationDB.parse(yaml: fileContents) + } + + guard let object = try? JSONSerialization.jsonObject(with: fileContents), + let compileDB = object as? [[String: Any]] else { + throw CompileCommandsLoadError.malformedCommands(path) + } + + // Convert the compilation database to a dictionary, with source files as keys and compiler arguments as values. + // + // Compilation databases are an array of dictionaries. Each dict has "file" and "arguments" keys. + var commands = [File: Arguments]() + for (index, entry) in compileDB.enumerated() { + guard let file = entry["file"] as? String else { + throw CompileCommandsLoadError.malformedFile(path, index) + } + + guard let arguments = entry["arguments"] as? [String] else { + throw CompileCommandsLoadError.malformedArguments(path, index) + } + + guard arguments.contains(file) else { + throw CompileCommandsLoadError.missingFileInArguments(path, index, arguments) + } + + commands[file] = arguments.filteringCompilerArguments + } + + return commands + } +} + +private enum CompileCommandsLoadError: LocalizedError { + case nonExistentFile(String) + case malformedCommands(String) + case malformedFile(String, Int) + case malformedArguments(String, Int) + case missingFileInArguments(String, Int, [String]) + + var errorDescription: String? { + switch self { + case let .nonExistentFile(path): + return "Could not read compile commands file at '\(path)'" + case let .malformedCommands(path): + return "Compile commands file at '\(path)' isn't in the correct format" + case let .malformedFile(path, index): + return "Missing or invalid (must be a string) 'file' key in \(path) at index \(index)" + case let .malformedArguments(path, index): + return "Missing or invalid (must be an array of strings) 'arguments' key in \(path) at index \(index)" + case let .missingFileInArguments(path, index, arguments): + return "Entry in \(path) at index \(index) has 'arguments' which do not contain the 'file': \(arguments)" + } + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/ProgressBar.swift b/Sources/Cargo/swiftlint/Helpers/ProgressBar.swift new file mode 100644 index 00000000..0d50555d --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/ProgressBar.swift @@ -0,0 +1,63 @@ +import Dispatch +import Foundation +import SwiftLintFramework + +// Inspired by https://github.com/jkandzi/Progress.swift +actor ProgressBar { + private var index = 1 + private var lastPrintedTime: TimeInterval = 0.0 + private let startTime = uptime() + private let count: Int + + init(count: Int) { + self.count = count + } + + func initialize() { + // When progress is printed, the previous line is reset, so print an empty line before anything else + queuedPrintError("") + } + + func printNext() { + guard index <= count else { return } + + let currentTime = uptime() + if currentTime - lastPrintedTime > 0.1 || index == count { + let lineReset = "\u{1B}[1A\u{1B}[K" + let bar = makeBar() + let timeEstimate = makeTimeEstimate(currentTime: currentTime) + let lineContents = "\(index) of \(count) \(bar) \(timeEstimate)" + queuedPrintError("\(lineReset)\(lineContents)") + lastPrintedTime = currentTime + } + + index += 1 + } + + // MARK: - Private + + private func makeBar() -> String { + let barLength = 30 + let completedBarElements = Int(Double(barLength) * (Double(index) / Double(count))) + let barArray = Array(repeating: "=", count: completedBarElements) + + Array(repeating: " ", count: barLength - completedBarElements) + return "[\(barArray.joined())]" + } + + private func makeTimeEstimate(currentTime: TimeInterval) -> String { + let totalTime = currentTime - startTime + let itemsPerSecond = Double(index) / totalTime + let estimatedTimeRemaining = Double(count - index) / itemsPerSecond + let estimatedTimeRemainingString = "\(Int(estimatedTimeRemaining))s" + return "ETA: \(estimatedTimeRemainingString) (\(Int(itemsPerSecond)) files/s)" + } +} + +#if os(Linux) +// swiftlint:disable:next identifier_name +private let NSEC_PER_SEC = 1_000_000_000 +#endif + +private func uptime() -> TimeInterval { + Double(DispatchTime.now().uptimeNanoseconds) / Double(NSEC_PER_SEC) +} diff --git a/Sources/Cargo/swiftlint/Helpers/RulesFilter.swift b/Sources/Cargo/swiftlint/Helpers/RulesFilter.swift new file mode 100644 index 00000000..f28b81d7 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/RulesFilter.swift @@ -0,0 +1,49 @@ +@_spi(TestHelper) +import SwiftLintFramework + +extension RulesFilter { + struct ExcludingOptions: OptionSet { + let rawValue: Int + + static let enabled = Self(rawValue: 1 << 0) + static let disabled = Self(rawValue: 1 << 1) + static let uncorrectable = Self(rawValue: 1 << 2) + } +} + +class RulesFilter { + private let allRules: RuleList + private let enabledRules: [Rule] + + init(allRules: RuleList = primaryRuleList, enabledRules: [Rule]) { + self.allRules = allRules + self.enabledRules = enabledRules + } + + func getRules(excluding excludingOptions: ExcludingOptions) -> RuleList { + if excludingOptions.isEmpty { + return allRules + } + + let filtered: [Rule.Type] = allRules.list.compactMap { ruleID, ruleType in + let enabledRule = enabledRules.first { rule in + type(of: rule).description.identifier == ruleID + } + let isRuleEnabled = enabledRule != nil + + if excludingOptions.contains(.enabled) && isRuleEnabled { + return nil + } + if excludingOptions.contains(.disabled) && !isRuleEnabled { + return nil + } + if excludingOptions.contains(.uncorrectable) && !(ruleType is CorrectableRule.Type) { + return nil + } + + return ruleType + } + + return RuleList(rules: filtered) + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/Signposts.swift b/Sources/Cargo/swiftlint/Helpers/Signposts.swift new file mode 100644 index 00000000..e58be90b --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/Signposts.swift @@ -0,0 +1,73 @@ +#if canImport(os) +import os.signpost +private let timelineLog = OSLog(subsystem: "io.realm.swiftlint", category: "Timeline") +private let fileLog = OSLog(subsystem: "io.realm.swiftlint", category: "File") +#endif + +struct Signposts { + enum Span { + case timeline, file(String) + } + + static func record(name: StaticString, span: Span = .timeline, body: () throws -> R) rethrows -> R { +#if canImport(os) + let log: OSLog + let description: String? + switch span { + case .timeline: + log = timelineLog + description = nil + case .file(let file): + log = fileLog + description = file + } + let signpostID = OSSignpostID(log: log) + if let description { + os_signpost(.begin, log: log, name: name, signpostID: signpostID, "%{public}s", description) + } else { + os_signpost(.begin, log: log, name: name, signpostID: signpostID) + } + + let result = try body() + if let description { + os_signpost(.end, log: log, name: name, signpostID: signpostID, "%{public}s", description) + } else { + os_signpost(.end, log: log, name: name, signpostID: signpostID) + } + return result +#else + return try body() +#endif + } + + static func record(name: StaticString, span: Span = .timeline, body: () async throws -> R) async rethrows -> R { +#if canImport(os) + let log: OSLog + let description: String? + switch span { + case .timeline: + log = timelineLog + description = nil + case .file(let file): + log = fileLog + description = file + } + let signpostID = OSSignpostID(log: log) + if let description { + os_signpost(.begin, log: log, name: name, signpostID: signpostID, "%{public}s", description) + } else { + os_signpost(.begin, log: log, name: name, signpostID: signpostID) + } + + let result = try await body() + if let description { + os_signpost(.end, log: log, name: name, signpostID: signpostID, "%{public}s", description) + } else { + os_signpost(.end, log: log, name: name, signpostID: signpostID) + } + return result +#else + return try await body() +#endif + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/SwiftLintError.swift b/Sources/Cargo/swiftlint/Helpers/SwiftLintError.swift new file mode 100644 index 00000000..cf17a123 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/SwiftLintError.swift @@ -0,0 +1,12 @@ +import Foundation + +enum SwiftLintError: LocalizedError { + case usageError(description: String) + + var errorDescription: String? { + switch self { + case .usageError(let description): + return description + } + } +} diff --git a/Sources/Cargo/swiftlint/Helpers/SwiftPMCompilationDB.swift b/Sources/Cargo/swiftlint/Helpers/SwiftPMCompilationDB.swift new file mode 100644 index 00000000..b71ea344 --- /dev/null +++ b/Sources/Cargo/swiftlint/Helpers/SwiftPMCompilationDB.swift @@ -0,0 +1,74 @@ +import Foundation +import Yams + +private struct SwiftPMCommand: Codable { + let tool: String + let module: String? + let sources: [String]? + let args: [String]? + let importPaths: [String]? + + enum CodingKeys: String, CodingKey { + case tool + case module = "module-name" + case sources + case args = "other-args" + case importPaths = "import-paths" + } +} + +private struct SwiftPMNode: Codable {} + +private struct SwiftPMNodes: Codable { + let nodes: [String: SwiftPMNode] +} + +struct SwiftPMCompilationDB: Codable { + private let commands: [String: SwiftPMCommand] + + static func parse(yaml: Data) throws -> [File: Arguments] { + let decoder = YAMLDecoder() + let compilationDB: SwiftPMCompilationDB + + if ProcessInfo.processInfo.environment["TEST_SRCDIR"] != nil { + // Running tests + let nodes = try decoder.decode(SwiftPMNodes.self, from: yaml) + let suffix = "/Source/swiftlint/" + let pathToReplace = Array(nodes.nodes.keys.filter({ node in + node.hasSuffix(suffix) + }))[0].dropLast(suffix.count - 1) + let stringFileContents = String(data: yaml, encoding: .utf8)! + .replacingOccurrences(of: pathToReplace, with: "") + compilationDB = try decoder.decode(Self.self, from: stringFileContents) + } else { + compilationDB = try decoder.decode(Self.self, from: yaml) + } + + let swiftCompilerCommands = compilationDB.commands + .filter { $0.value.tool == "swift-compiler" } + let allSwiftSources = swiftCompilerCommands + .flatMap { $0.value.sources ?? [] } + .filter { $0.hasSuffix(".swift") } + return Dictionary(uniqueKeysWithValues: allSwiftSources.map { swiftSource in + let command = swiftCompilerCommands + .values + .first { $0.sources?.contains(swiftSource) == true } + + guard let command, + let module = command.module, + let sources = command.sources, + let arguments = command.args, + let importPaths = command.importPaths + else { + return (swiftSource, []) + } + + let args = ["-module-name", module] + + sources + + arguments.filteringCompilerArguments + + ["-I"] + importPaths + + return (swiftSource, args) + }) + } +} diff --git a/Sources/Cargo/xcframework/BuildSetting.swift b/Sources/Cargo/xcframework/BuildSetting.swift new file mode 100644 index 00000000..2762c0a2 --- /dev/null +++ b/Sources/Cargo/xcframework/BuildSetting.swift @@ -0,0 +1,59 @@ +// +// BuildSettings.swift +// Cargo +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + + +//set -eu; +// +//BUILT_SRC="./em_proxy/$LIB_FILE_NAME.a" +//ln -f -- "$BUILT_SRC" "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" || cp "$BUILT_SRC" "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" +//echo "$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH" + +//# generated with cargo-xcode 1.5.0 +//# modified to use prebuilt binaries +// +//set -eu; +// +//BUILT_SRC="./minimuxer/$LIB_FILE_NAME.a" +//ln -f -- "$BUILT_SRC" "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" || cp "$BUILT_SRC" "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" +//echo "$BUILT_SRC -> $TARGET_BUILD_DIR/$EXECUTABLE_PATH" +// +//# xcode generates dep file, but for its own path, so append our rename to it +// #DEP_FILE_SRC="minimuxer/target/${CARGO_XCODE_TARGET_TRIPLE}/release/${CARGO_XCODE_CARGO_DEP_FILE_NAME}" +// #if [ -f "$DEP_FILE_SRC" ]; then +//# DEP_FILE_DST="${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d" +//# cp -f "$DEP_FILE_SRC" "$DEP_FILE_DST" +//# echo >> "$DEP_FILE_DST" "$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC" +//#fi +// +//# lipo script needs to know all the platform-specific files that have been built +//# archs is in the file name, so that paths don't stay around after archs change +//# must match input for LipoScript +// #FILE_LIST="${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist" +// #touch "$FILE_LIST" +// #if ! egrep -q "$SCRIPT_OUTPUT_FILE_0" "$FILE_LIST" ; then +//# echo >> "$FILE_LIST" "$SCRIPT_OUTPUT_FILE_0" +//#fi + + +import ArgumentParser + +/// A representation of a build setting in an Xcode project, e.g. +/// `IPHONEOS_DEPLOYMENT_TARGET=13.0` +struct BuildSetting: ExpressibleByArgument { + /// The name of the build setting, e.g. `IPHONEOS_DEPLOYMENT_TARGET` + let name: String + /// The value of the build setting + let value: String + + init?(argument: String) { + let components = argument.components(separatedBy: "=") + guard components.count == 2 else { return nil } + name = components[0].trimmingCharacters(in: .whitespacesAndNewlines) + value = components[1].trimmingCharacters(in: .whitespacesAndNewlines) + } +} diff --git a/Sources/Cargo/xcframework/Command+Options.swift b/Sources/Cargo/xcframework/Command+Options.swift new file mode 100644 index 00000000..0f80d5b6 --- /dev/null +++ b/Sources/Cargo/xcframework/Command+Options.swift @@ -0,0 +1,71 @@ +// +// Command+Options.swift +// Cargo +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import ArgumentParser +import PackageModel + +extension Command { + struct Options: ParsableArguments { + // MARK: - Package Loading + + @Option(help: ArgumentHelp("The location of the Package", valueName: "directory")) + var packagePath = "." + + // MARK: - Building + + @Option(help: ArgumentHelp("The location of the build/cache directory to use", valueName: "directory")) + var buildPath = ".build" + + @Option(help: ArgumentHelp("Build with a specific configuration", valueName: "debug|release")) + var configuration = PackageModel.BuildConfiguration.release + + @Flag(inversion: .prefixedNo, help: "Whether to clean before we build") + var clean = true + + @Flag(inversion: .prefixedNo, help: "Whether to include debug symbols in the built XCFramework") + var debugSymbols = true + + @Flag(help: "Prints the available products and targets") + var listProducts = false + + @Option(help: "The path to a .xcconfig file that can be used to override Xcode build settings. Relative to the package path.") + var xcconfig: String? + + @Flag(help: "Enables Library Evolution for the whole build stack. Normally we apply it only to the targets listed to be built to work around issues with projects that don't support it.") + var stackEvolution: Bool = false + + @Option(help: ArgumentHelp("Arbitrary Xcode build settings that are passed directly to the `xcodebuild` invocation. Can be specified multiple times.", valueName: "NAME=VALUE")) + var xcSetting: [BuildSetting] = [] + + // MARK: - Output Options + + @Option( + help: ArgumentHelp( + "A list of platforms you want to build for. Can be specified multiple times." + + " Default is to build for all platforms supported in your Package.swift, or all Apple platforms (except for maccatalyst platform) if omitted", + valueName: TargetPlatform.allCases.map { $0.rawValue }.joined(separator: "|") + ) + ) + var platform: [TargetPlatform] = [] + + @Option(help: ArgumentHelp("Where to place the compiled library", valueName: "directory")) + var output = "." + + @Flag(help: .hidden) + var githubAction: Bool = false + + // MARK: - Targets + + @Argument(help: "An optional list of products (or targets) to build. Defaults to building all `.library` products") + var products: [String] = [] + } +} + +// MARK: - ParsableArguments Extensions + +extension PackageModel.BuildConfiguration: ExpressibleByArgument {} diff --git a/Sources/Cargo/xcframework/Command.swift b/Sources/Cargo/xcframework/Command.swift new file mode 100644 index 00000000..a02805ca --- /dev/null +++ b/Sources/Cargo/xcframework/Command.swift @@ -0,0 +1,142 @@ +// +// Command.swift +// Cargo +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import ArgumentParser +import Foundation +import PackageLoading +import PackageModel +import TSCBasic +import Workspace +import Xcodeproj + +struct Command: ParsableCommand { + // MARK: - Configuration + + static var configuration = CommandConfiguration( + abstract: "Builds a `rust` package using `cargo`.", + discussion: + """ + + """, + version: "1.1.0" + ) + + // MARK: - Arguments + + @OptionGroup() + var options: Options + + // MARK: - Execution + + // swiftlint:disable:next function_body_length + func run() throws { + // load all/validate of the package info + let package = try PackageInfo(options: options) + + // validate that package to make sure we can generate it + let validation = package.validationErrors() + if validation.isEmpty == false { + for error in validation { + print(error.isFatal ? "Error:" : "Warning:", error.errorDescription!) + } + if validation.contains(where: { $0.isFatal }) { + Darwin.exit(1) + } + } + + // generate the Xcode project file + let generator = ProjectGenerator(package: package) + + let platforms = try package.supportedPlatforms() + + // get what we're building + try generator.writeDistributionXcconfig() + let project = try generator.generate() + + // printing packages? + if options.listProducts { + package.printAllProducts(project: project) + Darwin.exit(0) + } + + // get valid packages and their SDKs + let productNames = try package.validProductNames(project: project) + let sdks = platforms.flatMap { $0.sdks } + + // we've applied the xcconfig to everything, but some dependencies (*cough* swift-nio) + // have build errors, so we remove it from targets we're not building + if options.stackEvolution == false { + try project.enableDistribution(targets: productNames, xcconfig: AbsolutePath(package.distributionBuildXcconfig.path).relative(to: AbsolutePath(package.rootDirectory.path))) + } + + // save the project + try project.save(to: generator.projectPath) + + // start building + let builder = XcodeBuilder(project: project, projectPath: generator.projectPath, package: package, options: options) + + // clean first + if options.clean { + try builder.clean() + } + + // all of our targets for each platform, then group the resulting .frameworks by target + var frameworkFiles: [String: [XcodeBuilder.BuildResult]] = [:] + + for sdk in sdks { + try builder.build(targets: productNames, sdk: sdk) + .forEach { pair in + if frameworkFiles[pair.key] == nil { + frameworkFiles[pair.key] = [] + } + frameworkFiles[pair.key]?.append(pair.value) + } + } + + var xcframeworkFiles: [(String, Foundation.URL)] = [] + + // then we merge the resulting frameworks + try frameworkFiles + .forEach { pair in + xcframeworkFiles.append((pair.key, try builder.merge(target: pair.key, buildResults: pair.value))) + } + + // zip it up if thats what they want + if options.zip { + let zipper = Zipper(package: package) + let zipped = try xcframeworkFiles + .flatMap { pair -> [Foundation.URL] in + let zip = try zipper.zip(target: pair.0, version: self.options.zipVersion, file: pair.1) + let checksum = try zipper.checksum(file: zip) + try zipper.clean(file: pair.1) + + return [zip, checksum] + } + + // notify the action if we have one + if options.githubAction { + let zips = zipped.map { $0.path }.joined(separator: "\n") + let data = Data(zips.utf8) + let url = Foundation.URL(fileURLWithPath: options.buildPath).appendingPathComponent("xcframework-zipfile.url") + try data.write(to: url) + } + } + } +} + +// MARK: - Errors + +private enum Error: Swift.Error, LocalizedError { + case noProducts + + var errorDescription: String? { + switch self { + case .noProducts: return "" + } + } +} diff --git a/Sources/Cargo/xcframework/Extensions/Collection+Extensions.swift b/Sources/Cargo/xcframework/Extensions/Collection+Extensions.swift new file mode 100644 index 00000000..aea8216d --- /dev/null +++ b/Sources/Cargo/xcframework/Extensions/Collection+Extensions.swift @@ -0,0 +1,12 @@ +// +// Collection-Extensions.swift +// swift-create-xcframework +// +// Created by Rob Amos on 9/5/20. +// + +extension Collection { + var nonEmpty: Self? { + isEmpty ? nil : self + } +} diff --git a/Sources/Cargo/xcframework/Extensions/PackageModel+Extensions.swift b/Sources/Cargo/xcframework/Extensions/PackageModel+Extensions.swift new file mode 100644 index 00000000..8f4e8d8a --- /dev/null +++ b/Sources/Cargo/xcframework/Extensions/PackageModel+Extensions.swift @@ -0,0 +1,27 @@ +// +// PackageDescription+Extensions.swift +// swift-create-xcframework +// +// Created by Rob Amos on 7/5/20. +// + +import PackageModel + +extension ProductType { + var isLibrary: Bool { + if case .library = self { + return true + } + return false + } +} + +extension Manifest { + var libraryProductNames: [String] { + products + .compactMap { product in + guard product.type.isLibrary else { return nil } + return product.name + } + } +} diff --git a/Sources/Cargo/xcframework/Platforms.swift b/Sources/Cargo/xcframework/Platforms.swift new file mode 100644 index 00000000..f1c7c484 --- /dev/null +++ b/Sources/Cargo/xcframework/Platforms.swift @@ -0,0 +1,113 @@ +// +// Platforms.swift +// Cargo +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import ArgumentParser +import PackageModel + +enum TargetPlatform: String, ExpressibleByArgument, CaseIterable { + case ios + case macos + case maccatalyst + case tvos + case watchos + + init?(argument: String) { + self.init(rawValue: argument.lowercased()) + } + + var platformName: String { + switch self { + case .ios: "ios" + case .macos: "macos" + case .maccatalyst: "macos" + case .tvos: "tvos" + case .watchos: "watchos" + } + } + + // MARK: - Target SDKs + + struct SDK { + let destination: String + let archiveName: String + let releaseFolder: String + let buildSettings: [String: String]? + } + + var sdks: [SDK] { + switch self { + case .ios: + return [ + SDK( + destination: "generic/platform=iOS", + archiveName: "iphoneos.xcarchive", + releaseFolder: "Release-iphoneos", + buildSettings: nil + ), + SDK( + destination: "generic/platform=iOS Simulator", + archiveName: "iphonesimulator.xcarchive", + releaseFolder: "Release-iphonesimulator", + buildSettings: nil + ) + ] + + case .macos: + return [ + SDK( + destination: "generic/platform=macOS,name=Any Mac", + archiveName: "macos.xcarchive", + releaseFolder: "Release", + buildSettings: nil + ) + ] + + case .maccatalyst: + return [ + SDK( + destination: "generic/platform=macOS,variant=Mac Catalyst", + archiveName: "maccatalyst.xcarchive", + releaseFolder: "Release-maccatalyst", + buildSettings: ["SUPPORTS_MACCATALYST": "YES"] + ) + ] + + case .tvos: + return [ + SDK( + destination: "generic/platform=tvOS", + archiveName: "appletvos.xcarchive", + releaseFolder: "Release-appletvos", + buildSettings: nil + ), + SDK( + destination: "generic/platform=tvOS Simulator", + archiveName: "appletvsimulator.xcarchive", + releaseFolder: "Release-appletvsimulator", + buildSettings: nil + ) + ] + + case .watchos: + return [ + SDK( + destination: "generic/platform=watchOS", + archiveName: "watchos.xcarchive", + releaseFolder: "Release-watchos", + buildSettings: nil + ), + SDK( + destination: "generic/platform=watchOS Simulator", + archiveName: "watchsimulator.xcarchive", + releaseFolder: "Release-watchsimulator", + buildSettings: nil + ) + ] + } + } +} diff --git a/Sources/Cargo/xcframework/main.swift b/Sources/Cargo/xcframework/main.swift new file mode 100644 index 00000000..e536e09c --- /dev/null +++ b/Sources/Cargo/xcframework/main.swift @@ -0,0 +1,9 @@ +// +// main.swift +// Cargo +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +Command.main() diff --git a/EmotionalDamage/EmotionalDamage.swift b/Sources/EmotionalDamage/EmotionalDamage.swift similarity index 85% rename from EmotionalDamage/EmotionalDamage.swift rename to Sources/EmotionalDamage/EmotionalDamage.swift index 163bdfc9..8ac1d2bd 100644 --- a/EmotionalDamage/EmotionalDamage.swift +++ b/Sources/EmotionalDamage/EmotionalDamage.swift @@ -6,11 +6,12 @@ // import Foundation +import em_proxy public func start_em_proxy(bind_addr: String) { let host = NSString(string: bind_addr) let host_pointer = UnsafeMutablePointer(mutating: host.utf8String) - let _ = start_emotional_damage(host_pointer) + _ = start_emotional_damage(host_pointer) } public func stop_em_proxy() { diff --git a/minimuxer/minimuxer.swift b/Sources/MiniMuxerSwift/MiniMuxer.swift similarity index 67% rename from minimuxer/minimuxer.swift rename to Sources/MiniMuxerSwift/MiniMuxer.swift index fb024f63..47bc2e22 100644 --- a/minimuxer/minimuxer.swift +++ b/Sources/MiniMuxerSwift/MiniMuxer.swift @@ -6,6 +6,8 @@ // import Foundation +import os.log +import minimuxer public enum Uhoh: Error { case Good @@ -27,16 +29,16 @@ public func set_usbmuxd_socket() { public func debug_app(app_id: String) throws -> Uhoh { let ai = NSString(string: app_id) let ai_pointer = UnsafeMutablePointer(mutating: ai.utf8String) - #if false // Retries - var res = minimuxer_debug_app(ai_pointer) - var attempts = 10 - while (attempts != 0 && res != 0) { - print("(JIT) ATTEMPTS: \(attempts)") - res = minimuxer_debug_app(ai_pointer) - attempts -= 1 - } + #if true // Retries + var res = minimuxer_debug_app(ai_pointer) + var attempts = 10 + while attempts != 0, res != 0 { + os_log("(JIT) ATTEMPTS: %@", type: .debug, attempts) + res = minimuxer_debug_app(ai_pointer) + attempts -= 1 + } #else - let res = minimuxer_debug_app(ai_pointer) + let res = minimuxer_debug_app(ai_pointer) #endif if res != 0 { throw Uhoh.Bad(code: res) @@ -49,15 +51,15 @@ public func install_provisioning_profile(plist: Data) throws -> Uhoh { print(pls) print(plist) #if false // Retries - var res = minimuxer_install_provisioning_profile(x, UInt32(plist.count)) - var attempts = 10 - while (attempts != 0 && res != 0) { - print("(INSTALL) ATTEMPTS: \(attempts)") - res = minimuxer_install_provisioning_profile(x, UInt32(plist.count)) - attempts -= 1 - } + var res = minimuxer_install_provisioning_profile(x, UInt32(plist.count)) + var attempts = 10 + while attempts != 0, res != 0 { + print("(INSTALL) ATTEMPTS: \(attempts)") + res = minimuxer_install_provisioning_profile(x, UInt32(plist.count)) + attempts -= 1 + } #else - let x = plist.withUnsafeBytes { buf in UnsafeMutableRawPointer(mutating: buf) } + let x = plist.withUnsafeBytes { buf in UnsafeMutableRawPointer(mutating: buf) } #endif let res = minimuxer_install_provisioning_profile(x, UInt32(plist.count)) if res != 0 { @@ -70,15 +72,15 @@ public func remove_provisioning_profile(id: String) throws -> Uhoh { let id_ns = NSString(string: id) let id_pointer = UnsafeMutablePointer(mutating: id_ns.utf8String) #if false // Retries - var res = minimuxer_remove_provisioning_profile(id_pointer) - var attempts = 10 - while (attempts != 0 && res != 0) { - print("(REMOVE PROFILE) ATTEMPTS: \(attempts)") - res = minimuxer_remove_provisioning_profile(id_pointer) - attempts -= 1 - } + var res = minimuxer_remove_provisioning_profile(id_pointer) + var attempts = 10 + while attempts != 0, res != 0 { + print("(REMOVE PROFILE) ATTEMPTS: \(attempts)") + res = minimuxer_remove_provisioning_profile(id_pointer) + attempts -= 1 + } #else - let res = minimuxer_remove_provisioning_profile(id_pointer) + let res = minimuxer_remove_provisioning_profile(id_pointer) #endif if res != 0 { throw Uhoh.Bad(code: res) diff --git a/Sources/Shared/AltConstants.swift b/Sources/Shared/AltConstants.swift new file mode 100644 index 00000000..9e9b4096 --- /dev/null +++ b/Sources/Shared/AltConstants.swift @@ -0,0 +1,10 @@ +// +// AltConstants.swift +// +// +// Created by Joseph Mattiello on 2/28/23. +// + +import Foundation + +public let ALTDeviceListeningSocket: UInt16 = 28151 diff --git a/Sources/Shared/CFNotificationName+AltStore.swift b/Sources/Shared/CFNotificationName+AltStore.swift new file mode 100644 index 00000000..ad86f547 --- /dev/null +++ b/Sources/Shared/CFNotificationName+AltStore.swift @@ -0,0 +1,13 @@ +// +// CFNotificationName+SideStore.swift +// SideKit +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import Foundation + +public let ALTWiredServerConnectionAvailableRequest = CFNotificationName("io.altstore.Request.WiredServerConnectionAvailable" as CFString) +public let ALTWiredServerConnectionAvailableResponse = CFNotificationName("io.altstore.Response.WiredServerConnectionAvailable" as CFString) +public let ALTWiredServerConnectionStartRequest = CFNotificationName("io.altstore.Request.WiredServerConnectionStart" as CFString) diff --git a/Shared/Connections/Connection.swift b/Sources/Shared/Connections/Connection.swift similarity index 66% rename from Shared/Connections/Connection.swift rename to Sources/Shared/Connections/Connection.swift index 4caa0fc4..5cd1ae2c 100644 --- a/Shared/Connections/Connection.swift +++ b/Sources/Shared/Connections/Connection.swift @@ -15,104 +15,85 @@ public protocol SideConnection: Connection { func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void) } -public extension SideConnection -{ - func send(_ data: Data, completionHandler: @escaping (Result) -> Void) - { - self.__send(data) { (success, error) in - let result = Result(success, error).mapError { (failure :Error) -> ALTServerError in - guard let nwError = failure as? NWError else { return ALTServerError.init(failure) } - return ALTServerError.lostConnection(underlyingError: nwError) - - } - - completionHandler(result) - } - } - - func receiveData(expectedSize: Int, completionHandler: @escaping (Result) -> Void) - { - self.__receiveData(expectedSize: expectedSize) { (data, error) in - let result = Result(data, error).mapError { (failure :Error) -> ALTServerError in - guard let nwError = failure as? NWError else { return ALTServerError.init(failure) } +public extension SideConnection { + func send(_ data: Data, completionHandler: @escaping (Result) -> Void) { + __send(data) { success, error in + let result = Result(success, error).mapError { (failure: Error) -> ALTServerError in + guard let nwError = failure as? NWError else { return ALTServerError(failure) } return ALTServerError.lostConnection(underlyingError: nwError) } completionHandler(result) } } - - func send(_ response: T, shouldDisconnect: Bool = false, completionHandler: @escaping (Result) -> Void) - { - func finish(_ result: Result) - { + + func receiveData(expectedSize: Int, completionHandler: @escaping (Result) -> Void) { + __receiveData(expectedSize: expectedSize) { data, error in + let result = Result(data, error).mapError { (failure: Error) -> ALTServerError in + guard let nwError = failure as? NWError else { return ALTServerError(failure) } + return ALTServerError.lostConnection(underlyingError: nwError) + } + completionHandler(result) - - if shouldDisconnect - { + } + } + + func send(_ response: T, shouldDisconnect: Bool = false, completionHandler: @escaping (Result) -> Void) { + func finish(_ result: Result) { + completionHandler(result) + + if shouldDisconnect { // Add short delay to prevent us from dropping connection too quickly. DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) { self.disconnect() } } } - - do - { + + do { let data = try JSONEncoder().encode(response) let responseSize = withUnsafeBytes(of: Int32(data.count)) { Data($0) } - - self.send(responseSize) { (result) in - switch result - { - case .failure(let error): finish(.failure(error)) + + send(responseSize) { result in + switch result { + case let .failure(error): finish(.failure(error)) case .success: - self.send(data) { (result) in - switch result - { - case .failure(let error): finish(.failure(error)) + self.send(data) { result in + switch result { + case let .failure(error): finish(.failure(error)) case .success: finish(.success(())) } } } } - } - catch - { + } catch { finish(.failure(.invalidResponse(underlyingError: error))) } } - - func receiveRequest(completionHandler: @escaping (Result) -> Void) - { + + func receiveRequest(completionHandler: @escaping (Result) -> Void) { let size = MemoryLayout.size - + print("Receiving request size from connection:", self) - self.receiveData(expectedSize: size) { (result) in - do - { + receiveData(expectedSize: size) { result in + do { let data = try result.get() - + let expectedSize = Int(data.withUnsafeBytes { $0.load(as: Int32.self) }) print("Receiving request from connection: \(self)... (\(expectedSize) bytes)") - - self.receiveData(expectedSize: expectedSize) { (result) in - do - { + + self.receiveData(expectedSize: expectedSize) { result in + do { let data = try result.get() let request = try JSONDecoder().decode(ServerRequest.self, from: data) - + print("Received request:", request) completionHandler(.success(request)) - } - catch - { + } catch { completionHandler(.failure(ALTServerError(error))) } } - } - catch - { + } catch { completionHandler(.failure(ALTServerError(error))) } } diff --git a/Shared/Connections/ConnectionManager.swift b/Sources/Shared/Connections/ConnectionManager.swift similarity index 62% rename from Shared/Connections/ConnectionManager.swift rename to Sources/Shared/Connections/ConnectionManager.swift index ce18c155..f2ab04ac 100644 --- a/Shared/Connections/ConnectionManager.swift +++ b/Sources/Shared/Connections/ConnectionManager.swift @@ -10,164 +10,146 @@ import Foundation import Network import SideKit -public protocol RequestHandler -{ +public protocol RequestHandler { func handleAnisetteDataRequest(_ request: AnisetteDataRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) func handlePrepareAppRequest(_ request: PrepareAppRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - + func handleInstallProvisioningProfilesRequest(_ request: InstallProvisioningProfilesRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) func handleRemoveProvisioningProfilesRequest(_ request: RemoveProvisioningProfilesRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - + func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - + func handleEnableUnsignedCodeExecutionRequest(_ request: EnableUnsignedCodeExecutionRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) } -public protocol ConnectionHandler: AnyObject -{ +public protocol ConnectionHandler: AnyObject { associatedtype ConnectionType = Connection var connectionHandler: ((ConnectionType) -> Void)? { get set } var disconnectionHandler: ((ConnectionType) -> Void)? { get set } - + func startListening() func stopListening() } -public class ConnectionManager where ConnectionHandlerType.ConnectionType == ConnectionType -{ +public class ConnectionManager where ConnectionHandlerType.ConnectionType == ConnectionType { public let requestHandler: RequestHandlerType public let connectionHandlers: [ConnectionHandlerType] - + public var isStarted = false - + private var connections = [ConnectionType]() private let connectionsLock = NSLock() - - public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandlerType]) - { + + public init(requestHandler: RequestHandlerType, connectionHandlers: [ConnectionHandlerType]) { self.requestHandler = requestHandler self.connectionHandlers = connectionHandlers - - for handler in connectionHandlers - { - handler.connectionHandler = { [weak self] (connection) in + + for handler in connectionHandlers { + handler.connectionHandler = { [weak self] connection in self?.prepare(connection) } - - handler.disconnectionHandler = { [weak self] (connection) in + + handler.disconnectionHandler = { [weak self] connection in self?.disconnect(connection) } } } - - public func start() - { - guard !self.isStarted else { return } - - for connectionHandler in self.connectionHandlers - { + + public func start() { + guard !isStarted else { return } + + for connectionHandler in connectionHandlers { connectionHandler.startListening() } - - self.isStarted = true + + isStarted = true } - - public func stop() - { - guard self.isStarted else { return } - - for connectionHandler in self.connectionHandlers - { + + public func stop() { + guard isStarted else { return } + + for connectionHandler in connectionHandlers { connectionHandler.stopListening() } - - self.isStarted = false + + isStarted = false } } -private extension ConnectionManager -{ - func prepare(_ connection: ConnectionType) - { - self.connectionsLock.lock() +private extension ConnectionManager { + func prepare(_ connection: ConnectionType) { + connectionsLock.lock() defer { self.connectionsLock.unlock() } - - guard !self.connections.contains(where: { $0 === connection }) else { return } - self.connections.append(connection) - - self.handleRequest(for: connection) + + guard !connections.contains(where: { $0 === connection }) else { return } + connections.append(connection) + + handleRequest(for: connection) } - - func disconnect(_ connection: ConnectionType) - { - self.connectionsLock.lock() + + func disconnect(_ connection: ConnectionType) { + connectionsLock.lock() defer { self.connectionsLock.unlock() } - - guard let index = self.connections.firstIndex(where: { $0 === connection }) else { return } - self.connections.remove(at: index) + + guard let index = connections.firstIndex(where: { $0 === connection }) else { return } + connections.remove(at: index) } - - func handleRequest(for connection: ConnectionType) - { - func finish(_ result: Result) - { - do - { + + func handleRequest(for connection: ConnectionType) { + func finish(_ result: Result) { + do { let response = try result.get() - connection.send(response, shouldDisconnect: true) { (result) in + connection.send(response, shouldDisconnect: true) { result in print("Sent response \(response) with result:", result) } - } - catch - { + } catch { let response = ErrorResponse(error: ALTServerError(error)) - connection.send(response, shouldDisconnect: true) { (result) in + connection.send(response, shouldDisconnect: true) { result in print("Sent error response \(response) with result:", result) } } } - - connection.receiveRequest() { (result) in + + connection.receiveRequest { result in print("Received request with result:", result) - - switch result - { - case .failure(let error): finish(Result.failure(error)) - - case .success(.anisetteData(let request)): - self.requestHandler.handleAnisetteDataRequest(request, for: connection) { (result) in + + switch result { + case let .failure(error): finish(Result.failure(error)) + + case let .success(.anisetteData(request)): + self.requestHandler.handleAnisetteDataRequest(request, for: connection) { result in finish(result) } - - case .success(.prepareApp(let request)): - self.requestHandler.handlePrepareAppRequest(request, for: connection) { (result) in + + case let .success(.prepareApp(request)): + self.requestHandler.handlePrepareAppRequest(request, for: connection) { result in finish(result) } - + case .success(.beginInstallation): break - - case .success(.installProvisioningProfiles(let request)): - self.requestHandler.handleInstallProvisioningProfilesRequest(request, for: connection) { (result) in + + case let .success(.installProvisioningProfiles(request)): + self.requestHandler.handleInstallProvisioningProfilesRequest(request, for: connection) { result in finish(result) } - - case .success(.removeProvisioningProfiles(let request)): - self.requestHandler.handleRemoveProvisioningProfilesRequest(request, for: connection) { (result) in + + case let .success(.removeProvisioningProfiles(request)): + self.requestHandler.handleRemoveProvisioningProfilesRequest(request, for: connection) { result in finish(result) } - - case .success(.removeApp(let request)): - self.requestHandler.handleRemoveAppRequest(request, for: connection) { (result) in + + case let .success(.removeApp(request)): + self.requestHandler.handleRemoveAppRequest(request, for: connection) { result in finish(result) } - - case .success(.enableUnsignedCodeExecution(let request)): - self.requestHandler.handleEnableUnsignedCodeExecutionRequest(request, for: connection) { (result) in + + case let .success(.enableUnsignedCodeExecution(request)): + self.requestHandler.handleEnableUnsignedCodeExecutionRequest(request, for: connection) { result in finish(result) } - + case .success(.unknown): finish(Result.failure(ALTServerError.unknownRequest)) } diff --git a/Shared/Connections/NetworkConnection.swift b/Sources/Shared/Connections/NetworkConnection.swift similarity index 52% rename from Shared/Connections/NetworkConnection.swift rename to Sources/Shared/Connections/NetworkConnection.swift index d81af08b..cb1f22ba 100644 --- a/Shared/Connections/NetworkConnection.swift +++ b/Sources/Shared/Connections/NetworkConnection.swift @@ -10,46 +10,39 @@ import Foundation import Network import SideKit -public class NetworkConnection: NSObject, SideConnection -{ +public class NetworkConnection: NSObject, SideConnection { public let nwConnection: NWConnection - - public init(_ nwConnection: NWConnection) - { + + public init(_ nwConnection: NWConnection) { self.nwConnection = nwConnection } - - public func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) - { - self.nwConnection.send(content: data, completion: .contentProcessed { (error) in + + public func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) { + nwConnection.send(content: data, completion: .contentProcessed { error in completionHandler(error == nil, error) }) } - - public func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void) - { - self.nwConnection.receive(minimumIncompleteLength: expectedSize, maximumLength: expectedSize) { (data, context, isComplete, error) in + + public func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void) { + nwConnection.receive(minimumIncompleteLength: expectedSize, maximumLength: expectedSize) { data, _, _, error in guard data != nil || error != nil else { return completionHandler(nil, ALTServerError.lostConnection(underlyingError: error)) } - + completionHandler(data, error) } } - - public func disconnect() - { - switch self.nwConnection.state - { + + public func disconnect() { + switch nwConnection.state { case .cancelled, .failed: break - default: self.nwConnection.cancel() + default: nwConnection.cancel() } } } -extension NetworkConnection -{ - override public var description: String { - return "\(self.nwConnection.endpoint) (Network)" +public extension NetworkConnection { + override var description: String { + "\(nwConnection.endpoint) (Network)" } } diff --git a/Shared/Connections/XPCConnection.swift b/Sources/Shared/Connections/XPCConnection.swift similarity index 65% rename from Shared/Connections/XPCConnection.swift rename to Sources/Shared/Connections/XPCConnection.swift index e3fb5453..d7bc27ca 100644 --- a/Shared/Connections/XPCConnection.swift +++ b/Sources/Shared/Connections/XPCConnection.swift @@ -9,74 +9,65 @@ import Foundation import SideKit -@objc private protocol XPCConnectionProxy -{ +@objc private protocol XPCConnectionProxy { func ping(completionHandler: @escaping () -> Void) func receive(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) } -extension XPCConnection -{ - public static let unc0verMachServiceName = "cy:io.altstore.altdaemon" - public static let odysseyMachServiceName = "lh:io.altstore.altdaemon" - - public static let machServiceNames = [unc0verMachServiceName, odysseyMachServiceName] +public extension XPCConnection { + static let unc0verMachServiceName = "cy:io.altstore.altdaemon" + static let odysseyMachServiceName = "lh:io.altstore.altdaemon" + + static let machServiceNames = [unc0verMachServiceName, odysseyMachServiceName] } -public class XPCConnection: NSObject, SideConnection -{ +public class XPCConnection: NSObject, SideConnection { public let xpcConnection: NSXPCConnection - + private let queue = DispatchQueue(label: "io.altstore.XPCConnection") private let dispatchGroup = DispatchGroup() private var semaphore: DispatchSemaphore? private var buffer = Data(capacity: 1024) - + private var error: Error? - - public init(_ xpcConnection: NSXPCConnection) - { + + public init(_ xpcConnection: NSXPCConnection) { let proxyInterface = NSXPCInterface(with: XPCConnectionProxy.self) xpcConnection.remoteObjectInterface = proxyInterface xpcConnection.exportedInterface = proxyInterface self.xpcConnection = xpcConnection - + super.init() - + xpcConnection.interruptionHandler = { self.error = ALTServerError.lostConnection(underlyingError: nil) } - + xpcConnection.exportedObject = self xpcConnection.resume() } - deinit - { + deinit { self.disconnect() } } -private extension XPCConnection -{ - func makeProxy(errorHandler: @escaping (Error) -> Void) -> XPCConnectionProxy - { - let proxy = self.xpcConnection.remoteObjectProxyWithErrorHandler { (error) in +private extension XPCConnection { + func makeProxy(errorHandler: @escaping (Error) -> Void) -> XPCConnectionProxy { + let proxy = xpcConnection.remoteObjectProxyWithErrorHandler { error in print("Error messaging remote object proxy:", error) self.error = error errorHandler(error) } as! XPCConnectionProxy - + return proxy } } -public extension XPCConnection -{ - func connect(completionHandler: @escaping (Result) -> Void) - { - let proxy = self.makeProxy { (error) in +public extension XPCConnection { + func connect(completionHandler: @escaping (Result) -> Void) { + let proxy = makeProxy { error in completionHandler(.failure(error)) } @@ -84,30 +75,27 @@ public extension XPCConnection completionHandler(.success(())) } } - - func disconnect() - { - self.xpcConnection.invalidate() + + func disconnect() { + xpcConnection.invalidate() } - - func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) - { - guard self.error == nil else { return completionHandler(false, self.error) } - - let proxy = self.makeProxy { (error) in + + func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) { + guard error == nil else { return completionHandler(false, error) } + + let proxy = makeProxy { error in completionHandler(false, error) } - - proxy.receive(data) { (success, error) in + + proxy.receive(data) { success, error in completionHandler(success, error) } } - - func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void) - { - guard self.error == nil else { return completionHandler(nil, self.error) } - - self.queue.async { + + func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void) { + guard error == nil else { return completionHandler(nil, error) } + + queue.async { let copiedBuffer = self.buffer // Copy buffer to prevent runtime crashes. guard copiedBuffer.count >= expectedSize else { self.semaphore = DispatchSemaphore(value: 0) @@ -117,37 +105,33 @@ public extension XPCConnection } return } - + let data = copiedBuffer.prefix(expectedSize) self.buffer = copiedBuffer.dropFirst(expectedSize) - + completionHandler(data, nil) } } } -extension XPCConnection -{ - override public var description: String { - return "\(self.xpcConnection.endpoint) (XPC)" +public extension XPCConnection { + override var description: String { + "\(xpcConnection.endpoint) (XPC)" } } -extension XPCConnection: XPCConnectionProxy -{ - fileprivate func ping(completionHandler: @escaping () -> Void) - { +extension XPCConnection: XPCConnectionProxy { + fileprivate func ping(completionHandler: @escaping () -> Void) { completionHandler() } - - fileprivate func receive(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) - { - self.queue.async { + + fileprivate func receive(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void) { + queue.async { self.buffer.append(data) - + self.semaphore?.signal() self.semaphore = nil - + completionHandler(true, nil) } } diff --git a/Shared/Extensions/Bundle+AltStore.swift b/Sources/Shared/Extensions/Bundle+AltStore.swift similarity index 61% rename from Shared/Extensions/Bundle+AltStore.swift rename to Sources/Shared/Extensions/Bundle+AltStore.swift index cd3eff27..640b1fac 100644 --- a/Shared/Extensions/Bundle+AltStore.swift +++ b/Sources/Shared/Extensions/Bundle+AltStore.swift @@ -7,22 +7,21 @@ // import Foundation +import Shared -public extension Bundle -{ - struct Info - { +public extension Bundle { + enum Info { public static let deviceID = "ALTDeviceID" public static let serverID = "ALTServerID" public static let certificateID = "ALTCertificateID" public static let appGroups = "ALTAppGroups" public static let altBundleID = "ALTBundleIdentifier" - public static let orgbundleIdentifier = "com.SideStore" - public static let appbundleIdentifier = orgbundleIdentifier + ".SideStore" + public static let orgbundleIdentifier = "com.SideStore" + public static let appbundleIdentifier = orgbundleIdentifier + ".SideStore" public static let devicePairingString = "ALTPairingFile" public static let urlTypes = "CFBundleURLTypes" public static let exportedUTIs = "UTExportedTypeDeclarations" - + public static let untetherURL = "ALTFugu14UntetherURL" public static let untetherRequired = "ALTFugu14UntetherRequired" public static let untetherMinimumiOSVersion = "ALTFugu14UntetherMinimumVersion" @@ -30,44 +29,42 @@ public extension Bundle } } -public extension Bundle -{ +public extension Bundle { var infoPlistURL: URL { - let infoPlistURL = self.bundleURL.appendingPathComponent("Info.plist") + let infoPlistURL = bundleURL.appendingPathComponent("Info.plist") return infoPlistURL } - + var provisioningProfileURL: URL { - let provisioningProfileURL = self.bundleURL.appendingPathComponent("embedded.mobileprovision") + let provisioningProfileURL = bundleURL.appendingPathComponent("embedded.mobileprovision") return provisioningProfileURL } - + var certificateURL: URL { - let certificateURL = self.bundleURL.appendingPathComponent("ALTCertificate.p12") + let certificateURL = bundleURL.appendingPathComponent("ALTCertificate.p12") return certificateURL } - + var altstorePlistURL: URL { - let altstorePlistURL = self.bundleURL.appendingPathComponent("AltStore.plist") + let altstorePlistURL = bundleURL.appendingPathComponent("AltStore.plist") return altstorePlistURL } } -public extension Bundle -{ +public extension Bundle { static var baseAltStoreAppGroupID = "group.com.SideStore.SideStore" - + var appGroups: [String] { - return self.infoDictionary?[Bundle.Info.appGroups] as? [String] ?? [] + infoDictionary?[Bundle.Info.appGroups] as? [String] ?? [] } - - var altstoreAppGroup: String? { - let appGroup = self.appGroups.first { $0.contains(Bundle.baseAltStoreAppGroupID) } + + var altstoreAppGroup: String? { + let appGroup = appGroups.first { $0.contains(Bundle.baseAltStoreAppGroupID) } return appGroup } - - var completeInfoDictionary: [String : Any]? { + + var completeInfoDictionary: [String: Any]? { let infoPlistURL = self.infoPlistURL - return NSDictionary(contentsOf: infoPlistURL) as? [String : Any] + return NSDictionary(contentsOf: infoPlistURL) as? [String: Any] } } diff --git a/Sources/Shared/Extensions/NSError+AltStore.swift b/Sources/Shared/Extensions/NSError+AltStore.swift new file mode 100644 index 00000000..bb549742 --- /dev/null +++ b/Sources/Shared/Extensions/NSError+AltStore.swift @@ -0,0 +1,128 @@ +// +// NSError+AltStore.swift +// AltStore +// +// Created by Riley Testut on 3/11/20. +// Copyright © 2020 Riley Testut. All rights reserved. +// + +import Foundation + +extension NSError { + @objc(alt_localizedFailure) + var localizedFailure: String? { + let localizedFailure = (userInfo[NSLocalizedFailureErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: domain)?(self, NSLocalizedFailureErrorKey) as? String) + return localizedFailure + } + + @objc(alt_localizedDebugDescription) + var localizedDebugDescription: String? { + let debugDescription = (userInfo[NSDebugDescriptionErrorKey] as? String) ?? (NSError.userInfoValueProvider(forDomain: domain)?(self, NSDebugDescriptionErrorKey) as? String) + return debugDescription + } + + @objc(alt_errorWithLocalizedFailure:) + func withLocalizedFailure(_ failure: String) -> NSError { + var userInfo = self.userInfo + userInfo[NSLocalizedFailureErrorKey] = failure + + if let failureReason = localizedFailureReason { + userInfo[NSLocalizedFailureReasonErrorKey] = failureReason + } else if localizedFailure == nil && localizedFailureReason == nil && localizedDescription.contains(localizedErrorCode) { + // Default localizedDescription, so replace with just the localized error code portion. + userInfo[NSLocalizedFailureReasonErrorKey] = "(\(localizedErrorCode).)" + } else { + userInfo[NSLocalizedFailureReasonErrorKey] = localizedDescription + } + + if let localizedDescription = NSError.userInfoValueProvider(forDomain: domain)?(self, NSLocalizedDescriptionKey) as? String { + userInfo[NSLocalizedDescriptionKey] = localizedDescription + } + + // Don't accidentally remove localizedDescription from dictionary + // userInfo[NSLocalizedDescriptionKey] = NSError.userInfoValueProvider(forDomain: self.domain)?(self, NSLocalizedDescriptionKey) as? String + + if let recoverySuggestion = localizedRecoverySuggestion { + userInfo[NSLocalizedRecoverySuggestionErrorKey] = recoverySuggestion + } + + let error = NSError(domain: domain, code: code, userInfo: userInfo) + return error + } + + func sanitizedForCoreData() -> NSError { + var userInfo = self.userInfo + userInfo[NSLocalizedFailureErrorKey] = localizedFailure + userInfo[NSLocalizedDescriptionKey] = localizedDescription + userInfo[NSLocalizedFailureReasonErrorKey] = localizedFailureReason + userInfo[NSLocalizedRecoverySuggestionErrorKey] = localizedRecoverySuggestion + + // Remove userInfo values that don't conform to NSSecureEncoding. + userInfo = userInfo.filter { _, value in + (value as AnyObject) is NSSecureCoding + } + + // Sanitize underlying errors. + if let underlyingError = userInfo[NSUnderlyingErrorKey] as? Error { + let sanitizedError = (underlyingError as NSError).sanitizedForCoreData() + userInfo[NSUnderlyingErrorKey] = sanitizedError + } + + if #available(iOS 14.5, macOS 11.3, *), let underlyingErrors = userInfo[NSMultipleUnderlyingErrorsKey] as? [Error] { + let sanitizedErrors = underlyingErrors.map { ($0 as NSError).sanitizedForCoreData() } + userInfo[NSMultipleUnderlyingErrorsKey] = sanitizedErrors + } + + let error = NSError(domain: domain, code: code, userInfo: userInfo) + return error + } +} + +extension Error { + var underlyingError: Error? { + let underlyingError = (self as NSError).userInfo[NSUnderlyingErrorKey] as? Error + return underlyingError + } + + var localizedErrorCode: String { + let localizedErrorCode = String(format: NSLocalizedString("%@ error %@", comment: ""), (self as NSError).domain, (self as NSError).code as NSNumber) + return localizedErrorCode + } +} + +protocol ALTLocalizedError: LocalizedError, CustomNSError { + var failure: String? { get } + + var underlyingError: Error? { get } +} + +extension ALTLocalizedError { + var errorUserInfo: [String: Any] { + let userInfo = ([ + NSLocalizedDescriptionKey: errorDescription, + NSLocalizedFailureReasonErrorKey: failureReason, + NSLocalizedFailureErrorKey: failure, + NSUnderlyingErrorKey: underlyingError + ] as [String: Any?]).compactMapValues { $0 } + return userInfo + } + + var underlyingError: Error? { + // Error's default implementation calls errorUserInfo, + // but ALTLocalizedError.errorUserInfo calls underlyingError. + // Return nil to prevent infinite recursion. + nil + } + + var errorDescription: String? { + guard let errorFailure = failure else { return (underlyingError as NSError?)?.localizedDescription } + guard let failureReason = failureReason else { return errorFailure } + + let errorDescription = errorFailure + " " + failureReason + return errorDescription + } + + var failureReason: String? { (underlyingError as NSError?)?.localizedDescription } + var recoverySuggestion: String? { (underlyingError as NSError?)?.localizedRecoverySuggestion } + var helpAnchor: String? { (underlyingError as NSError?)?.helpAnchor } +} diff --git a/Shared/Extensions/NSXPCConnection+MachServices.swift b/Sources/Shared/Extensions/NSXPCConnection+MachServices.swift similarity index 85% rename from Shared/Extensions/NSXPCConnection+MachServices.swift rename to Sources/Shared/Extensions/NSXPCConnection+MachServices.swift index 711e8deb..7cffceb4 100644 --- a/Shared/Extensions/NSXPCConnection+MachServices.swift +++ b/Sources/Shared/Extensions/NSXPCConnection+MachServices.swift @@ -8,25 +8,20 @@ import Foundation -@objc private protocol XPCPrivateAPI -{ +@objc private protocol XPCPrivateAPI { init(machServiceName: String) init(machServiceName: String, options: NSXPCConnection.Options) } -public extension NSXPCConnection -{ - class func makeConnection(machServiceName: String) -> NSXPCConnection - { +public extension NSXPCConnection { + class func makeConnection(machServiceName: String) -> NSXPCConnection { let connection = unsafeBitCast(self, to: XPCPrivateAPI.Type.self).init(machServiceName: machServiceName, options: .privileged) return unsafeBitCast(connection, to: NSXPCConnection.self) } } -public extension NSXPCListener -{ - class func makeListener(machServiceName: String) -> NSXPCListener - { +public extension NSXPCListener { + class func makeListener(machServiceName: String) -> NSXPCListener { let listener = unsafeBitCast(self, to: XPCPrivateAPI.Type.self).init(machServiceName: machServiceName) return unsafeBitCast(listener, to: NSXPCListener.self) } diff --git a/Shared/Extensions/Result+Conveniences.swift b/Sources/Shared/Extensions/Result+Conveniences.swift similarity index 51% rename from Shared/Extensions/Result+Conveniences.swift rename to Sources/Shared/Extensions/Result+Conveniences.swift index 2ffec681..1997455a 100644 --- a/Shared/Extensions/Result+Conveniences.swift +++ b/Sources/Shared/Extensions/Result+Conveniences.swift @@ -8,68 +8,49 @@ import Foundation -public extension Result -{ +public extension Result { var value: Success? { - switch self - { - case .success(let value): return value + switch self { + case let .success(value): return value case .failure: return nil } } - + var error: Failure? { - switch self - { + switch self { case .success: return nil - case .failure(let error): return error + case let .failure(error): return error } } - - init(_ value: Success?, _ error: Failure?) - { - switch (value, error) - { - case (let value?, _): self = .success(value) - case (_, let error?): self = .failure(error) + + init(_ value: Success?, _ error: Failure?) { + switch (value, error) { + case let (value?, _): self = .success(value) + case let (_, error?): self = .failure(error) case (nil, nil): preconditionFailure("Either value or error must be non-nil") } } } -public extension Result where Success == Void -{ - init(_ success: Bool, _ error: Failure?) - { - if success - { +public extension Result where Success == Void { + init(_ success: Bool, _ error: Failure?) { + if success { self = .success(()) - } - else if let error = error - { + } else if let error = error { self = .failure(error) - } - else - { + } else { preconditionFailure("Error must be non-nil if success is false") } } } -public extension Result -{ - init(_ values: (T?, U?), _ error: Failure?) where Success == (T, U) - { - if let value1 = values.0, let value2 = values.1 - { +public extension Result { + init(_ values: (T?, U?), _ error: Failure?) where Success == (T, U) { + if let value1 = values.0, let value2 = values.1 { self = .success((value1, value2)) - } - else if let error = error - { + } else if let error = error { self = .failure(error) - } - else - { + } else { preconditionFailure("Error must be non-nil if either provided values are nil") } } diff --git a/Sources/Shared/XPC/AltXPCProtocol.swift b/Sources/Shared/XPC/AltXPCProtocol.swift new file mode 100644 index 00000000..f8f0ad18 --- /dev/null +++ b/Sources/Shared/XPC/AltXPCProtocol.swift @@ -0,0 +1,21 @@ +// +// AltXPCProtocol.swift +// SideStore +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import Foundation + +public typealias AltXPCProtocol = SideXPCProtocol + +@objc +public protocol SideXPCProtocol { + func ping(completionHandler: @escaping () -> Void) + func requestAnisetteData(completionHandler: @escaping (ALTAnisetteData?, Error?) -> Void) +} + +@objc public class ALTAnisetteData: NSObject { + // implementation +} diff --git a/Sources/AltBackup/AltBackup.entitlements b/Sources/SideBackup/AltBackup.entitlements similarity index 100% rename from Sources/AltBackup/AltBackup.entitlements rename to Sources/SideBackup/AltBackup.entitlements diff --git a/Sources/AltBackup/AppDelegate.swift b/Sources/SideBackup/AppDelegate.swift similarity index 73% rename from Sources/AltBackup/AppDelegate.swift rename to Sources/SideBackup/AppDelegate.swift index 5d8a21a7..7ae80900 100644 --- a/Sources/AltBackup/AppDelegate.swift +++ b/Sources/SideBackup/AppDelegate.swift @@ -8,114 +8,104 @@ import UIKit -extension AppDelegate -{ +extension AppDelegate { static let startBackupNotification = Notification.Name("io.altstore.StartBackup") static let startRestoreNotification = Notification.Name("io.altstore.StartRestore") - + static let operationDidFinishNotification = Notification.Name("io.altstore.BackupOperationFinished") - + static let operationResultKey = "result" } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - + private var currentBackupReturnURL: URL? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool - { + + func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - + NotificationCenter.default.addObserver(self, selector: #selector(AppDelegate.operationDidFinish(_:)), name: AppDelegate.operationDidFinishNotification, object: nil) - + let viewController = ViewController() - - self.window = UIWindow(frame: UIScreen.main.bounds) - self.window?.rootViewController = viewController - self.window?.makeKeyAndVisible() - + + window = UIWindow(frame: UIScreen.main.bounds) + window?.rootViewController = viewController + window?.makeKeyAndVisible() + return true } - func applicationWillResignActive(_ application: UIApplication) { + func applicationWillResignActive(_: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - func applicationDidBecomeActive(_ application: UIApplication) { + func applicationDidBecomeActive(_: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(_ application: UIApplication) { + func applicationWillTerminate(_: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool - { - return self.open(url) + + func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { + open(url) } } -private extension AppDelegate -{ - func open(_ url: URL) -> Bool - { +private extension AppDelegate { + func open(_ url: URL) -> Bool { guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return false } guard let command = components.host?.lowercased() else { return false } - - switch command - { + + switch command { case "backup": guard let returnString = components.queryItems?.first(where: { $0.name == "returnURL" })?.value, let returnURL = URL(string: returnString) else { return false } - self.currentBackupReturnURL = returnURL + currentBackupReturnURL = returnURL NotificationCenter.default.post(name: AppDelegate.startBackupNotification, object: nil) - + return true - + case "restore": guard let returnString = components.queryItems?.first(where: { $0.name == "returnURL" })?.value, let returnURL = URL(string: returnString) else { return false } - self.currentBackupReturnURL = returnURL + currentBackupReturnURL = returnURL NotificationCenter.default.post(name: AppDelegate.startRestoreNotification, object: nil) - + return true - + default: return false } } - - @objc func operationDidFinish(_ notification: Notification) - { + + @objc func operationDidFinish(_ notification: Notification) { defer { self.currentBackupReturnURL = nil } - + guard - let returnURL = self.currentBackupReturnURL, + let returnURL = currentBackupReturnURL, let result = notification.userInfo?[AppDelegate.operationResultKey] as? Result else { return } - + guard var components = URLComponents(url: returnURL, resolvingAgainstBaseURL: false) else { return } - - switch result - { + + switch result { case .success: components.path = "/success" - - case .failure(let error as NSError): + + case let .failure(error as NSError): components.path = "/failure" components.queryItems = ["errorDomain": error.domain, "errorCode": String(error.code), "errorDescription": error.localizedDescription].map { URLQueryItem(name: $0, value: $1) } } - + guard let responseURL = components.url else { return } - + DispatchQueue.main.async { - UIApplication.shared.open(responseURL, options: [:]) { (success) in + UIApplication.shared.open(responseURL, options: [:]) { success in print("Sent response to app with success:", success) } } } } - diff --git a/AltWidget/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/SideBackup/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Sources/SideBackup/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Sources/AltBackup/Assets.xcassets/Background.colorset/Contents.json b/Sources/SideBackup/Assets.xcassets/Background.colorset/Contents.json similarity index 100% rename from Sources/AltBackup/Assets.xcassets/Background.colorset/Contents.json rename to Sources/SideBackup/Assets.xcassets/Background.colorset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Colors/Contents.json b/Sources/SideBackup/Assets.xcassets/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Colors/Contents.json rename to Sources/SideBackup/Assets.xcassets/Contents.json diff --git a/Sources/AltBackup/Assets.xcassets/Text.colorset/Contents.json b/Sources/SideBackup/Assets.xcassets/Text.colorset/Contents.json similarity index 100% rename from Sources/AltBackup/Assets.xcassets/Text.colorset/Contents.json rename to Sources/SideBackup/Assets.xcassets/Text.colorset/Contents.json diff --git a/Sources/AltBackup/BackupController.swift b/Sources/SideBackup/BackupController.swift similarity index 76% rename from Sources/AltBackup/BackupController.swift rename to Sources/SideBackup/BackupController.swift index 93435e9c..f365b47d 100644 --- a/Sources/AltBackup/BackupController.swift +++ b/Sources/SideBackup/BackupController.swift @@ -8,14 +8,12 @@ import Foundation -extension ErrorUserInfoKey -{ +extension ErrorUserInfoKey { static let sourceFile: String = "alt_sourceFile" static let sourceFileLine: String = "alt_sourceFileLine" } -extension Error -{ +extension Error { var sourceDescription: String? { guard let sourceFile = (self as NSError).userInfo[ErrorUserInfoKey.sourceFile] as? String, let sourceFileLine = (self as NSError).userInfo[ErrorUserInfoKey.sourceFileLine] else { return nil @@ -24,267 +22,225 @@ extension Error } } -struct BackupError: ALTLocalizedError -{ - enum Code - { +struct BackupError: ALTLocalizedError { + enum Code { case invalidBundleID case appGroupNotFound(String?) case randomError // Used for debugging. } - + let code: Code - + let sourceFile: String let sourceFileLine: Int - + var failure: String? var failureReason: String? { - switch self.code - { + switch code { case .invalidBundleID: return NSLocalizedString("The bundle identifier is invalid.", comment: "") - case .appGroupNotFound(let appGroup): - if let appGroup = appGroup - { + case let .appGroupNotFound(appGroup): + if let appGroup = appGroup { return String(format: NSLocalizedString("The app group “%@” could not be found.", comment: ""), appGroup) - } - else - { + } else { return NSLocalizedString("The AltStore app group could not be found.", comment: "") } case .randomError: return NSLocalizedString("A random error occured.", comment: "") } } - - var errorUserInfo: [String : Any] { - let userInfo: [String: Any?] = [NSLocalizedDescriptionKey: self.errorDescription, - NSLocalizedFailureReasonErrorKey: self.failureReason, - NSLocalizedFailureErrorKey: self.failure, - ErrorUserInfoKey.sourceFile: self.sourceFile, - ErrorUserInfoKey.sourceFileLine: self.sourceFileLine] + + var errorUserInfo: [String: Any] { + let userInfo: [String: Any?] = [NSLocalizedDescriptionKey: errorDescription, + NSLocalizedFailureReasonErrorKey: failureReason, + NSLocalizedFailureErrorKey: failure, + ErrorUserInfoKey.sourceFile: sourceFile, + ErrorUserInfoKey.sourceFileLine: sourceFileLine] return userInfo.compactMapValues { $0 } } - - init(_ code: Code, description: String? = nil, file: String = #file, line: Int = #line) - { + + init(_ code: Code, description: String? = nil, file: String = #file, line: Int = #line) { self.code = code - self.failure = description - self.sourceFile = file - self.sourceFileLine = line + failure = description + sourceFile = file + sourceFileLine = line } } -class BackupController: NSObject -{ +class BackupController: NSObject { private let fileCoordinator = NSFileCoordinator(filePresenter: nil) private let operationQueue = OperationQueue() - - override init() - { - self.operationQueue.name = "AltBackup-BackupQueue" + + override init() { + operationQueue.name = "AltBackup-BackupQueue" } - - func performBackup(completionHandler: @escaping (Result) -> Void) - { - do - { + + func performBackup(completionHandler: @escaping (Result) -> Void) { + do { guard let bundleIdentifier = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.altBundleID) as? String else { throw BackupError(.invalidBundleID, description: NSLocalizedString("Unable to create backup directory.", comment: "")) } - + guard let altstoreAppGroup = Bundle.main.altstoreAppGroup, let sharedDirectoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: altstoreAppGroup) else { throw BackupError(.appGroupNotFound(nil), description: NSLocalizedString("Unable to create backup directory.", comment: "")) } - + let backupsDirectory = sharedDirectoryURL.appendingPathComponent("Backups") - + // Use temporary directory to prevent messing up successful backup with incomplete one. let temporaryAppBackupDirectory = backupsDirectory.appendingPathComponent("Temp", isDirectory: true).appendingPathComponent(UUID().uuidString) let appBackupDirectory = backupsDirectory.appendingPathComponent(bundleIdentifier) - + let writingIntent = NSFileAccessIntent.writingIntent(with: temporaryAppBackupDirectory, options: []) let replacementIntent = NSFileAccessIntent.writingIntent(with: appBackupDirectory, options: [.forReplacing]) - self.fileCoordinator.coordinate(with: [writingIntent, replacementIntent], queue: self.operationQueue) { (error) in - do - { - if let error = error - { + fileCoordinator.coordinate(with: [writingIntent, replacementIntent], queue: operationQueue) { error in + do { + if let error = error { throw error } - - do - { + + do { let mainGroupBackupDirectory = temporaryAppBackupDirectory.appendingPathComponent("App") try FileManager.default.createDirectory(at: mainGroupBackupDirectory, withIntermediateDirectories: true, attributes: nil) - + let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let backupDocumentsDirectory = mainGroupBackupDirectory.appendingPathComponent(documentsDirectory.lastPathComponent) - - if FileManager.default.fileExists(atPath: backupDocumentsDirectory.path) - { + + if FileManager.default.fileExists(atPath: backupDocumentsDirectory.path) { try FileManager.default.removeItem(at: backupDocumentsDirectory) } - - if FileManager.default.fileExists(atPath: documentsDirectory.path) - { + + if FileManager.default.fileExists(atPath: documentsDirectory.path) { try FileManager.default.copyItem(at: documentsDirectory, to: backupDocumentsDirectory) } - + print("Copied Documents directory from \(documentsDirectory) to \(backupDocumentsDirectory)") - + let libraryDirectory = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)[0] let backupLibraryDirectory = mainGroupBackupDirectory.appendingPathComponent(libraryDirectory.lastPathComponent) - - if FileManager.default.fileExists(atPath: backupLibraryDirectory.path) - { + + if FileManager.default.fileExists(atPath: backupLibraryDirectory.path) { try FileManager.default.removeItem(at: backupLibraryDirectory) } - - if FileManager.default.fileExists(atPath: libraryDirectory.path) - { + + if FileManager.default.fileExists(atPath: libraryDirectory.path) { try FileManager.default.copyItem(at: libraryDirectory, to: backupLibraryDirectory) } - + print("Copied Library directory from \(libraryDirectory) to \(backupLibraryDirectory)") } - - for appGroup in Bundle.main.appGroups where appGroup != altstoreAppGroup - { + + for appGroup in Bundle.main.appGroups where appGroup != altstoreAppGroup { guard let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { throw BackupError(.appGroupNotFound(appGroup), description: NSLocalizedString("Unable to create app group backup directory.", comment: "")) } - + let backupAppGroupURL = temporaryAppBackupDirectory.appendingPathComponent(appGroup) - + // There are several system hidden files that we don't have permission to read, so we just skip all hidden files in app group directories. try self.copyDirectoryContents(at: appGroupURL, to: backupAppGroupURL, options: [.skipsHiddenFiles]) } - + // Replace previous backup with new backup. _ = try FileManager.default.replaceItemAt(appBackupDirectory, withItemAt: temporaryAppBackupDirectory) - + print("Replaced previous backup with new backup:", temporaryAppBackupDirectory) - + completionHandler(.success(())) - } - catch - { - do { try FileManager.default.removeItem(at: temporaryAppBackupDirectory) } - catch { print("Failed to remove temporary directory.", error) } - + } catch { + do { try FileManager.default.removeItem(at: temporaryAppBackupDirectory) } catch { print("Failed to remove temporary directory.", error) } + completionHandler(.failure(error)) } } - } - catch - { + } catch { completionHandler(.failure(error)) } } - - func restoreBackup(completionHandler: @escaping (Result) -> Void) - { - do - { + + func restoreBackup(completionHandler: @escaping (Result) -> Void) { + do { guard let bundleIdentifier = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.altBundleID) as? String else { throw BackupError(.invalidBundleID, description: NSLocalizedString("Unable to access backup.", comment: "")) } - + guard let altstoreAppGroup = Bundle.main.altstoreAppGroup, let sharedDirectoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: altstoreAppGroup) else { throw BackupError(.appGroupNotFound(nil), description: NSLocalizedString("Unable to access backup.", comment: "")) } - + let backupsDirectory = sharedDirectoryURL.appendingPathComponent("Backups") let appBackupDirectory = backupsDirectory.appendingPathComponent(bundleIdentifier) - + let readingIntent = NSFileAccessIntent.readingIntent(with: appBackupDirectory, options: []) - self.fileCoordinator.coordinate(with: [readingIntent], queue: self.operationQueue) { (error) in - do - { - if let error = error - { + fileCoordinator.coordinate(with: [readingIntent], queue: operationQueue) { error in + do { + if let error = error { throw error } - + let mainGroupBackupDirectory = appBackupDirectory.appendingPathComponent("App") - + let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let backupDocumentsDirectory = mainGroupBackupDirectory.appendingPathComponent(documentsDirectory.lastPathComponent) - + let libraryDirectory = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)[0] let backupLibraryDirectory = mainGroupBackupDirectory.appendingPathComponent(libraryDirectory.lastPathComponent) - + try self.copyDirectoryContents(at: backupDocumentsDirectory, to: documentsDirectory) try self.copyDirectoryContents(at: backupLibraryDirectory, to: libraryDirectory) - - for appGroup in Bundle.main.appGroups where appGroup != altstoreAppGroup - { + + for appGroup in Bundle.main.appGroups where appGroup != altstoreAppGroup { guard let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { throw BackupError(.appGroupNotFound(appGroup), description: NSLocalizedString("Unable to read app group backup.", comment: "")) } - + let backupAppGroupURL = appBackupDirectory.appendingPathComponent(appGroup) try self.copyDirectoryContents(at: backupAppGroupURL, to: appGroupURL) } - + completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } } - } - catch - { + } catch { completionHandler(.failure(error)) } } } -private extension BackupController -{ - func copyDirectoryContents(at sourceDirectoryURL: URL, to destinationDirectoryURL: URL, options: FileManager.DirectoryEnumerationOptions = []) throws - { +private extension BackupController { + func copyDirectoryContents(at sourceDirectoryURL: URL, to destinationDirectoryURL: URL, options: FileManager.DirectoryEnumerationOptions = []) throws { guard FileManager.default.fileExists(atPath: sourceDirectoryURL.path) else { return } - - if !FileManager.default.fileExists(atPath: destinationDirectoryURL.path) - { + + if !FileManager.default.fileExists(atPath: destinationDirectoryURL.path) { try FileManager.default.createDirectory(at: destinationDirectoryURL, withIntermediateDirectories: true, attributes: nil) } - - for fileURL in try FileManager.default.contentsOfDirectory(at: sourceDirectoryURL, includingPropertiesForKeys: [.isDirectoryKey], options: options) - { + + for fileURL in try FileManager.default.contentsOfDirectory(at: sourceDirectoryURL, includingPropertiesForKeys: [.isDirectoryKey], options: options) { let isDirectory = try fileURL.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false let destinationURL = destinationDirectoryURL.appendingPathComponent(fileURL.lastPathComponent) - - if FileManager.default.fileExists(atPath: destinationURL.path) - { + + if FileManager.default.fileExists(atPath: destinationURL.path) { do { try FileManager.default.removeItem(at: destinationURL) - } - catch CocoaError.fileWriteNoPermission where isDirectory { - try self.copyDirectoryContents(at: fileURL, to: destinationURL, options: options) + } catch CocoaError.fileWriteNoPermission where isDirectory { + try copyDirectoryContents(at: fileURL, to: destinationURL, options: options) continue - } - catch { + } catch { print(error) throw error } } - + do { try FileManager.default.copyItem(at: fileURL, to: destinationURL) print("Copied item from \(fileURL) to \(destinationURL)") - } - catch let error where fileURL.lastPathComponent == "Inbox" && fileURL.deletingLastPathComponent().lastPathComponent == "Documents" { + } catch let error where fileURL.lastPathComponent == "Inbox" && fileURL.deletingLastPathComponent().lastPathComponent == "Documents" { // Ignore errors for /Documents/Inbox print("Failed to copy Inbox directory:", error) - } - catch { + } catch { print(error) throw error } diff --git a/Sources/AltBackup/Base.lproj/LaunchScreen.storyboard b/Sources/SideBackup/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from Sources/AltBackup/Base.lproj/LaunchScreen.storyboard rename to Sources/SideBackup/Base.lproj/LaunchScreen.storyboard diff --git a/Sources/AltBackup/Info.plist b/Sources/SideBackup/Info.plist similarity index 100% rename from Sources/AltBackup/Info.plist rename to Sources/SideBackup/Info.plist diff --git a/Sources/AltBackup/UIColor+AltBackup.swift b/Sources/SideBackup/UIColor+AltBackup.swift similarity index 93% rename from Sources/AltBackup/UIColor+AltBackup.swift rename to Sources/SideBackup/UIColor+AltBackup.swift index 73c7ceeb..4c635764 100644 --- a/Sources/AltBackup/UIColor+AltBackup.swift +++ b/Sources/SideBackup/UIColor+AltBackup.swift @@ -8,8 +8,7 @@ import UIKit -extension UIColor -{ +extension UIColor { static let altstoreBackground = UIColor(named: "Background")! static let altstoreText = UIColor(named: "Text")! } diff --git a/Sources/SideBackup/ViewController.swift b/Sources/SideBackup/ViewController.swift new file mode 100644 index 00000000..a20b9ee3 --- /dev/null +++ b/Sources/SideBackup/ViewController.swift @@ -0,0 +1,189 @@ +// +// ViewController.swift +// AltBackup +// +// Created by Riley Testut on 5/11/20. +// Copyright © 2020 Riley Testut. All rights reserved. +// + +import UIKit + +extension Bundle { + var appName: String? { + let appName = + Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? + Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as? String + return appName + } +} + +extension ViewController { + enum BackupOperation { + case backup + case restore + } +} + +class ViewController: UIViewController { + private let backupController = BackupController() + + private var currentOperation: BackupOperation? { + didSet { + DispatchQueue.main.async { + self.update() + } + } + } + + private var textLabel: UILabel! + private var detailTextLabel: UILabel! + private var activityIndicatorView: UIActivityIndicatorView! + + override var preferredStatusBarStyle: UIStatusBarStyle { + .lightContent + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + NotificationCenter.default.addObserver(self, selector: #selector(ViewController.backup), name: AppDelegate.startBackupNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ViewController.restore), name: AppDelegate.startRestoreNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError() + } + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .altstoreBackground + + textLabel = UILabel(frame: .zero) + textLabel.font = UIFont.preferredFont(forTextStyle: .title2) + textLabel.textColor = .altstoreText + textLabel.textAlignment = .center + textLabel.numberOfLines = 0 + + detailTextLabel = UILabel(frame: .zero) + detailTextLabel.font = UIFont.preferredFont(forTextStyle: .body) + detailTextLabel.textColor = .altstoreText + detailTextLabel.textAlignment = .center + detailTextLabel.numberOfLines = 0 + + activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge) + activityIndicatorView.color = .altstoreText + activityIndicatorView.startAnimating() + + #if DEBUG + let button1 = UIButton(type: .system) + button1.setTitle("Backup", for: .normal) + button1.setTitleColor(.white, for: .normal) + button1.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) + button1.addTarget(self, action: #selector(ViewController.backup), for: .primaryActionTriggered) + + let button2 = UIButton(type: .system) + button2.setTitle("Restore", for: .normal) + button2.setTitleColor(.white, for: .normal) + button2.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) + button2.addTarget(self, action: #selector(ViewController.restore), for: .primaryActionTriggered) + + let arrangedSubviews = [textLabel!, detailTextLabel!, activityIndicatorView!, button1, button2] + #else + let arrangedSubviews = [textLabel!, detailTextLabel!, activityIndicatorView!] + #endif + + let stackView = UIStackView(arrangedSubviews: arrangedSubviews) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.spacing = 22 + stackView.axis = .vertical + stackView.alignment = .center + view.addSubview(stackView) + + NSLayoutConstraint.activate([stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor), + stackView.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1.0), + view.safeAreaLayoutGuide.trailingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: stackView.trailingAnchor, multiplier: 1.0)]) + + update() + } +} + +private extension ViewController { + @objc func backup() { + currentOperation = .backup + + backupController.performBackup { result in + let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "") + + let title = String(format: NSLocalizedString("%@ could not be backed up.", comment: ""), appName) + self.process(result, errorTitle: title) + } + } + + @objc func restore() { + currentOperation = .restore + + backupController.restoreBackup { result in + let appName = Bundle.main.appName ?? NSLocalizedString("App", comment: "") + + let title = String(format: NSLocalizedString("%@ could not be restored.", comment: ""), appName) + self.process(result, errorTitle: title) + } + } + + func update() { + switch currentOperation { + case .backup: + textLabel.text = NSLocalizedString("Backing up app data…", comment: "") + detailTextLabel.isHidden = true + activityIndicatorView.startAnimating() + + case .restore: + textLabel.text = NSLocalizedString("Restoring app data…", comment: "") + detailTextLabel.isHidden = true + activityIndicatorView.startAnimating() + + case .none: + textLabel.text = String(format: NSLocalizedString("%@ is inactive.", comment: ""), + Bundle.main.appName ?? NSLocalizedString("App", comment: "")) + + detailTextLabel.text = String(format: NSLocalizedString("Refresh %@ in SideStore to continue using it.", comment: ""), + Bundle.main.appName ?? NSLocalizedString("this app", comment: "")) + + detailTextLabel.isHidden = false + activityIndicatorView.stopAnimating() + } + } +} + +private extension ViewController { + func process(_ result: Result, errorTitle: String) { + DispatchQueue.main.async { + switch result { + case .success: break + case let .failure(error as NSError): + let message: String + + if let sourceDescription = error.sourceDescription { + message = error.localizedDescription + "\n\n" + sourceDescription + } else { + message = error.localizedDescription + } + + let alertController = UIAlertController(title: errorTitle, message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + self.present(alertController, animated: true, completion: nil) + } + + NotificationCenter.default.post(name: AppDelegate.operationDidFinishNotification, object: nil, userInfo: [AppDelegate.operationResultKey: result]) + } + } + + @objc func didEnterBackground(_: Notification) { + // Reset UI once we've left app (but not before). + currentOperation = nil + } +} diff --git a/AltDaemon/AltDaemon-Bridging-Header.h b/Sources/SideDaemon/AltDaemon-Bridging-Header.h similarity index 100% rename from AltDaemon/AltDaemon-Bridging-Header.h rename to Sources/SideDaemon/AltDaemon-Bridging-Header.h diff --git a/AltDaemon/AltDaemon.entitlements b/Sources/SideDaemon/AltDaemon.entitlements similarity index 100% rename from AltDaemon/AltDaemon.entitlements rename to Sources/SideDaemon/AltDaemon.entitlements diff --git a/AltDaemon/AnisetteDataManager.swift b/Sources/SideDaemon/AnisetteDataManager.swift similarity index 79% rename from AltDaemon/AnisetteDataManager.swift rename to Sources/SideDaemon/AnisetteDataManager.swift index daff25d6..0bb15d19 100644 --- a/AltDaemon/AnisetteDataManager.swift +++ b/Sources/SideDaemon/AnisetteDataManager.swift @@ -10,46 +10,41 @@ import Foundation import AltSign -private extension UserDefaults -{ +private extension UserDefaults { @objc var localUserID: String? { - get { return self.string(forKey: #keyPath(UserDefaults.localUserID)) } - set { self.set(newValue, forKey: #keyPath(UserDefaults.localUserID)) } + get { string(forKey: #keyPath(UserDefaults.localUserID)) } + set { set(newValue, forKey: #keyPath(UserDefaults.localUserID)) } } } -struct AnisetteDataManager -{ +struct AnisetteDataManager { static let shared = AnisetteDataManager() - + private let dateFormatter = ISO8601DateFormatter() - - private init() - { - dlopen("/System/Library/PrivateFrameworks/AuthKit.framework/AuthKit", RTLD_NOW); + + private init() { + dlopen("/System/Library/PrivateFrameworks/AuthKit.framework/AuthKit", RTLD_NOW) } - - func requestAnisetteData() throws -> ALTAnisetteData - { + + func requestAnisetteData() throws -> ALTAnisetteData { var request = URLRequest(url: URL(string: "https://developerservices2.apple.com/services/QH65B2/listTeams.action?clientId=XABBG36SBA")!) request.httpMethod = "POST" - + let akAppleIDSession = unsafeBitCast(NSClassFromString("AKAppleIDSession")!, to: AKAppleIDSession.Type.self) let akDevice = unsafeBitCast(NSClassFromString("AKDevice")!, to: AKDevice.Type.self) - + let session = akAppleIDSession.init(identifier: "com.apple.gs.xcode.auth") let headers = session.appleIDHeaders(for: request) - + let device = akDevice.current - let date = self.dateFormatter.date(from: headers["X-Apple-I-Client-Time"] ?? "") ?? Date() - + let date = dateFormatter.date(from: headers["X-Apple-I-Client-Time"] ?? "") ?? Date() + var localUserID = UserDefaults.standard.localUserID - if localUserID == nil - { + if localUserID == nil { localUserID = UUID().uuidString UserDefaults.standard.localUserID = localUserID } - + let anisetteData = ALTAnisetteData(machineID: headers["X-Apple-I-MD-M"] ?? "", oneTimePassword: headers["X-Apple-I-MD"] ?? "", localUserID: headers["X-Apple-I-MD-LU"] ?? localUserID ?? "", diff --git a/AltDaemon/AppManager.swift b/Sources/SideDaemon/AppManager.swift similarity index 73% rename from AltDaemon/AppManager.swift rename to Sources/SideDaemon/AppManager.swift index a0408ba2..d13b8638 100644 --- a/AltDaemon/AppManager.swift +++ b/Sources/SideDaemon/AppManager.swift @@ -10,127 +10,105 @@ import Foundation import AltSign -private extension URL -{ +private extension URL { static let profilesDirectoryURL = URL(fileURLWithPath: "/var/MobileDevice/ProvisioningProfiles", isDirectory: true) } -private extension CFNotificationName -{ +private extension CFNotificationName { static let updatedProvisioningProfiles = CFNotificationName("MISProvisioningProfileRemoved" as CFString) } -struct AppManager -{ +struct AppManager { static let shared = AppManager() - + private let appQueue = DispatchQueue(label: "com.rileytestut.AltDaemon.appQueue", qos: .userInitiated) private let profilesQueue = OperationQueue() - + private let fileCoordinator = NSFileCoordinator() - - private init() - { - self.profilesQueue.name = "com.rileytestut.AltDaemon.profilesQueue" - self.profilesQueue.qualityOfService = .userInitiated + + private init() { + profilesQueue.name = "com.rileytestut.AltDaemon.profilesQueue" + profilesQueue.qualityOfService = .userInitiated } - - func installApp(at fileURL: URL, bundleIdentifier: String, activeProfiles: Set?, completionHandler: @escaping (Result) -> Void) - { - self.appQueue.async { + + func installApp(at fileURL: URL, bundleIdentifier: String, activeProfiles _: Set?, completionHandler: @escaping (Result) -> Void) { + appQueue.async { let lsApplicationWorkspace = unsafeBitCast(NSClassFromString("LSApplicationWorkspace")!, to: LSApplicationWorkspace.Type.self) - - let options = ["CFBundleIdentifier": bundleIdentifier, "AllowInstallLocalProvisioned": NSNumber(value: true)] as [String : Any] + + let options = ["CFBundleIdentifier": bundleIdentifier, "AllowInstallLocalProvisioned": NSNumber(value: true)] as [String: Any] let result = Result { try lsApplicationWorkspace.default.installApplication(fileURL, withOptions: options) } - + completionHandler(result) } } - - func removeApp(forBundleIdentifier bundleIdentifier: String, completionHandler: @escaping (Result) -> Void) - { - self.appQueue.async { + + func removeApp(forBundleIdentifier bundleIdentifier: String, completionHandler: @escaping (Result) -> Void) { + appQueue.async { let lsApplicationWorkspace = unsafeBitCast(NSClassFromString("LSApplicationWorkspace")!, to: LSApplicationWorkspace.Type.self) lsApplicationWorkspace.default.uninstallApplication(bundleIdentifier, withOptions: nil) - + completionHandler(.success(())) } } - - func install(_ profiles: Set, activeProfiles: Set?, completionHandler: @escaping (Result) -> Void) - { + + func install(_ profiles: Set, activeProfiles: Set?, completionHandler: @escaping (Result) -> Void) { let intent = NSFileAccessIntent.writingIntent(with: .profilesDirectoryURL, options: []) - self.fileCoordinator.coordinate(with: [intent], queue: self.profilesQueue) { (error) in - do - { - if let error = error - { + fileCoordinator.coordinate(with: [intent], queue: profilesQueue) { error in + do { + if let error = error { throw error } - + let installingBundleIDs = Set(profiles.map(\.bundleIdentifier)) - + let profileURLs = try FileManager.default.contentsOfDirectory(at: intent.url, includingPropertiesForKeys: nil, options: []) - + // Remove all inactive profiles (if active profiles are provided), and the previous profiles. - for fileURL in profileURLs - { + for fileURL in profileURLs { // Use memory mapping to reduce peak memory usage and stay within limit. guard let profile = try? ALTProvisioningProfile(url: fileURL, options: [.mappedIfSafe]) else { continue } - - if installingBundleIDs.contains(profile.bundleIdentifier) || (activeProfiles?.contains(profile.bundleIdentifier) == false && profile.isFreeProvisioningProfile) - { + + if installingBundleIDs.contains(profile.bundleIdentifier) || (activeProfiles?.contains(profile.bundleIdentifier) == false && profile.isFreeProvisioningProfile) { try FileManager.default.removeItem(at: fileURL) - } - else - { + } else { print("Ignoring:", profile.bundleIdentifier, profile.uuid) } } - - for profile in profiles - { + + for profile in profiles { let destinationURL = URL.profilesDirectoryURL.appendingPathComponent(profile.uuid.uuidString.lowercased()) try profile.data.write(to: destinationURL, options: .atomic) } - + completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } - + // Notify system to prevent accidentally untrusting developer certificate. CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), .updatedProvisioningProfiles, nil, nil, true) } } - - func removeProvisioningProfiles(forBundleIdentifiers bundleIdentifiers: Set, completionHandler: @escaping (Result) -> Void) - { + + func removeProvisioningProfiles(forBundleIdentifiers bundleIdentifiers: Set, completionHandler: @escaping (Result) -> Void) { let intent = NSFileAccessIntent.writingIntent(with: .profilesDirectoryURL, options: []) - self.fileCoordinator.coordinate(with: [intent], queue: self.profilesQueue) { (error) in - do - { + fileCoordinator.coordinate(with: [intent], queue: profilesQueue) { error in + do { let profileURLs = try FileManager.default.contentsOfDirectory(at: intent.url, includingPropertiesForKeys: nil, options: []) - - for fileURL in profileURLs - { + + for fileURL in profileURLs { guard let profile = ALTProvisioningProfile(url: fileURL) else { continue } - - if bundleIdentifiers.contains(profile.bundleIdentifier) - { + + if bundleIdentifiers.contains(profile.bundleIdentifier) { try FileManager.default.removeItem(at: fileURL) } } - + completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } - + // Notify system to prevent accidentally untrusting developer certificate. CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), .updatedProvisioningProfiles, nil, nil, true) } diff --git a/AltDaemon/DaemonRequestHandler.swift b/Sources/SideDaemon/DaemonRequestHandler.swift similarity index 71% rename from AltDaemon/DaemonRequestHandler.swift rename to Sources/SideDaemon/DaemonRequestHandler.swift index 48b2d7c7..45ffabdd 100644 --- a/AltDaemon/DaemonRequestHandler.swift +++ b/Sources/SideDaemon/DaemonRequestHandler.swift @@ -13,108 +13,92 @@ typealias DaemonConnectionManager = ConnectionManager private let connectionManager = ConnectionManager(requestHandler: DaemonRequestHandler(), connectionHandlers: [XPCConnectionHandler()]) -extension DaemonConnectionManager -{ +extension DaemonConnectionManager { static var shared: ConnectionManager { - return connectionManager + connectionManager } } -struct DaemonRequestHandler: RequestHandler -{ - func handleAnisetteDataRequest(_ request: AnisetteDataRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - { - do - { +struct DaemonRequestHandler: RequestHandler { + func handleAnisetteDataRequest(_: AnisetteDataRequest, for _: Connection, completionHandler: @escaping (Result) -> Void) { + do { let anisetteData = try AnisetteDataManager.shared.requestAnisetteData() - + let response = AnisetteDataResponse(anisetteData: anisetteData) completionHandler(.success(response)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - - func handlePrepareAppRequest(_ request: PrepareAppRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - { + + func handlePrepareAppRequest(_ request: PrepareAppRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) { guard let fileURL = request.fileURL else { return completionHandler(.failure(ALTServerError(.invalidRequest))) } - + print("Awaiting begin installation request...") - - connection.receiveRequest() { (result) in + + connection.receiveRequest { result in print("Received begin installation request with result:", result) - - do - { - guard case .beginInstallation(let request) = try result.get() else { throw ALTServerError(.unknownRequest) } + + do { + guard case let .beginInstallation(request) = try result.get() else { throw ALTServerError(.unknownRequest) } guard let bundleIdentifier = request.bundleIdentifier else { throw ALTServerError(.invalidRequest) } - - AppManager.shared.installApp(at: fileURL, bundleIdentifier: bundleIdentifier, activeProfiles: request.activeProfiles) { (result) in + + AppManager.shared.installApp(at: fileURL, bundleIdentifier: bundleIdentifier, activeProfiles: request.activeProfiles) { result in let result = result.map { InstallationProgressResponse(progress: 1.0) } print("Installed app with result:", result) - + completionHandler(result) } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func handleInstallProvisioningProfilesRequest(_ request: InstallProvisioningProfilesRequest, for connection: Connection, - completionHandler: @escaping (Result) -> Void) - { - AppManager.shared.install(request.provisioningProfiles, activeProfiles: request.activeProfiles) { (result) in - switch result - { - case .failure(let error): + + func handleInstallProvisioningProfilesRequest(_ request: InstallProvisioningProfilesRequest, for _: Connection, + completionHandler: @escaping (Result) -> Void) { + AppManager.shared.install(request.provisioningProfiles, activeProfiles: request.activeProfiles) { result in + switch result { + case let .failure(error): print("Failed to install profiles \(request.provisioningProfiles.map { $0.bundleIdentifier }):", error) completionHandler(.failure(error)) - + case .success: print("Installed profiles:", request.provisioningProfiles.map { $0.bundleIdentifier }) - + let response = InstallProvisioningProfilesResponse() completionHandler(.success(response)) } } } - - func handleRemoveProvisioningProfilesRequest(_ request: RemoveProvisioningProfilesRequest, for connection: Connection, - completionHandler: @escaping (Result) -> Void) - { - AppManager.shared.removeProvisioningProfiles(forBundleIdentifiers: request.bundleIdentifiers) { (result) in - switch result - { - case .failure(let error): + + func handleRemoveProvisioningProfilesRequest(_ request: RemoveProvisioningProfilesRequest, for _: Connection, + completionHandler: @escaping (Result) -> Void) { + AppManager.shared.removeProvisioningProfiles(forBundleIdentifiers: request.bundleIdentifiers) { result in + switch result { + case let .failure(error): print("Failed to remove profiles \(request.bundleIdentifiers):", error) completionHandler(.failure(error)) - + case .success: print("Removed profiles:", request.bundleIdentifiers) - + let response = RemoveProvisioningProfilesResponse() completionHandler(.success(response)) } } } - - func handleRemoveAppRequest(_ request: RemoveAppRequest, for connection: Connection, completionHandler: @escaping (Result) -> Void) - { - AppManager.shared.removeApp(forBundleIdentifier: request.bundleIdentifier) { (result) in - switch result - { - case .failure(let error): + + func handleRemoveAppRequest(_ request: RemoveAppRequest, for _: Connection, completionHandler: @escaping (Result) -> Void) { + AppManager.shared.removeApp(forBundleIdentifier: request.bundleIdentifier) { result in + switch result { + case let .failure(error): print("Failed to remove app \(request.bundleIdentifier):", error) completionHandler(.failure(error)) - + case .success: print("Removed app:", request.bundleIdentifier) - + let response = RemoveAppResponse() completionHandler(.success(response)) } diff --git a/AltDaemon/XPCConnectionHandler.swift b/Sources/SideDaemon/XPCConnectionHandler.swift similarity index 75% rename from AltDaemon/XPCConnectionHandler.swift rename to Sources/SideDaemon/XPCConnectionHandler.swift index c1571a3f..9627fef0 100644 --- a/AltDaemon/XPCConnectionHandler.swift +++ b/Sources/SideDaemon/XPCConnectionHandler.swift @@ -9,85 +9,76 @@ import Foundation import Security -class XPCConnectionHandler: NSObject, ConnectionHandler -{ +class XPCConnectionHandler: NSObject, ConnectionHandler { var connectionHandler: ((Connection) -> Void)? var disconnectionHandler: ((Connection) -> Void)? - + private let dispatchQueue = DispatchQueue(label: "io.altstore.XPCConnectionListener", qos: .utility) private let listeners = XPCConnection.machServiceNames.map { NSXPCListener.makeListener(machServiceName: $0) } - - deinit - { + + deinit { self.stopListening() } - - func startListening() - { - for listener in self.listeners - { + + func startListening() { + for listener in listeners { listener.delegate = self listener.resume() } } - - func stopListening() - { - self.listeners.forEach { $0.suspend() } + + func stopListening() { + listeners.forEach { $0.suspend() } } } -private extension XPCConnectionHandler -{ - func disconnect(_ connection: Connection) - { +private extension XPCConnectionHandler { + func disconnect(_ connection: Connection) { connection.disconnect() - - self.disconnectionHandler?(connection) + + disconnectionHandler?(connection) } } -extension XPCConnectionHandler: NSXPCListenerDelegate -{ - func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool - { +extension XPCConnectionHandler: NSXPCListenerDelegate { + func listener(_: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { let maximumPathLength = 4 * UInt32(MAXPATHLEN) - + let pathBuffer = UnsafeMutablePointer.allocate(capacity: Int(maximumPathLength)) defer { pathBuffer.deallocate() } - + proc_pidpath(newConnection.processIdentifier, pathBuffer, maximumPathLength) - + let path = String(cString: pathBuffer) let fileURL = URL(fileURLWithPath: path) - + var code: UnsafeMutableRawPointer? defer { code.map { Unmanaged.fromOpaque($0).release() } } - + var status = SecStaticCodeCreateWithPath(fileURL as CFURL, 0, &code) guard status == 0 else { return false } - + var signingInfo: CFDictionary? defer { signingInfo.map { Unmanaged.passUnretained($0).release() } } - + status = SecCodeCopySigningInformation(code, kSecCSInternalInformation | kSecCSSigningInformation, &signingInfo) guard status == 0 else { return false } - + // Only accept connections from AltStore. guard let codeSigningInfo = signingInfo as? [String: Any], let bundleIdentifier = codeSigningInfo["identifier"] as? String, bundleIdentifier.contains(Bundle.Info.appbundleIdentifier) else { return false } - + let connection = XPCConnection(newConnection) newConnection.invalidationHandler = { [weak self, weak connection] in guard let self = self, let connection = connection else { return } self.disconnect(connection) } - self.connectionHandler?(connection) - + connectionHandler?(connection) + return true } } diff --git a/AltDaemon/main.swift b/Sources/SideDaemon/main.swift similarity index 100% rename from AltDaemon/main.swift rename to Sources/SideDaemon/main.swift diff --git a/AltDaemon/package/DEBIAN/control b/Sources/SideDaemon/package/DEBIAN/control similarity index 100% rename from AltDaemon/package/DEBIAN/control rename to Sources/SideDaemon/package/DEBIAN/control diff --git a/AltDaemon/package/DEBIAN/postinst b/Sources/SideDaemon/package/DEBIAN/postinst similarity index 100% rename from AltDaemon/package/DEBIAN/postinst rename to Sources/SideDaemon/package/DEBIAN/postinst diff --git a/AltDaemon/package/DEBIAN/preinst b/Sources/SideDaemon/package/DEBIAN/preinst similarity index 100% rename from AltDaemon/package/DEBIAN/preinst rename to Sources/SideDaemon/package/DEBIAN/preinst diff --git a/AltDaemon/package/DEBIAN/prerm b/Sources/SideDaemon/package/DEBIAN/prerm similarity index 100% rename from AltDaemon/package/DEBIAN/prerm rename to Sources/SideDaemon/package/DEBIAN/prerm diff --git a/AltDaemon/package/Library/LaunchDaemons/com.rileytestut.altdaemon.plist b/Sources/SideDaemon/package/Library/LaunchDaemons/com.rileytestut.altdaemon.plist similarity index 100% rename from AltDaemon/package/Library/LaunchDaemons/com.rileytestut.altdaemon.plist rename to Sources/SideDaemon/package/Library/LaunchDaemons/com.rileytestut.altdaemon.plist diff --git a/AltDaemon/package/usr/bin/AltDaemon b/Sources/SideDaemon/package/usr/bin/AltDaemon similarity index 100% rename from AltDaemon/package/usr/bin/AltDaemon rename to Sources/SideDaemon/package/usr/bin/AltDaemon diff --git a/Shared/Extensions/ALTApplication+AltStoreApp.swift b/Sources/SideStore/ALTApplication+AltStoreApp.swift similarity index 71% rename from Shared/Extensions/ALTApplication+AltStoreApp.swift rename to Sources/SideStore/ALTApplication+AltStoreApp.swift index dc983b66..c130d123 100644 --- a/Shared/Extensions/ALTApplication+AltStoreApp.swift +++ b/Sources/SideStore/ALTApplication+AltStoreApp.swift @@ -8,12 +8,11 @@ import AltSign -extension ALTApplication -{ +extension ALTApplication { static let altstoreBundleID = Bundle.Info.appbundleIdentifier - + var isAltStoreApp: Bool { - let isAltStoreApp = self.bundleIdentifier.contains(ALTApplication.altstoreBundleID) + let isAltStoreApp = bundleIdentifier.contains(ALTApplication.altstoreBundleID) return isAltStoreApp } } diff --git a/AltStore/Analytics/AnalyticsManager.swift b/Sources/SideStore/Analytics/AnalyticsManager.swift similarity index 77% rename from AltStore/Analytics/AnalyticsManager.swift rename to Sources/SideStore/Analytics/AnalyticsManager.swift index 8c88647f..f7b8bf0e 100644 --- a/AltStore/Analytics/AnalyticsManager.swift +++ b/Sources/SideStore/Analytics/AnalyticsManager.swift @@ -8,7 +8,7 @@ import Foundation -import AltStoreCore +import SideStoreCore import AppCenter import AppCenterAnalytics @@ -16,10 +16,8 @@ import AppCenterCrashes private let appCenterAppSecret = "73532d3e-e573-4693-99a4-9f85840bbb44" -extension AnalyticsManager -{ - enum EventProperty: String - { +extension AnalyticsManager { + enum EventProperty: String { case name case bundleIdentifier case developerName @@ -29,31 +27,28 @@ extension AnalyticsManager case sourceIdentifier case sourceURL } - - enum Event - { + + enum Event { case installedApp(InstalledApp) case updatedApp(InstalledApp) case refreshedApp(InstalledApp) - + var name: String { - switch self - { + switch self { case .installedApp: return "installed_app" case .updatedApp: return "updated_app" case .refreshedApp: return "refreshed_app" } } - + var properties: [EventProperty: String] { let properties: [EventProperty: String?] - - switch self - { - case .installedApp(let app), .updatedApp(let app), .refreshedApp(let app): + + switch self { + case let .installedApp(app), let .updatedApp(app), let .refreshedApp(app): let appBundleURL = InstalledApp.fileURL(for: app) let appBundleSize = FileManager.default.directorySize(at: appBundleURL) - + properties = [ .name: app.name, .bundleIdentifier: app.bundleIdentifier, @@ -65,37 +60,31 @@ extension AnalyticsManager .sourceURL: app.storeApp?.source?.sourceURL.absoluteString ] } - + return properties.compactMapValues { $0 } } } } -final class AnalyticsManager -{ +final class AnalyticsManager { static let shared = AnalyticsManager() - - private init() - { - } + + private init() {} } -extension AnalyticsManager -{ - func start() - { +extension AnalyticsManager { + func start() { AppCenter.start(withAppSecret: appCenterAppSecret, services: [ Analytics.self, Crashes.self ]) } - - func trackEvent(_ event: Event) - { - let properties = event.properties.reduce(into: [:]) { (properties, item) in + + func trackEvent(_ event: Event) { + let properties = event.properties.reduce(into: [:]) { properties, item in properties[item.key.rawValue] = item.value } - + Analytics.trackEvent(event.name, withProperties: properties) } } diff --git a/AltStore/App Detail/AppContentViewController.swift b/Sources/SideStore/App Detail/AppContentViewController.swift similarity index 51% rename from AltStore/App Detail/AppContentViewController.swift rename to Sources/SideStore/App Detail/AppContentViewController.swift index ea4c22e0..3819300e 100644 --- a/AltStore/App Detail/AppContentViewController.swift +++ b/Sources/SideStore/App Detail/AppContentViewController.swift @@ -8,15 +8,13 @@ import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI import Nuke -extension AppContentViewController -{ - private enum Row: Int, CaseIterable - { +extension AppContentViewController { + private enum Row: Int, CaseIterable { case subtitle case screenshots case description @@ -25,186 +23,169 @@ extension AppContentViewController } } -final class AppContentViewController: UITableViewController -{ +final class AppContentViewController: UITableViewController { var app: StoreApp! - + private lazy var screenshotsDataSource = self.makeScreenshotsDataSource() private lazy var permissionsDataSource = self.makePermissionsDataSource() - + private lazy var dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .none return dateFormatter }() - + private lazy var byteCountFormatter: ByteCountFormatter = { let formatter = ByteCountFormatter() return formatter }() - + @IBOutlet private var subtitleLabel: UILabel! @IBOutlet private var descriptionTextView: CollapsingTextView! @IBOutlet private var versionDescriptionTextView: CollapsingTextView! @IBOutlet private var versionLabel: UILabel! @IBOutlet private var versionDateLabel: UILabel! @IBOutlet private var sizeLabel: UILabel! - + @IBOutlet private var screenshotsCollectionView: UICollectionView! @IBOutlet private var permissionsCollectionView: UICollectionView! - - var preferredScreenshotSize: CGSize? { + + var preferredScreenshotSize: CGSize? { let layout = self.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout - + let aspectRatio: CGFloat = 16.0 / 9.0 // Hardcoded for now. - + let width = self.screenshotsCollectionView.bounds.width - (layout.minimumInteritemSpacing * 2) - + let itemWidth = width / 1.5 let itemHeight = itemWidth * aspectRatio - + return CGSize(width: itemWidth, height: itemHeight) } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.tableView.contentInset.bottom = 20 - - self.screenshotsCollectionView.dataSource = self.screenshotsDataSource - self.screenshotsCollectionView.prefetchDataSource = self.screenshotsDataSource - - self.permissionsCollectionView.dataSource = self.permissionsDataSource - - self.subtitleLabel.text = self.app.subtitle - self.descriptionTextView.text = self.app.localizedDescription - - if let version = self.app.latestVersion - { - self.versionDescriptionTextView.text = version.localizedDescription - self.versionLabel.text = String(format: NSLocalizedString("Version %@", comment: ""), version.version) - self.versionDateLabel.text = Date().relativeDateString(since: version.date, dateFormatter: self.dateFormatter) - self.sizeLabel.text = self.byteCountFormatter.string(fromByteCount: version.size) + + tableView.contentInset.bottom = 20 + + screenshotsCollectionView.dataSource = screenshotsDataSource + screenshotsCollectionView.prefetchDataSource = screenshotsDataSource + + permissionsCollectionView.dataSource = permissionsDataSource + + subtitleLabel.text = app.subtitle + descriptionTextView.text = app.localizedDescription + + if let version = app.latestVersion { + versionDescriptionTextView.text = version.localizedDescription + versionLabel.text = String(format: NSLocalizedString("Version %@", comment: ""), version.version) + versionDateLabel.text = Date().relativeDateString(since: version.date, dateFormatter: dateFormatter) + sizeLabel.text = byteCountFormatter.string(fromByteCount: version.size) + } else { + versionDescriptionTextView.text = nil + versionLabel.text = nil + versionDateLabel.text = nil + sizeLabel.text = byteCountFormatter.string(fromByteCount: 0) } - else - { - self.versionDescriptionTextView.text = nil - self.versionLabel.text = nil - self.versionDateLabel.text = nil - self.sizeLabel.text = self.byteCountFormatter.string(fromByteCount: 0) - } - - self.descriptionTextView.maximumNumberOfLines = 5 - self.descriptionTextView.moreButton.addTarget(self, action: #selector(AppContentViewController.toggleCollapsingSection(_:)), for: .primaryActionTriggered) - - self.versionDescriptionTextView.maximumNumberOfLines = 3 - self.versionDescriptionTextView.moreButton.addTarget(self, action: #selector(AppContentViewController.toggleCollapsingSection(_:)), for: .primaryActionTriggered) + + descriptionTextView.maximumNumberOfLines = 5 + descriptionTextView.moreButton.addTarget(self, action: #selector(AppContentViewController.toggleCollapsingSection(_:)), for: .primaryActionTriggered) + + versionDescriptionTextView.maximumNumberOfLines = 3 + versionDescriptionTextView.moreButton.addTarget(self, action: #selector(AppContentViewController.toggleCollapsingSection(_:)), for: .primaryActionTriggered) } - - override func viewDidLayoutSubviews() - { + + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - - guard var size = self.preferredScreenshotSize else { return } - size.height = min(size.height, self.screenshotsCollectionView.bounds.height) // Silence temporary "item too tall" warning. - - let layout = self.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout + + guard var size = preferredScreenshotSize else { return } + size.height = min(size.height, screenshotsCollectionView.bounds.height) // Silence temporary "item too tall" warning. + + let layout = screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.itemSize = size } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) - { + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "showPermission" else { return } - - guard let cell = sender as? UICollectionViewCell, let indexPath = self.permissionsCollectionView.indexPath(for: cell) else { return } - - let permission = self.permissionsDataSource.item(at: indexPath) - - let maximumWidth = self.view.bounds.width - 20 - + + guard let cell = sender as? UICollectionViewCell, let indexPath = permissionsCollectionView.indexPath(for: cell) else { return } + + let permission = permissionsDataSource.item(at: indexPath) + + let maximumWidth = view.bounds.width - 20 + let permissionPopoverViewController = segue.destination as! PermissionPopoverViewController permissionPopoverViewController.permission = permission permissionPopoverViewController.view.widthAnchor.constraint(lessThanOrEqualToConstant: maximumWidth).isActive = true - + let size = permissionPopoverViewController.view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) permissionPopoverViewController.preferredContentSize = size - + permissionPopoverViewController.popoverPresentationController?.delegate = self permissionPopoverViewController.popoverPresentationController?.sourceRect = cell.frame - permissionPopoverViewController.popoverPresentationController?.sourceView = self.permissionsCollectionView + permissionPopoverViewController.popoverPresentationController?.sourceView = permissionsCollectionView } } -private extension AppContentViewController -{ - func makeScreenshotsDataSource() -> RSTArrayCollectionViewPrefetchingDataSource - { - let dataSource = RSTArrayCollectionViewPrefetchingDataSource(items: self.app.screenshotURLs as [NSURL]) - dataSource.cellConfigurationHandler = { (cell, screenshot, indexPath) in +private extension AppContentViewController { + func makeScreenshotsDataSource() -> RSTArrayCollectionViewPrefetchingDataSource { + let dataSource = RSTArrayCollectionViewPrefetchingDataSource(items: app.screenshotURLs as [NSURL]) + dataSource.cellConfigurationHandler = { cell, _, _ in let cell = cell as! ScreenshotCollectionViewCell cell.imageView.image = nil cell.imageView.isIndicatingActivity = true } - dataSource.prefetchHandler = { (imageURL, indexPath, completionHandler) in - return RSTAsyncBlockOperation() { (operation) in + dataSource.prefetchHandler = { imageURL, _, completionHandler in + RSTAsyncBlockOperation { operation in let request = ImageRequest(url: imageURL as URL, processor: .screenshot) - ImagePipeline.shared.loadImage(with: request, progress: nil, completion: { (response, error) in + ImagePipeline.shared.loadImage(with: request, progress: nil, completion: { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completionHandler(image, nil) - } - else - { + } else { completionHandler(nil, error) } }) } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, error in let cell = cell as! ScreenshotCollectionViewCell cell.imageView.isIndicatingActivity = false cell.imageView.image = image - - if let error = error - { + + if let error = error { print("Error loading image:", error) } } - + return dataSource } - - func makePermissionsDataSource() -> RSTArrayCollectionViewDataSource - { - let dataSource = RSTArrayCollectionViewDataSource(items: self.app.permissions) - dataSource.cellConfigurationHandler = { (cell, permission, indexPath) in + + func makePermissionsDataSource() -> RSTArrayCollectionViewDataSource { + let dataSource = RSTArrayCollectionViewDataSource(items: app.permissions) + dataSource.cellConfigurationHandler = { cell, permission, _ in let cell = cell as! PermissionCollectionViewCell cell.button.setImage(permission.type.icon, for: .normal) cell.button.tintColor = .label cell.textLabel.text = permission.type.localizedShortName ?? permission.type.localizedName } - + return dataSource } } -private extension AppContentViewController -{ - @objc func toggleCollapsingSection(_ sender: UIButton) - { +private extension AppContentViewController { + @objc func toggleCollapsingSection(_ sender: UIButton) { let indexPath: IndexPath - - switch sender - { - case self.descriptionTextView.moreButton: indexPath = IndexPath(row: Row.description.rawValue, section: 0) - case self.versionDescriptionTextView.moreButton: indexPath = IndexPath(row: Row.versionDescription.rawValue, section: 0) + + switch sender { + case descriptionTextView.moreButton: indexPath = IndexPath(row: Row.description.rawValue, section: 0) + case versionDescriptionTextView.moreButton: indexPath = IndexPath(row: Row.versionDescription.rawValue, section: 0) default: return } - + // Disable animations to prevent some potentially strange ones. UIView.performWithoutAnimation { self.tableView.reloadRows(at: [indexPath], with: .none) @@ -212,35 +193,29 @@ private extension AppContentViewController } } -extension AppContentViewController -{ - override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) - { - cell.tintColor = self.app.tintColor +extension AppContentViewController { + override func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt _: IndexPath) { + cell.tintColor = app.tintColor } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat - { - switch Row.allCases[indexPath.row] - { + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + switch Row.allCases[indexPath.row] { case .screenshots: - guard let size = self.preferredScreenshotSize else { return 0.0 } + guard let size = preferredScreenshotSize else { return 0.0 } return size.height - + case .permissions: - guard !self.app.permissions.isEmpty else { return 0.0 } + guard !app.permissions.isEmpty else { return 0.0 } return super.tableView(tableView, heightForRowAt: indexPath) - + default: return super.tableView(tableView, heightForRowAt: indexPath) } } } -extension AppContentViewController: UIPopoverPresentationControllerDelegate -{ - func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle - { - return .none +extension AppContentViewController: UIPopoverPresentationControllerDelegate { + func adaptivePresentationStyle(for _: UIPresentationController, traitCollection _: UITraitCollection) -> UIModalPresentationStyle { + .none } } diff --git a/AltStore/App Detail/AppContentViewControllerCells.swift b/Sources/SideStore/App Detail/AppContentViewControllerCells.swift similarity index 57% rename from AltStore/App Detail/AppContentViewControllerCells.swift rename to Sources/SideStore/App Detail/AppContentViewControllerCells.swift index f0eded1a..e05c9410 100644 --- a/AltStore/App Detail/AppContentViewControllerCells.swift +++ b/Sources/SideStore/App Detail/AppContentViewControllerCells.swift @@ -8,36 +8,31 @@ import UIKit -final class PermissionCollectionViewCell: UICollectionViewCell -{ +final class PermissionCollectionViewCell: UICollectionViewCell { @IBOutlet var button: UIButton! @IBOutlet var textLabel: UILabel! - - override func layoutSubviews() - { + + override func layoutSubviews() { super.layoutSubviews() - - self.button.layer.cornerRadius = self.button.bounds.midY + + button.layer.cornerRadius = button.bounds.midY } - - override func tintColorDidChange() - { + + override func tintColorDidChange() { super.tintColorDidChange() - - self.button.backgroundColor = self.tintColor.withAlphaComponent(0.15) - self.textLabel.textColor = self.tintColor + + button.backgroundColor = tintColor.withAlphaComponent(0.15) + textLabel.textColor = tintColor } } -final class AppContentTableViewCell: UITableViewCell -{ - override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize - { +final class AppContentTableViewCell: UITableViewCell { + override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { // Ensure cell is laid out so it will report correct size. - self.layoutIfNeeded() - + layoutIfNeeded() + let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority) - + return size } } diff --git a/Sources/SideStore/App Detail/AppViewController.swift b/Sources/SideStore/App Detail/AppViewController.swift new file mode 100644 index 00000000..9f02dadf --- /dev/null +++ b/Sources/SideStore/App Detail/AppViewController.swift @@ -0,0 +1,503 @@ +// +// AppViewController.swift +// AltStore +// +// Created by Riley Testut on 7/22/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import SideStoreCore +import RoxasUI + +import Nuke + +final class AppViewController: UIViewController { + var app: StoreApp! + + private var contentViewController: AppContentViewController! + private var contentViewControllerShadowView: UIView! + + private var blurAnimator: UIViewPropertyAnimator? + private var navigationBarAnimator: UIViewPropertyAnimator? + + private var contentSizeObservation: NSKeyValueObservation? + + @IBOutlet private var scrollView: UIScrollView! + @IBOutlet private var contentView: UIView! + + @IBOutlet private var bannerView: AppBannerView! + + @IBOutlet private var backButton: UIButton! + @IBOutlet private var backButtonContainerView: UIVisualEffectView! + + @IBOutlet private var backgroundAppIconImageView: UIImageView! + @IBOutlet private var backgroundBlurView: UIVisualEffectView! + + @IBOutlet private var navigationBarTitleView: UIView! + @IBOutlet private var navigationBarDownloadButton: PillButton! + @IBOutlet private var navigationBarAppIconImageView: UIImageView! + @IBOutlet private var navigationBarAppNameLabel: UILabel! + + private var _shouldResetLayout = false + private var _backgroundBlurEffect: UIBlurEffect? + private var _backgroundBlurTintColor: UIColor? + + private var _preferredStatusBarStyle: UIStatusBarStyle = .default + + override var preferredStatusBarStyle: UIStatusBarStyle { + _preferredStatusBarStyle + } + + override func viewDidLoad() { + super.viewDidLoad() + + navigationBarTitleView.sizeToFit() + navigationItem.titleView = navigationBarTitleView + + contentViewControllerShadowView = UIView() + contentViewControllerShadowView.backgroundColor = .white + contentViewControllerShadowView.layer.cornerRadius = 38 + contentViewControllerShadowView.layer.shadowColor = UIColor.black.cgColor + contentViewControllerShadowView.layer.shadowOffset = CGSize(width: 0, height: -1) + contentViewControllerShadowView.layer.shadowRadius = 10 + contentViewControllerShadowView.layer.shadowOpacity = 0.3 + contentViewController.view.superview?.insertSubview(contentViewControllerShadowView, at: 0) + + contentView.addGestureRecognizer(scrollView.panGestureRecognizer) + + contentViewController.view.layer.cornerRadius = 38 + contentViewController.view.layer.masksToBounds = true + + contentViewController.tableView.panGestureRecognizer.require(toFail: scrollView.panGestureRecognizer) + contentViewController.tableView.showsVerticalScrollIndicator = false + + // Bring to front so the scroll indicators are visible. + view.bringSubviewToFront(scrollView) + scrollView.isUserInteractionEnabled = false + + bannerView.frame = CGRect(x: 0, y: 0, width: 300, height: 93) + bannerView.backgroundEffectView.effect = UIBlurEffect(style: .regular) + bannerView.backgroundEffectView.backgroundColor = .clear + bannerView.iconImageView.image = nil + bannerView.iconImageView.tintColor = app.tintColor + bannerView.button.tintColor = app.tintColor + bannerView.tintColor = app.tintColor + + bannerView.configure(for: app) + bannerView.accessibilityTraits.remove(.button) + + bannerView.button.addTarget(self, action: #selector(AppViewController.performAppAction(_:)), for: .primaryActionTriggered) + + backButtonContainerView.tintColor = app.tintColor + + navigationController?.navigationBar.tintColor = app.tintColor + navigationBarDownloadButton.tintColor = app.tintColor + navigationBarAppNameLabel.text = app.name + navigationBarAppIconImageView.tintColor = app.tintColor + + contentSizeObservation = contentViewController.tableView.observe(\.contentSize) { [weak self] _, _ in + self?.view.setNeedsLayout() + self?.view.layoutIfNeeded() + } + + update() + + NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.didChangeApp(_:)), name: .NSManagedObjectContextObjectsDidChange, object: DatabaseManager.shared.viewContext) + NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(AppViewController.didBecomeActive(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) + + _backgroundBlurEffect = backgroundBlurView.effect as? UIBlurEffect + _backgroundBlurTintColor = backgroundBlurView.contentView.backgroundColor + + // Load Images + for imageView in [bannerView.iconImageView!, backgroundAppIconImageView!, navigationBarAppIconImageView!] { + imageView.isIndicatingActivity = true + + Nuke.loadImage(with: app.iconURL, options: .shared, into: imageView, progress: nil) { [weak imageView] response, _ in + if response?.image != nil { + imageView?.isIndicatingActivity = false + } + } + } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + prepareBlur() + + // Update blur immediately. + view.setNeedsLayout() + view.layoutIfNeeded() + + transitionCoordinator?.animate(alongsideTransition: { _ in + self.hideNavigationBar() + }, completion: nil) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + _shouldResetLayout = true + view.setNeedsLayout() + view.layoutIfNeeded() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + // Guard against "dismissing" when presenting via 3D Touch pop. + guard self.navigationController != nil else { return } + + // Store reference since self.navigationController will be nil after disappearing. + let navigationController = self.navigationController + navigationController?.navigationBar.barStyle = .default // Don't animate, or else status bar might appear messed-up. + + transitionCoordinator?.animate(alongsideTransition: { _ in + self.showNavigationBar(for: navigationController) + }, completion: { context in + if !context.isCancelled { + self.showNavigationBar(for: navigationController) + } + }) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if navigationController == nil { + resetNavigationBarAnimation() + } + } + + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { + guard segue.identifier == "embedAppContentViewController" else { return } + + contentViewController = segue.destination as? AppContentViewController + contentViewController.app = app + + if #available(iOS 15, *) { + // Fix navigation bar + tab bar appearance on iOS 15. + self.setContentScrollView(self.scrollView) + self.navigationItem.scrollEdgeAppearance = self.navigationController?.navigationBar.standardAppearance + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if _shouldResetLayout { + // Various events can cause UI to mess up, so reset affected components now. + + if navigationController?.topViewController == self { + hideNavigationBar() + } + + prepareBlur() + + // Reset navigation bar animation, and create a new one later in this method if necessary. + resetNavigationBarAnimation() + + _shouldResetLayout = false + } + + let statusBarHeight = UIApplication.shared.statusBarFrame.height + let cornerRadius = contentViewControllerShadowView.layer.cornerRadius + + let inset = 12 as CGFloat + let padding = 20 as CGFloat + + let backButtonSize = backButton.sizeThatFits(CGSize(width: 1000, height: 1000)) + var backButtonFrame = CGRect(x: inset, y: statusBarHeight, + width: backButtonSize.width + 20, height: backButtonSize.height + 20) + + var headerFrame = CGRect(x: inset, y: 0, width: view.bounds.width - inset * 2, height: bannerView.bounds.height) + var contentFrame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height) + var backgroundIconFrame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.width) + + let minimumHeaderY = backButtonFrame.maxY + 8 + + let minimumContentY = minimumHeaderY + headerFrame.height + padding + let maximumContentY = view.bounds.width * 0.667 + + // A full blur is too much, so we reduce the visible blur by 0.3, resulting in 70% blur. + let minimumBlurFraction = 0.3 as CGFloat + + contentFrame.origin.y = maximumContentY - scrollView.contentOffset.y + headerFrame.origin.y = contentFrame.origin.y - padding - headerFrame.height + + // Stretch the app icon image to fill additional vertical space if necessary. + let height = max(contentFrame.origin.y + cornerRadius * 2, backgroundIconFrame.height) + backgroundIconFrame.size.height = height + + let blurThreshold = 0 as CGFloat + if scrollView.contentOffset.y < blurThreshold { + // Determine how much to lessen blur by. + + let range = 75 as CGFloat + let difference = -scrollView.contentOffset.y + + let fraction = min(difference, range) / range + + let fractionComplete = (fraction * (1.0 - minimumBlurFraction)) + minimumBlurFraction + blurAnimator?.fractionComplete = fractionComplete + } else { + // Set blur to default. + + blurAnimator?.fractionComplete = minimumBlurFraction + } + + // Animate navigation bar. + let showNavigationBarThreshold = (maximumContentY - minimumContentY) + backButtonFrame.origin.y + if scrollView.contentOffset.y > showNavigationBarThreshold { + if navigationBarAnimator == nil { + prepareNavigationBarAnimation() + } + + let difference = scrollView.contentOffset.y - showNavigationBarThreshold + let range = (headerFrame.height + padding) - (navigationController?.navigationBar.bounds.height ?? view.safeAreaInsets.top) + + let fractionComplete = min(difference, range) / range + navigationBarAnimator?.fractionComplete = fractionComplete + } else { + resetNavigationBarAnimation() + } + + let beginMovingBackButtonThreshold = (maximumContentY - minimumContentY) + if scrollView.contentOffset.y > beginMovingBackButtonThreshold { + let difference = scrollView.contentOffset.y - beginMovingBackButtonThreshold + backButtonFrame.origin.y -= difference + } + + let pinContentToTopThreshold = maximumContentY + if scrollView.contentOffset.y > pinContentToTopThreshold { + contentFrame.origin.y = 0 + backgroundIconFrame.origin.y = 0 + + let difference = scrollView.contentOffset.y - pinContentToTopThreshold + contentViewController.tableView.contentOffset.y = difference + } else { + // Keep content table view's content offset at the top. + contentViewController.tableView.contentOffset.y = 0 + } + + // Keep background app icon centered in gap between top of content and top of screen. + backgroundIconFrame.origin.y = (contentFrame.origin.y / 2) - backgroundIconFrame.height / 2 + + // Set frames. + contentViewController.view.superview?.frame = contentFrame + bannerView.frame = headerFrame + backgroundAppIconImageView.frame = backgroundIconFrame + backgroundBlurView.frame = backgroundIconFrame + backButtonContainerView.frame = backButtonFrame + + contentViewControllerShadowView.frame = contentViewController.view.frame + + backButtonContainerView.layer.cornerRadius = backButtonContainerView.bounds.midY + + scrollView.scrollIndicatorInsets.top = statusBarHeight + + // Adjust content offset + size. + let contentOffset = scrollView.contentOffset + + var contentSize = contentViewController.tableView.contentSize + contentSize.height += maximumContentY + + scrollView.contentSize = contentSize + scrollView.contentOffset = contentOffset + + bannerView.backgroundEffectView.backgroundColor = .clear + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + _shouldResetLayout = true + } + + deinit { + self.blurAnimator?.stopAnimation(true) + self.navigationBarAnimator?.stopAnimation(true) + } +} + +extension AppViewController { + final class func makeAppViewController(app: StoreApp) -> AppViewController { + let storyboard = UIStoryboard(name: "Main", bundle: nil) + + let appViewController = storyboard.instantiateViewController(withIdentifier: "appViewController") as! AppViewController + appViewController.app = app + return appViewController + } +} + +private extension AppViewController { + func update() { + for button in [bannerView.button!, navigationBarDownloadButton!] { + button.tintColor = app.tintColor + button.isIndicatingActivity = false + + if app.installedApp == nil { + button.setTitle(NSLocalizedString("FREE", comment: ""), for: .normal) + } else { + button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) + } + + let progress = AppManager.shared.installationProgress(for: app) + button.progress = progress + } + + if let versionDate = app.latestVersion?.date, versionDate > Date() { + bannerView.button.countdownDate = versionDate + navigationBarDownloadButton.countdownDate = versionDate + } else { + bannerView.button.countdownDate = nil + navigationBarDownloadButton.countdownDate = nil + } + + let barButtonItem = navigationItem.rightBarButtonItem + navigationItem.rightBarButtonItem = nil + navigationItem.rightBarButtonItem = barButtonItem + } + + func showNavigationBar(for navigationController: UINavigationController? = nil) { + let navigationController = navigationController ?? self.navigationController + navigationController?.navigationBar.alpha = 1.0 + navigationController?.navigationBar.tintColor = .altPrimary + navigationController?.navigationBar.setNeedsLayout() + + if traitCollection.userInterfaceStyle == .dark { + _preferredStatusBarStyle = .lightContent + } else { + _preferredStatusBarStyle = .default + } + + navigationController?.setNeedsStatusBarAppearanceUpdate() + } + + func hideNavigationBar(for navigationController: UINavigationController? = nil) { + let navigationController = navigationController ?? self.navigationController + navigationController?.navigationBar.alpha = 0.0 + + _preferredStatusBarStyle = .lightContent + navigationController?.setNeedsStatusBarAppearanceUpdate() + } + + func prepareBlur() { + if let animator = blurAnimator { + animator.stopAnimation(true) + } + + backgroundBlurView.effect = _backgroundBlurEffect + backgroundBlurView.contentView.backgroundColor = _backgroundBlurTintColor + + blurAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) { [weak self] in + self?.backgroundBlurView.effect = nil + self?.backgroundBlurView.contentView.backgroundColor = .clear + } + + blurAnimator?.startAnimation() + blurAnimator?.pauseAnimation() + } + + func prepareNavigationBarAnimation() { + resetNavigationBarAnimation() + + navigationBarAnimator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) { [weak self] in + self?.showNavigationBar() + self?.navigationController?.navigationBar.tintColor = self?.app.tintColor + self?.navigationController?.navigationBar.barTintColor = nil + self?.contentViewController.view.layer.cornerRadius = 0 + } + + navigationBarAnimator?.startAnimation() + navigationBarAnimator?.pauseAnimation() + + update() + } + + func resetNavigationBarAnimation() { + navigationBarAnimator?.stopAnimation(true) + navigationBarAnimator = nil + + hideNavigationBar() + + contentViewController.view.layer.cornerRadius = contentViewControllerShadowView.layer.cornerRadius + } +} + +extension AppViewController { + @IBAction func popViewController(_: UIButton) { + navigationController?.popViewController(animated: true) + } + + @IBAction func performAppAction(_: PillButton) { + if let installedApp = app.installedApp { + open(installedApp) + } else { + downloadApp() + } + } + + func downloadApp() { + guard app.installedApp == nil else { return } + + let group = AppManager.shared.install(app, presentingViewController: self) { result in + do { + _ = try result.get() + } catch OperationError.cancelled { + // Ignore + } catch { + DispatchQueue.main.async { + let toastView = ToastView(error: error) + toastView.show(in: self) + } + } + + DispatchQueue.main.async { + self.bannerView.button.progress = nil + self.navigationBarDownloadButton.progress = nil + self.update() + } + } + + bannerView.button.progress = group.progress + navigationBarDownloadButton.progress = group.progress + } + + func open(_ installedApp: InstalledApp) { + UIApplication.shared.open(installedApp.openAppURL) + } +} + +private extension AppViewController { + @objc func didChangeApp(_: Notification) { + // Async so that AppManager.installationProgress(for:) is nil when we update. + DispatchQueue.main.async { + self.update() + } + } + + @objc func willEnterForeground(_: Notification) { + guard let navigationController = navigationController, navigationController.topViewController == self else { return } + + _shouldResetLayout = true + view.setNeedsLayout() + } + + @objc func didBecomeActive(_: Notification) { + guard let navigationController = navigationController, navigationController.topViewController == self else { return } + + // Fixes Navigation Bar appearing after app becomes inactive -> active again. + _shouldResetLayout = true + view.setNeedsLayout() + } +} + +extension AppViewController: UIScrollViewDelegate { + func scrollViewDidScroll(_: UIScrollView) { + view.setNeedsLayout() + view.layoutIfNeeded() + } +} diff --git a/AltStore/App Detail/PermissionPopoverViewController.swift b/Sources/SideStore/App Detail/PermissionPopoverViewController.swift similarity index 55% rename from AltStore/App Detail/PermissionPopoverViewController.swift rename to Sources/SideStore/App Detail/PermissionPopoverViewController.swift index 52174a68..aa4acfb3 100644 --- a/AltStore/App Detail/PermissionPopoverViewController.swift +++ b/Sources/SideStore/App Detail/PermissionPopoverViewController.swift @@ -8,20 +8,18 @@ import UIKit -import AltStoreCore +import SideStoreCore -final class PermissionPopoverViewController: UIViewController -{ +final class PermissionPopoverViewController: UIViewController { var permission: AppPermission! - + @IBOutlet private var nameLabel: UILabel! @IBOutlet private var descriptionLabel: UILabel! - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.nameLabel.text = self.permission.type.localizedName - self.descriptionLabel.text = self.permission.usageDescription + + nameLabel.text = permission.type.localizedName + descriptionLabel.text = permission.usageDescription } } diff --git a/AltStore/App IDs/AppIDsViewController.swift b/Sources/SideStore/App IDs/AppIDsViewController.swift similarity index 73% rename from AltStore/App IDs/AppIDsViewController.swift rename to Sources/SideStore/App IDs/AppIDsViewController.swift index abe82fa0..20c1c53a 100644 --- a/AltStore/App IDs/AppIDsViewController.swift +++ b/Sources/SideStore/App IDs/AppIDsViewController.swift @@ -8,233 +8,202 @@ import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI -final class AppIDsViewController: UICollectionViewController -{ +final class AppIDsViewController: UICollectionViewController { private lazy var dataSource = self.makeDataSource() - + private var didInitialFetch = false private var isLoading = false { didSet { - self.update() + update() } } - + @IBOutlet var activityIndicatorBarButtonItem: UIBarButtonItem! - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.collectionView.dataSource = self.dataSource - - self.activityIndicatorBarButtonItem.isIndicatingActivity = true - + + collectionView.dataSource = dataSource + + activityIndicatorBarButtonItem.isIndicatingActivity = true + let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: #selector(AppIDsViewController.fetchAppIDs), for: .primaryActionTriggered) - self.collectionView.refreshControl = refreshControl + collectionView.refreshControl = refreshControl } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - if !self.didInitialFetch - { - self.fetchAppIDs() + + if !didInitialFetch { + fetchAppIDs() } } } -private extension AppIDsViewController -{ - func makeDataSource() -> RSTFetchedResultsCollectionViewDataSource - { +private extension AppIDsViewController { + func makeDataSource() -> RSTFetchedResultsCollectionViewDataSource { let fetchRequest = AppID.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \AppID.name, ascending: true), NSSortDescriptor(keyPath: \AppID.bundleIdentifier, ascending: true), NSSortDescriptor(keyPath: \AppID.expirationDate, ascending: true)] fetchRequest.returnsObjectsAsFaults = false - - if let team = DatabaseManager.shared.activeTeam() - { + + if let team = DatabaseManager.shared.activeTeam() { fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(AppID.team), team) - } - else - { + } else { fetchRequest.predicate = NSPredicate(value: false) } - + let dataSource = RSTFetchedResultsCollectionViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) dataSource.proxy = self - dataSource.cellConfigurationHandler = { (cell, appID, indexPath) in + dataSource.cellConfigurationHandler = { cell, appID, _ in let tintColor = UIColor.altPrimary - + let cell = cell as! BannerCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right cell.tintColor = tintColor - + cell.bannerView.iconImageView.isHidden = true cell.bannerView.button.isIndicatingActivity = false - + cell.bannerView.buttonLabel.text = NSLocalizedString("Expires in", comment: "") - + let attributedAccessibilityLabel = NSMutableAttributedString(string: appID.name + ". ") - - if let expirationDate = appID.expirationDate - { + + if let expirationDate = appID.expirationDate { cell.bannerView.button.isHidden = false cell.bannerView.button.isUserInteractionEnabled = false - + cell.bannerView.buttonLabel.isHidden = false - + let currentDate = Date() - + let numberOfDays = expirationDate.numberOfCalendarDays(since: currentDate) let numberOfDaysText = (numberOfDays == 1) ? NSLocalizedString("1 day", comment: "") : String(format: NSLocalizedString("%@ days", comment: ""), NSNumber(value: numberOfDays)) cell.bannerView.button.setTitle(numberOfDaysText.uppercased(), for: .normal) - + attributedAccessibilityLabel.mutableString.append(String(format: NSLocalizedString("Expires in %@.", comment: ""), numberOfDaysText) + " ") - } - else - { + } else { cell.bannerView.button.isHidden = true cell.bannerView.button.isUserInteractionEnabled = true - + cell.bannerView.buttonLabel.isHidden = true } - + cell.bannerView.titleLabel.text = appID.name cell.bannerView.subtitleLabel.text = appID.bundleIdentifier cell.bannerView.subtitleLabel.numberOfLines = 2 - + let attributedBundleIdentifier = NSMutableAttributedString(string: appID.bundleIdentifier.lowercased(), attributes: [.accessibilitySpeechPunctuation: true]) - - if let team = appID.team, let range = attributedBundleIdentifier.string.range(of: team.identifier.lowercased()), #available(iOS 13, *) - { + + if let team = appID.team, let range = attributedBundleIdentifier.string.range(of: team.identifier.lowercased()), #available(iOS 13, *) { // Prefer to speak the team ID one character at a time. let nsRange = NSRange(range, in: attributedBundleIdentifier.string) attributedBundleIdentifier.addAttributes([.accessibilitySpeechSpellOut: true], range: nsRange) } - + attributedAccessibilityLabel.append(attributedBundleIdentifier) cell.bannerView.accessibilityAttributedLabel = attributedAccessibilityLabel - + // Make sure refresh button is correct size. cell.layoutIfNeeded() } - + return dataSource } - - @objc func fetchAppIDs() - { - guard !self.isLoading else { return } - self.isLoading = true - - AppManager.shared.fetchAppIDs { (result) in - do - { + + @objc func fetchAppIDs() { + guard !isLoading else { return } + isLoading = true + + AppManager.shared.fetchAppIDs { result in + do { let (_, context) = try result.get() try context.save() - } - catch - { + } catch { DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) } } - + DispatchQueue.main.async { self.isLoading = false } } } - - func update() - { - if !self.isLoading - { - self.collectionView.refreshControl?.endRefreshing() - self.activityIndicatorBarButtonItem.isIndicatingActivity = false + + func update() { + if !isLoading { + collectionView.refreshControl?.endRefreshing() + activityIndicatorBarButtonItem.isIndicatingActivity = false } } } -extension AppIDsViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { - return CGSize(width: collectionView.bounds.width, height: 80) +extension AppIDsViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize { + CGSize(width: collectionView.bounds.width, height: 80) } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize - { + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { let indexPath = IndexPath(row: 0, section: section) let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath) - + // Use this view to calculate the optimal size based on the collection view's width let size = headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, // Width is fixed verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed return size } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize - { - return CGSize(width: collectionView.bounds.width, height: 50) + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForFooterInSection _: Int) -> CGSize { + CGSize(width: collectionView.bounds.width, height: 50) } - - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { - switch kind - { + + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + switch kind { case UICollectionView.elementKindSectionHeader: let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath) as! TextCollectionReusableView - headerView.layoutMargins.left = self.view.layoutMargins.left - headerView.layoutMargins.right = self.view.layoutMargins.right - - if let activeTeam = DatabaseManager.shared.activeTeam(), activeTeam.type == .free - { + headerView.layoutMargins.left = view.layoutMargins.left + headerView.layoutMargins.right = view.layoutMargins.right + + if let activeTeam = DatabaseManager.shared.activeTeam(), activeTeam.type == .free { let text = NSLocalizedString(""" Each app and app extension installed with SideStore must register an App ID with Apple. Apple limits non-developer Apple IDs to 10 App IDs at a time. **App IDs can't be deleted**, but they do expire after one week. SideStore will automatically renew App IDs for all active apps once they've expired. """, comment: "") - + let attributedText = NSAttributedString(markdownRepresentation: text, attributes: [.font: headerView.textLabel.font as Any]) headerView.textLabel.attributedText = attributedText - } - else - { + } else { headerView.textLabel.text = NSLocalizedString(""" Each app and app extension installed with SideStore must register an App ID with Apple. - + App IDs for paid developer accounts never expire, and there is no limit to how many you can create. """, comment: "") } - + return headerView - + case UICollectionView.elementKindSectionFooter: let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Footer", for: indexPath) as! TextCollectionReusableView - - let count = self.dataSource.itemCount - if count == 1 - { + + let count = dataSource.itemCount + if count == 1 { footerView.textLabel.text = NSLocalizedString("1 App ID", comment: "") - } - else - { + } else { footerView.textLabel.text = String(format: NSLocalizedString("%@ App IDs", comment: ""), NSNumber(value: count)) } - + return footerView - + default: fatalError() } } diff --git a/AltStore/AppDelegate.swift b/Sources/SideStore/AppDelegate.swift similarity index 72% rename from AltStore/AppDelegate.swift rename to Sources/SideStore/AppDelegate.swift index 8c7eb983..e17cbcc4 100644 --- a/AltStore/AppDelegate.swift +++ b/Sources/SideStore/AppDelegate.swift @@ -6,24 +6,23 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit -import UserNotifications import AVFoundation import Intents +import UIKit +import UserNotifications -import AltStoreCore import AltSign -import RoxasUI +import SideStoreCore import EmotionalDamage +import RoxasUI -extension AppDelegate -{ +extension AppDelegate { static let openPatreonSettingsDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".OpenPatreonSettingsDeepLinkNotification") static let importAppDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".ImportAppDeepLinkNotification") static let addSourceDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".AddSourceDeepLinkNotification") - + static let appBackupDidFinish = Notification.Name(Bundle.Info.appbundleIdentifier + ".AppBackupDidFinish") - + static let importAppDeepLinkURLKey = "fileURL" static let appBackupResultKey = "result" static let addSourceDeepLinkURLKey = "sourceURL" @@ -31,167 +30,143 @@ extension AppDelegate @UIApplicationMain final class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? - + @available(iOS 14, *) private var intentHandler: IntentHandler { get { _intentHandler as! IntentHandler } set { _intentHandler = newValue } } - + @available(iOS 14, *) private var viewAppIntentHandler: ViewAppIntentHandler { get { _viewAppIntentHandler as! ViewAppIntentHandler } set { _viewAppIntentHandler = newValue } } - + private lazy var _intentHandler: Any = { guard #available(iOS 14, *) else { fatalError() } return IntentHandler() }() - + private lazy var _viewAppIntentHandler: Any = { guard #available(iOS 14, *) else { fatalError() } return ViewAppIntentHandler() }() - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool - { + + func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Register default settings before doing anything else. UserDefaults.registerDefaults() - - DatabaseManager.shared.start { (error) in - if let error = error - { + + DatabaseManager.shared.start { error in + if let error = error { print("Failed to start DatabaseManager. Error:", error as Any) - } - else - { + } else { print("Started DatabaseManager.") } } - + AnalyticsManager.shared.start() - - self.setTintColor() - - SecureValueTransformer.register() - - if UserDefaults.standard.firstLaunch == nil - { + + setTintColor() + + SecureValueTransformer.register() + + if UserDefaults.standard.firstLaunch == nil { Keychain.shared.reset() UserDefaults.standard.firstLaunch = Date() } - + UserDefaults.standard.preferredServerID = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.serverID) as? String - + #if DEBUG || BETA - UserDefaults.standard.isDebugModeEnabled = true + UserDefaults.standard.isDebugModeEnabled = true #endif - - self.prepareForBackgroundFetch() - + + prepareForBackgroundFetch() + return true } - - func applicationDidEnterBackground(_ application: UIApplication) - { + + func applicationDidEnterBackground(_: UIApplication) { // Make sure to update SceneDelegate.sceneDidEnterBackground() as well. - + guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return } - + let midnightOneMonthAgo = Calendar.current.startOfDay(for: oneMonthAgo) DatabaseManager.shared.purgeLoggedErrors(before: midnightOneMonthAgo) { result in - switch result - { + switch result { case .success: break - case .failure(let error): print("[ALTLog] Failed to purge logged errors before \(midnightOneMonthAgo).", error) + case let .failure(error): print("[ALTLog] Failed to purge logged errors before \(midnightOneMonthAgo).", error) } } - } - func applicationWillEnterForeground(_ application: UIApplication) - { + func applicationWillEnterForeground(_: UIApplication) { AppManager.shared.update() start_em_proxy(bind_addr: Consts.Proxy.serverURL) } - - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool - { - return self.open(url) + + func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { + open(url) } - - func application(_ application: UIApplication, handlerFor intent: INIntent) -> Any? - { + + func application(_: UIApplication, handlerFor intent: INIntent) -> Any? { guard #available(iOS 14, *) else { return nil } - - switch intent - { - case is RefreshAllIntent: return self.intentHandler - case is ViewAppIntent: return self.viewAppIntentHandler + + switch intent { + case is RefreshAllIntent: return intentHandler + case is ViewAppIntent: return viewAppIntentHandler default: return nil } } } @available(iOS 13, *) -extension AppDelegate -{ - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration - { +extension AppDelegate { + func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) - { + + func application(_: UIApplication, didDiscardSceneSessions _: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } -private extension AppDelegate -{ - func setTintColor() - { - self.window?.tintColor = .altPrimary +private extension AppDelegate { + func setTintColor() { + window?.tintColor = .altPrimary } - - func open(_ url: URL) -> Bool - { - if url.isFileURL - { + + func open(_ url: URL) -> Bool { + if url.isFileURL { guard url.pathExtension.lowercased() == "ipa" else { return false } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: url]) } - + return true - } - else - { + } else { guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return false } guard let host = components.host?.lowercased() else { return false } - - switch host - { + + switch host { case "patreon": DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) } - + return true - + case "appbackupresponse": let result: Result - - switch url.path.lowercased() - { + + switch url.path.lowercased() { case "/success": result = .success(()) case "/failure": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name] = $1.value } ?? [:] @@ -200,216 +175,193 @@ private extension AppDelegate let errorCodeString = queryItems["errorCode"], let errorCode = Int(errorCodeString), let errorDescription = queryItems["errorDescription"] else { return false } - + let error = NSError(domain: errorDomain, code: errorCode, userInfo: [NSLocalizedDescriptionKey: errorDescription]) result = .failure(error) - + default: return false } - + NotificationCenter.default.post(name: AppDelegate.appBackupDidFinish, object: nil, userInfo: [AppDelegate.appBackupResultKey: result]) - + return true - + case "install": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] guard let downloadURLString = queryItems["url"], let downloadURL = URL(string: downloadURLString) else { return false } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: downloadURL]) } - + return true - + case "source": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] guard let sourceURLString = queryItems["url"], let sourceURL = URL(string: sourceURLString) else { return false } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL]) } - + return true - + default: return false } } } } -extension AppDelegate -{ - private func prepareForBackgroundFetch() - { +extension AppDelegate { + private func prepareForBackgroundFetch() { // "Fetch" every hour, but then refresh only those that need to be refreshed (so we don't drain the battery). UIApplication.shared.setMinimumBackgroundFetchInterval(1 * 60 * 60) - - UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (success, error) in + + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in } - + #if DEBUG - UIApplication.shared.registerForRemoteNotifications() + UIApplication.shared.registerForRemoteNotifications() #endif } - - func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) + + func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let tokenParts = deviceToken.map { data -> String in - return String(format: "%02.2hhx", data) + String(format: "%02.2hhx", data) } - + let token = tokenParts.joined() print("Push Token:", token) } - - func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) - { + + func application(_ application: UIApplication, didReceiveRemoteNotification _: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { self.application(application, performFetchWithCompletionHandler: completionHandler) } - - func application(_ application: UIApplication, performFetchWithCompletionHandler backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void) - { - if UserDefaults.standard.isBackgroundRefreshEnabled && !UserDefaults.standard.presentedLaunchReminderNotification - { + + func application(_: UIApplication, performFetchWithCompletionHandler backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + if UserDefaults.standard.isBackgroundRefreshEnabled && !UserDefaults.standard.presentedLaunchReminderNotification { let threeHours: TimeInterval = 3 * 60 * 60 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: threeHours, repeats: false) - + let content = UNMutableNotificationContent() content.title = NSLocalizedString("App Refresh Tip", comment: "") content.body = NSLocalizedString("The more you open SideStore, the more chances it's given to refresh apps in the background.", comment: "") - + let request = UNNotificationRequest(identifier: "background-refresh-reminder5", content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) - + UserDefaults.standard.presentedLaunchReminderNotification = true } - - BackgroundTaskManager.shared.performExtendedBackgroundTask { (taskResult, taskCompletionHandler) in - if let error = taskResult.error - { + + BackgroundTaskManager.shared.performExtendedBackgroundTask { taskResult, taskCompletionHandler in + if let error = taskResult.error { print("Error starting extended background task. Aborting.", error) backgroundFetchCompletionHandler(.failed) taskCompletionHandler() return } - - if !DatabaseManager.shared.isStarted - { - DatabaseManager.shared.start() { (error) in - if error != nil - { + + if !DatabaseManager.shared.isStarted { + DatabaseManager.shared.start { error in + if error != nil { backgroundFetchCompletionHandler(.failed) taskCompletionHandler() - } - else - { - self.performBackgroundFetch { (backgroundFetchResult) in + } else { + self.performBackgroundFetch { backgroundFetchResult in backgroundFetchCompletionHandler(backgroundFetchResult) - } refreshAppsCompletionHandler: { (refreshAppsResult) in + } refreshAppsCompletionHandler: { _ in taskCompletionHandler() } } } - } - else - { - self.performBackgroundFetch { (backgroundFetchResult) in + } else { + self.performBackgroundFetch { backgroundFetchResult in backgroundFetchCompletionHandler(backgroundFetchResult) - } refreshAppsCompletionHandler: { (refreshAppsResult) in + } refreshAppsCompletionHandler: { _ in taskCompletionHandler() } } } } - + func performBackgroundFetch(backgroundFetchCompletionHandler: @escaping (UIBackgroundFetchResult) -> Void, - refreshAppsCompletionHandler: @escaping (Result<[String: Result], Error>) -> Void) - { - self.fetchSources { (result) in - switch result - { + refreshAppsCompletionHandler: @escaping (Result<[String: Result], Error>) -> Void) { + fetchSources { result in + switch result { case .failure: backgroundFetchCompletionHandler(.failed) case .success: backgroundFetchCompletionHandler(.newData) } - - if !UserDefaults.standard.isBackgroundRefreshEnabled - { + + if !UserDefaults.standard.isBackgroundRefreshEnabled { refreshAppsCompletionHandler(.success([:])) } } - + guard UserDefaults.standard.isBackgroundRefreshEnabled else { return } - - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let installedApps = InstalledApp.fetchAppsForBackgroundRefresh(in: context) AppManager.shared.backgroundRefresh(installedApps, completionHandler: refreshAppsCompletionHandler) } } } -private extension AppDelegate -{ - func fetchSources(completionHandler: @escaping (Result, Error>) -> Void) - { - AppManager.shared.fetchSources() { (result) in - do - { +private extension AppDelegate { + func fetchSources(completionHandler: @escaping (Result, Error>) -> Void) { + AppManager.shared.fetchSources { result in + do { let (sources, context) = try result.get() - + let previousUpdatesFetchRequest = InstalledApp.updatesFetchRequest() as! NSFetchRequest previousUpdatesFetchRequest.includesPendingChanges = false previousUpdatesFetchRequest.resultType = .dictionaryResultType previousUpdatesFetchRequest.propertiesToFetch = [#keyPath(InstalledApp.bundleIdentifier)] - + let previousNewsItemsFetchRequest = NewsItem.fetchRequest() as NSFetchRequest previousNewsItemsFetchRequest.includesPendingChanges = false previousNewsItemsFetchRequest.resultType = .dictionaryResultType previousNewsItemsFetchRequest.propertiesToFetch = [#keyPath(NewsItem.identifier)] - + let previousUpdates = try context.fetch(previousUpdatesFetchRequest) as! [[String: String]] let previousNewsItems = try context.fetch(previousNewsItemsFetchRequest) as! [[String: String]] - + try context.save() - + let updatesFetchRequest = InstalledApp.updatesFetchRequest() let newsItemsFetchRequest = NewsItem.fetchRequest() as NSFetchRequest - + let updates = try context.fetch(updatesFetchRequest) let newsItems = try context.fetch(newsItemsFetchRequest) - - for update in updates - { + + for update in updates { guard !previousUpdates.contains(where: { $0[#keyPath(InstalledApp.bundleIdentifier)] == update.bundleIdentifier }) else { continue } guard let storeApp = update.storeApp, let version = storeApp.version else { continue } - + let content = UNMutableNotificationContent() content.title = NSLocalizedString("New Update Available", comment: "") content.body = String(format: NSLocalizedString("%@ %@ is now available for download.", comment: ""), update.name, version) content.sound = .default - + let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) } - - for newsItem in newsItems - { + + for newsItem in newsItems { guard !previousNewsItems.contains(where: { $0[#keyPath(NewsItem.identifier)] == newsItem.identifier }) else { continue } guard !newsItem.isSilent else { continue } - + let content = UNMutableNotificationContent() - - if let app = newsItem.storeApp - { + + if let app = newsItem.storeApp { content.title = String(format: NSLocalizedString("%@ News", comment: ""), app.name) - } - else - { + } else { content.title = NSLocalizedString("SideStore News", comment: "") } - + content.body = newsItem.title content.sound = .default - + let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) } @@ -417,11 +369,9 @@ private extension AppDelegate DispatchQueue.main.async { UIApplication.shared.applicationIconBadgeNumber = updates.count } - + completionHandler(.success(sources)) - } - catch - { + } catch { print("Error fetching apps:", error) completionHandler(.failure(error)) } diff --git a/AltStore/Authentication/Authentication.storyboard b/Sources/SideStore/Authentication/Authentication.storyboard similarity index 100% rename from AltStore/Authentication/Authentication.storyboard rename to Sources/SideStore/Authentication/Authentication.storyboard diff --git a/Sources/SideStore/Authentication/AuthenticationViewController.swift b/Sources/SideStore/Authentication/AuthenticationViewController.swift new file mode 100644 index 00000000..69ba1f39 --- /dev/null +++ b/Sources/SideStore/Authentication/AuthenticationViewController.swift @@ -0,0 +1,150 @@ +// +// AuthenticationViewController.swift +// AltStore +// +// Created by Riley Testut on 9/5/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import AltSign + +final class AuthenticationViewController: UIViewController { + var authenticationHandler: ((String, String, @escaping (Result<(ALTAccount, ALTAppleAPISession), Error>) -> Void) -> Void)? + var completionHandler: (((ALTAccount, ALTAppleAPISession, String)?) -> Void)? + + private weak var toastView: ToastView? + + @IBOutlet private var appleIDTextField: UITextField! + @IBOutlet private var passwordTextField: UITextField! + @IBOutlet private var signInButton: UIButton! + + @IBOutlet private var appleIDBackgroundView: UIView! + @IBOutlet private var passwordBackgroundView: UIView! + + @IBOutlet private var scrollView: UIScrollView! + @IBOutlet private var contentStackView: UIStackView! + + override func viewDidLoad() { + super.viewDidLoad() + + signInButton.activityIndicatorView.style = .medium + + for view in [appleIDBackgroundView!, passwordBackgroundView!, signInButton!] { + view.clipsToBounds = true + view.layer.cornerRadius = 16 + } + + if UIScreen.main.isExtraCompactHeight { + contentStackView.spacing = 20 + } + + NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: appleIDTextField) + NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: passwordTextField) + + update() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + signInButton.isIndicatingActivity = false + toastView?.dismiss() + } +} + +private extension AuthenticationViewController { + func update() { + if let _ = validate() { + signInButton.isEnabled = true + signInButton.alpha = 1.0 + } else { + signInButton.isEnabled = false + signInButton.alpha = 0.6 + } + } + + func validate() -> (String, String)? { + guard + let emailAddress = appleIDTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !emailAddress.isEmpty, + let password = passwordTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !password.isEmpty + else { return nil } + + return (emailAddress, password) + } +} + +private extension AuthenticationViewController { + @IBAction func authenticate() { + guard let (emailAddress, password) = validate() else { return } + + appleIDTextField.resignFirstResponder() + passwordTextField.resignFirstResponder() + + signInButton.isIndicatingActivity = true + + authenticationHandler?(emailAddress, password) { result in + switch result { + case .failure(ALTAppleAPIError.requiresTwoFactorAuthentication): + // Ignore + DispatchQueue.main.async { + self.signInButton.isIndicatingActivity = false + } + + case let .failure(error as NSError): + DispatchQueue.main.async { + let error = error.withLocalizedFailure(NSLocalizedString("Failed to Log In", comment: "")) + + let toastView = ToastView(error: error) + toastView.textLabel.textColor = .altPink + toastView.detailTextLabel.textColor = .altPink + toastView.show(in: self) + self.toastView = toastView + + self.signInButton.isIndicatingActivity = false + } + + case let .success((account, session)): + self.completionHandler?((account, session, password)) + } + + DispatchQueue.main.async { + self.scrollView.setContentOffset(CGPoint(x: 0, y: -self.view.safeAreaInsets.top), animated: true) + } + } + } + + @IBAction func cancel(_: UIBarButtonItem) { + completionHandler?(nil) + } +} + +extension AuthenticationViewController: UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + switch textField { + case appleIDTextField: passwordTextField.becomeFirstResponder() + case passwordTextField: authenticate() + default: break + } + + update() + + return false + } + + func textFieldDidBeginEditing(_: UITextField) { + guard UIScreen.main.isExtraCompactHeight else { return } + + // Position all the controls within visible frame. + var contentOffset = scrollView.contentOffset + contentOffset.y = 44 + scrollView.setContentOffset(contentOffset, animated: true) + } +} + +extension AuthenticationViewController { + @objc func textFieldDidChangeText(_: Notification) { + update() + } +} diff --git a/Sources/SideStore/Authentication/InstructionsViewController.swift b/Sources/SideStore/Authentication/InstructionsViewController.swift new file mode 100644 index 00000000..d5ab2c1d --- /dev/null +++ b/Sources/SideStore/Authentication/InstructionsViewController.swift @@ -0,0 +1,46 @@ +// +// InstructionsViewController.swift +// AltStore +// +// Created by Riley Testut on 9/6/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class InstructionsViewController: UIViewController { + var completionHandler: (() -> Void)? + + var showsBottomButton: Bool = false + + @IBOutlet private var contentStackView: UIStackView! + @IBOutlet private var dismissButton: UIButton! + + override var preferredStatusBarStyle: UIStatusBarStyle { + .lightContent + } + + override func viewDidLoad() { + super.viewDidLoad() + + if UIScreen.main.isExtraCompactHeight { + contentStackView.layoutMargins.top = 0 + contentStackView.layoutMargins.bottom = contentStackView.layoutMargins.left + } + + dismissButton.clipsToBounds = true + dismissButton.layer.cornerRadius = 16 + + if showsBottomButton { + navigationItem.hidesBackButton = true + } else { + dismissButton.isHidden = true + } + } +} + +private extension InstructionsViewController { + @IBAction func dismiss() { + completionHandler?() + } +} diff --git a/AltStore/Authentication/RefreshAltStoreViewController.swift b/Sources/SideStore/Authentication/RefreshAltStoreViewController.swift similarity index 58% rename from AltStore/Authentication/RefreshAltStoreViewController.swift rename to Sources/SideStore/Authentication/RefreshAltStoreViewController.swift index 0c07d77b..c440214e 100644 --- a/AltStore/Authentication/RefreshAltStoreViewController.swift +++ b/Sources/SideStore/Authentication/RefreshAltStoreViewController.swift @@ -8,77 +8,69 @@ import UIKit -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI -final class RefreshAltStoreViewController: UIViewController -{ +final class RefreshAltStoreViewController: UIViewController { var context: AuthenticatedOperationContext! - + var completionHandler: ((Result) -> Void)? - + @IBOutlet private var placeholderView: RSTPlaceholderView! - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.placeholderView.textLabel.isHidden = true - - self.placeholderView.detailTextLabel.textAlignment = .left - self.placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6) - self.placeholderView.detailTextLabel.text = NSLocalizedString("SideStore was unable to use an existing signing certificate, so it had to create a new one. This will cause any apps installed with an existing certificate to expire — including SideStore.\n\nTo prevent SideStore from expiring early, please refresh the app now. SideStore will quit once refreshing is complete.", comment: "") + + placeholderView.textLabel.isHidden = true + + placeholderView.detailTextLabel.textAlignment = .left + placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6) + placeholderView.detailTextLabel.text = NSLocalizedString("SideStore was unable to use an existing signing certificate, so it had to create a new one. This will cause any apps installed with an existing certificate to expire — including SideStore.\n\nTo prevent SideStore from expiring early, please refresh the app now. SideStore will quit once refreshing is complete.", comment: "") } } -private extension RefreshAltStoreViewController -{ - @IBAction func refreshAltStore(_ sender: PillButton) - { +private extension RefreshAltStoreViewController { + @IBAction func refreshAltStore(_ sender: PillButton) { guard let altStore = InstalledApp.fetchAltStore(in: DatabaseManager.shared.viewContext) else { return } - - func refresh() - { + + func refresh() { sender.isIndicatingActivity = true - - if let progress = AppManager.shared.installationProgress(for: altStore) - { + + if let progress = AppManager.shared.installationProgress(for: altStore) { // Cancel pending AltStore installation so we can start a new one. progress.cancel() } - + // Install, _not_ refresh, to ensure we are installing with a non-revoked certificate. - let group = AppManager.shared.install(altStore, presentingViewController: self, context: self.context) { (result) in - switch result - { + let group = AppManager.shared.install(altStore, presentingViewController: self, context: context) { result in + switch result { case .success: self.completionHandler?(.success(())) - case .failure(let error as NSError): + case let .failure(error as NSError): DispatchQueue.main.async { sender.progress = nil sender.isIndicatingActivity = false - + let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh SideStore", comment: ""), message: error.localizedFailureReason ?? error.localizedDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { _ in refresh() })) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Refresh Later", comment: ""), style: .cancel, handler: { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Refresh Later", comment: ""), style: .cancel, handler: { _ in self.completionHandler?(.failure(error)) })) - + self.present(alertController, animated: true, completion: nil) } } } - + sender.progress = group.progress } - + refresh() } - - @IBAction func cancel(_ sender: UIButton) - { - self.completionHandler?(.failure(OperationError.cancelled)) + + @IBAction func cancel(_: UIButton) { + completionHandler?(.failure(OperationError.cancelled)) } } diff --git a/AltStore/Authentication/SelectTeamViewController.swift b/Sources/SideStore/Authentication/SelectTeamViewController.swift similarity index 57% rename from AltStore/Authentication/SelectTeamViewController.swift rename to Sources/SideStore/Authentication/SelectTeamViewController.swift index d42f425c..d98fd2dc 100644 --- a/AltStore/Authentication/SelectTeamViewController.swift +++ b/Sources/SideStore/Authentication/SelectTeamViewController.swift @@ -6,44 +6,42 @@ // Copyright © 2021 Riley Testut. All rights reserved. // -import UIKit -import SafariServices -import MessageUI import Intents import IntentsUI +import MessageUI +import SafariServices +import UIKit import AltSign -final class SelectTeamViewController: UITableViewController -{ +final class SelectTeamViewController: UITableViewController { public var teams: [ALTTeam]? - public var completionHandler: ((Result) -> Void)? - + public var completionHandler: ((Result) -> Void)? + private var prototypeHeaderFooterView: SettingsHeaderFooterView! - + override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent + .lightContent } - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 + + override func numberOfSections(in _: UITableView) -> Int { + 1 } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return teams?.count ?? 0 + + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + teams?.count ?? 0 } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - return self.completionHandler!(.success((self.teams?[indexPath.row])!)) + + override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { + completionHandler!(.success(teams?[indexPath.row]!)) } - + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TeamCell", for: indexPath) as! InsetGroupTableViewCell - cell.textLabel?.text = self.teams?[indexPath.row].name - cell.detailTextLabel?.text = self.teams?[indexPath.row].type.localizedDescription - if indexPath.row == 0 - { + cell.textLabel?.text = teams?[indexPath.row].name + cell.detailTextLabel?.text = teams?[indexPath.row].type.localizedDescription + if indexPath.row == 0 { cell.style = InsetGroupTableViewCell.Style.top } else if indexPath.row == self.tableView(self.tableView, numberOfRowsInSection: indexPath.section) - 1 { cell.style = InsetGroupTableViewCell.Style.bottom @@ -53,9 +51,8 @@ final class SelectTeamViewController: UITableViewController return cell } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + + override func tableView(_: UITableView, titleForHeaderInSection _: Int) -> String? { "Teams" } - } diff --git a/AltStore/Browse/BrowseCollectionViewCell.swift b/Sources/SideStore/Browse/BrowseCollectionViewCell.swift similarity index 61% rename from AltStore/Browse/BrowseCollectionViewCell.swift rename to Sources/SideStore/Browse/BrowseCollectionViewCell.swift index 8ef4673c..a5ec7107 100644 --- a/AltStore/Browse/BrowseCollectionViewCell.swift +++ b/Sources/SideStore/Browse/BrowseCollectionViewCell.swift @@ -12,81 +12,72 @@ import RoxasUI import Nuke -@objc final class BrowseCollectionViewCell: UICollectionViewCell -{ +@objc final class BrowseCollectionViewCell: UICollectionViewCell { var imageURLs: [URL] = [] { didSet { - self.dataSource.items = self.imageURLs as [NSURL] + dataSource.items = imageURLs as [NSURL] } } + private lazy var dataSource = self.makeDataSource() - + @IBOutlet var bannerView: AppBannerView! @IBOutlet var subtitleLabel: UILabel! - + @IBOutlet private(set) var screenshotsCollectionView: UICollectionView! - - override func awakeFromNib() - { + + override func awakeFromNib() { super.awakeFromNib() - - self.contentView.preservesSuperviewLayoutMargins = true - + + contentView.preservesSuperviewLayoutMargins = true + // Must be registered programmatically, not in BrowseCollectionViewCell.xib, or else it'll throw an exception 🤷‍♂️. - self.screenshotsCollectionView.register(ScreenshotCollectionViewCell.self, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) - - self.screenshotsCollectionView.delegate = self - self.screenshotsCollectionView.dataSource = self.dataSource - self.screenshotsCollectionView.prefetchDataSource = self.dataSource + screenshotsCollectionView.register(ScreenshotCollectionViewCell.self, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) + + screenshotsCollectionView.delegate = self + screenshotsCollectionView.dataSource = dataSource + screenshotsCollectionView.prefetchDataSource = dataSource } } -private extension BrowseCollectionViewCell -{ - func makeDataSource() -> RSTArrayCollectionViewPrefetchingDataSource - { +private extension BrowseCollectionViewCell { + func makeDataSource() -> RSTArrayCollectionViewPrefetchingDataSource { let dataSource = RSTArrayCollectionViewPrefetchingDataSource(items: []) - dataSource.cellConfigurationHandler = { (cell, screenshot, indexPath) in + dataSource.cellConfigurationHandler = { cell, _, _ in let cell = cell as! ScreenshotCollectionViewCell cell.imageView.image = nil cell.imageView.isIndicatingActivity = true } - dataSource.prefetchHandler = { (imageURL, indexPath, completionHandler) in - return RSTAsyncBlockOperation() { (operation) in + dataSource.prefetchHandler = { imageURL, _, completionHandler in + RSTAsyncBlockOperation { operation in let request = ImageRequest(url: imageURL as URL, processor: .screenshot) - ImagePipeline.shared.loadImage(with: request, progress: nil, completion: { (response, error) in + ImagePipeline.shared.loadImage(with: request, progress: nil, completion: { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completionHandler(image, nil) - } - else - { + } else { completionHandler(nil, error) } }) } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, error in let cell = cell as! ScreenshotCollectionViewCell cell.imageView.isIndicatingActivity = false cell.imageView.image = image - - if let error = error - { + + if let error = error { print("Error loading image:", error) } } - + return dataSource } } -extension BrowseCollectionViewCell: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { +extension BrowseCollectionViewCell: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize { // Assuming 9.0 / 16.0 ratio for now. let aspectRatio: CGFloat = 9.0 / 16.0 diff --git a/AltStore/Browse/BrowseCollectionViewCell.xib b/Sources/SideStore/Browse/BrowseCollectionViewCell.xib similarity index 100% rename from AltStore/Browse/BrowseCollectionViewCell.xib rename to Sources/SideStore/Browse/BrowseCollectionViewCell.xib diff --git a/AltStore/Browse/BrowseViewController.swift b/Sources/SideStore/Browse/BrowseViewController.swift similarity index 53% rename from AltStore/Browse/BrowseViewController.swift rename to Sources/SideStore/Browse/BrowseViewController.swift index eca1b134..ccf94be7 100644 --- a/AltStore/Browse/BrowseViewController.swift +++ b/Sources/SideStore/Browse/BrowseViewController.swift @@ -8,69 +8,63 @@ import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI import Nuke -class BrowseViewController: UICollectionViewController -{ +class BrowseViewController: UICollectionViewController { private lazy var dataSource = self.makeDataSource() private lazy var placeholderView = RSTPlaceholderView(frame: .zero) - + private let prototypeCell = BrowseCollectionViewCell.instantiate(with: BrowseCollectionViewCell.nib!)! - + private var loadingState: LoadingState = .loading { didSet { - self.update() + update() } } - + private var cachedItemSizes = [String: CGSize]() - + @IBOutlet private var sourcesBarButtonItem: UIBarButtonItem! - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - + #if BETA - self.dataSource.searchController.searchableKeyPaths = [#keyPath(InstalledApp.name)] - self.navigationItem.searchController = self.dataSource.searchController + dataSource.searchController.searchableKeyPaths = [#keyPath(InstalledApp.name)] + navigationItem.searchController = dataSource.searchController #endif - - self.prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = false - - self.collectionView.register(BrowseCollectionViewCell.nib, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) - - self.collectionView.dataSource = self.dataSource - self.collectionView.prefetchDataSource = self.dataSource - - self.registerForPreviewing(with: self, sourceView: self.collectionView) - - self.update() + + prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = false + + collectionView.register(BrowseCollectionViewCell.nib, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) + + collectionView.dataSource = dataSource + collectionView.prefetchDataSource = dataSource + + registerForPreviewing(with: self, sourceView: collectionView) + + update() } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - self.fetchSource() - self.updateDataSource() - - self.update() + + fetchSource() + updateDataSource() + + update() } - - @IBAction private func unwindFromSourcesViewController(_ segue: UIStoryboardSegue) - { - self.fetchSource() + + @IBAction private func unwindFromSourcesViewController(_: UIStoryboardSegue) { + fetchSource() } } -private extension BrowseViewController -{ - func makeDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource - { +private extension BrowseViewController { + func makeDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource { let fetchRequest = StoreApp.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \StoreApp.sourceIdentifier, ascending: true), NSSortDescriptor(keyPath: \StoreApp.sortIndex, ascending: true), @@ -78,52 +72,46 @@ private extension BrowseViewController NSSortDescriptor(keyPath: \StoreApp.bundleIdentifier, ascending: true)] fetchRequest.returnsObjectsAsFaults = false fetchRequest.predicate = NSPredicate(format: "%K != %@", #keyPath(StoreApp.bundleIdentifier), StoreApp.altstoreAppID) - + let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) - dataSource.cellConfigurationHandler = { (cell, app, indexPath) in + dataSource.cellConfigurationHandler = { cell, app, _ in let cell = cell as! BrowseCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right - + cell.subtitleLabel.text = app.subtitle cell.imageURLs = Array(app.screenshotURLs.prefix(2)) - + cell.bannerView.configure(for: app) - + cell.bannerView.iconImageView.image = nil cell.bannerView.iconImageView.isIndicatingActivity = true - + cell.bannerView.button.addTarget(self, action: #selector(BrowseViewController.performAppAction(_:)), for: .primaryActionTriggered) cell.bannerView.button.activityIndicatorView.style = .medium - + // Explicitly set to false to ensure we're starting from a non-activity indicating state. // Otherwise, cell reuse can mess up some cached values. cell.bannerView.button.isIndicatingActivity = false - + let tintColor = app.tintColor ?? .altPrimary cell.tintColor = tintColor - - if app.installedApp == nil - { + + if app.installedApp == nil { let buttonTitle = NSLocalizedString("Free", comment: "") cell.bannerView.button.setTitle(buttonTitle.uppercased(), for: .normal) cell.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Download %@", comment: ""), app.name) cell.bannerView.button.accessibilityValue = buttonTitle - + let progress = AppManager.shared.installationProgress(for: app) cell.bannerView.button.progress = progress - - if let versionDate = app.latestVersion?.date, versionDate > Date() - { + + if let versionDate = app.latestVersion?.date, versionDate > Date() { cell.bannerView.button.countdownDate = app.versionDate - } - else - { + } else { cell.bannerView.button.countdownDate = nil } - } - else - { + } else { cell.bannerView.button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) cell.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Open %@", comment: ""), app.name) cell.bannerView.button.accessibilityValue = nil @@ -131,234 +119,204 @@ private extension BrowseViewController cell.bannerView.button.countdownDate = nil } } - dataSource.prefetchHandler = { (storeApp, indexPath, completionHandler) -> Foundation.Operation? in + dataSource.prefetchHandler = { storeApp, _, completionHandler -> Foundation.Operation? in let iconURL = storeApp.iconURL - - return RSTAsyncBlockOperation() { (operation) in - ImagePipeline.shared.loadImage(with: iconURL, progress: nil, completion: { (response, error) in + + return RSTAsyncBlockOperation { operation in + ImagePipeline.shared.loadImage(with: iconURL, progress: nil, completion: { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completionHandler(image, nil) - } - else - { + } else { completionHandler(nil, error) } }) } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, error in let cell = cell as! BrowseCollectionViewCell cell.bannerView.iconImageView.isIndicatingActivity = false cell.bannerView.iconImageView.image = image - - if let error = error - { + + if let error = error { print("Error loading image:", error) } } - - dataSource.placeholderView = self.placeholderView - + + dataSource.placeholderView = placeholderView + return dataSource } - - func updateDataSource() - { - self.dataSource.predicate = nil + + func updateDataSource() { + dataSource.predicate = nil } - - func fetchSource() - { - self.loadingState = .loading - - AppManager.shared.fetchSources() { (result) in - do - { - do - { + + func fetchSource() { + loadingState = .loading + + AppManager.shared.fetchSources { result in + do { + do { let (_, context) = try result.get() try context.save() - + DispatchQueue.main.async { self.loadingState = .finished(.success(())) } - } - catch let error as AppManager.FetchSourcesError - { + } catch let error as AppManager.FetchSourcesError { try error.managedObjectContext?.save() throw error } - } - catch - { + } catch { DispatchQueue.main.async { - if self.dataSource.itemCount > 0 - { + if self.dataSource.itemCount > 0 { let toastView = ToastView(error: error) toastView.addTarget(nil, action: #selector(TabBarController.presentSources), for: .touchUpInside) toastView.show(in: self) } - + self.loadingState = .finished(.failure(error)) } } } } - - func update() - { - switch self.loadingState - { + + func update() { + switch loadingState { case .loading: - self.placeholderView.textLabel.isHidden = true - self.placeholderView.detailTextLabel.isHidden = false - - self.placeholderView.detailTextLabel.text = NSLocalizedString("Loading...", comment: "") - - self.placeholderView.activityIndicatorView.startAnimating() - - case .finished(.failure(let error)): - self.placeholderView.textLabel.isHidden = false - self.placeholderView.detailTextLabel.isHidden = false - - self.placeholderView.textLabel.text = NSLocalizedString("Unable to Fetch Apps", comment: "") - self.placeholderView.detailTextLabel.text = error.localizedDescription - - self.placeholderView.activityIndicatorView.stopAnimating() - + placeholderView.textLabel.isHidden = true + placeholderView.detailTextLabel.isHidden = false + + placeholderView.detailTextLabel.text = NSLocalizedString("Loading...", comment: "") + + placeholderView.activityIndicatorView.startAnimating() + + case let .finished(.failure(error)): + placeholderView.textLabel.isHidden = false + placeholderView.detailTextLabel.isHidden = false + + placeholderView.textLabel.text = NSLocalizedString("Unable to Fetch Apps", comment: "") + placeholderView.detailTextLabel.text = error.localizedDescription + + placeholderView.activityIndicatorView.stopAnimating() + case .finished(.success): - self.placeholderView.textLabel.isHidden = true - self.placeholderView.detailTextLabel.isHidden = true - - self.placeholderView.activityIndicatorView.stopAnimating() + placeholderView.textLabel.isHidden = true + placeholderView.detailTextLabel.isHidden = true + + placeholderView.activityIndicatorView.stopAnimating() } } } -private extension BrowseViewController -{ - @IBAction func performAppAction(_ sender: PillButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let app = self.dataSource.item(at: indexPath) - - if let installedApp = app.installedApp - { - self.open(installedApp) - } - else - { - self.install(app, at: indexPath) +private extension BrowseViewController { + @IBAction func performAppAction(_ sender: PillButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let app = dataSource.item(at: indexPath) + + if let installedApp = app.installedApp { + open(installedApp) + } else { + install(app, at: indexPath) } } - - func install(_ app: StoreApp, at indexPath: IndexPath) - { + + func install(_ app: StoreApp, at indexPath: IndexPath) { let previousProgress = AppManager.shared.installationProgress(for: app) guard previousProgress == nil else { previousProgress?.cancel() return } - - _ = AppManager.shared.install(app, presentingViewController: self) { (result) in + + _ = AppManager.shared.install(app, presentingViewController: self) { result in DispatchQueue.main.async { - switch result - { + switch result { case .failure(OperationError.cancelled): break // Ignore - case .failure(let error): + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) - + case .success: print("Installed app:", app.bundleIdentifier) } - + self.collectionView.reloadItems(at: [indexPath]) } } - - self.collectionView.reloadItems(at: [indexPath]) + + collectionView.reloadItems(at: [indexPath]) } - - func open(_ installedApp: InstalledApp) - { + + func open(_ installedApp: InstalledApp) { UIApplication.shared.open(installedApp.openAppURL) } } -extension BrowseViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { - let item = self.dataSource.item(at: indexPath) +extension BrowseViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let item = dataSource.item(at: indexPath) - if let previousSize = self.cachedItemSizes[item.bundleIdentifier] - { + if let previousSize = cachedItemSizes[item.bundleIdentifier] { return previousSize } let maxVisibleScreenshots = 2 as CGFloat let aspectRatio: CGFloat = 16.0 / 9.0 - - let layout = self.prototypeCell.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout + + let layout = prototypeCell.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout let padding = (layout.minimumInteritemSpacing * (maxVisibleScreenshots - 1)) + layout.sectionInset.left + layout.sectionInset.right - self.dataSource.cellConfigurationHandler(self.prototypeCell, item, indexPath) + dataSource.cellConfigurationHandler(prototypeCell, item, indexPath) - let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) + let widthConstraint = prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) widthConstraint.isActive = true defer { widthConstraint.isActive = false } // Manually update cell width & layout so we can accurately calculate screenshot sizes. - self.prototypeCell.frame.size.width = widthConstraint.constant - self.prototypeCell.layoutIfNeeded() - - let collectionViewWidth = self.prototypeCell.screenshotsCollectionView.bounds.width + prototypeCell.frame.size.width = widthConstraint.constant + prototypeCell.layoutIfNeeded() + + let collectionViewWidth = prototypeCell.screenshotsCollectionView.bounds.width let screenshotWidth = ((collectionViewWidth - padding) / maxVisibleScreenshots).rounded(.down) let screenshotHeight = screenshotWidth * aspectRatio - let heightConstraint = self.prototypeCell.screenshotsCollectionView.heightAnchor.constraint(equalToConstant: screenshotHeight) + let heightConstraint = prototypeCell.screenshotsCollectionView.heightAnchor.constraint(equalToConstant: screenshotHeight) heightConstraint.priority = .defaultHigh // Prevent temporary unsatisfiable constraints error. heightConstraint.isActive = true defer { heightConstraint.isActive = false } - let itemSize = self.prototypeCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - self.cachedItemSizes[item.bundleIdentifier] = itemSize + let itemSize = prototypeCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + cachedItemSizes[item.bundleIdentifier] = itemSize return itemSize } - - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) - { - let app = self.dataSource.item(at: indexPath) - + + override func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let app = dataSource.item(at: indexPath) + let appViewController = AppViewController.makeAppViewController(app: app) - self.navigationController?.pushViewController(appViewController, animated: true) + navigationController?.pushViewController(appViewController, animated: true) } } -extension BrowseViewController: UIViewControllerPreviewingDelegate -{ - func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? - { +extension BrowseViewController: UIViewControllerPreviewingDelegate { + func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { guard - let indexPath = self.collectionView.indexPathForItem(at: location), - let cell = self.collectionView.cellForItem(at: indexPath) + let indexPath = collectionView.indexPathForItem(at: location), + let cell = collectionView.cellForItem(at: indexPath) else { return nil } - + previewingContext.sourceRect = cell.frame - - let app = self.dataSource.item(at: indexPath) - + + let app = dataSource.item(at: indexPath) + let appViewController = AppViewController.makeAppViewController(app: app) return appViewController } - - func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) - { - self.navigationController?.pushViewController(viewControllerToCommit, animated: true) + + func previewingContext(_: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { + navigationController?.pushViewController(viewControllerToCommit, animated: true) } } diff --git a/Sources/SideStore/Browse/ScreenshotCollectionViewCell.swift b/Sources/SideStore/Browse/ScreenshotCollectionViewCell.swift new file mode 100644 index 00000000..8b165538 --- /dev/null +++ b/Sources/SideStore/Browse/ScreenshotCollectionViewCell.swift @@ -0,0 +1,39 @@ +// +// ScreenshotCollectionViewCell.swift +// AltStore +// +// Created by Riley Testut on 7/15/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import RoxasUI + +@objc(ScreenshotCollectionViewCell) +class ScreenshotCollectionViewCell: UICollectionViewCell { + let imageView = UIImageView(image: nil) + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + imageView.layer.masksToBounds = true + addSubview(imageView, pinningEdgesWith: .zero) + } + + override func layoutSubviews() { + super.layoutSubviews() + + imageView.layer.cornerRadius = 4 + } +} diff --git a/Sources/SideStore/Components/AppBannerView.swift b/Sources/SideStore/Components/AppBannerView.swift new file mode 100644 index 00000000..511b563a --- /dev/null +++ b/Sources/SideStore/Components/AppBannerView.swift @@ -0,0 +1,128 @@ +// +// AppBannerView.swift +// AltStore +// +// Created by Riley Testut on 8/29/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import SideStoreCore +import RoxasUI + +class AppBannerView: RSTNibView { + override var accessibilityLabel: String? { + get { self.accessibilityView?.accessibilityLabel } + set { self.accessibilityView?.accessibilityLabel = newValue } + } + + override open var accessibilityAttributedLabel: NSAttributedString? { + get { self.accessibilityView?.accessibilityAttributedLabel } + set { self.accessibilityView?.accessibilityAttributedLabel = newValue } + } + + override var accessibilityValue: String? { + get { self.accessibilityView?.accessibilityValue } + set { self.accessibilityView?.accessibilityValue = newValue } + } + + override open var accessibilityAttributedValue: NSAttributedString? { + get { self.accessibilityView?.accessibilityAttributedValue } + set { self.accessibilityView?.accessibilityAttributedValue = newValue } + } + + override open var accessibilityTraits: UIAccessibilityTraits { + get { accessibilityView?.accessibilityTraits ?? [] } + set { accessibilityView?.accessibilityTraits = newValue } + } + + private var originalTintColor: UIColor? + + @IBOutlet var titleLabel: UILabel! + @IBOutlet var subtitleLabel: UILabel! + @IBOutlet var iconImageView: AppIconImageView! + @IBOutlet var button: PillButton! + @IBOutlet var buttonLabel: UILabel! + @IBOutlet var betaBadgeView: UIView! + + @IBOutlet var backgroundEffectView: UIVisualEffectView! + + @IBOutlet private var vibrancyView: UIVisualEffectView! + @IBOutlet private var accessibilityView: UIView! + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + + initialize() + } + + private func initialize() { + accessibilityView.accessibilityTraits.formUnion(.button) + + isAccessibilityElement = false + accessibilityElements = [accessibilityView, button].compactMap { $0 } + + betaBadgeView.isHidden = true + } + + override func tintColorDidChange() { + super.tintColorDidChange() + + if tintAdjustmentMode != .dimmed { + originalTintColor = tintColor + } + + update() + } +} + +extension AppBannerView { + func configure(for app: AppProtocol) { + struct AppValues { + var name: String + var developerName: String? + var isBeta: Bool = false + + init(app: AppProtocol) { + name = app.name + + guard let storeApp = (app as? StoreApp) ?? (app as? InstalledApp)?.storeApp else { return } + developerName = storeApp.developerName + + if storeApp.isBeta { + name = String(format: NSLocalizedString("%@ beta", comment: ""), app.name) + isBeta = true + } + } + } + + let values = AppValues(app: app) + titleLabel.text = app.name // Don't use values.name since that already includes "beta". + betaBadgeView.isHidden = !values.isBeta + + if let developerName = values.developerName { + subtitleLabel.text = developerName + accessibilityLabel = String(format: NSLocalizedString("%@ by %@", comment: ""), values.name, developerName) + } else { + subtitleLabel.text = NSLocalizedString("Sideloaded", comment: "") + accessibilityLabel = values.name + } + } +} + +private extension AppBannerView { + func update() { + clipsToBounds = true + layer.cornerRadius = 22 + + subtitleLabel.textColor = originalTintColor ?? tintColor + backgroundEffectView.backgroundColor = originalTintColor ?? tintColor + } +} diff --git a/AltStore/Components/AppBannerView.xib b/Sources/SideStore/Components/AppBannerView.xib similarity index 100% rename from AltStore/Components/AppBannerView.xib rename to Sources/SideStore/Components/AppBannerView.xib diff --git a/Sources/SideStore/Components/AppIconImageView.swift b/Sources/SideStore/Components/AppIconImageView.swift new file mode 100644 index 00000000..0d39c0c1 --- /dev/null +++ b/Sources/SideStore/Components/AppIconImageView.swift @@ -0,0 +1,36 @@ +// +// AppIconImageView.swift +// AltStore +// +// Created by Riley Testut on 5/9/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class AppIconImageView: UIImageView { + override func awakeFromNib() { + super.awakeFromNib() + + contentMode = .scaleAspectFill + clipsToBounds = true + + backgroundColor = .white + + if #available(iOS 13, *) { + self.layer.cornerCurve = .continuous + } else { + if layer.responds(to: Selector(("continuousCorners"))) { + layer.setValue(true, forKey: "continuousCorners") + } + } + } + + override func layoutSubviews() { + super.layoutSubviews() + + // Based off of 60pt icon having 12pt radius. + let radius = bounds.height / 5 + layer.cornerRadius = radius + } +} diff --git a/AltStore/Components/BackgroundTaskManager.swift b/Sources/SideStore/Components/BackgroundTaskManager.swift similarity index 57% rename from AltStore/Components/BackgroundTaskManager.swift rename to Sources/SideStore/Components/BackgroundTaskManager.swift index 5ab54b33..84b7bac3 100644 --- a/AltStore/Components/BackgroundTaskManager.swift +++ b/Sources/SideStore/Components/BackgroundTaskManager.swift @@ -8,78 +8,67 @@ import AVFoundation -final class BackgroundTaskManager -{ +final class BackgroundTaskManager { static let shared = BackgroundTaskManager() - + private var isPlaying = false - + private let audioEngine: AVAudioEngine private let player: AVAudioPlayerNode private let audioFile: AVAudioFile - + private let audioEngineQueue: DispatchQueue - - private init() - { - self.audioEngine = AVAudioEngine() - self.audioEngine.mainMixerNode.outputVolume = 0.0 - - self.player = AVAudioPlayerNode() - self.audioEngine.attach(self.player) - - do - { + + private init() { + audioEngine = AVAudioEngine() + audioEngine.mainMixerNode.outputVolume = 0.0 + + player = AVAudioPlayerNode() + audioEngine.attach(player) + + do { let audioFileURL = Bundle.main.url(forResource: "Silence", withExtension: "m4a")! - - self.audioFile = try AVAudioFile(forReading: audioFileURL) - self.audioEngine.connect(self.player, to: self.audioEngine.mainMixerNode, format: self.audioFile.processingFormat) - } - catch - { + + audioFile = try AVAudioFile(forReading: audioFileURL) + audioEngine.connect(player, to: audioEngine.mainMixerNode, format: audioFile.processingFormat) + } catch { fatalError("Error. \(error)") } - - self.audioEngineQueue = DispatchQueue(label: "com.altstore.BackgroundTaskManager") + + audioEngineQueue = DispatchQueue(label: "com.altstore.BackgroundTaskManager") } } -extension BackgroundTaskManager -{ - func performExtendedBackgroundTask(taskHandler: @escaping ((Result, @escaping () -> Void) -> Void)) - { - func finish() - { - self.player.stop() - self.audioEngine.stop() - - self.isPlaying = false +extension BackgroundTaskManager { + func performExtendedBackgroundTask(taskHandler: @escaping ((Result, @escaping () -> Void) -> Void)) { + func finish() { + player.stop() + audioEngine.stop() + + isPlaying = false } - - self.audioEngineQueue.sync { - do - { + + audioEngineQueue.sync { + do { try AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers) try AVAudioSession.sharedInstance().setActive(true) - + // Schedule audio file buffers. self.scheduleAudioFile() self.scheduleAudioFile() - + let outputFormat = self.audioEngine.outputNode.outputFormat(forBus: 0) self.audioEngine.connect(self.audioEngine.mainMixerNode, to: self.audioEngine.outputNode, format: outputFormat) - + try self.audioEngine.start() self.player.play() - + self.isPlaying = true - + taskHandler(.success(())) { finish() } - } - catch - { + } catch { taskHandler(.failure(error)) { finish() } @@ -88,11 +77,9 @@ extension BackgroundTaskManager } } -private extension BackgroundTaskManager -{ - func scheduleAudioFile() - { - self.player.scheduleFile(self.audioFile, at: nil) { +private extension BackgroundTaskManager { + func scheduleAudioFile() { + player.scheduleFile(audioFile, at: nil) { self.audioEngineQueue.async { guard self.isPlaying else { return } self.scheduleAudioFile() diff --git a/AltStore/Components/BannerCollectionViewCell.swift b/Sources/SideStore/Components/BannerCollectionViewCell.swift similarity index 82% rename from AltStore/Components/BannerCollectionViewCell.swift rename to Sources/SideStore/Components/BannerCollectionViewCell.swift index a1a810a8..172a909d 100644 --- a/AltStore/Components/BannerCollectionViewCell.swift +++ b/Sources/SideStore/Components/BannerCollectionViewCell.swift @@ -8,46 +8,43 @@ import UIKit -final class BannerCollectionViewCell: UICollectionViewCell -{ +final class BannerCollectionViewCell: UICollectionViewCell { private(set) var errorBadge: UIView? @IBOutlet private(set) var bannerView: AppBannerView! - - override func awakeFromNib() - { + + override func awakeFromNib() { super.awakeFromNib() - - self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.contentView.preservesSuperviewLayoutMargins = true - - if #available(iOS 13.0, *) - { + + contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + contentView.preservesSuperviewLayoutMargins = true + + if #available(iOS 13.0, *) { let errorBadge = UIView() errorBadge.translatesAutoresizingMaskIntoConstraints = false errorBadge.isHidden = true self.addSubview(errorBadge) - + // Solid background to make the X opaque white. let backgroundView = UIView() backgroundView.translatesAutoresizingMaskIntoConstraints = false backgroundView.backgroundColor = .white errorBadge.addSubview(backgroundView) - + let badgeView = UIImageView(image: UIImage(systemName: "exclamationmark.circle.fill")) badgeView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(scale: .large) badgeView.tintColor = .systemRed errorBadge.addSubview(badgeView, pinningEdgesWith: .zero) - + NSLayoutConstraint.activate([ errorBadge.centerXAnchor.constraint(equalTo: self.bannerView.trailingAnchor, constant: -5), errorBadge.centerYAnchor.constraint(equalTo: self.bannerView.topAnchor, constant: 5), - + backgroundView.centerXAnchor.constraint(equalTo: badgeView.centerXAnchor), backgroundView.centerYAnchor.constraint(equalTo: badgeView.centerYAnchor), backgroundView.widthAnchor.constraint(equalTo: badgeView.widthAnchor, multiplier: 0.5), backgroundView.heightAnchor.constraint(equalTo: badgeView.heightAnchor, multiplier: 0.5) ]) - + self.errorBadge = errorBadge } } diff --git a/AltStore/Components/Button.swift b/Sources/SideStore/Components/Button.swift similarity index 50% rename from AltStore/Components/Button.swift rename to Sources/SideStore/Components/Button.swift index 02f43840..29b1d5bb 100644 --- a/AltStore/Components/Button.swift +++ b/Sources/SideStore/Components/Button.swift @@ -8,58 +8,50 @@ import UIKit -final class Button: UIButton -{ +final class Button: UIButton { override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize size.width += 20 size.height += 10 return size } - - override func awakeFromNib() - { + + override func awakeFromNib() { super.awakeFromNib() - - self.setTitleColor(.white, for: .normal) - - self.layer.masksToBounds = true - self.layer.cornerRadius = 8 - - self.update() + + setTitleColor(.white, for: .normal) + + layer.masksToBounds = true + layer.cornerRadius = 8 + + update() } - - override func tintColorDidChange() - { + + override func tintColorDidChange() { super.tintColorDidChange() - - self.update() + + update() } - + override var isHighlighted: Bool { didSet { self.update() } } - + override var isEnabled: Bool { didSet { - self.update() + update() } } } -private extension Button -{ - func update() - { - if self.isEnabled - { - self.backgroundColor = self.tintColor - } - else - { - self.backgroundColor = .lightGray +private extension Button { + func update() { + if isEnabled { + backgroundColor = tintColor + } else { + backgroundColor = .lightGray } } } diff --git a/Sources/SideStore/Components/CollapsingTextView.swift b/Sources/SideStore/Components/CollapsingTextView.swift new file mode 100644 index 00000000..1598001c --- /dev/null +++ b/Sources/SideStore/Components/CollapsingTextView.swift @@ -0,0 +1,106 @@ +// +// CollapsingTextView.swift +// AltStore +// +// Created by Riley Testut on 7/23/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class CollapsingTextView: UITextView { + var isCollapsed = true { + didSet { + setNeedsLayout() + } + } + + var maximumNumberOfLines = 2 { + didSet { + setNeedsLayout() + } + } + + var lineSpacing: CGFloat = 2 { + didSet { + setNeedsLayout() + } + } + + let moreButton = UIButton(type: .system) + + override func awakeFromNib() { + super.awakeFromNib() + + layoutManager.delegate = self + + textContainerInset = .zero + textContainer.lineFragmentPadding = 0 + textContainer.lineBreakMode = .byTruncatingTail + textContainer.heightTracksTextView = true + textContainer.widthTracksTextView = true + + moreButton.setTitle(NSLocalizedString("More", comment: ""), for: .normal) + moreButton.addTarget(self, action: #selector(CollapsingTextView.toggleCollapsed(_:)), for: .primaryActionTriggered) + addSubview(moreButton) + + setNeedsLayout() + } + + override func layoutSubviews() { + super.layoutSubviews() + + guard let font = font else { return } + + let buttonFont = UIFont.systemFont(ofSize: font.pointSize, weight: .medium) + moreButton.titleLabel?.font = buttonFont + + let buttonY = (font.lineHeight + lineSpacing) * CGFloat(maximumNumberOfLines - 1) + let size = moreButton.sizeThatFits(CGSize(width: 1000, height: 1000)) + + let moreButtonFrame = CGRect(x: bounds.width - moreButton.bounds.width, + y: buttonY, + width: size.width, + height: font.lineHeight) + moreButton.frame = moreButtonFrame + + if isCollapsed { + textContainer.maximumNumberOfLines = maximumNumberOfLines + + let boundingSize = attributedText.boundingRect(with: CGSize(width: textContainer.size.width, height: .infinity), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) + let maximumCollapsedHeight = font.lineHeight * Double(maximumNumberOfLines) + + if boundingSize.height.rounded() > maximumCollapsedHeight.rounded() { + var exclusionFrame = moreButtonFrame + exclusionFrame.origin.y += moreButton.bounds.midY + exclusionFrame.size.width = bounds.width // Extra wide to make sure it wraps to next line. + textContainer.exclusionPaths = [UIBezierPath(rect: exclusionFrame)] + + moreButton.isHidden = false + } else { + textContainer.exclusionPaths = [] + + moreButton.isHidden = true + } + } else { + textContainer.maximumNumberOfLines = 0 + textContainer.exclusionPaths = [] + + moreButton.isHidden = true + } + + invalidateIntrinsicContentSize() + } +} + +private extension CollapsingTextView { + @objc func toggleCollapsed(_: UIButton) { + isCollapsed.toggle() + } +} + +extension CollapsingTextView: NSLayoutManagerDelegate { + func layoutManager(_: NSLayoutManager, lineSpacingAfterGlyphAt _: Int, withProposedLineFragmentRect _: CGRect) -> CGFloat { + lineSpacing + } +} diff --git a/AltStore/Components/ForwardingNavigationController.swift b/Sources/SideStore/Components/ForwardingNavigationController.swift similarity index 81% rename from AltStore/Components/ForwardingNavigationController.swift rename to Sources/SideStore/Components/ForwardingNavigationController.swift index 554bb728..ca820523 100644 --- a/AltStore/Components/ForwardingNavigationController.swift +++ b/Sources/SideStore/Components/ForwardingNavigationController.swift @@ -8,13 +8,12 @@ import UIKit -final class ForwardingNavigationController: UINavigationController -{ +final class ForwardingNavigationController: UINavigationController { override var childForStatusBarStyle: UIViewController? { - return self.topViewController + self.topViewController } - + override var childForStatusBarHidden: UIViewController? { - return self.topViewController + topViewController } } diff --git a/AltStore/Components/NavigationBar.swift b/Sources/SideStore/Components/NavigationBar.swift similarity index 60% rename from AltStore/Components/NavigationBar.swift rename to Sources/SideStore/Components/NavigationBar.swift index 89e1e9d6..b599c3ba 100644 --- a/AltStore/Components/NavigationBar.swift +++ b/Sources/SideStore/Components/NavigationBar.swift @@ -10,91 +10,74 @@ import UIKit import RoxasUI -final class NavigationBar: UINavigationBar -{ +final class NavigationBar: UINavigationBar { @IBInspectable var automaticallyAdjustsItemPositions: Bool = true - + private let backgroundColorView = UIView() - - override init(frame: CGRect) - { + + override init(frame: CGRect) { super.init(frame: frame) - - self.initialize() + + initialize() } - - required init?(coder aDecoder: NSCoder) - { + + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - - self.initialize() + + initialize() } - - private func initialize() - { - if #available(iOS 13, *) - { + + private func initialize() { + if #available(iOS 13, *) { let standardAppearance = UINavigationBarAppearance() standardAppearance.configureWithDefaultBackground() standardAppearance.shadowColor = nil - + let edgeAppearance = UINavigationBarAppearance() edgeAppearance.configureWithOpaqueBackground() edgeAppearance.backgroundColor = self.barTintColor edgeAppearance.shadowColor = nil - - if let tintColor = self.barTintColor - { + + if let tintColor = self.barTintColor { let textAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] - + standardAppearance.backgroundColor = tintColor standardAppearance.titleTextAttributes = textAttributes standardAppearance.largeTitleTextAttributes = textAttributes - + edgeAppearance.titleTextAttributes = textAttributes edgeAppearance.largeTitleTextAttributes = textAttributes - } - else - { + } else { standardAppearance.backgroundColor = nil } - + self.scrollEdgeAppearance = edgeAppearance self.standardAppearance = standardAppearance - } - else - { - self.shadowImage = UIImage() - - if let tintColor = self.barTintColor - { - self.backgroundColorView.backgroundColor = tintColor - + } else { + shadowImage = UIImage() + + if let tintColor = barTintColor { + backgroundColorView.backgroundColor = tintColor + // Top = -50 to cover status bar area above navigation bar on any device. // Bottom = -1 to prevent a flickering gray line from appearing. - self.addSubview(self.backgroundColorView, pinningEdgesWith: UIEdgeInsets(top: -50, left: 0, bottom: -1, right: 0)) - } - else - { - self.barTintColor = .white + addSubview(backgroundColorView, pinningEdgesWith: UIEdgeInsets(top: -50, left: 0, bottom: -1, right: 0)) + } else { + barTintColor = .white } } } - - override func layoutSubviews() - { + + override func layoutSubviews() { super.layoutSubviews() - - if self.backgroundColorView.superview != nil - { - self.insertSubview(self.backgroundColorView, at: 1) + + if backgroundColorView.superview != nil { + insertSubview(backgroundColorView, at: 1) } - - if self.automaticallyAdjustsItemPositions - { + + if automaticallyAdjustsItemPositions { // We can't easily shift just the back button up, so we shift the entire content view slightly. - for contentView in self.subviews - { + for contentView in subviews { guard NSStringFromClass(type(of: contentView)).contains("ContentView") else { continue } contentView.center.y -= 2 } diff --git a/Sources/SideStore/Components/PillButton.swift b/Sources/SideStore/Components/PillButton.swift new file mode 100644 index 00000000..705a3b1c --- /dev/null +++ b/Sources/SideStore/Components/PillButton.swift @@ -0,0 +1,172 @@ +// +// PillButton.swift +// AltStore +// +// Created by Riley Testut on 7/15/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class PillButton: UIButton { + override var accessibilityValue: String? { + get { + guard progress != nil else { return super.accessibilityValue } + return progressView.accessibilityValue + } + set { super.accessibilityValue = newValue } + } + + var progress: Progress? { + didSet { + progressView.progress = Float(progress?.fractionCompleted ?? 0) + progressView.observedProgress = progress + + let isUserInteractionEnabled = self.isUserInteractionEnabled + isIndicatingActivity = (progress != nil) + self.isUserInteractionEnabled = isUserInteractionEnabled + + update() + } + } + + var progressTintColor: UIColor? { + get { + progressView.progressTintColor + } + set { + progressView.progressTintColor = newValue + } + } + + var countdownDate: Date? { + didSet { + isEnabled = (countdownDate == nil) + displayLink.isPaused = (countdownDate == nil) + + if countdownDate == nil { + setTitle(nil, for: .disabled) + } + } + } + + private let progressView = UIProgressView(progressViewStyle: .default) + + private lazy var displayLink: CADisplayLink = { + let displayLink = CADisplayLink(target: self, selector: #selector(PillButton.updateCountdown)) + displayLink.preferredFramesPerSecond = 15 + displayLink.isPaused = true + displayLink.add(to: .main, forMode: .common) + return displayLink + }() + + private let dateComponentsFormatter: DateComponentsFormatter = { + let dateComponentsFormatter = DateComponentsFormatter() + dateComponentsFormatter.zeroFormattingBehavior = [.pad] + dateComponentsFormatter.collapsesLargestUnit = false + return dateComponentsFormatter + }() + + override var intrinsicContentSize: CGSize { + var size = super.intrinsicContentSize + size.width += 26 + size.height += 3 + return size + } + + deinit { + self.displayLink.remove(from: .main, forMode: RunLoop.Mode.default) + } + + override func awakeFromNib() { + super.awakeFromNib() + + layer.masksToBounds = true + accessibilityTraits.formUnion([.updatesFrequently, .button]) + + activityIndicatorView.style = .medium + activityIndicatorView.isUserInteractionEnabled = false + + progressView.progress = 0 + progressView.trackImage = UIImage() + progressView.isUserInteractionEnabled = false + addSubview(progressView) + + update() + } + + override func layoutSubviews() { + super.layoutSubviews() + + progressView.bounds.size.width = bounds.width + + let scale = bounds.height / progressView.bounds.height + + progressView.transform = CGAffineTransform.identity.scaledBy(x: 1, y: scale) + progressView.center = CGPoint(x: bounds.midX, y: bounds.midY) + + layer.cornerRadius = bounds.midY + } + + override func tintColorDidChange() { + super.tintColorDidChange() + + update() + } +} + +private extension PillButton { + func update() { + if progress == nil { + setTitleColor(.white, for: .normal) + backgroundColor = tintColor + } else { + setTitleColor(tintColor, for: .normal) + backgroundColor = tintColor.withAlphaComponent(0.15) + } + + progressView.progressTintColor = tintColor + } + + @objc func updateCountdown() { + guard let endDate = countdownDate else { return } + + let startDate = Date() + + let interval = endDate.timeIntervalSince(startDate) + guard interval > 0 else { + isEnabled = true + return + } + + let text: String? + + if interval < (1 * 60 * 60) { + dateComponentsFormatter.unitsStyle = .positional + dateComponentsFormatter.allowedUnits = [.minute, .second] + + text = dateComponentsFormatter.string(from: startDate, to: endDate) + } else if interval < (2 * 24 * 60 * 60) { + dateComponentsFormatter.unitsStyle = .positional + dateComponentsFormatter.allowedUnits = [.hour, .minute, .second] + + text = dateComponentsFormatter.string(from: startDate, to: endDate) + } else { + dateComponentsFormatter.unitsStyle = .full + dateComponentsFormatter.allowedUnits = [.day] + + let numberOfDays = endDate.numberOfCalendarDays(since: startDate) + text = String(format: NSLocalizedString("%@ DAYS", comment: ""), NSNumber(value: numberOfDays)) + } + + if let text = text { + UIView.performWithoutAnimation { + self.isEnabled = false + self.setTitle(text, for: .disabled) + self.layoutIfNeeded() + } + } else { + isEnabled = true + } + } +} diff --git a/AltStore/Components/TextCollectionReusableView.swift b/Sources/SideStore/Components/TextCollectionReusableView.swift similarity index 87% rename from AltStore/Components/TextCollectionReusableView.swift rename to Sources/SideStore/Components/TextCollectionReusableView.swift index fa2561f8..f3bde447 100644 --- a/AltStore/Components/TextCollectionReusableView.swift +++ b/Sources/SideStore/Components/TextCollectionReusableView.swift @@ -8,10 +8,9 @@ import UIKit -class TextCollectionReusableView: UICollectionReusableView -{ +class TextCollectionReusableView: UICollectionReusableView { @IBOutlet var textLabel: UILabel! - + @IBOutlet var topLayoutConstraint: NSLayoutConstraint! @IBOutlet var bottomLayoutConstraint: NSLayoutConstraint! @IBOutlet var leadingLayoutConstraint: NSLayoutConstraint! diff --git a/AltStore/Components/ToastView.swift b/Sources/SideStore/Components/ToastView.swift similarity index 58% rename from AltStore/Components/ToastView.swift rename to Sources/SideStore/Components/ToastView.swift index 648e6177..dfc9be5d 100644 --- a/AltStore/Components/ToastView.swift +++ b/Sources/SideStore/Components/ToastView.swift @@ -8,123 +8,106 @@ import RoxasUI -import AltStoreCore +import SideStoreCore -extension TimeInterval -{ +extension TimeInterval { static let shortToastViewDuration = 4.0 static let longToastViewDuration = 8.0 } -final class ToastView: RSTToastView -{ +final class ToastView: RSTToastView { var preferredDuration: TimeInterval - - override init(text: String, detailText detailedText: String?) - { - if detailedText == nil - { - self.preferredDuration = .shortToastViewDuration + + override init(text: String, detailText detailedText: String?) { + if detailedText == nil { + preferredDuration = .shortToastViewDuration + } else { + preferredDuration = .longToastViewDuration } - else - { - self.preferredDuration = .longToastViewDuration - } - + super.init(text: text, detailText: detailedText) - - self.isAccessibilityElement = true - - self.layoutMargins = UIEdgeInsets(top: 8, left: 16, bottom: 10, right: 16) - self.setNeedsLayout() - - if let stackView = self.textLabel.superview as? UIStackView - { + + isAccessibilityElement = true + + layoutMargins = UIEdgeInsets(top: 8, left: 16, bottom: 10, right: 16) + setNeedsLayout() + + if let stackView = textLabel.superview as? UIStackView { // RSTToastView does not expose stack view containing labels, // so we access it indirectly as the labels' superview. stackView.spacing = (detailedText != nil) ? 4.0 : 0.0 } } - - convenience init(error: Error) - { + + convenience init(error: Error) { var error = error as NSError var underlyingError = error.underlyingError - + var preferredDuration: TimeInterval? - + if let unwrappedUnderlyingError = underlyingError, error.domain == AltServerErrorDomain && error.code == ALTServerError.Code.underlyingError.rawValue { // Treat underlyingError as the primary error. - + error = unwrappedUnderlyingError as NSError underlyingError = nil - + preferredDuration = .longToastViewDuration } - + let text: String let detailText: String? - - if let failure = error.localizedFailure - { + + if let failure = error.localizedFailure { text = failure detailText = error.localizedFailureReason ?? error.localizedRecoverySuggestion ?? underlyingError?.localizedDescription ?? error.localizedDescription - } - else if let reason = error.localizedFailureReason - { + } else if let reason = error.localizedFailureReason { text = reason detailText = error.localizedRecoverySuggestion ?? underlyingError?.localizedDescription - } - else - { + } else { text = error.localizedDescription detailText = underlyingError?.localizedDescription ?? error.localizedRecoverySuggestion } - + self.init(text: text, detailText: detailText) - - if let preferredDuration = preferredDuration - { + + if let preferredDuration = preferredDuration { self.preferredDuration = preferredDuration } } - - required init(coder aDecoder: NSCoder) { + + @available(*, unavailable) + required init(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - - override func layoutSubviews() - { + + override func layoutSubviews() { super.layoutSubviews() - + // Rough calculation to determine height of ToastView with one-line textLabel. - let minimumHeight = self.textLabel.font.lineHeight.rounded() + 18 - self.layer.cornerRadius = minimumHeight/2 + let minimumHeight = textLabel.font.lineHeight.rounded() + 18 + layer.cornerRadius = minimumHeight / 2 } - - func show(in viewController: UIViewController) - { - self.show(in: viewController.navigationController?.view ?? viewController.view, duration: self.preferredDuration) + + func show(in viewController: UIViewController) { + show(in: viewController.navigationController?.view ?? viewController.view, duration: preferredDuration) } - - override func show(in view: UIView, duration: TimeInterval) - { + + override func show(in view: UIView, duration: TimeInterval) { super.show(in: view, duration: duration) - - let announcement = (self.textLabel.text ?? "") + ". " + (self.detailTextLabel.text ?? "") - self.accessibilityLabel = announcement - + + let announcement = (textLabel.text ?? "") + ". " + (detailTextLabel.text ?? "") + accessibilityLabel = announcement + // Minimum 0.75 delay to prevent announcement being cut off by VoiceOver. DispatchQueue.main.asyncAfter(deadline: .now() + 0.75) { UIAccessibility.post(notification: .announcement, argument: announcement) } } - - override func show(in view: UIView) - { - self.show(in: view, duration: self.preferredDuration) + + override func show(in view: UIView) { + show(in: view, duration: preferredDuration) } } diff --git a/AltStore/Consts/Consts+Proxy.swift b/Sources/SideStore/Consts/Consts+Proxy.swift similarity index 94% rename from AltStore/Consts/Consts+Proxy.swift rename to Sources/SideStore/Consts/Consts+Proxy.swift index 31aa1add..318344b0 100644 --- a/AltStore/Consts/Consts+Proxy.swift +++ b/Sources/SideStore/Consts/Consts+Proxy.swift @@ -9,7 +9,7 @@ import Foundation public extension Consts { - enum Proxy { + enum Proxy { static let address = "127.0.0.1" static let port = "51820" static let serverURL = "\(address):\(port)" diff --git a/AltStore/Consts/Consts.swift b/Sources/SideStore/Consts/Consts.swift similarity index 87% rename from AltStore/Consts/Consts.swift rename to Sources/SideStore/Consts/Consts.swift index 77ea7e70..433f7b47 100644 --- a/AltStore/Consts/Consts.swift +++ b/Sources/SideStore/Consts/Consts.swift @@ -8,6 +8,4 @@ import Foundation -public enum Consts { - -} +public enum Consts {} diff --git a/AltStore/Extensions/FileManager+DirectorySize.swift b/Sources/SideStore/Extensions/FileManager+DirectorySize.swift similarity index 69% rename from AltStore/Extensions/FileManager+DirectorySize.swift rename to Sources/SideStore/Extensions/FileManager+DirectorySize.swift index 44ca93c3..d6585be6 100644 --- a/AltStore/Extensions/FileManager+DirectorySize.swift +++ b/Sources/SideStore/Extensions/FileManager+DirectorySize.swift @@ -8,29 +8,23 @@ import Foundation -extension FileManager -{ - func directorySize(at directoryURL: URL) -> Int? - { +extension FileManager { + func directorySize(at directoryURL: URL) -> Int? { guard let enumerator = FileManager.default.enumerator(at: directoryURL, includingPropertiesForKeys: [.fileSizeKey]) else { return nil } - - var total: Int = 0 - - for case let fileURL as URL in enumerator - { - do - { + + var total = 0 + + for case let fileURL as URL in enumerator { + do { let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey]) guard let fileSize = resourceValues.fileSize else { continue } - + total += fileSize - } - catch - { + } catch { print("Failed to read file size for item: \(fileURL).", error) } } - + return total } } diff --git a/AltStore/Extensions/INInteraction+AltStore.swift b/Sources/SideStore/Extensions/INInteraction+AltStore.swift similarity index 85% rename from AltStore/Extensions/INInteraction+AltStore.swift rename to Sources/SideStore/Extensions/INInteraction+AltStore.swift index e758304e..83a7ec84 100644 --- a/AltStore/Extensions/INInteraction+AltStore.swift +++ b/Sources/SideStore/Extensions/INInteraction+AltStore.swift @@ -10,13 +10,11 @@ import Intents // Requires iOS 14 in-app intent handling. @available(iOS 14, *) -extension INInteraction -{ - static func refreshAllApps() -> INInteraction - { +extension INInteraction { + static func refreshAllApps() -> INInteraction { let refreshAllIntent = RefreshAllIntent() refreshAllIntent.suggestedInvocationPhrase = NSString.deferredLocalizedIntentsString(with: "Refresh my apps") as String - + let interaction = INInteraction(intent: refreshAllIntent, response: nil) return interaction } diff --git a/AltStore/Extensions/OSLog+SideStore.swift b/Sources/SideStore/Extensions/OSLog+SideStore.swift similarity index 77% rename from AltStore/Extensions/OSLog+SideStore.swift rename to Sources/SideStore/Extensions/OSLog+SideStore.swift index 0cb11525..0b6b441a 100644 --- a/AltStore/Extensions/OSLog+SideStore.swift +++ b/Sources/SideStore/Extensions/OSLog+SideStore.swift @@ -10,8 +10,7 @@ import Foundation import OSLog public let customLog = OSLog(subsystem: "org.sidestore.sidestore", - category: "ios") - + category: "ios") public extension OSLog { /// Error logger extension @@ -22,7 +21,7 @@ public extension OSLog { static func error(_ message: StaticString, _ args: CVarArg...) { os_log(message, log: customLog, type: .error, args) } - + /// Info logger extension /// - Parameters: /// - message: String or format string @@ -31,7 +30,7 @@ public extension OSLog { static func info(_ message: StaticString, _ args: CVarArg...) { os_log(message, log: customLog, type: .info, args) } - + /// Debug logger extension /// - Parameters: /// - message: String or format string @@ -49,7 +48,7 @@ public extension OSLog { /// - message: String or format string /// - args: optional args for format string @inlinable -public func ELOG(_ message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, _ args: CVarArg...) { +public func ELOG(_ message: StaticString, file _: StaticString = #file, function _: StaticString = #function, line _: UInt = #line, _ args: CVarArg...) { OSLog.error(message, args) } @@ -58,7 +57,7 @@ public func ELOG(_ message: StaticString, file: StaticString = #file, function: /// - message: String or format string /// - args: optional args for format string @inlinable -public func ILOG(_ message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, _ args: CVarArg...) { +public func ILOG(_ message: StaticString, file _: StaticString = #file, function _: StaticString = #function, line _: UInt = #line, _ args: CVarArg...) { OSLog.info(message, args) } @@ -67,8 +66,8 @@ public func ILOG(_ message: StaticString, file: StaticString = #file, function: /// - message: String or format string /// - args: optional args for format string @inlinable -public func DLOG(_ message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, _ args: CVarArg...) { +public func DLOG(_ message: StaticString, file _: StaticString = #file, function _: StaticString = #function, line _: UInt = #line, _ args: CVarArg...) { OSLog.debug(message, args) } -// mark: Helpers +// MARK: Helpers diff --git a/AltStore/Extensions/UIDevice+Jailbreak.swift b/Sources/SideStore/Extensions/UIDevice+Jailbreak.swift similarity index 75% rename from AltStore/Extensions/UIDevice+Jailbreak.swift rename to Sources/SideStore/Extensions/UIDevice+Jailbreak.swift index 78a6542e..5566fe82 100644 --- a/AltStore/Extensions/UIDevice+Jailbreak.swift +++ b/Sources/SideStore/Extensions/UIDevice+Jailbreak.swift @@ -6,11 +6,10 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import UIKit import ARKit +import UIKit -extension UIDevice -{ +extension UIDevice { var isJailbroken: Bool { if FileManager.default.fileExists(atPath: "/Applications/Cydia.app") || @@ -19,31 +18,29 @@ extension UIDevice FileManager.default.fileExists(atPath: "/usr/sbin/sshd") || FileManager.default.fileExists(atPath: "/etc/apt") || FileManager.default.fileExists(atPath: "/private/var/lib/apt/") || - UIApplication.shared.canOpenURL(URL(string:"cydia://")!) + UIApplication.shared.canOpenURL(URL(string: "cydia://")!) { return true - } - else - { + } else { return false } } - + @available(iOS 14, *) var supportsFugu14: Bool { #if targetEnvironment(simulator) - return true + return true #else - // Fugu14 is supported on devices with an A12 processor or better. - // ARKit 3 is only supported by devices with an A12 processor or better, according to the documentation. - return ARBodyTrackingConfiguration.isSupported + // Fugu14 is supported on devices with an A12 processor or better. + // ARKit 3 is only supported by devices with an A12 processor or better, according to the documentation. + return ARBodyTrackingConfiguration.isSupported #endif } - + @available(iOS 14, *) var isUntetheredJailbreakRequired: Bool { let ios14_4 = OperatingSystemVersion(majorVersion: 14, minorVersion: 4, patchVersion: 0) - + let isUntetheredJailbreakRequired = ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14_4) return isUntetheredJailbreakRequired } diff --git a/AltStore/Extensions/UIDevice+Vibration.swift b/Sources/SideStore/Extensions/UIDevice+Vibration.swift similarity index 64% rename from AltStore/Extensions/UIDevice+Vibration.swift rename to Sources/SideStore/Extensions/UIDevice+Vibration.swift index 3295e3c2..8a3b9690 100644 --- a/AltStore/Extensions/UIDevice+Vibration.swift +++ b/Sources/SideStore/Extensions/UIDevice+Vibration.swift @@ -9,36 +9,30 @@ import AudioToolbox import CoreHaptics -private extension SystemSoundID -{ +private extension SystemSoundID { static let pop = SystemSoundID(1520) static let cancelled = SystemSoundID(1521) static let tryAgain = SystemSoundID(1102) } @available(iOS 13, *) -extension UIDevice -{ - enum VibrationPattern - { +extension UIDevice { + enum VibrationPattern { case success case error } } @available(iOS 13, *) -extension UIDevice -{ +extension UIDevice { var isVibrationSupported: Bool { - return CHHapticEngine.capabilitiesForHardware().supportsHaptics + CHHapticEngine.capabilitiesForHardware().supportsHaptics } - func vibrate(pattern: VibrationPattern) - { - guard self.isVibrationSupported else { return } - - switch pattern - { + func vibrate(pattern: VibrationPattern) { + guard isVibrationSupported else { return } + + switch pattern { case .success: AudioServicesPlaySystemSound(.tryAgain) case .error: AudioServicesPlaySystemSound(.cancelled) } diff --git a/AltStore/Extensions/UIScreen+CompactHeight.swift b/Sources/SideStore/Extensions/UIScreen+CompactHeight.swift similarity index 72% rename from AltStore/Extensions/UIScreen+CompactHeight.swift rename to Sources/SideStore/Extensions/UIScreen+CompactHeight.swift index 8ca350ac..6e83fb45 100644 --- a/AltStore/Extensions/UIScreen+CompactHeight.swift +++ b/Sources/SideStore/Extensions/UIScreen+CompactHeight.swift @@ -8,9 +8,8 @@ import UIKit -extension UIScreen -{ +extension UIScreen { var isExtraCompactHeight: Bool { - return self.fixedCoordinateSpace.bounds.height < 600 + fixedCoordinateSpace.bounds.height < 600 } } diff --git a/AltStore/Intents/IntentHandler.swift b/Sources/SideStore/Intents/IntentHandler.swift similarity index 67% rename from AltStore/Intents/IntentHandler.swift rename to Sources/SideStore/Intents/IntentHandler.swift index cad45e75..431c84bc 100644 --- a/AltStore/Intents/IntentHandler.swift +++ b/Sources/SideStore/Intents/IntentHandler.swift @@ -8,83 +8,69 @@ import Foundation -import AltStoreCore +import SideStoreCore @available(iOS 14, *) -final class IntentHandler: NSObject, RefreshAllIntentHandling -{ +final class IntentHandler: NSObject, RefreshAllIntentHandling { private let queue = DispatchQueue(label: "io.altstore.IntentHandler") - + private var completionHandlers = [RefreshAllIntent: (RefreshAllIntentResponse) -> Void]() private var queuedResponses = [RefreshAllIntent: RefreshAllIntentResponse]() - + private var operations = [RefreshAllIntent: BackgroundRefreshAppsOperation]() - - func confirm(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) - { + + func confirm(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) { // Refreshing apps usually, but not always, completes within alotted time. // As a workaround, we'll start refreshing apps in confirm() so we can // take advantage of some extra time before starting handle() timeout timer. - self.completionHandlers[intent] = { (response) in - if response.code != .ready - { + completionHandlers[intent] = { response in + if response.code != .ready { // Operation finished before confirmation "timeout". // Cache response to return it when handle() is called. self.queuedResponses[intent] = response } - + completion(RefreshAllIntentResponse(code: .ready, userActivity: nil)) } - + // Give ourselves 9 extra seconds before starting handle() timeout timer. // 10 seconds or longer results in timeout regardless. - self.queue.asyncAfter(deadline: .now() + 9.0) { + queue.asyncAfter(deadline: .now() + 9.0) { self.finish(intent, response: RefreshAllIntentResponse(code: .ready, userActivity: nil)) } - - if !DatabaseManager.shared.isStarted - { - DatabaseManager.shared.start() { (error) in - if let error = error - { + + if !DatabaseManager.shared.isStarted { + DatabaseManager.shared.start { error in + if let error = error { self.finish(intent, response: RefreshAllIntentResponse.failure(localizedDescription: error.localizedDescription)) - } - else - { + } else { self.refreshApps(intent: intent) } } - } - else - { - self.refreshApps(intent: intent) + } else { + refreshApps(intent: intent) } } - - func handle(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) - { - self.completionHandlers[intent] = { (response) in + + func handle(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) { + completionHandlers[intent] = { response in // Ignore .ready response from confirm() timeout. guard response.code != .ready else { return } completion(response) } - if let response = self.queuedResponses[intent] - { - self.queuedResponses[intent] = nil - self.finish(intent, response: response) - } - else - { - self.queue.asyncAfter(deadline: .now() + 7.0) { - if let operation = self.operations[intent] - { + if let response = queuedResponses[intent] { + queuedResponses[intent] = nil + finish(intent, response: response) + } else { + queue.asyncAfter(deadline: .now() + 7.0) { + if let operation = self.operations[intent] { // We took too long to finish and return the final result, // so we'll now present a normal notification when finished. operation.presentsFinishedNotification = true } - + self.finish(intent, response: RefreshAllIntentResponse(code: .inProgress, userActivity: nil)) } } @@ -92,54 +78,42 @@ final class IntentHandler: NSObject, RefreshAllIntentHandling } @available(iOS 14, *) -private extension IntentHandler -{ - func finish(_ intent: RefreshAllIntent, response: RefreshAllIntentResponse) - { - self.queue.async { - if let completionHandler = self.completionHandlers[intent] - { +private extension IntentHandler { + func finish(_ intent: RefreshAllIntent, response: RefreshAllIntentResponse) { + queue.async { + if let completionHandler = self.completionHandlers[intent] { self.completionHandlers[intent] = nil completionHandler(response) - } - else if response.code != .ready && response.code != .inProgress - { + } else if response.code != .ready && response.code != .inProgress { // Queue response in case refreshing finishes after confirm() but before handle(). self.queuedResponses[intent] = response } } } - - func refreshApps(intent: RefreshAllIntent) - { - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + func refreshApps(intent: RefreshAllIntent) { + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let installedApps = InstalledApp.fetchActiveApps(in: context) - let operation = AppManager.shared.backgroundRefresh(installedApps, presentsNotifications: false) { (result) in - do - { + let operation = AppManager.shared.backgroundRefresh(installedApps, presentsNotifications: false) { result in + do { let results = try result.get() - - for (_, result) in results - { + + for (_, result) in results { guard case let .failure(error) = result else { continue } throw error } - + self.finish(intent, response: RefreshAllIntentResponse(code: .success, userActivity: nil)) - } - catch RefreshError.noInstalledApps - { + } catch RefreshError.noInstalledApps { self.finish(intent, response: RefreshAllIntentResponse(code: .success, userActivity: nil)) - } - catch let error as NSError - { + } catch let error as NSError { print("Failed to refresh apps in background.", error) self.finish(intent, response: RefreshAllIntentResponse.failure(localizedDescription: error.localizedFailureReason ?? error.localizedDescription)) } - + self.operations[intent] = nil } - + self.operations[intent] = operation } } diff --git a/AltStore/Intents/Intents.intentdefinition b/Sources/SideStore/Intents/Intents.intentdefinition similarity index 100% rename from AltStore/Intents/Intents.intentdefinition rename to Sources/SideStore/Intents/Intents.intentdefinition diff --git a/AltStore/LaunchViewController.swift b/Sources/SideStore/LaunchViewController.swift similarity index 73% rename from AltStore/LaunchViewController.swift rename to Sources/SideStore/LaunchViewController.swift index f228dc6a..ec642a3c 100644 --- a/AltStore/LaunchViewController.swift +++ b/Sources/SideStore/LaunchViewController.swift @@ -6,58 +6,56 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit -import RoxasUI import EmotionalDamage import minimuxer +import RoxasUI +import UIKit -import AltStoreCore +import SideStoreCore import UniformTypeIdentifiers -final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDelegate -{ +final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDelegate { private var didFinishLaunching = false - + private var destinationViewController: UIViewController! - + override var launchConditions: [RSTLaunchCondition] { - let isDatabaseStarted = RSTLaunchCondition(condition: { DatabaseManager.shared.isStarted }) { (completionHandler) in + let isDatabaseStarted = RSTLaunchCondition(condition: { DatabaseManager.shared.isStarted }) { completionHandler in DatabaseManager.shared.start(completionHandler: completionHandler) } return [isDatabaseStarted] } - + override var childForStatusBarStyle: UIViewController? { - return self.children.first + self.children.first } - + override var childForStatusBarHidden: UIViewController? { - return self.children.first + self.children.first } - - override func viewDidLoad() - { + + override func viewDidLoad() { defer { // Create destinationViewController now so view controllers can register for receiving Notifications. self.destinationViewController = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as! TabBarController } super.viewDidLoad() } - - override func viewDidAppear(_ animated: Bool) { + + override func viewDidAppear(_: Bool) { super.viewDidAppear(true) #if !targetEnvironment(simulator) - start_em_proxy(bind_addr: Consts.Proxy.serverURL) - - guard let pf = fetchPairingFile() else { - displayError("Device pairing file not found.") - return - } - start_minimuxer_threads(pf) + start_em_proxy(bind_addr: Consts.Proxy.serverURL) + + guard let pf = fetchPairingFile() else { + displayError("Device pairing file not found.") + return + } + start_minimuxer_threads(pf) #endif } - + func fetchPairingFile() -> String? { let filename = "ALTPairingFile.mobiledevicepairing" let fm = FileManager.default @@ -70,19 +68,20 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg fm.fileExists(atPath: appResourcePath.path), let data = fm.contents(atPath: appResourcePath.path), let contents = String(data: data, encoding: .utf8), - !contents.isEmpty { + !contents.isEmpty + { print("Loaded ALTPairingFile from \(appResourcePath.path)") return contents - } else if let plistString = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String, !plistString.isEmpty, !plistString.contains("insert pairing file here"){ + } else if let plistString = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String, !plistString.isEmpty, !plistString.contains("insert pairing file here") { print("Loaded ALTPairingFile from Info.plist") return plistString } else { // Show an alert explaining the pairing file // Create new Alert let dialogMessage = UIAlertController(title: "Pairing File", message: "Select the pairing file for your device. For more information, go to https://wiki.sidestore.io/guides/install#pairing-process", preferredStyle: .alert) - + // Create OK button with action handler - let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in + let ok = UIAlertAction(title: "OK", style: .default, handler: { _ in // Try to load it from a file picker var types = UTType.types(tag: "plist", tagClass: UTTagClass.filenameExtension, conformingTo: nil) types.append(contentsOf: UTType.types(tag: "mobiledevicepairing", tagClass: UTTagClass.filenameExtension, conformingTo: UTType.data)) @@ -91,13 +90,13 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg documentPickerController.shouldShowFileExtensions = true documentPickerController.delegate = self self.present(documentPickerController, animated: true, completion: nil) - }) - - //Add OK button to a dialog message + }) + + // Add OK button to a dialog message dialogMessage.addAction(ok) // Present Alert to - self.present(dialogMessage, animated: true, completion: nil) + present(dialogMessage, animated: true, completion: nil) return nil } @@ -109,9 +108,9 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg let dialogMessage = UIAlertController(title: "Error launching SideStore", message: msg, preferredStyle: .alert) // Present alert to user - self.present(dialogMessage, animated: true, completion: nil) + present(dialogMessage, animated: true, completion: nil) } - + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { let url = urls[0] let isSecuredURL = url.startAccessingSecurityScopedResource() == true @@ -123,42 +122,42 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg if pairing_string == nil { displayError("Unable to read pairing file") } - + // Save to a file for next launch let filename = "ALTPairingFile.mobiledevicepairing" let fm = FileManager.default let documentsPath = fm.documentsDirectory.appendingPathComponent("/\(filename)") try pairing_string?.write(to: documentsPath, atomically: true, encoding: String.Encoding.utf8) - + // Start minimuxer now that we have a file start_minimuxer_threads(pairing_string!) - + } catch { displayError("Unable to read pairing file") } - - if (isSecuredURL) { + + if isSecuredURL { url.stopAccessingSecurityScopedResource() } controller.dismiss(animated: true, completion: nil) } - - func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { + + func documentPickerWasCancelled(_: UIDocumentPickerViewController) { displayError("Choosing a pairing file was cancelled. Please re-open the app and try again.") } - + func start_minimuxer_threads(_ pairing_file: String) { set_usbmuxd_socket() #if false // Retries - var res = start_minimuxer(pairing_file: pairing_file) - var attempts = 10 - while (attempts != 0 && res != 0) { - print("start_minimuxer `res` != 0, retry #\(attempts)") - res = start_minimuxer(pairing_file: pairing_file) - attempts -= 1 - } + var res = start_minimuxer(pairing_file: pairing_file) + var attempts = 10 + while attempts != 0, res != 0 { + print("start_minimuxer `res` != 0, retry #\(attempts)") + res = start_minimuxer(pairing_file: pairing_file) + attempts -= 1 + } #else - let res = start_minimuxer(pairing_file: pairing_file) + let res = start_minimuxer(pairing_file: pairing_file) #endif if res != 0 { displayError("minimuxer failed to start. Incorrect arguments were passed.") @@ -167,60 +166,51 @@ final class LaunchViewController: RSTLaunchViewController, UIDocumentPickerDeleg } } -extension LaunchViewController -{ - override func handleLaunchError(_ error: Error) - { - do - { +extension LaunchViewController { + override func handleLaunchError(_ error: Error) { + do { throw error - } - catch let error as NSError - { + } catch let error as NSError { let title = error.userInfo[NSLocalizedFailureErrorKey] as? String ?? NSLocalizedString("Unable to Launch SideStore", comment: "") - + let errorDescription: String - - if #available(iOS 14.5, *) - { + + if #available(iOS 14.5, *) { let errorMessages = [error.debugDescription] + error.underlyingErrors.map { ($0 as NSError).debugDescription } errorDescription = errorMessages.joined(separator: "\n\n") - } - else - { + } else { errorDescription = error.debugDescription } - + let alertController = UIAlertController(title: title, message: errorDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Retry", comment: ""), style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Retry", comment: ""), style: .default, handler: { _ in self.handleLaunchConditions() })) self.present(alertController, animated: true, completion: nil) } } - - override func finishLaunching() - { + + override func finishLaunching() { super.finishLaunching() - - guard !self.didFinishLaunching else { return } - + + guard !didFinishLaunching else { return } + AppManager.shared.update() - AppManager.shared.updatePatronsIfNeeded() + AppManager.shared.updatePatronsIfNeeded() PatreonAPI.shared.refreshPatreonAccount() - + // Add view controller as child (rather than presenting modally) // so tint adjustment + card presentations works correctly. - self.destinationViewController.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height) - self.destinationViewController.view.alpha = 0.0 - self.addChild(self.destinationViewController) - self.view.addSubview(self.destinationViewController.view, pinningEdgesWith: .zero) - self.destinationViewController.didMove(toParent: self) - + destinationViewController.view.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height) + destinationViewController.view.alpha = 0.0 + addChild(destinationViewController) + view.addSubview(destinationViewController.view, pinningEdgesWith: .zero) + destinationViewController.didMove(toParent: self) + UIView.animate(withDuration: 0.2) { self.destinationViewController.view.alpha = 1.0 } - - self.didFinishLaunching = true + + didFinishLaunching = true } } diff --git a/AltStore/Managing Apps/AppManager.swift b/Sources/SideStore/Managing Apps/AppManager.swift similarity index 68% rename from AltStore/Managing Apps/AppManager.swift rename to Sources/SideStore/Managing Apps/AppManager.swift index 8b9b9d0a..e066a147 100644 --- a/AltStore/Managing Apps/AppManager.swift +++ b/Sources/SideStore/Managing Apps/AppManager.swift @@ -6,774 +6,674 @@ // Copyright © 2019 Riley Testut. All rights reserved. // +import Combine import Foundation +import Intents +import MobileCoreServices import UIKit import UserNotifications -import MobileCoreServices -import Intents -import Combine import WidgetKit -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI -extension AppManager -{ +extension AppManager { static let didFetchSourceNotification = Notification.Name("io.altstore.AppManager.didFetchSource") static let didUpdatePatronsNotification = Notification.Name("io.altstore.AppManager.didUpdatePatrons") - + static let expirationWarningNotificationID = "altstore-expiration-warning" static let enableJITResultNotificationID = "altstore-enable-jit" } @available(iOS 13, *) -final class AppManagerPublisher: ObservableObject -{ +final class AppManagerPublisher: ObservableObject { @Published fileprivate(set) var installationProgress = [String: Progress]() - + @Published fileprivate(set) var refreshProgress = [String: Progress]() } -private func ==(lhs: OperatingSystemVersion, rhs: OperatingSystemVersion) -> Bool -{ - return (lhs.majorVersion == rhs.majorVersion && lhs.minorVersion == rhs.minorVersion && lhs.patchVersion == rhs.patchVersion) +private func == (lhs: OperatingSystemVersion, rhs: OperatingSystemVersion) -> Bool { + lhs.majorVersion == rhs.majorVersion && lhs.minorVersion == rhs.minorVersion && lhs.patchVersion == rhs.patchVersion } -final class AppManager -{ +final class AppManager { static let shared = AppManager() - + private(set) var updatePatronsResult: Result? - + private let operationQueue = OperationQueue() private let serialOperationQueue = OperationQueue() private var installationProgress = [String: Progress]() { didSet { guard #available(iOS 13, *) else { return } - self.publisher.installationProgress = self.installationProgress + publisher.installationProgress = installationProgress } } + private var refreshProgress = [String: Progress]() { didSet { guard #available(iOS 13, *) else { return } - self.publisher.refreshProgress = self.refreshProgress + publisher.refreshProgress = refreshProgress } } - + @available(iOS 13, *) private(set) var publisher: AppManagerPublisher { get { _publisher as! AppManagerPublisher } set { _publisher = newValue } } - + @available(iOS 13, *) private(set) var cancellables: Set { get { _cancellables as! Set } set { _cancellables = newValue } } - + private lazy var _publisher: Any = { guard #available(iOS 13, *) else { fatalError() } return AppManagerPublisher() }() - + private lazy var _cancellables: Any = { guard #available(iOS 13, *) else { fatalError() } return Set() }() - - private init() - { - self.operationQueue.name = "com.altstore.AppManager.operationQueue" - - self.serialOperationQueue.name = "com.altstore.AppManager.serialOperationQueue" - self.serialOperationQueue.maxConcurrentOperationCount = 1 - - if #available(iOS 13, *) - { + + private init() { + operationQueue.name = "com.altstore.AppManager.operationQueue" + + serialOperationQueue.name = "com.altstore.AppManager.serialOperationQueue" + serialOperationQueue.maxConcurrentOperationCount = 1 + + if #available(iOS 13, *) { self.prepareSubscriptions() } } - + @available(iOS 13, *) - func prepareSubscriptions() - { + func prepareSubscriptions() { /// Every time refreshProgress is changed, update all InstalledApps in memory /// so that app.isRefreshing == refreshProgress.keys.contains(app.bundleID) - - self.publisher.$refreshProgress + + publisher.$refreshProgress .receive(on: RunLoop.main) .map(\.keys) - .flatMap { (bundleIDs) in + .flatMap { bundleIDs in DatabaseManager.shared.viewContext.registeredObjects.publisher .compactMap { $0 as? InstalledApp } .map { ($0, bundleIDs.contains($0.bundleIdentifier)) } } - .sink { (installedApp, isRefreshing) in + .sink { installedApp, isRefreshing in installedApp.isRefreshing = isRefreshing } - .store(in: &self.cancellables) + .store(in: &cancellables) } } -extension AppManager -{ - func update() - { - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in +extension AppManager { + func update() { + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in #if targetEnvironment(simulator) // Apps aren't ever actually installed to simulator, so just do nothing rather than delete them from database. #else - do - { - let installedApps = InstalledApp.all(in: context) - - if UserDefaults.standard.legacySideloadedApps == nil - { - // First time updating apps since updating AltStore to use custom UTIs, - // so cache all existing apps temporarily to prevent us from accidentally - // deleting them due to their custom UTI not existing (yet). - let apps = installedApps.map { $0.bundleIdentifier } - UserDefaults.standard.legacySideloadedApps = apps - } - - let legacySideloadedApps = Set(UserDefaults.standard.legacySideloadedApps ?? []) - - for app in installedApps - { - guard app.bundleIdentifier != StoreApp.altstoreAppID else { - self.scheduleExpirationWarningLocalNotification(for: app) - continue + do { + let installedApps = InstalledApp.all(in: context) + + if UserDefaults.standard.legacySideloadedApps == nil { + // First time updating apps since updating AltStore to use custom UTIs, + // so cache all existing apps temporarily to prevent us from accidentally + // deleting them due to their custom UTI not existing (yet). + let apps = installedApps.map { $0.bundleIdentifier } + UserDefaults.standard.legacySideloadedApps = apps } - - guard !self.isActivelyManagingApp(withBundleID: app.bundleIdentifier) else { continue } - - if !UserDefaults.standard.isLegacyDeactivationSupported - { - // We can't (ab)use provisioning profiles to deactivate apps, - // which means we must delete apps to free up active slots. - // So, only check if active apps are installed to prevent - // false positives when checking inactive apps. - guard app.isActive else { continue } - } - - let uti = UTTypeCopyDeclaration(app.installedAppUTI as CFString)?.takeRetainedValue() as NSDictionary? - if uti == nil && !legacySideloadedApps.contains(app.bundleIdentifier) - { - // This UTI is not declared by any apps, which means this app has been deleted by the user. - // This app is also not a legacy sideloaded app, so we can assume it's fine to delete it. - context.delete(app) - - if var patchedApps = UserDefaults.standard.patchedApps, let index = patchedApps.firstIndex(of: app.bundleIdentifier) - { - patchedApps.remove(at: index) - UserDefaults.standard.patchedApps = patchedApps + + let legacySideloadedApps = Set(UserDefaults.standard.legacySideloadedApps ?? []) + + for app in installedApps { + guard app.bundleIdentifier != StoreApp.altstoreAppID else { + self.scheduleExpirationWarningLocalNotification(for: app) + continue + } + + guard !self.isActivelyManagingApp(withBundleID: app.bundleIdentifier) else { continue } + + if !UserDefaults.standard.isLegacyDeactivationSupported { + // We can't (ab)use provisioning profiles to deactivate apps, + // which means we must delete apps to free up active slots. + // So, only check if active apps are installed to prevent + // false positives when checking inactive apps. + guard app.isActive else { continue } + } + + let uti = UTTypeCopyDeclaration(app.installedAppUTI as CFString)?.takeRetainedValue() as NSDictionary? + if uti == nil, !legacySideloadedApps.contains(app.bundleIdentifier) { + // This UTI is not declared by any apps, which means this app has been deleted by the user. + // This app is also not a legacy sideloaded app, so we can assume it's fine to delete it. + context.delete(app) + + if var patchedApps = UserDefaults.standard.patchedApps, let index = patchedApps.firstIndex(of: app.bundleIdentifier) { + patchedApps.remove(at: index) + UserDefaults.standard.patchedApps = patchedApps + } } } + + try context.save() + } catch { + print("Error while fetching installed apps.", error) } - - try context.save() - } - catch - { - print("Error while fetching installed apps.", error) - } #endif - - do - { + + do { let installedAppBundleIDs = InstalledApp.all(in: context).map { $0.bundleIdentifier } - + let cachedAppDirectories = try FileManager.default.contentsOfDirectory(at: InstalledApp.appsDirectoryURL, includingPropertiesForKeys: [.isDirectoryKey, .nameKey], options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles]) - for appDirectory in cachedAppDirectories - { - do - { + for appDirectory in cachedAppDirectories { + do { let resourceValues = try appDirectory.resourceValues(forKeys: [.isDirectoryKey, .nameKey]) guard let isDirectory = resourceValues.isDirectory, let bundleID = resourceValues.name else { continue } - - if isDirectory && !installedAppBundleIDs.contains(bundleID) && !self.isActivelyManagingApp(withBundleID: bundleID) - { + + if isDirectory && !installedAppBundleIDs.contains(bundleID) && !self.isActivelyManagingApp(withBundleID: bundleID) { print("DELETING CACHED APP:", bundleID) try FileManager.default.removeItem(at: appDirectory) } - } - catch - { + } catch { print("Failed to remove cached app directory.", error) } } - } - catch - { + } catch { print("Failed to remove cached apps.", error) } } } - + @discardableResult - func authenticate(presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result<(ALTTeam, ALTCertificate, ALTAppleAPISession), Error>) -> Void) -> AuthenticationOperation - { - if let operation = context.authenticationOperation - { + func authenticate(presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result<(ALTTeam, ALTCertificate, ALTAppleAPISession), Error>) -> Void) -> AuthenticationOperation { + if let operation = context.authenticationOperation { return operation } - + let authenticationOperation = AuthenticationOperation(context: context, presentingViewController: presentingViewController) - authenticationOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error + authenticationOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error case .success: break } - + completionHandler(result) } - - self.run([authenticationOperation], context: context) - + + run([authenticationOperation], context: context) + return authenticationOperation } - - func deactivateApps(for app: ALTApplication, presentingViewController: UIViewController, completion: @escaping (Result) -> Void) - { + + func deactivateApps(for app: ALTApplication, presentingViewController: UIViewController, completion: @escaping (Result) -> Void) { guard let activeAppsLimit = UserDefaults.standard.activeAppsLimit else { return completion(.success(())) } - + DispatchQueue.main.async { let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext) .filter { $0.bundleIdentifier != app.bundleIdentifier } // Don't count app towards total if it matches activating app .sorted { ($0.name, $0.refreshedDate) < ($1.name, $1.refreshedDate) } - + var title: String = NSLocalizedString("Cannot Activate More than 3 Apps", comment: "") let message: String - - if UserDefaults.standard.activeAppLimitIncludesExtensions - { - if app.appExtensions.isEmpty - { + + if UserDefaults.standard.activeAppLimitIncludesExtensions { + if app.appExtensions.isEmpty { message = NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps and app extensions. Please choose an app to deactivate.", comment: "") - } - else - { + } else { title = NSLocalizedString("Cannot Activate More than 3 Apps and App Extensions", comment: "") - + let appExtensionText = app.appExtensions.count == 1 ? NSLocalizedString("app extension", comment: "") : NSLocalizedString("app extensions", comment: "") message = String(format: NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps and app extensions, and “%@” contains %@ %@. Please choose an app to deactivate.", comment: ""), app.name, NSNumber(value: app.appExtensions.count), appExtensionText) } - } - else - { + } else { message = NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps. Please choose an app to deactivate.", comment: "") } - + let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +) - + let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0) let requiredActiveSlots = UserDefaults.standard.activeAppLimitIncludesExtensions ? (1 + app.appExtensions.count) : 1 guard requiredActiveSlots > availableActiveApps else { return completion(.success(())) } - + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { (action) in + alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { _ in completion(.failure(OperationError.cancelled)) }) - - for activeApp in activeApps where activeApp.bundleIdentifier != StoreApp.altstoreAppID - { - alertController.addAction(UIAlertAction(title: activeApp.name, style: .default) { (action) in + + for activeApp in activeApps where activeApp.bundleIdentifier != StoreApp.altstoreAppID { + alertController.addAction(UIAlertAction(title: activeApp.name, style: .default) { _ in activeApp.isActive = false - - self.deactivate(activeApp, presentingViewController: presentingViewController) { (result) in - switch result - { - case .failure(let error): + + self.deactivate(activeApp, presentingViewController: presentingViewController) { result in + switch result { + case let .failure(error): activeApp.managedObjectContext?.perform { activeApp.isActive = true completion(.failure(error)) } - + case .success: self.deactivateApps(for: app, presentingViewController: presentingViewController, completion: completion) } } }) } - + presentingViewController.present(alertController, animated: true, completion: nil) } } } -extension AppManager -{ +extension AppManager { func fetchSource(sourceURL: URL, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext(), dependencies: [Foundation.Operation] = [], - completionHandler: @escaping (Result) -> Void) - { + completionHandler: @escaping (Result) -> Void) { let fetchSourceOperation = FetchSourceOperation(sourceURL: sourceURL, managedObjectContext: managedObjectContext) - fetchSourceOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): + fetchSourceOperation.resultHandler = { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) - - case .success(let source): + + case let .success(source): completionHandler(.success(source)) } } - - for dependency in dependencies - { + + for dependency in dependencies { fetchSourceOperation.addDependency(dependency) } - - self.run([fetchSourceOperation], context: nil) + + run([fetchSourceOperation], context: nil) } - - func fetchSources(completionHandler: @escaping (Result<(Set, NSManagedObjectContext), FetchSourcesError>) -> Void) - { - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + func fetchSources(completionHandler: @escaping (Result<(Set, NSManagedObjectContext), FetchSourcesError>) -> Void) { + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let sources = Source.all(in: context) guard !sources.isEmpty else { return completionHandler(.failure(.init(OperationError.noSources))) } - + let dispatchGroup = DispatchGroup() var fetchedSources = Set() - + var errors = [Source: Error]() - + let managedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext() - - let operations = sources.map { (source) -> FetchSourceOperation in + + let operations = sources.map { source -> FetchSourceOperation in dispatchGroup.enter() - + let fetchSourceOperation = FetchSourceOperation(sourceURL: source.sourceURL, managedObjectContext: managedObjectContext) - fetchSourceOperation.resultHandler = { (result) in - switch result - { - case .success(let source): fetchedSources.insert(source) - case .failure(let error): + fetchSourceOperation.resultHandler = { result in + switch result { + case let .success(source): fetchedSources.insert(source) + case let .failure(error): let source = managedObjectContext.object(with: source.objectID) as! Source source.error = (error as NSError).sanitizedForCoreData() errors[source] = error } - + dispatchGroup.leave() } - + return fetchSourceOperation } - + dispatchGroup.notify(queue: .global()) { managedObjectContext.perform { - if !errors.isEmpty - { + if !errors.isEmpty { let sources = Set(sources.compactMap { managedObjectContext.object(with: $0.objectID) as? Source }) completionHandler(.failure(.init(sources: sources, errors: errors, context: managedObjectContext))) - } - else - { + } else { completionHandler(.success((fetchedSources, managedObjectContext))) } } - + NotificationCenter.default.post(name: AppManager.didFetchSourceNotification, object: self) } - + self.run(operations, context: nil) } } - + func fetchAppIDs(completionHandler: @escaping (Result<([AppID], NSManagedObjectContext), Error>) -> Void) { let authenticationOperation = self.authenticate(presentingViewController: nil) { (result) in // result contains name, email, auth token, OTP and other possibly personal/account specific info. we don't want this logged //print("Authenticated for fetching App IDs with result:", result) } - + let fetchAppIDsOperation = FetchAppIDsOperation(context: authenticationOperation.context) fetchAppIDsOperation.resultHandler = completionHandler fetchAppIDsOperation.addDependency(authenticationOperation) - self.run([fetchAppIDsOperation], context: authenticationOperation.context) + run([fetchAppIDsOperation], context: authenticationOperation.context) } - + @discardableResult - func fetchTrustedSources(completionHandler: @escaping (Result<[FetchTrustedSourcesOperation.TrustedSource], Error>) -> Void) -> FetchTrustedSourcesOperation - { + func fetchTrustedSources(completionHandler: @escaping (Result<[FetchTrustedSourcesOperation.TrustedSource], Error>) -> Void) -> FetchTrustedSourcesOperation { let fetchTrustedSourcesOperation = FetchTrustedSourcesOperation() fetchTrustedSourcesOperation.resultHandler = completionHandler - self.run([fetchTrustedSourcesOperation], context: nil) - + run([fetchTrustedSourcesOperation], context: nil) + return fetchTrustedSourcesOperation } - - func updatePatronsIfNeeded() - { - guard self.operationQueue.operations.allSatisfy({ !($0 is UpdatePatronsOperation) }) else { + + func updatePatronsIfNeeded() { + guard operationQueue.operations.allSatisfy({ !($0 is UpdatePatronsOperation) }) else { // There's already an UpdatePatronsOperation running. return } - - self.updatePatronsResult = nil - + + updatePatronsResult = nil + let updatePatronsOperation = UpdatePatronsOperation() - updatePatronsOperation.resultHandler = { (result) in - do - { + updatePatronsOperation.resultHandler = { result in + do { try result.get() self.updatePatronsResult = .success(()) - } - catch - { + } catch { print("Error updating Friend Zone Patrons:", error) self.updatePatronsResult = .failure(error) } - + NotificationCenter.default.post(name: AppManager.didUpdatePatronsNotification, object: self) } - - self.run([updatePatronsOperation], context: nil) + + run([updatePatronsOperation], context: nil) } - + @discardableResult - func install(_ app: T, presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result) -> Void) -> RefreshGroup - { + func install(_ app: T, presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result) -> Void) -> RefreshGroup { let group = RefreshGroup(context: context) - group.completionHandler = { (results) in - do - { + group.completionHandler = { results in + do { guard let result = results.values.first else { throw context.error ?? OperationError.unknown } completionHandler(result) - } - catch - { + } catch { completionHandler(.failure(error)) } } - + let operation = AppOperation.install(app) - self.perform([operation], presentingViewController: presentingViewController, group: group) - + perform([operation], presentingViewController: presentingViewController, group: group) + return group } - + @discardableResult - func update(_ app: InstalledApp, presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result) -> Void) -> Progress - { + func update(_ app: InstalledApp, presentingViewController: UIViewController?, context: AuthenticatedOperationContext = AuthenticatedOperationContext(), completionHandler: @escaping (Result) -> Void) -> Progress { guard let storeApp = app.storeApp else { completionHandler(.failure(OperationError.appNotFound)) return Progress.discreteProgress(totalUnitCount: 1) } - + let group = RefreshGroup(context: context) - group.completionHandler = { (results) in - do - { + group.completionHandler = { results in + do { guard let result = results.values.first else { throw OperationError.unknown } completionHandler(result) - } - catch - { + } catch { completionHandler(.failure(error)) } } - + let operation = AppOperation.update(storeApp) assert(operation.app as AnyObject === storeApp) // Make sure we never accidentally "update" to already installed app. - - self.perform([operation], presentingViewController: presentingViewController, group: group) - + + perform([operation], presentingViewController: presentingViewController, group: group) + return group.progress } - + @discardableResult - func refresh(_ installedApps: [InstalledApp], presentingViewController: UIViewController?, group: RefreshGroup? = nil) -> RefreshGroup - { + func refresh(_ installedApps: [InstalledApp], presentingViewController: UIViewController?, group: RefreshGroup? = nil) -> RefreshGroup { let group = group ?? RefreshGroup() - + let operations = installedApps.map { AppOperation.refresh($0) } - return self.perform(operations, presentingViewController: presentingViewController, group: group) + return perform(operations, presentingViewController: presentingViewController, group: group) } - - func activate(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) - { + + func activate(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) { let group = RefreshGroup() - + let operation = AppOperation.activate(installedApp) - self.perform([operation], presentingViewController: presentingViewController, group: group) - - group.completionHandler = { (results) in - do - { + perform([operation], presentingViewController: presentingViewController, group: group) + + group.completionHandler = { results in + do { guard let result = results.values.first else { throw OperationError.unknown } - + let installedApp = try result.get() assert(installedApp.managedObjectContext != nil) - + installedApp.managedObjectContext?.perform { installedApp.isActive = true completionHandler(.success(installedApp)) } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func deactivate(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) - { - if UserDefaults.standard.isLegacyDeactivationSupported - { + + func deactivate(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) { + if UserDefaults.standard.isLegacyDeactivationSupported { // Normally we pipe everything down into perform(), // but the pre-iOS 13.5 deactivation method doesn't require // authentication, so we keep it separate. let context = OperationContext() - + let deactivateAppOperation = DeactivateAppOperation(app: installedApp, context: context) - deactivateAppOperation.resultHandler = { (result) in + deactivateAppOperation.resultHandler = { result in completionHandler(result) } - - self.run([deactivateAppOperation], context: context, requiresSerialQueue: true) - } - else - { + + run([deactivateAppOperation], context: context, requiresSerialQueue: true) + } else { let group = RefreshGroup() - group.completionHandler = { (results) in - do - { + group.completionHandler = { results in + do { guard let result = results.values.first else { throw OperationError.unknown } let installedApp = try result.get() assert(installedApp.managedObjectContext != nil) - + installedApp.managedObjectContext?.perform { completionHandler(.success(installedApp)) } - } - catch - { + } catch { completionHandler(.failure(error)) } } - + let operation = AppOperation.deactivate(installedApp) - self.perform([operation], presentingViewController: presentingViewController, group: group) + perform([operation], presentingViewController: presentingViewController, group: group) } } - - func backup(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) - { + + func backup(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) { let group = RefreshGroup() - group.completionHandler = { (results) in - do - { + group.completionHandler = { results in + do { guard let result = results.values.first else { throw OperationError.unknown } - + let installedApp = try result.get() assert(installedApp.managedObjectContext != nil) - + installedApp.managedObjectContext?.perform { completionHandler(.success(installedApp)) } - } - catch - { + } catch { completionHandler(.failure(error)) } } - + let operation = AppOperation.backup(installedApp) - self.perform([operation], presentingViewController: presentingViewController, group: group) + perform([operation], presentingViewController: presentingViewController, group: group) } - - func restore(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) - { + + func restore(_ installedApp: InstalledApp, presentingViewController: UIViewController?, completionHandler: @escaping (Result) -> Void) { let group = RefreshGroup() - group.completionHandler = { (results) in - do - { + group.completionHandler = { results in + do { guard let result = results.values.first else { throw OperationError.unknown } - + let installedApp = try result.get() assert(installedApp.managedObjectContext != nil) - + installedApp.managedObjectContext?.perform { installedApp.isActive = true completionHandler(.success(installedApp)) } - } - catch - { + } catch { completionHandler(.failure(error)) } } - + let operation = AppOperation.restore(installedApp) - self.perform([operation], presentingViewController: presentingViewController, group: group) + perform([operation], presentingViewController: presentingViewController, group: group) } - - func remove(_ installedApp: InstalledApp, completionHandler: @escaping (Result) -> Void) - { + + func remove(_ installedApp: InstalledApp, completionHandler: @escaping (Result) -> Void) { let authenticationContext = AuthenticatedOperationContext() let appContext = InstallAppOperationContext(bundleIdentifier: installedApp.bundleIdentifier, authenticatedContext: authenticationContext) appContext.installedApp = installedApp - let removeAppOperation = RSTAsyncBlockOperation { (operation) in - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + let removeAppOperation = RSTAsyncBlockOperation { operation in + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let installedApp = context.object(with: installedApp.objectID) as! InstalledApp context.delete(installedApp) - - do { try context.save() } - catch { appContext.error = error } - + + do { try context.save() } catch { appContext.error = error } + operation.finish() } } - + let removeAppBackupOperation = RemoveAppBackupOperation(context: appContext) - removeAppBackupOperation.resultHandler = { (result) in - switch result - { + removeAppBackupOperation.resultHandler = { result in + switch result { case .success: break - case .failure(let error): print("Failed to remove app backup.", error) + case let .failure(error): print("Failed to remove app backup.", error) } - + // Throw the error from removeAppOperation, // since that's the error we really care about. - if let error = appContext.error - { + if let error = appContext.error { completionHandler(.failure(error)) - } - else - { + } else { completionHandler(.success(())) } } removeAppBackupOperation.addDependency(removeAppOperation) - - self.run([removeAppOperation, removeAppBackupOperation], context: authenticationContext) + + run([removeAppOperation, removeAppBackupOperation], context: authenticationContext) } - + @available(iOS 14, *) - func enableJIT(for installedApp: InstalledApp, completionHandler: @escaping (Result) -> Void) - { - final class Context: OperationContext, EnableJITContext - { + func enableJIT(for installedApp: InstalledApp, completionHandler: @escaping (Result) -> Void) { + final class Context: OperationContext, EnableJITContext { var installedApp: InstalledApp? } - + let context = Context() context.installedApp = installedApp - - + let enableJITOperation = EnableJITOperation(context: context) - enableJITOperation.resultHandler = { (result) in + enableJITOperation.resultHandler = { result in completionHandler(result) } - - self.run([enableJITOperation], context: context, requiresSerialQueue: true) + + run([enableJITOperation], context: context, requiresSerialQueue: true) } - + @available(iOS 14.0, *) - func patch(resignedApp: ALTApplication, presentingViewController: UIViewController, context authContext: AuthenticatedOperationContext, completionHandler: @escaping (Result) -> Void) -> PatchAppOperation - { - final class Context: InstallAppOperationContext, PatchAppContext - { - } - + func patch(resignedApp: ALTApplication, presentingViewController _: UIViewController, context authContext: AuthenticatedOperationContext, completionHandler: @escaping (Result) -> Void) -> PatchAppOperation { + final class Context: InstallAppOperationContext, PatchAppContext {} + guard let originalBundleID = resignedApp.bundle.infoDictionary?[Bundle.Info.altBundleID] as? String else { let context = Context(bundleIdentifier: resignedApp.bundleIdentifier, authenticatedContext: authContext) completionHandler(.failure(OperationError.invalidApp)) - + return PatchAppOperation(context: context) } - + let context = Context(bundleIdentifier: originalBundleID, authenticatedContext: authContext) context.resignedApp = resignedApp - + let patchAppOperation = PatchAppOperation(context: context) let sendAppOperation = SendAppOperation(context: context) let installOperation = InstallAppOperation(context: context) - + let installationProgress = Progress.discreteProgress(totalUnitCount: 100) installationProgress.addChild(sendAppOperation.progress, withPendingUnitCount: 40) installationProgress.addChild(installOperation.progress, withPendingUnitCount: 60) - + /* Patch */ - patchAppOperation.resultHandler = { [weak patchAppOperation] (result) in - switch result - { - case .failure(let error): context.error = error + patchAppOperation.resultHandler = { [weak patchAppOperation] result in + switch result { + case let .failure(error): context.error = error case .success: // Kinda hacky that we're calling patchAppOperation's progressHandler manually, but YOLO. patchAppOperation?.progressHandler?(installationProgress, NSLocalizedString("Patching placeholder app...", comment: "")) } } - + /* Send */ - sendAppOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(_): print("App sent over AFC") + sendAppOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case .success: print("App sent over AFC") } } sendAppOperation.addDependency(patchAppOperation) - /* Install */ - installOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let installedApp): completionHandler(.success(installedApp)) + installOperation.resultHandler = { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(installedApp): completionHandler(.success(installedApp)) } } installOperation.addDependency(sendAppOperation) - - self.run([patchAppOperation, sendAppOperation, installOperation], context: context.authenticatedContext) + + run([patchAppOperation, sendAppOperation, installOperation], context: context.authenticatedContext) return patchAppOperation } - - func installationProgress(for app: AppProtocol) -> Progress? - { - let progress = self.installationProgress[app.bundleIdentifier] + + func installationProgress(for app: AppProtocol) -> Progress? { + let progress = installationProgress[app.bundleIdentifier] return progress } - - func refreshProgress(for app: AppProtocol) -> Progress? - { - let progress = self.refreshProgress[app.bundleIdentifier] + + func refreshProgress(for app: AppProtocol) -> Progress? { + let progress = refreshProgress[app.bundleIdentifier] return progress } } -extension AppManager -{ +extension AppManager { @discardableResult - func backgroundRefresh(_ installedApps: [InstalledApp], presentsNotifications: Bool = false, completionHandler: @escaping (Result<[String: Result], Error>) -> Void) -> BackgroundRefreshAppsOperation - { + func backgroundRefresh(_ installedApps: [InstalledApp], presentsNotifications: Bool = false, completionHandler: @escaping (Result<[String: Result], Error>) -> Void) -> BackgroundRefreshAppsOperation { let backgroundRefreshAppsOperation = BackgroundRefreshAppsOperation(installedApps: installedApps) backgroundRefreshAppsOperation.resultHandler = completionHandler backgroundRefreshAppsOperation.presentsFinishedNotification = presentsNotifications - self.run([backgroundRefreshAppsOperation], context: nil) - + run([backgroundRefreshAppsOperation], context: nil) + return backgroundRefreshAppsOperation } } -private extension AppManager -{ - enum AppOperation - { +private extension AppManager { + enum AppOperation { case install(AppProtocol) case update(AppProtocol) case refresh(InstalledApp) @@ -781,291 +681,248 @@ private extension AppManager case deactivate(InstalledApp) case backup(InstalledApp) case restore(InstalledApp) - + var app: AppProtocol { - switch self - { - case .install(let app), .update(let app), .refresh(let app as AppProtocol), + switch self { + case let .install(app), let .update(app), let .refresh(app as AppProtocol), .activate(let app as AppProtocol), .deactivate(let app as AppProtocol), .backup(let app as AppProtocol), .restore(let app as AppProtocol): return app } } - + var bundleIdentifier: String { var bundleIdentifier: String! - - if let context = (self.app as? NSManagedObject)?.managedObjectContext - { + + if let context = (app as? NSManagedObject)?.managedObjectContext { context.performAndWait { bundleIdentifier = self.app.bundleIdentifier } + } else { + bundleIdentifier = app.bundleIdentifier } - else - { - bundleIdentifier = self.app.bundleIdentifier - } - + return bundleIdentifier } } - - func isActivelyManagingApp(withBundleID bundleID: String) -> Bool - { - let isActivelyManaging = self.installationProgress.keys.contains(bundleID) || self.refreshProgress.keys.contains(bundleID) + + func isActivelyManagingApp(withBundleID bundleID: String) -> Bool { + let isActivelyManaging = installationProgress.keys.contains(bundleID) || refreshProgress.keys.contains(bundleID) return isActivelyManaging } - + @discardableResult - private func perform(_ operations: [AppOperation], presentingViewController: UIViewController?, group: RefreshGroup) -> RefreshGroup - { + private func perform(_ operations: [AppOperation], presentingViewController: UIViewController?, group: RefreshGroup) -> RefreshGroup { let operations = operations.filter { self.progress(for: $0) == nil || self.progress(for: $0)?.isCancelled == true } - - for operation in operations - { + + for operation in operations { let progress = Progress.discreteProgress(totalUnitCount: 100) - self.set(progress, for: operation) + set(progress, for: operation) } - - if let viewController = presentingViewController - { + + if let viewController = presentingViewController { group.context.presentingViewController = viewController } - + /* Authenticate (if necessary) */ var authenticationOperation: AuthenticationOperation? - if group.context.session == nil - { - authenticationOperation = self.authenticate(presentingViewController: presentingViewController, context: group.context) { (result) in - switch result - { - case .failure(let error): group.context.error = error + if group.context.session == nil { + authenticationOperation = authenticate(presentingViewController: presentingViewController, context: group.context) { result in + switch result { + case let .failure(error): group.context.error = error case .success: break } } } - - func performAppOperations() - { - for operation in operations - { + + func performAppOperations() { + for operation in operations { let progress = self.progress(for: operation) - - if let progress = progress - { + + if let progress = progress { group.progress.totalUnitCount += 1 group.progress.addChild(progress, withPendingUnitCount: 1) - - if group.context.session != nil - { + + if group.context.session != nil { // Finished authenticating, so increase completed unit count. progress.completedUnitCount += 20 } } - - switch operation - { - case .install(let app), .update(let app): - let installProgress = self._install(app, operation: operation, group: group) { (result) in + + switch operation { + case let .install(app), let .update(app): + let installProgress = _install(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(installProgress, withPendingUnitCount: 80) - - case .activate(let app) where UserDefaults.standard.isLegacyDeactivationSupported: fallthrough - case .refresh(let app): + + case let .activate(app) where UserDefaults.standard.isLegacyDeactivationSupported: fallthrough + case let .refresh(app): // Check if backup app is installed in place of real app. let uti = UTTypeCopyDeclaration(app.installedBackupAppUTI as CFString)?.takeRetainedValue() as NSDictionary? if app.certificateSerialNumber != group.context.certificate?.serialNumber || uti != nil || - app.needsResign - { + app.needsResign { // Resign app instead of just refreshing profiles because either: // * Refreshing using different certificate // * Backup app is still installed // * App explicitly needs resigning // * Device is jailbroken and using AltDaemon on iOS 14.0 or later (b/c refreshing with provisioning profiles is broken) - - let installProgress = self._install(app, operation: operation, group: group) { (result) in + + let installProgress = _install(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(installProgress, withPendingUnitCount: 80) - } - else - { + } else { // Refreshing with same certificate as last time, and backup app isn't still installed, // so we can just refresh provisioning profiles. - - let refreshProgress = self._refresh(app, operation: operation, group: group) { (result) in + + let refreshProgress = _refresh(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(refreshProgress, withPendingUnitCount: 80) } - - case .activate(let app): - let activateProgress = self._activate(app, operation: operation, group: group) { (result) in + + case let .activate(app): + let activateProgress = _activate(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(activateProgress, withPendingUnitCount: 80) - - case .deactivate(let app): - let deactivateProgress = self._deactivate(app, operation: operation, group: group) { (result) in + + case let .deactivate(app): + let deactivateProgress = _deactivate(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(deactivateProgress, withPendingUnitCount: 80) - - case .backup(let app): - let backupProgress = self._backup(app, operation: operation, group: group) { (result) in + + case let .backup(app): + let backupProgress = _backup(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(backupProgress, withPendingUnitCount: 80) - - case .restore(let app): + + case let .restore(app): // Restoring, which is effectively just activating an app. - - let activateProgress = self._activate(app, operation: operation, group: group) { (result) in + + let activateProgress = _activate(app, operation: operation, group: group) { result in self.finish(operation, result: result, group: group, progress: progress) } progress?.addChild(activateProgress, withPendingUnitCount: 80) } } } - - if let authenticationOperation = authenticationOperation - { + + if let authenticationOperation = authenticationOperation { let awaitAuthenticationOperation = BlockOperation { - if let managedObjectContext = operations.lazy.compactMap({ ($0.app as? NSManagedObject)?.managedObjectContext }).first - { + if let managedObjectContext = operations.lazy.compactMap({ ($0.app as? NSManagedObject)?.managedObjectContext }).first { managedObjectContext.perform { performAppOperations() } - } - else - { + } else { performAppOperations() } } awaitAuthenticationOperation.addDependency(authenticationOperation) - self.run([awaitAuthenticationOperation], context: group.context, requiresSerialQueue: true) - } - else - { + run([awaitAuthenticationOperation], context: group.context, requiresSerialQueue: true) + } else { performAppOperations() } - + return group } - - private func _install(_ app: AppProtocol, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext? = nil, additionalEntitlements: [ALTEntitlement: Any]? = nil, cacheApp: Bool = true, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _install(_ app: AppProtocol, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext? = nil, additionalEntitlements: [ALTEntitlement: Any]? = nil, cacheApp: Bool = true, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) - + let context = context ?? InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) assert(context.authenticatedContext === group.context) - - context.beginInstallationHandler = { (installedApp) in - switch appOperation - { + + context.beginInstallationHandler = { installedApp in + switch appOperation { case .update where installedApp.bundleIdentifier == StoreApp.altstoreAppID: // AltStore will quit before installation finishes, // so assume if we get this far the update will finish successfully. let event = AnalyticsManager.Event.updatedApp(installedApp) AnalyticsManager.shared.trackEvent(event) - + default: break } - + group.beginInstallationHandler?(installedApp) } - + var downloadingApp = app - - if let installedApp = app as? InstalledApp - { - if let storeApp = installedApp.storeApp, !FileManager.default.fileExists(atPath: installedApp.fileURL.path) - { + + if let installedApp = app as? InstalledApp { + if let storeApp = installedApp.storeApp, !FileManager.default.fileExists(atPath: installedApp.fileURL.path) { // Cached app has been deleted, so we need to redownload it. downloadingApp = storeApp } - - if installedApp.hasAlternateIcon - { + + if installedApp.hasAlternateIcon { context.alternateIconURL = installedApp.alternateIconURL } } - + let downloadedAppURL = context.temporaryDirectory.appendingPathComponent("Cached.app") - + /* Download */ let downloadOperation = DownloadAppOperation(app: downloadingApp, destinationURL: downloadedAppURL, context: context) - downloadOperation.resultHandler = { (result) in - do - { + downloadOperation.resultHandler = { result in + do { let app = try result.get() context.app = app - - if cacheApp - { + + if cacheApp { try FileManager.default.copyItem(at: app.fileURL, to: InstalledApp.fileURL(for: app), shouldReplace: true) } - } - catch - { + } catch { context.error = error } } progress.addChild(downloadOperation.progress, withPendingUnitCount: 25) - - + /* Verify App */ let verifyOperation = VerifyAppOperation(context: context) - verifyOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error + verifyOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error case .success: break } } verifyOperation.addDependency(downloadOperation) - - + /* Deactivate Apps (if necessary) */ - let deactivateAppsOperation = RSTAsyncBlockOperation { [weak self] (operation) in - do - { + let deactivateAppsOperation = RSTAsyncBlockOperation { [weak self] operation in + do { // Only attempt to deactivate apps if we're installing a new app. // We handle deactivating apps separately when activating an app. guard case .install = appOperation else { operation.finish() return } - - if let error = context.error - { + + if let error = context.error { throw error } - + guard let app = context.app, let presentingViewController = context.authenticatedContext.presentingViewController else { throw OperationError.invalidParameters } - + self?.deactivateApps(for: app, presentingViewController: presentingViewController) { result in - switch result - { - case .failure(let error): group.context.error = error + switch result { + case let .failure(error): group.context.error = error case .success: break } - + operation.finish() } - } - catch - { + } catch { group.context.error = error operation.finish() } } deactivateAppsOperation.addDependency(verifyOperation) - - + /* Patch App */ let patchAppOperation = RSTAsyncBlockOperation { operation in - do - { + do { // Only attempt to patch app if we're installing a new app, not refreshing existing app. // Post reboot, we install the correct jailbreak app by refreshing the patched app, // so this check avoids infinite recursion. @@ -1073,255 +930,232 @@ private extension AppManager operation.finish() return } - + guard let presentingViewController = context.presentingViewController, #available(iOS 14, *) else { return operation.finish() } - - if let error = context.error - { + + if let error = context.error { throw error } - + guard let app = context.app else { throw OperationError.invalidParameters } - + guard let isUntetherRequired = app.bundle.infoDictionary?[Bundle.Info.untetherRequired] as? Bool, let minimumiOSVersionString = app.bundle.infoDictionary?[Bundle.Info.untetherMinimumiOSVersion] as? String, let maximumiOSVersionString = app.bundle.infoDictionary?[Bundle.Info.untetherMaximumiOSVersion] as? String, case let minimumiOSVersion = OperatingSystemVersion(string: minimumiOSVersionString), case let maximumiOSVersion = OperatingSystemVersion(string: maximumiOSVersionString) else { return operation.finish() } - + let iOSVersion = ProcessInfo.processInfo.operatingSystemVersion let iOSVersionSupported = ProcessInfo.processInfo.isOperatingSystemAtLeast(minimumiOSVersion) && - (!ProcessInfo.processInfo.isOperatingSystemAtLeast(maximumiOSVersion) || maximumiOSVersion == iOSVersion) - + (!ProcessInfo.processInfo.isOperatingSystemAtLeast(maximumiOSVersion) || maximumiOSVersion == iOSVersion) + guard isUntetherRequired, iOSVersionSupported, UIDevice.current.supportsFugu14 else { return operation.finish() } - + guard let patchAppLink = app.bundle.infoDictionary?[Bundle.Info.untetherURL] as? String, let patchAppURL = URL(string: patchAppLink) else { throw OperationError.invalidApp } - + let patchApp = AnyApp(name: app.name, bundleIdentifier: app.bundleIdentifier, url: patchAppURL) - + DispatchQueue.main.async { let storyboard = UIStoryboard(name: "PatchApp", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController - + let patchViewController = navigationController.topViewController as! PatchViewController patchViewController.patchApp = patchApp - patchViewController.completionHandler = { [weak presentingViewController] (result) in - switch result - { + patchViewController.completionHandler = { [weak presentingViewController] result in + switch result { case .failure(OperationError.cancelled): break // Ignore - case .failure(let error): group.context.error = error + case let .failure(error): group.context.error = error case .success: group.context.error = OperationError.cancelled } - + operation.finish() - + DispatchQueue.main.async { presentingViewController?.dismiss(animated: true, completion: nil) } } - presentingViewController.present(navigationController, animated: true, completion: nil) + presentingViewController.present(navigationController, animated: true, completion: nil) } - } - catch - { + } catch { group.context.error = error operation.finish() } } patchAppOperation.addDependency(deactivateAppsOperation) - - + /* Refresh Anisette Data */ let refreshAnisetteDataOperation = FetchAnisetteDataOperation(context: group.context) - refreshAnisetteDataOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(let anisetteData): group.context.session?.anisetteData = anisetteData + refreshAnisetteDataOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case let .success(anisetteData): group.context.session?.anisetteData = anisetteData } } refreshAnisetteDataOperation.addDependency(patchAppOperation) - - + /* Fetch Provisioning Profiles */ let fetchProvisioningProfilesOperation = FetchProvisioningProfilesOperation(context: context) fetchProvisioningProfilesOperation.additionalEntitlements = additionalEntitlements - fetchProvisioningProfilesOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(let provisioningProfiles): context.provisioningProfiles = provisioningProfiles + fetchProvisioningProfilesOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case let .success(provisioningProfiles): context.provisioningProfiles = provisioningProfiles } } fetchProvisioningProfilesOperation.addDependency(refreshAnisetteDataOperation) progress.addChild(fetchProvisioningProfilesOperation.progress, withPendingUnitCount: 5) - - + /* Resign */ let resignAppOperation = ResignAppOperation(context: context) - resignAppOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(let resignedApp): context.resignedApp = resignedApp + resignAppOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case let .success(resignedApp): context.resignedApp = resignedApp } } resignAppOperation.addDependency(fetchProvisioningProfilesOperation) progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20) - - + /* Send */ let sendAppOperation = SendAppOperation(context: context) - sendAppOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(_): print("App reported as installed") + sendAppOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case .success: print("App reported as installed") } } sendAppOperation.addDependency(resignAppOperation) progress.addChild(sendAppOperation.progress, withPendingUnitCount: 20) - - + /* Install */ let installOperation = InstallAppOperation(context: context) - installOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let installedApp): + installOperation.resultHandler = { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(installedApp): context.installedApp = installedApp - - if let app = app as? StoreApp, let storeApp = installedApp.managedObjectContext?.object(with: app.objectID) as? StoreApp - { + + if let app = app as? StoreApp, let storeApp = installedApp.managedObjectContext?.object(with: app.objectID) as? StoreApp { installedApp.storeApp = storeApp } - - if let index = UserDefaults.standard.legacySideloadedApps?.firstIndex(of: installedApp.bundleIdentifier) - { + + if let index = UserDefaults.standard.legacySideloadedApps?.firstIndex(of: installedApp.bundleIdentifier) { // No longer a legacy sideloaded app, so remove it from cached list. UserDefaults.standard.legacySideloadedApps?.remove(at: index) } - + completionHandler(.success(installedApp)) } } progress.addChild(installOperation.progress, withPendingUnitCount: 30) installOperation.addDependency(sendAppOperation) - + let operations = [downloadOperation, verifyOperation, deactivateAppsOperation, patchAppOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, resignAppOperation, sendAppOperation, installOperation] group.add(operations) - self.run(operations, context: group.context) - + run(operations, context: group.context) + return progress } - - private func _refresh(_ app: InstalledApp, operation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _refresh(_ app: InstalledApp, operation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) - + let context = AppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) context.app = ALTApplication(fileURL: app.fileURL) - + /* Fetch Provisioning Profiles */ let fetchProvisioningProfilesOperation = FetchProvisioningProfilesOperation(context: context) - fetchProvisioningProfilesOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error - case .success(let provisioningProfiles): context.provisioningProfiles = provisioningProfiles + fetchProvisioningProfilesOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error + case let .success(provisioningProfiles): context.provisioningProfiles = provisioningProfiles } } progress.addChild(fetchProvisioningProfilesOperation.progress, withPendingUnitCount: 60) - + /* Refresh */ let refreshAppOperation = RefreshAppOperation(context: context) - refreshAppOperation.resultHandler = { (result) in - switch result - { - case .success(let installedApp): + refreshAppOperation.resultHandler = { result in + switch result { + case let .success(installedApp): completionHandler(.success(installedApp)) - + case .failure(ALTServerError.unknownRequest), .failure(OperationError.appNotFound): // Fall back to installation if AltServer doesn't support newer provisioning profile requests, // OR if the cached app could not be found and we may need to redownload it. app.managedObjectContext?.performAndWait { // Must performAndWait to ensure we add operations before we return. - let installProgress = self._install(app, operation: operation, group: group) { (result) in + let installProgress = self._install(app, operation: operation, group: group) { result in completionHandler(result) } progress.addChild(installProgress, withPendingUnitCount: 40) } - - case .failure(let error): + + case let .failure(error): completionHandler(.failure(error)) } } progress.addChild(refreshAppOperation.progress, withPendingUnitCount: 40) refreshAppOperation.addDependency(fetchProvisioningProfilesOperation) - + let operations = [fetchProvisioningProfilesOperation, refreshAppOperation] group.add(operations) - self.run(operations, context: group.context) + run(operations, context: group.context) return progress } - - private func _activate(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _activate(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) - + let restoreContext = InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) let appContext = InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) - + let installBackupAppProgress = Progress.discreteProgress(totalUnitCount: 100) - let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] operation in app.managedObjectContext?.perform { guard let self = self else { return } - - let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: restoreContext) { (result) in - switch result - { - case .success(let installedApp): restoreContext.installedApp = installedApp - case .failure(let error): + + let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: restoreContext) { result in + switch result { + case let .success(installedApp): restoreContext.installedApp = installedApp + case let .failure(error): restoreContext.error = error appContext.error = error } - + operation.finish() } installBackupAppProgress.addChild(progress, withPendingUnitCount: 100) } } progress.addChild(installBackupAppProgress, withPendingUnitCount: 30) - + let restoreAppOperation = BackupAppOperation(action: .restore, context: restoreContext) - restoreAppOperation.resultHandler = { (result) in - switch result - { + restoreAppOperation.resultHandler = { result in + switch result { case .success: break - case .failure(let error): + case let .failure(error): restoreContext.error = error appContext.error = error } } restoreAppOperation.addDependency(installBackupAppOperation) progress.addChild(restoreAppOperation.progress, withPendingUnitCount: 15) - + let installAppProgress = Progress.discreteProgress(totalUnitCount: 100) - let installAppOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installAppOperation = RSTAsyncBlockOperation { [weak self] operation in app.managedObjectContext?.perform { guard let self = self else { return } - - let progress = self._install(app, operation: appOperation, group: group, context: appContext) { (result) in - switch result - { - case .success(let installedApp): appContext.installedApp = installedApp - case .failure(let error): appContext.error = error + + let progress = self._install(app, operation: appOperation, group: group, context: appContext) { result in + switch result { + case let .success(installedApp): appContext.installedApp = installedApp + case let .failure(error): appContext.error = error } - + operation.finish() } installAppProgress.addChild(progress, withPendingUnitCount: 100) @@ -1329,61 +1163,55 @@ private extension AppManager } installAppOperation.addDependency(restoreAppOperation) progress.addChild(installAppProgress, withPendingUnitCount: 50) - + let cleanUpProgress = Progress.discreteProgress(totalUnitCount: 100) - let cleanUpOperation = RSTAsyncBlockOperation { (operation) in - do - { + let cleanUpOperation = RSTAsyncBlockOperation { operation in + do { let installedApp = try Result(appContext.installedApp, appContext.error).get() - + var result: Result! installedApp.managedObjectContext?.performAndWait { result = Result { try installedApp.managedObjectContext?.save() } } try result.get() - + // Successfully saved, so _now_ we can remove backup. - + let removeAppBackupOperation = RemoveAppBackupOperation(context: appContext) - removeAppBackupOperation.resultHandler = { (result) in + removeAppBackupOperation.resultHandler = { result in installedApp.managedObjectContext?.perform { - switch result - { - case .failure(let error): + switch result { + case let .failure(error): // Don't report error, since it doesn't really matter. print("Failed to delete app backup.", error) - + case .success: break } - + completionHandler(.success(installedApp)) operation.finish() } } cleanUpProgress.addChild(removeAppBackupOperation.progress, withPendingUnitCount: 100) - + group.add([removeAppBackupOperation]) self.run([removeAppBackupOperation], context: group.context) - } - catch let error where restoreContext.installedApp != nil - { + } catch let error where restoreContext.installedApp != nil { // Activation failed, but restore app was installed, so remove the app. - + // Remove error so operation doesn't quit early, restoreContext.error = nil - + let removeAppOperation = RemoveAppOperation(context: restoreContext) - removeAppOperation.resultHandler = { (result) in + removeAppOperation.resultHandler = { _ in completionHandler(.failure(error)) operation.finish() } cleanUpProgress.addChild(removeAppOperation.progress, withPendingUnitCount: 100) - + group.add([removeAppOperation]) self.run([removeAppOperation], context: group.context) - } - catch - { + } catch { // Activation failed. completionHandler(.failure(error)) operation.finish() @@ -1391,108 +1219,102 @@ private extension AppManager } cleanUpOperation.addDependency(installAppOperation) progress.addChild(cleanUpProgress, withPendingUnitCount: 5) - + group.add([installBackupAppOperation, restoreAppOperation, installAppOperation, cleanUpOperation]) - self.run([installBackupAppOperation, installAppOperation, restoreAppOperation, cleanUpOperation], context: group.context) - + run([installBackupAppOperation, installAppOperation, restoreAppOperation, cleanUpOperation], context: group.context) + return progress } - - private func _deactivate(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _deactivate(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) let context = InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) - + let installBackupAppProgress = Progress.discreteProgress(totalUnitCount: 100) - let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] operation in app.managedObjectContext?.perform { guard let self = self else { return } - - let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: context) { (result) in - switch result - { - case .success(let installedApp): context.installedApp = installedApp - case .failure(let error): context.error = error + + let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: context) { result in + switch result { + case let .success(installedApp): context.installedApp = installedApp + case let .failure(error): context.error = error } - + operation.finish() } installBackupAppProgress.addChild(progress, withPendingUnitCount: 100) } } progress.addChild(installBackupAppProgress, withPendingUnitCount: 70) - + let backupAppOperation = BackupAppOperation(action: .backup, context: context) - backupAppOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): context.error = error + backupAppOperation.resultHandler = { result in + switch result { + case let .failure(error): context.error = error case .success: break } } backupAppOperation.addDependency(installBackupAppOperation) progress.addChild(backupAppOperation.progress, withPendingUnitCount: 15) - + let removeAppOperation = RemoveAppOperation(context: context) - removeAppOperation.resultHandler = { (result) in + removeAppOperation.resultHandler = { result in completionHandler(result) } removeAppOperation.addDependency(backupAppOperation) progress.addChild(removeAppOperation.progress, withPendingUnitCount: 15) - + group.add([installBackupAppOperation, backupAppOperation, removeAppOperation]) - self.run([installBackupAppOperation, backupAppOperation, removeAppOperation], context: group.context) - + run([installBackupAppOperation, backupAppOperation, removeAppOperation], context: group.context) + return progress } - - private func _backup(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _backup(_ app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) - + let restoreContext = InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) let appContext = InstallAppOperationContext(bundleIdentifier: app.bundleIdentifier, authenticatedContext: group.context) - + let installBackupAppProgress = Progress.discreteProgress(totalUnitCount: 100) - let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installBackupAppOperation = RSTAsyncBlockOperation { [weak self] operation in app.managedObjectContext?.perform { guard let self = self else { return } - - let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: restoreContext) { (result) in - switch result - { - case .success(let installedApp): restoreContext.installedApp = installedApp - case .failure(let error): + + let progress = self._installBackupApp(for: app, operation: appOperation, group: group, context: restoreContext) { result in + switch result { + case let .success(installedApp): restoreContext.installedApp = installedApp + case let .failure(error): restoreContext.error = error appContext.error = error } - + operation.finish() } installBackupAppProgress.addChild(progress, withPendingUnitCount: 100) } } progress.addChild(installBackupAppProgress, withPendingUnitCount: 30) - + let backupAppOperation = BackupAppOperation(action: .backup, context: restoreContext) - backupAppOperation.resultHandler = { (result) in - switch result - { + backupAppOperation.resultHandler = { result in + switch result { case .success: break - case .failure(let error): + case let .failure(error): restoreContext.error = error appContext.error = error } } backupAppOperation.addDependency(installBackupAppOperation) progress.addChild(backupAppOperation.progress, withPendingUnitCount: 15) - + let installAppProgress = Progress.discreteProgress(totalUnitCount: 100) - let installAppOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installAppOperation = RSTAsyncBlockOperation { [weak self] operation in app.managedObjectContext?.perform { guard let self = self else { return } - - let progress = self._install(app, operation: appOperation, group: group, context: appContext) { (result) in + + let progress = self._install(app, operation: appOperation, group: group, context: appContext) { result in completionHandler(result) operation.finish() } @@ -1501,113 +1323,102 @@ private extension AppManager } installAppOperation.addDependency(backupAppOperation) progress.addChild(installAppProgress, withPendingUnitCount: 55) - + group.add([installBackupAppOperation, backupAppOperation, installAppOperation]) - self.run([installBackupAppOperation, installAppOperation, backupAppOperation], context: group.context) - + run([installBackupAppOperation, installAppOperation, backupAppOperation], context: group.context) + return progress } - - private func _installBackupApp(for app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext, completionHandler: @escaping (Result) -> Void) -> Progress - { + + private func _installBackupApp(for app: InstalledApp, operation appOperation: AppOperation, group: RefreshGroup, context: InstallAppOperationContext, completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 100) - - if let error = context.error - { + + if let error = context.error { completionHandler(.failure(error)) return progress } - + guard let application = ALTApplication(fileURL: app.fileURL) else { completionHandler(.failure(OperationError.appNotFound)) return progress } - + let prepareProgress = Progress.discreteProgress(totalUnitCount: 1) - let prepareOperation = RSTAsyncBlockOperation { (operation) in + let prepareOperation = RSTAsyncBlockOperation { operation in app.managedObjectContext?.perform { - do - { + do { let temporaryDirectoryURL = context.temporaryDirectory.appendingPathComponent("AltBackup-" + UUID().uuidString) try FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true, attributes: nil) - + guard let altbackupFileURL = Bundle.main.url(forResource: "AltBackup", withExtension: "ipa") else { throw OperationError.appNotFound } - + let unzippedAppBundleURL = try FileManager.default.unzipAppBundle(at: altbackupFileURL, toDirectory: temporaryDirectoryURL) guard let unzippedAppBundle = Bundle(url: unzippedAppBundleURL) else { throw OperationError.invalidApp } - - if var infoDictionary = unzippedAppBundle.infoDictionary - { + + if var infoDictionary = unzippedAppBundle.infoDictionary { // Replace name + bundle identifier so AltStore treats it as the same app. infoDictionary["CFBundleDisplayName"] = app.name infoDictionary[kCFBundleIdentifierKey as String] = app.bundleIdentifier - + // Add app-specific exported UTI so we can check later if this temporary backup app is still installed or not. let installedAppUTI = ["UTTypeConformsTo": [], "UTTypeDescription": "AltStore Backup App", "UTTypeIconFiles": [], "UTTypeIdentifier": app.installedBackupAppUTI, - "UTTypeTagSpecification": [:]] as [String : Any] - + "UTTypeTagSpecification": [:]] as [String: Any] + var exportedUTIs = infoDictionary[Bundle.Info.exportedUTIs] as? [[String: Any]] ?? [] exportedUTIs.append(installedAppUTI) infoDictionary[Bundle.Info.exportedUTIs] = exportedUTIs - - if let cachedApp = ALTApplication(fileURL: app.fileURL), let icon = cachedApp.icon?.resizing(to: CGSize(width: 180, height: 180)) - { + + if let cachedApp = ALTApplication(fileURL: app.fileURL), let icon = cachedApp.icon?.resizing(to: CGSize(width: 180, height: 180)) { let iconFileURL = unzippedAppBundleURL.appendingPathComponent("AppIcon.png") - - if let iconData = icon.pngData() - { - do - { + + if let iconData = icon.pngData() { + do { try iconData.write(to: iconFileURL, options: .atomic) - + let bundleIcons = ["CFBundlePrimaryIcon": ["CFBundleIconFiles": [iconFileURL.lastPathComponent]]] infoDictionary["CFBundleIcons"] = bundleIcons - } - catch - { + } catch { print("Failed to write app icon data.", error) } } } - + try (infoDictionary as NSDictionary).write(to: unzippedAppBundle.infoPlistURL) } - + guard let backupApp = ALTApplication(fileURL: unzippedAppBundleURL) else { throw OperationError.invalidApp } context.app = backupApp - + prepareProgress.completedUnitCount += 1 - } - catch - { + } catch { print(error) - + context.error = error } - + operation.finish() } } progress.addChild(prepareProgress, withPendingUnitCount: 20) - + let installProgress = Progress.discreteProgress(totalUnitCount: 100) - let installOperation = RSTAsyncBlockOperation { [weak self] (operation) in + let installOperation = RSTAsyncBlockOperation { [weak self] operation in guard let self = self else { return } - + guard let backupApp = context.app else { context.error = OperationError.invalidApp operation.finish() return } - + var appGroups = application.entitlements[.appGroups] as? [String] ?? [] appGroups.append(Bundle.baseAltStoreAppGroupID) - + let additionalEntitlements: [ALTEntitlement: Any] = [.appGroups: appGroups] - let progress = self._install(backupApp, operation: appOperation, group: group, context: context, additionalEntitlements: additionalEntitlements, cacheApp: false) { (result) in + let progress = self._install(backupApp, operation: appOperation, group: group, context: context, additionalEntitlements: additionalEntitlements, cacheApp: false) { result in completionHandler(result) operation.finish() } @@ -1615,36 +1426,31 @@ private extension AppManager } installOperation.addDependency(prepareOperation) progress.addChild(installProgress, withPendingUnitCount: 80) - + group.add([prepareOperation, installOperation]) - self.run([prepareOperation, installOperation], context: group.context) - + run([prepareOperation, installOperation], context: group.context) + return progress } - - func finish(_ operation: AppOperation, result: Result, group: RefreshGroup, progress: Progress?) - { + + func finish(_ operation: AppOperation, result: Result, group: RefreshGroup, progress: Progress?) { // Must remove before saving installedApp. - if let currentProgress = self.progress(for: operation), currentProgress == progress - { + if let currentProgress = self.progress(for: operation), currentProgress == progress { // Only remove progress if it hasn't been replaced by another one. - self.set(nil, for: operation) + set(nil, for: operation) } - - do - { + + do { let installedApp = try result.get() group.set(.success(installedApp), forAppWithBundleIdentifier: installedApp.bundleIdentifier) - - if installedApp.bundleIdentifier == StoreApp.altstoreAppID - { - self.scheduleExpirationWarningLocalNotification(for: installedApp) + + if installedApp.bundleIdentifier == StoreApp.altstoreAppID { + scheduleExpirationWarningLocalNotification(for: installedApp) } - + let event: AnalyticsManager.Event? - - switch operation - { + + switch operation { case .install: event = .installedApp(installedApp) case .refresh: event = .refreshedApp(installedApp) case .update where installedApp.bundleIdentifier == StoreApp.altstoreAppID: @@ -1652,61 +1458,53 @@ private extension AppManager // In case AltStore doesn't quit, such as when update has a different bundle identifier, // make sure we don't log this update event a second time. event = nil - + case .update: event = .updatedApp(installedApp) case .activate, .deactivate, .backup, .restore: event = nil } - - if let event = event - { + + if let event = event { AnalyticsManager.shared.trackEvent(event) } - - if #available(iOS 14, *) - { + + if #available(iOS 14, *) { WidgetCenter.shared.reloadAllTimelines() } - - do { try installedApp.managedObjectContext?.save() } - catch { print("Error saving installed app.", error) } - } - catch - { + + do { try installedApp.managedObjectContext?.save() } catch { print("Error saving installed app.", error) } + } catch { group.set(.failure(error), forAppWithBundleIdentifier: operation.bundleIdentifier) - - self.log(error, for: operation) + + log(error, for: operation) } } - - func scheduleExpirationWarningLocalNotification(for app: InstalledApp) - { + + func scheduleExpirationWarningLocalNotification(for app: InstalledApp) { let notificationDate = app.expirationDate.addingTimeInterval(-1 * 60 * 60 * 24) // 24 hours before expiration. - + let timeIntervalUntilNotification = notificationDate.timeIntervalSinceNow guard timeIntervalUntilNotification > 0 else { // Crashes if we pass negative value to UNTimeIntervalNotificationTrigger initializer. return } - + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeIntervalUntilNotification, repeats: false) - + let content = UNMutableNotificationContent() content.title = NSLocalizedString("AltStore Expiring Soon", comment: "") content.body = NSLocalizedString("AltStore will expire in 24 hours. Open the app and refresh it to prevent it from expiring.", comment: "") content.sound = .default - + let request = UNNotificationRequest(identifier: AppManager.expirationWarningNotificationID, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) } - - func log(_ error: Error, for operation: AppOperation) - { + + func log(_ error: Error, for operation: AppOperation) { // Sanitize NSError on same thread before performing background task. let sanitizedError = (error as NSError).sanitizedForCoreData() - + let loggedErrorOperation: LoggedError.Operation = { - switch operation - { + switch operation { case .install: return .install case .update: return .update case .refresh: return .refresh @@ -1716,74 +1514,60 @@ private extension AppManager case .restore: return .restore } }() - + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in var app = operation.app - if let managedApp = app as? NSManagedObject, let tempApp = context.object(with: managedApp.objectID) as? AppProtocol - { + if let managedApp = app as? NSManagedObject, let tempApp = context.object(with: managedApp.objectID) as? AppProtocol { app = tempApp } - - do - { + + do { _ = LoggedError(error: sanitizedError, app: app, operation: loggedErrorOperation, context: context) try context.save() - } - catch let saveError - { + } catch let saveError { print("[ALTLog] Failed to log error \(sanitizedError.domain) code \(sanitizedError.code) for \(app.bundleIdentifier):", saveError) } } } - - func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false) - { + + func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false) { // Find "Install AltStore" operation if it already exists in `context` // so we can ensure it runs after any additional serial operations in `operations`. let installAltStoreOperation = context?.operations.allObjects.lazy.compactMap { $0 as? InstallAppOperation }.first { $0.context.bundleIdentifier == StoreApp.altstoreAppID } - - for operation in operations - { - switch operation - { + + for operation in operations { + switch operation { case _ where requiresSerialQueue: fallthrough case is InstallAppOperation, is RefreshAppOperation, is BackupAppOperation: - if let installAltStoreOperation = operation as? InstallAppOperation, installAltStoreOperation.context.bundleIdentifier == StoreApp.altstoreAppID - { + if let installAltStoreOperation = operation as? InstallAppOperation, installAltStoreOperation.context.bundleIdentifier == StoreApp.altstoreAppID { // Add dependencies on previous serial operations in `context` to ensure re-installing AltStore goes last. let previousSerialOperations = context?.operations.allObjects.filter { self.serialOperationQueue.operations.contains($0) } previousSerialOperations?.forEach { installAltStoreOperation.addDependency($0) } - } - else if let installAltStoreOperation = installAltStoreOperation - { + } else if let installAltStoreOperation = installAltStoreOperation { // Re-installing AltStore should _always_ be the last serial operation in `context`. installAltStoreOperation.addDependency(operation) } - - self.serialOperationQueue.addOperation(operation) - - default: self.operationQueue.addOperation(operation) + + serialOperationQueue.addOperation(operation) + + default: operationQueue.addOperation(operation) } - + context?.operations.add(operation) } } - - func progress(for operation: AppOperation) -> Progress? - { - switch operation - { - case .install, .update: return self.installationProgress[operation.bundleIdentifier] - case .refresh, .activate, .deactivate, .backup, .restore: return self.refreshProgress[operation.bundleIdentifier] + + func progress(for operation: AppOperation) -> Progress? { + switch operation { + case .install, .update: return installationProgress[operation.bundleIdentifier] + case .refresh, .activate, .deactivate, .backup, .restore: return refreshProgress[operation.bundleIdentifier] } } - - func set(_ progress: Progress?, for operation: AppOperation) - { - switch operation - { - case .install, .update: self.installationProgress[operation.bundleIdentifier] = progress - case .refresh, .activate, .deactivate, .backup, .restore: self.refreshProgress[operation.bundleIdentifier] = progress + + func set(_ progress: Progress?, for operation: AppOperation) { + switch operation { + case .install, .update: installationProgress[operation.bundleIdentifier] = progress + case .refresh, .activate, .deactivate, .backup, .restore: refreshProgress[operation.bundleIdentifier] = progress } } } diff --git a/AltStore/Managing Apps/AppManagerErrors.swift b/Sources/SideStore/Managing Apps/AppManagerErrors.swift similarity index 58% rename from AltStore/Managing Apps/AppManagerErrors.swift rename to Sources/SideStore/Managing Apps/AppManagerErrors.swift index 60fa34b9..30242a15 100644 --- a/AltStore/Managing Apps/AppManagerErrors.swift +++ b/Sources/SideStore/Managing Apps/AppManagerErrors.swift @@ -6,81 +6,64 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -import AltStoreCore +import SideStoreCore -extension AppManager -{ - struct FetchSourcesError: LocalizedError, CustomNSError - { +extension AppManager { + struct FetchSourcesError: LocalizedError, CustomNSError { var primaryError: Error? - + var sources: Set? var errors = [Source: Error]() - + var managedObjectContext: NSManagedObjectContext? - + var errorDescription: String? { - if let error = self.primaryError - { + if let error = primaryError { return error.localizedDescription - } - else - { + } else { var localizedDescription: String? - - self.managedObjectContext?.performAndWait { - if self.sources?.count == 1 - { + + managedObjectContext?.performAndWait { + if self.sources?.count == 1 { localizedDescription = NSLocalizedString("Could not refresh store.", comment: "") - } - else if self.errors.count == 1 - { + } else if self.errors.count == 1 { guard let source = self.errors.keys.first else { return } localizedDescription = String(format: NSLocalizedString("Could not refresh source “%@”.", comment: ""), source.name) - } - else - { + } else { localizedDescription = String(format: NSLocalizedString("Could not refresh %@ sources.", comment: ""), NSNumber(value: self.errors.count)) } } - + return localizedDescription } } - + var recoverySuggestion: String? { - if let error = self.primaryError as NSError? - { + if let error = primaryError as NSError? { return error.localizedRecoverySuggestion - } - else if self.errors.count == 1 - { + } else if errors.count == 1 { return nil - } - else - { + } else { return NSLocalizedString("Tap to view source errors.", comment: "") } } - - var errorUserInfo: [String : Any] { - guard let error = self.errors.values.first, self.errors.count == 1 else { return [:] } + + var errorUserInfo: [String: Any] { + guard let error = errors.values.first, errors.count == 1 else { return [:] } return [NSUnderlyingErrorKey: error] } - - init(_ error: Error) - { - self.primaryError = error + + init(_ error: Error) { + primaryError = error } - - init(sources: Set, errors: [Source: Error], context: NSManagedObjectContext) - { + + init(sources: Set, errors: [Source: Error], context: NSManagedObjectContext) { self.sources = sources self.errors = errors - self.managedObjectContext = context + managedObjectContext = context } } } diff --git a/Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.swift b/Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.swift new file mode 100644 index 00000000..4c5998ae --- /dev/null +++ b/Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.swift @@ -0,0 +1,43 @@ +// +// InstalledAppsCollectionHeaderView.swift +// AltStore +// +// Created by Riley Testut on 3/9/20. +// Copyright © 2020 Riley Testut. All rights reserved. +// + +import UIKit + +final class InstalledAppsCollectionHeaderView: UICollectionReusableView { + let textLabel: UILabel + let button: UIButton + + override init(frame: CGRect) { + textLabel = UILabel() + textLabel.translatesAutoresizingMaskIntoConstraints = false + textLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) + textLabel.accessibilityTraits.insert(.header) + + button = UIButton(type: .system) + button.translatesAutoresizingMaskIntoConstraints = false + button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium) + + super.init(frame: frame) + + addSubview(textLabel) + addSubview(button) + + NSLayoutConstraint.activate([textLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + textLabel.bottomAnchor.constraint(equalTo: bottomAnchor)]) + + NSLayoutConstraint.activate([button.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), + button.firstBaselineAnchor.constraint(equalTo: textLabel.firstBaselineAnchor)]) + + preservesSuperviewLayoutMargins = true + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/AltStore/My Apps/InstalledAppsCollectionHeaderView.xib b/Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.xib similarity index 100% rename from AltStore/My Apps/InstalledAppsCollectionHeaderView.xib rename to Sources/SideStore/My Apps/InstalledAppsCollectionHeaderView.xib diff --git a/AltStore/My Apps/MyAppsComponents.swift b/Sources/SideStore/My Apps/MyAppsComponents.swift similarity index 65% rename from AltStore/My Apps/MyAppsComponents.swift rename to Sources/SideStore/My Apps/MyAppsComponents.swift index b8a332f7..3212ca8a 100644 --- a/AltStore/My Apps/MyAppsComponents.swift +++ b/Sources/SideStore/My Apps/MyAppsComponents.swift @@ -6,92 +6,85 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit import RoxasUI +import UIKit -final class InstalledAppCollectionViewCell: UICollectionViewCell -{ +final class InstalledAppCollectionViewCell: UICollectionViewCell { private(set) var deactivateBadge: UIView? - + @IBOutlet var bannerView: AppBannerView! - - override func awakeFromNib() - { + + override func awakeFromNib() { super.awakeFromNib() - - self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - self.contentView.preservesSuperviewLayoutMargins = true - - if #available(iOS 13.0, *) - { + + contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + contentView.preservesSuperviewLayoutMargins = true + + if #available(iOS 13.0, *) { let deactivateBadge = UIView() deactivateBadge.translatesAutoresizingMaskIntoConstraints = false deactivateBadge.isHidden = true self.addSubview(deactivateBadge) - + // Solid background to make the X opaque white. let backgroundView = UIView() backgroundView.translatesAutoresizingMaskIntoConstraints = false backgroundView.backgroundColor = .white deactivateBadge.addSubview(backgroundView) - + let badgeView = UIImageView(image: UIImage(systemName: "xmark.circle.fill")) badgeView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(scale: .large) badgeView.tintColor = .systemRed deactivateBadge.addSubview(badgeView, pinningEdgesWith: .zero) - + NSLayoutConstraint.activate([ deactivateBadge.centerXAnchor.constraint(equalTo: self.bannerView.iconImageView.trailingAnchor), deactivateBadge.centerYAnchor.constraint(equalTo: self.bannerView.iconImageView.topAnchor), - + backgroundView.centerXAnchor.constraint(equalTo: badgeView.centerXAnchor), backgroundView.centerYAnchor.constraint(equalTo: badgeView.centerYAnchor), backgroundView.widthAnchor.constraint(equalTo: badgeView.widthAnchor, multiplier: 0.5), backgroundView.heightAnchor.constraint(equalTo: badgeView.heightAnchor, multiplier: 0.5) ]) - + self.deactivateBadge = deactivateBadge } } } -final class InstalledAppsCollectionFooterView: UICollectionReusableView -{ +final class InstalledAppsCollectionFooterView: UICollectionReusableView { @IBOutlet var textLabel: UILabel! @IBOutlet var button: UIButton! } -final class NoUpdatesCollectionViewCell: UICollectionViewCell -{ +final class NoUpdatesCollectionViewCell: UICollectionViewCell { @IBOutlet var blurView: UIVisualEffectView! - - override func awakeFromNib() - { + + override func awakeFromNib() { super.awakeFromNib() - - self.contentView.preservesSuperviewLayoutMargins = true + + contentView.preservesSuperviewLayoutMargins = true } } -final class UpdatesCollectionHeaderView: UICollectionReusableView -{ +final class UpdatesCollectionHeaderView: UICollectionReusableView { let button = PillButton(type: .system) - - override init(frame: CGRect) - { + + override init(frame: CGRect) { super.init(frame: frame) - - self.button.translatesAutoresizingMaskIntoConstraints = false - self.button.setTitle(">", for: .normal) - self.addSubview(self.button) - - NSLayoutConstraint.activate([self.button.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20), - self.button.topAnchor.constraint(equalTo: self.topAnchor), - self.button.widthAnchor.constraint(equalToConstant: 50), - self.button.heightAnchor.constraint(equalToConstant: 26)]) + + button.translatesAutoresizingMaskIntoConstraints = false + button.setTitle(">", for: .normal) + addSubview(button) + + NSLayoutConstraint.activate([button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + button.topAnchor.constraint(equalTo: topAnchor), + button.widthAnchor.constraint(equalToConstant: 50), + button.heightAnchor.constraint(equalToConstant: 26)]) } - - required init?(coder aDecoder: NSCoder) { + + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/AltStore/My Apps/MyAppsViewController.swift b/Sources/SideStore/My Apps/MyAppsViewController.swift similarity index 66% rename from AltStore/My Apps/MyAppsViewController.swift rename to Sources/SideStore/My Apps/MyAppsViewController.swift index a166067a..a8427b7f 100644 --- a/AltStore/My Apps/MyAppsViewController.swift +++ b/Sources/SideStore/My Apps/MyAppsViewController.swift @@ -6,23 +6,21 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit -import MobileCoreServices -import Intents import Combine +import Intents +import MobileCoreServices +import UIKit -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI import Nuke private let maximumCollapsedUpdatesCount = 2 -extension MyAppsViewController -{ - private enum Section: Int, CaseIterable - { +extension MyAppsViewController { + private enum Section: Int, CaseIterable { case noUpdates case updates case activeApps @@ -30,20 +28,19 @@ extension MyAppsViewController } } -final class MyAppsViewController: UICollectionViewController -{ +final class MyAppsViewController: UICollectionViewController { private let coordinator = NSFileCoordinator() private let operationQueue = OperationQueue() - + private lazy var dataSource = self.makeDataSource() private lazy var noUpdatesDataSource = self.makeNoUpdatesDataSource() private lazy var updatesDataSource = self.makeUpdatesDataSource() private lazy var activeAppsDataSource = self.makeActiveAppsDataSource() private lazy var inactiveAppsDataSource = self.makeInactiveAppsDataSource() - + private var prototypeUpdateCell: UpdateCollectionViewCell! private var sideloadingProgressView: UIProgressView! - + // State private var isUpdateSectionCollapsed = true private var expandedAppUpdates = Set() @@ -51,342 +48,304 @@ final class MyAppsViewController: UICollectionViewController private var refreshGroup: RefreshGroup? private var sideloadingProgress: Progress? private var dropDestinationIndexPath: IndexPath? - + private var _imagePickerInstalledApp: InstalledApp? - + // Cache private var cachedUpdateSizes = [String: CGSize]() - + private lazy var dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .none return dateFormatter }() - - required init?(coder aDecoder: NSCoder) - { + + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.didFetchSource(_:)), name: AppManager.didFetchSourceNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - + // Allows us to intercept delegate callbacks. - self.updatesDataSource.fetchedResultsController.delegate = self - - self.collectionView.dataSource = self.dataSource - self.collectionView.prefetchDataSource = self.dataSource - self.collectionView.dragDelegate = self - self.collectionView.dropDelegate = self - self.collectionView.dragInteractionEnabled = true - - self.prototypeUpdateCell = UpdateCollectionViewCell.instantiate(with: UpdateCollectionViewCell.nib!) - self.prototypeUpdateCell.contentView.translatesAutoresizingMaskIntoConstraints = false - - self.collectionView.register(UpdateCollectionViewCell.nib, forCellWithReuseIdentifier: "UpdateCell") - self.collectionView.register(UpdatesCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "UpdatesHeader") - self.collectionView.register(InstalledAppsCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "ActiveAppsHeader") - self.collectionView.register(InstalledAppsCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "InactiveAppsHeader") - - self.sideloadingProgressView = UIProgressView(progressViewStyle: .bar) - self.sideloadingProgressView.translatesAutoresizingMaskIntoConstraints = false - self.sideloadingProgressView.progressTintColor = .altPrimary - self.sideloadingProgressView.progress = 0 - - if let navigationBar = self.navigationController?.navigationBar - { - navigationBar.addSubview(self.sideloadingProgressView) - NSLayoutConstraint.activate([self.sideloadingProgressView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor), - self.sideloadingProgressView.trailingAnchor.constraint(equalTo: navigationBar.trailingAnchor), - self.sideloadingProgressView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor)]) + updatesDataSource.fetchedResultsController.delegate = self + + collectionView.dataSource = dataSource + collectionView.prefetchDataSource = dataSource + collectionView.dragDelegate = self + collectionView.dropDelegate = self + collectionView.dragInteractionEnabled = true + + prototypeUpdateCell = UpdateCollectionViewCell.instantiate(with: UpdateCollectionViewCell.nib!) + prototypeUpdateCell.contentView.translatesAutoresizingMaskIntoConstraints = false + + collectionView.register(UpdateCollectionViewCell.nib, forCellWithReuseIdentifier: "UpdateCell") + collectionView.register(UpdatesCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "UpdatesHeader") + collectionView.register(InstalledAppsCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "ActiveAppsHeader") + collectionView.register(InstalledAppsCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "InactiveAppsHeader") + + sideloadingProgressView = UIProgressView(progressViewStyle: .bar) + sideloadingProgressView.translatesAutoresizingMaskIntoConstraints = false + sideloadingProgressView.progressTintColor = .altPrimary + sideloadingProgressView.progress = 0 + + if let navigationBar = navigationController?.navigationBar { + navigationBar.addSubview(sideloadingProgressView) + NSLayoutConstraint.activate([sideloadingProgressView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor), + sideloadingProgressView.trailingAnchor.constraint(equalTo: navigationBar.trailingAnchor), + sideloadingProgressView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor)]) } - - if #available(iOS 13, *) {} - else - { - self.registerForPreviewing(with: self, sourceView: self.collectionView) + + if #available(iOS 13, *) {} else { + registerForPreviewing(with: self, sourceView: collectionView) } } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - self.updateDataSource() - - self.fetchAppIDs() + + updateDataSource() + + fetchAppIDs() } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) - { + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier else { return } - - switch identifier - { + + switch identifier { case "showApp", "showUpdate": - guard let cell = sender as? UICollectionViewCell, let indexPath = self.collectionView.indexPath(for: cell) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - + guard let cell = sender as? UICollectionViewCell, let indexPath = collectionView.indexPath(for: cell) else { return } + + let installedApp = dataSource.item(at: indexPath) + let appViewController = segue.destination as! AppViewController appViewController.app = installedApp.storeApp - + default: break } } - - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool - { + + override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { guard identifier == "showApp" else { return true } - - guard let cell = sender as? UICollectionViewCell, let indexPath = self.collectionView.indexPath(for: cell) else { return true } - - let installedApp = self.dataSource.item(at: indexPath) + + guard let cell = sender as? UICollectionViewCell, let indexPath = collectionView.indexPath(for: cell) else { return true } + + let installedApp = dataSource.item(at: indexPath) return !installedApp.isSideloaded } - - @IBAction func unwindToMyAppsViewController(_ segue: UIStoryboardSegue) - { - } + + @IBAction func unwindToMyAppsViewController(_: UIStoryboardSegue) {} } -private extension MyAppsViewController -{ - func makeDataSource() -> RSTCompositeCollectionViewPrefetchingDataSource - { - let dataSource = RSTCompositeCollectionViewPrefetchingDataSource(dataSources: [self.noUpdatesDataSource, self.updatesDataSource, self.activeAppsDataSource, self.inactiveAppsDataSource]) +private extension MyAppsViewController { + func makeDataSource() -> RSTCompositeCollectionViewPrefetchingDataSource { + let dataSource = RSTCompositeCollectionViewPrefetchingDataSource(dataSources: [noUpdatesDataSource, updatesDataSource, activeAppsDataSource, inactiveAppsDataSource]) dataSource.proxy = self return dataSource } - - func makeNoUpdatesDataSource() -> RSTDynamicCollectionViewPrefetchingDataSource - { + + func makeNoUpdatesDataSource() -> RSTDynamicCollectionViewPrefetchingDataSource { let dynamicDataSource = RSTDynamicCollectionViewPrefetchingDataSource() dynamicDataSource.numberOfSectionsHandler = { 1 } dynamicDataSource.numberOfItemsHandler = { _ in self.updatesDataSource.itemCount == 0 ? 1 : 0 } dynamicDataSource.cellIdentifierHandler = { _ in "NoUpdatesCell" } - dynamicDataSource.cellConfigurationHandler = { (cell, _, indexPath) in + dynamicDataSource.cellConfigurationHandler = { cell, _, _ in let cell = cell as! NoUpdatesCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right - + cell.blurView.layer.cornerRadius = 20 cell.blurView.layer.masksToBounds = true cell.blurView.backgroundColor = .altPrimary } - + return dynamicDataSource } - - func makeUpdatesDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource - { + + func makeUpdatesDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource { let fetchRequest = InstalledApp.updatesFetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \InstalledApp.storeApp?.latestVersion?.date, ascending: true), NSSortDescriptor(keyPath: \InstalledApp.name, ascending: true)] fetchRequest.returnsObjectsAsFaults = false - + let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) dataSource.liveFetchLimit = maximumCollapsedUpdatesCount dataSource.cellIdentifierHandler = { _ in "UpdateCell" } - dataSource.cellConfigurationHandler = { [weak self] (cell, installedApp, indexPath) in + dataSource.cellConfigurationHandler = { [weak self] cell, installedApp, _ in guard let self = self else { return } guard let app = installedApp.storeApp, let latestVersion = app.latestVersion else { return } - + let cell = cell as! UpdateCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right - + cell.tintColor = app.tintColor ?? .altPrimary cell.versionDescriptionTextView.text = app.versionDescription - + cell.bannerView.iconImageView.image = nil cell.bannerView.iconImageView.isIndicatingActivity = true - + cell.bannerView.configure(for: app) - + let versionDate = Date().relativeDateString(since: latestVersion.date, dateFormatter: self.dateFormatter) cell.bannerView.subtitleLabel.text = versionDate - + let appName: String - - if app.isBeta - { + + if app.isBeta { appName = String(format: NSLocalizedString("%@ beta", comment: ""), app.name) - } - else - { + } else { appName = app.name } - + cell.bannerView.accessibilityLabel = String(format: NSLocalizedString("%@ %@ update. Released on %@.", comment: ""), appName, latestVersion.version, versionDate) - + cell.bannerView.button.isIndicatingActivity = false cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.updateApp(_:)), for: .primaryActionTriggered) cell.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Update %@", comment: ""), installedApp.name) - - if self.expandedAppUpdates.contains(app.bundleIdentifier) - { + + if self.expandedAppUpdates.contains(app.bundleIdentifier) { cell.mode = .expanded - } - else - { + } else { cell.mode = .collapsed } - + cell.versionDescriptionTextView.moreButton.addTarget(self, action: #selector(MyAppsViewController.toggleUpdateCellMode(_:)), for: .primaryActionTriggered) - + let progress = AppManager.shared.installationProgress(for: app) cell.bannerView.button.progress = progress - + cell.setNeedsLayout() } - dataSource.prefetchHandler = { (installedApp, indexPath, completionHandler) in + dataSource.prefetchHandler = { installedApp, _, completionHandler in guard let iconURL = installedApp.storeApp?.iconURL else { return nil } - - return RSTAsyncBlockOperation() { (operation) in - ImagePipeline.shared.loadImage(with: iconURL, progress: nil, completion: { (response, error) in + + return RSTAsyncBlockOperation { operation in + ImagePipeline.shared.loadImage(with: iconURL, progress: nil, completion: { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completionHandler(image, nil) - } - else - { + } else { completionHandler(nil, error) } }) } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, error in let cell = cell as! UpdateCollectionViewCell cell.bannerView.iconImageView.isIndicatingActivity = false cell.bannerView.iconImageView.image = image - - if let error = error - { + + if let error = error { print("Error loading image:", error) } } - + return dataSource } - - func makeActiveAppsDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource - { + + func makeActiveAppsDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource { let fetchRequest = InstalledApp.activeAppsFetchRequest() fetchRequest.relationshipKeyPathsForPrefetching = [#keyPath(InstalledApp.storeApp)] fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \InstalledApp.expirationDate, ascending: true), NSSortDescriptor(keyPath: \InstalledApp.refreshedDate, ascending: false), NSSortDescriptor(keyPath: \InstalledApp.name, ascending: true)] fetchRequest.returnsObjectsAsFaults = false - + let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) dataSource.cellIdentifierHandler = { _ in "AppCell" } - dataSource.cellConfigurationHandler = { (cell, installedApp, indexPath) in + dataSource.cellConfigurationHandler = { cell, installedApp, indexPath in let tintColor = installedApp.storeApp?.tintColor ?? .altPrimary - + let cell = cell as! InstalledAppCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right cell.tintColor = tintColor - + cell.deactivateBadge?.isHidden = false - - if let dropIndexPath = self.dropDestinationIndexPath, dropIndexPath.section == Section.activeApps.rawValue && dropIndexPath.item == indexPath.item - { + + if let dropIndexPath = self.dropDestinationIndexPath, dropIndexPath.section == Section.activeApps.rawValue && dropIndexPath.item == indexPath.item { cell.bannerView.alpha = 0.4 - + cell.deactivateBadge?.alpha = 1.0 cell.deactivateBadge?.transform = .identity - } - else - { + } else { cell.bannerView.alpha = 1.0 - + cell.deactivateBadge?.alpha = 0.0 cell.deactivateBadge?.transform = CGAffineTransform.identity.scaledBy(x: 0.33, y: 0.33) } - + cell.bannerView.configure(for: installedApp) - + cell.bannerView.iconImageView.isIndicatingActivity = true - + cell.bannerView.buttonLabel.isHidden = false cell.bannerView.buttonLabel.text = NSLocalizedString("Expires in", comment: "") - + cell.bannerView.button.isIndicatingActivity = false cell.bannerView.button.removeTarget(self, action: nil, for: .primaryActionTriggered) cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.refreshApp(_:)), for: .primaryActionTriggered) - + let currentDate = Date() - + let numberOfDays = installedApp.expirationDate.numberOfCalendarDays(since: currentDate) let numberOfDaysText: String - - if numberOfDays == 1 - { + + if numberOfDays == 1 { numberOfDaysText = NSLocalizedString("1 day", comment: "") - } - else - { + } else { numberOfDaysText = String(format: NSLocalizedString("%@ days", comment: ""), NSNumber(value: numberOfDays)) } - + cell.bannerView.button.setTitle(numberOfDaysText.uppercased(), for: .normal) cell.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Refresh %@", comment: ""), installedApp.name) - + cell.bannerView.accessibilityLabel? += ". " + String(format: NSLocalizedString("Expires in %@", comment: ""), numberOfDaysText) - + // Make sure refresh button is correct size. cell.layoutIfNeeded() - - switch numberOfDays - { - case 2...3: cell.bannerView.button.tintColor = .refreshOrange - case 4...5: cell.bannerView.button.tintColor = .refreshYellow + + switch numberOfDays { + case 2 ... 3: cell.bannerView.button.tintColor = .refreshOrange + case 4 ... 5: cell.bannerView.button.tintColor = .refreshYellow case 6...: cell.bannerView.button.tintColor = .refreshGreen default: cell.bannerView.button.tintColor = .refreshRed } - - if let progress = AppManager.shared.refreshProgress(for: installedApp), progress.fractionCompleted < 1.0 - { + + if let progress = AppManager.shared.refreshProgress(for: installedApp), progress.fractionCompleted < 1.0 { cell.bannerView.button.progress = progress - } - else - { + } else { cell.bannerView.button.progress = nil } } - dataSource.prefetchHandler = { (item, indexPath, completion) in - RSTAsyncBlockOperation { (operation) in + dataSource.prefetchHandler = { item, _, completion in + RSTAsyncBlockOperation { _ in item.managedObjectContext?.perform { - item.loadIcon { (result) in - switch result - { - case .failure(let error): completion(nil, error) - case .success(let image): completion(image, nil) + item.loadIcon { result in + switch result { + case let .failure(error): completion(nil, error) + case let .success(image): completion(image, nil) } } } } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, _ in let cell = cell as! InstalledAppCollectionViewCell cell.bannerView.iconImageView.image = image cell.bannerView.iconImageView.isIndicatingActivity = false } - + return dataSource } - - func makeInactiveAppsDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource - { + + func makeInactiveAppsDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource { let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest fetchRequest.relationshipKeyPathsForPrefetching = [#keyPath(InstalledApp.storeApp)] fetchRequest.predicate = NSPredicate(format: "%K == NO", #keyPath(InstalledApp.isActive)) @@ -394,380 +353,327 @@ private extension MyAppsViewController NSSortDescriptor(keyPath: \InstalledApp.refreshedDate, ascending: false), NSSortDescriptor(keyPath: \InstalledApp.name, ascending: true)] fetchRequest.returnsObjectsAsFaults = false - + let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) dataSource.cellIdentifierHandler = { _ in "AppCell" } - dataSource.cellConfigurationHandler = { (cell, installedApp, indexPath) in + dataSource.cellConfigurationHandler = { cell, installedApp, _ in let tintColor = installedApp.storeApp?.tintColor ?? .altPrimary - + let cell = cell as! InstalledAppCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right cell.tintColor = UIColor.gray - + cell.bannerView.iconImageView.isIndicatingActivity = true cell.bannerView.buttonLabel.isHidden = true cell.bannerView.alpha = 1.0 - + cell.deactivateBadge?.isHidden = true cell.deactivateBadge?.alpha = 0.0 cell.deactivateBadge?.transform = CGAffineTransform.identity.scaledBy(x: 0.5, y: 0.5) - + cell.bannerView.configure(for: installedApp) - + cell.bannerView.button.isIndicatingActivity = false cell.bannerView.button.tintColor = tintColor cell.bannerView.button.setTitle(NSLocalizedString("ACTIVATE", comment: ""), for: .normal) cell.bannerView.button.removeTarget(self, action: nil, for: .primaryActionTriggered) cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.activateApp(_:)), for: .primaryActionTriggered) cell.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Activate %@", comment: ""), installedApp.name) - + // Make sure refresh button is correct size. cell.layoutIfNeeded() - + // Ensure no leftover progress from active apps cell reuse. cell.bannerView.button.progress = nil - - if let progress = AppManager.shared.refreshProgress(for: installedApp), progress.fractionCompleted < 1.0 - { + + if let progress = AppManager.shared.refreshProgress(for: installedApp), progress.fractionCompleted < 1.0 { cell.bannerView.button.progress = progress - } - else - { + } else { cell.bannerView.button.progress = nil } } - dataSource.prefetchHandler = { (item, indexPath, completion) in - RSTAsyncBlockOperation { (operation) in + dataSource.prefetchHandler = { item, _, completion in + RSTAsyncBlockOperation { _ in item.managedObjectContext?.perform { - item.loadIcon { (result) in - switch result - { - case .failure(let error): completion(nil, error) - case .success(let image): completion(image, nil) + item.loadIcon { result in + switch result { + case let .failure(error): completion(nil, error) + case let .success(image): completion(image, nil) } } } } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, _ in let cell = cell as! InstalledAppCollectionViewCell cell.bannerView.iconImageView.image = image cell.bannerView.iconImageView.isIndicatingActivity = false } - + return dataSource } - - func updateDataSource() - { - - self.dataSource.predicate = nil - - + + func updateDataSource() { + dataSource.predicate = nil } } -private extension MyAppsViewController -{ - func update() - { - if self.updatesDataSource.itemCount > 0 - { - self.navigationController?.tabBarItem.badgeValue = String(describing: self.updatesDataSource.itemCount) - UIApplication.shared.applicationIconBadgeNumber = Int(self.updatesDataSource.itemCount) - } - else - { - self.navigationController?.tabBarItem.badgeValue = nil +private extension MyAppsViewController { + func update() { + if updatesDataSource.itemCount > 0 { + navigationController?.tabBarItem.badgeValue = String(describing: updatesDataSource.itemCount) + UIApplication.shared.applicationIconBadgeNumber = Int(updatesDataSource.itemCount) + } else { + navigationController?.tabBarItem.badgeValue = nil UIApplication.shared.applicationIconBadgeNumber = 0 } - - if self.isViewLoaded - { + + if isViewLoaded { UIView.performWithoutAnimation { self.collectionView.reloadSections(IndexSet(integer: Section.updates.rawValue)) } - } + } } - - func fetchAppIDs() - { - AppManager.shared.fetchAppIDs { (result) in - do - { + + func fetchAppIDs() { + AppManager.shared.fetchAppIDs { result in + do { let (_, context) = try result.get() try context.save() - } - catch - { + } catch { print("Failed to fetch App IDs.", error) } } } - - func refresh(_ installedApps: [InstalledApp], completionHandler: @escaping ([String : Result]) -> Void) - { - let group = AppManager.shared.refresh(installedApps, presentingViewController: self, group: self.refreshGroup) - group.completionHandler = { (results) in + + func refresh(_ installedApps: [InstalledApp], completionHandler: @escaping ([String: Result]) -> Void) { + let group = AppManager.shared.refresh(installedApps, presentingViewController: self, group: refreshGroup) + group.completionHandler = { results in DispatchQueue.main.async { - let failures = results.compactMapValues { (result) -> Error? in - switch result - { + let failures = results.compactMapValues { result -> Error? in + switch result { case .failure(OperationError.cancelled): return nil - case .failure(let error): return error + case let .failure(error): return error case .success: return nil } } - + guard !failures.isEmpty else { return } - + let toastView: ToastView - - if let failure = failures.first, results.count == 1 - { + + if let failure = failures.first, results.count == 1 { toastView = ToastView(error: failure.value) - } - else - { + } else { let localizedText: String - - if failures.count == 1 - { + + if failures.count == 1 { localizedText = NSLocalizedString("Failed to refresh 1 app.", comment: "") - } - else - { + } else { localizedText = String(format: NSLocalizedString("Failed to refresh %@ apps.", comment: ""), NSNumber(value: failures.count)) } - + let error = failures.first?.value as NSError? let detailText = error?.localizedFailure ?? error?.localizedFailureReason ?? error?.localizedDescription - + toastView = ToastView(text: localizedText, detailText: detailText) toastView.preferredDuration = 4.0 } - + toastView.show(in: self) } - + self.refreshGroup = nil completionHandler(results) } - - self.refreshGroup = group - + + refreshGroup = group + UIView.performWithoutAnimation { self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue]) } } } -private extension MyAppsViewController -{ - @IBAction func toggleAppUpdates(_ sender: UIButton) - { - let visibleCells = self.collectionView.visibleCells - - self.collectionView.performBatchUpdates({ - +private extension MyAppsViewController { + @IBAction func toggleAppUpdates(_ sender: UIButton) { + let visibleCells = collectionView.visibleCells + + collectionView.performBatchUpdates({ self.isUpdateSectionCollapsed.toggle() - + UIView.animate(withDuration: 0.3, animations: { - if self.isUpdateSectionCollapsed - { + if self.isUpdateSectionCollapsed { self.updatesDataSource.liveFetchLimit = maximumCollapsedUpdatesCount self.expandedAppUpdates.removeAll() - - for case let cell as UpdateCollectionViewCell in visibleCells - { + + for case let cell as UpdateCollectionViewCell in visibleCells { cell.mode = .collapsed } - + self.cachedUpdateSizes.removeAll() - + sender.titleLabel?.transform = .identity - } - else - { + } else { self.updatesDataSource.liveFetchLimit = 0 - + sender.titleLabel?.transform = CGAffineTransform.identity.rotated(by: .pi) } }) - + self.collectionView.collectionViewLayout.invalidateLayout() - + }, completion: nil) } - - @IBAction func toggleUpdateCellMode(_ sender: UIButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - - let cell = self.collectionView.cellForItem(at: indexPath) as? UpdateCollectionViewCell - - if self.expandedAppUpdates.contains(installedApp.bundleIdentifier) - { - self.expandedAppUpdates.remove(installedApp.bundleIdentifier) + + @IBAction func toggleUpdateCellMode(_ sender: UIButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let installedApp = dataSource.item(at: indexPath) + + let cell = collectionView.cellForItem(at: indexPath) as? UpdateCollectionViewCell + + if expandedAppUpdates.contains(installedApp.bundleIdentifier) { + expandedAppUpdates.remove(installedApp.bundleIdentifier) cell?.mode = .collapsed - } - else - { - self.expandedAppUpdates.insert(installedApp.bundleIdentifier) + } else { + expandedAppUpdates.insert(installedApp.bundleIdentifier) cell?.mode = .expanded } - - self.cachedUpdateSizes[installedApp.bundleIdentifier] = nil - - self.collectionView.performBatchUpdates({ + + cachedUpdateSizes[installedApp.bundleIdentifier] = nil + + collectionView.performBatchUpdates({ self.collectionView.collectionViewLayout.invalidateLayout() }, completion: nil) } - - @IBAction func refreshApp(_ sender: UIButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - self.refresh(installedApp) + + @IBAction func refreshApp(_ sender: UIButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let installedApp = dataSource.item(at: indexPath) + refresh(installedApp) } - - @IBAction func refreshAllApps(_ sender: UIBarButtonItem) - { - self.isRefreshingAllApps = true - self.collectionView.collectionViewLayout.invalidateLayout() + + @IBAction func refreshAllApps(_: UIBarButtonItem) { + isRefreshingAllApps = true + collectionView.collectionViewLayout.invalidateLayout() let installedApps = InstalledApp.fetchAppsForRefreshingAll(in: DatabaseManager.shared.viewContext) - - self.refresh(installedApps) { (result) in + + refresh(installedApps) { _ in DispatchQueue.main.async { self.isRefreshingAllApps = false self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue]) } } - - if #available(iOS 14, *) - { + + if #available(iOS 14, *) { let interaction = INInteraction.refreshAllApps() - interaction.donate { (error) in + interaction.donate { error in guard let error = error else { return } print("Failed to donate intent \(interaction.intent).", error) } } } - - @IBAction func updateApp(_ sender: UIButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - + + @IBAction func updateApp(_ sender: UIButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let installedApp = dataSource.item(at: indexPath) + let previousProgress = AppManager.shared.installationProgress(for: installedApp) guard previousProgress == nil else { previousProgress?.cancel() return } - - _ = AppManager.shared.update(installedApp, presentingViewController: self) { (result) in + + _ = AppManager.shared.update(installedApp, presentingViewController: self) { result in DispatchQueue.main.async { - switch result - { + switch result { case .failure(OperationError.cancelled): self.collectionView.reloadItems(at: [indexPath]) - - case .failure(let error): + + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) - + self.collectionView.reloadItems(at: [indexPath]) - + case .success: print("Updated app:", installedApp.bundleIdentifier) // No need to reload, since the the update cell is gone now. } - + self.update() } } - - self.collectionView.reloadItems(at: [indexPath]) + + collectionView.reloadItems(at: [indexPath]) } - - @IBAction func sideloadApp(_ sender: UIBarButtonItem) - { + + @IBAction func sideloadApp(_: UIBarButtonItem) { let supportedTypes: [String] - - if let types = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, "ipa" as CFString, nil)?.takeRetainedValue() - { + + if let types = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, "ipa" as CFString, nil)?.takeRetainedValue() { supportedTypes = (types as NSArray).map { $0 as! String } - } - else - { + } else { supportedTypes = ["com.apple.itunes.ipa"] // Declared by the system. } - + let documentPickerViewController = UIDocumentPickerViewController(documentTypes: supportedTypes, in: .import) documentPickerViewController.delegate = self - self.present(documentPickerViewController, animated: true, completion: nil) + present(documentPickerViewController, animated: true, completion: nil) } - - func sideloadApp(at url: URL, completion: @escaping (Result) -> Void) - { + + func sideloadApp(at url: URL, completion: @escaping (Result) -> Void) { let progress = Progress.discreteProgress(totalUnitCount: 100) - - self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true - - class Context - { + + navigationItem.leftBarButtonItem?.isIndicatingActivity = true + + class Context { var fileURL: URL? var application: ALTApplication? var installedApp: InstalledApp? { didSet { - self.installedAppContext = self.installedApp?.managedObjectContext + installedAppContext = installedApp?.managedObjectContext } } + private var installedAppContext: NSManagedObjectContext? - + var error: Error? } - + let temporaryDirectory = FileManager.default.uniqueTemporaryURL() let unzippedAppDirectory = temporaryDirectory.appendingPathComponent("App") - + let context = Context() - + let downloadOperation: RSTAsyncBlockOperation? - - if url.isFileURL - { + + if url.isFileURL { downloadOperation = nil context.fileURL = url progress.totalUnitCount -= 20 - } - else - { + } else { let downloadProgress = Progress.discreteProgress(totalUnitCount: 100) - downloadOperation = RSTAsyncBlockOperation { (operation) in - let downloadTask = URLSession.shared.downloadTask(with: url) { (fileURL, response, error) in - do - { + downloadOperation = RSTAsyncBlockOperation { operation in + let downloadTask = URLSession.shared.downloadTask(with: url) { fileURL, response, error in + do { let (fileURL, _) = try Result((fileURL, response), error).get() - + try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) - + let destinationURL = temporaryDirectory.appendingPathComponent("App.ipa") try FileManager.default.moveItem(at: fileURL, to: destinationURL) - + context.fileURL = destinationURL - } - catch - { + } catch { context.error = error } operation.finish() @@ -777,296 +683,253 @@ private extension MyAppsViewController } progress.addChild(downloadProgress, withPendingUnitCount: 20) } - + let unzipProgress = Progress.discreteProgress(totalUnitCount: 1) let unzipAppOperation = BlockOperation { - do - { - if let error = context.error - { + do { + if let error = context.error { throw error } - + guard let fileURL = context.fileURL else { throw OperationError.invalidParameters } defer { try? FileManager.default.removeItem(at: fileURL) } - + try FileManager.default.createDirectory(at: unzippedAppDirectory, withIntermediateDirectories: true, attributes: nil) let unzippedApplicationURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: unzippedAppDirectory) - + guard let application = ALTApplication(fileURL: unzippedApplicationURL) else { throw OperationError.invalidApp } context.application = application - + unzipProgress.completedUnitCount = 1 - } - catch - { + } catch { context.error = error } } progress.addChild(unzipProgress, withPendingUnitCount: 10) - - if let downloadOperation = downloadOperation - { + + if let downloadOperation = downloadOperation { unzipAppOperation.addDependency(downloadOperation) } - + let removeAppExtensionsProgress = Progress.discreteProgress(totalUnitCount: 1) - let removeAppExtensionsOperation = RSTAsyncBlockOperation { [weak self] (operation) in - do - { - if let error = context.error - { + let removeAppExtensionsOperation = RSTAsyncBlockOperation { [weak self] operation in + do { + if let error = context.error { throw error } - + guard let application = context.application else { throw OperationError.invalidParameters } - + DispatchQueue.main.async { - self?.removeAppExtensions(from: application) { (result) in - switch result - { + self?.removeAppExtensions(from: application) { result in + switch result { case .success: removeAppExtensionsProgress.completedUnitCount = 1 - case .failure(let error): context.error = error + case let .failure(error): context.error = error } operation.finish() } } - } - catch - { + } catch { context.error = error operation.finish() } } removeAppExtensionsOperation.addDependency(unzipAppOperation) progress.addChild(removeAppExtensionsProgress, withPendingUnitCount: 5) - + let installProgress = Progress.discreteProgress(totalUnitCount: 100) - let installAppOperation = RSTAsyncBlockOperation { (operation) in - do - { - if let error = context.error - { + let installAppOperation = RSTAsyncBlockOperation { operation in + do { + if let error = context.error { throw error } - + guard let application = context.application else { throw OperationError.invalidParameters } - - let group = AppManager.shared.install(application, presentingViewController: self) { (result) in - switch result - { - case .success(let installedApp): context.installedApp = installedApp - case .failure(let error): context.error = error + + let group = AppManager.shared.install(application, presentingViewController: self) { result in + switch result { + case let .success(installedApp): context.installedApp = installedApp + case let .failure(error): context.error = error } operation.finish() } installProgress.addChild(group.progress, withPendingUnitCount: 100) - } - catch - { + } catch { context.error = error operation.finish() } } installAppOperation.completionBlock = { try? FileManager.default.removeItem(at: temporaryDirectory) - + DispatchQueue.main.async { self.navigationItem.leftBarButtonItem?.isIndicatingActivity = false self.sideloadingProgressView.observedProgress = nil self.sideloadingProgressView.setHidden(true, animated: true) - - switch Result(context.installedApp, context.error) - { - case .success(let app): + + switch Result(context.installedApp, context.error) { + case let .success(app): completion(.success(())) - + app.managedObjectContext?.perform { print("Successfully installed app:", app.bundleIdentifier) } - + case .failure(OperationError.cancelled): - completion(.failure((OperationError.cancelled))) - - case .failure(let error): + completion(.failure(OperationError.cancelled)) + + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) - + completion(.failure(error)) } } } progress.addChild(installProgress, withPendingUnitCount: 65) installAppOperation.addDependency(removeAppExtensionsOperation) - - self.sideloadingProgress = progress - self.sideloadingProgressView.progress = 0 - self.sideloadingProgressView.isHidden = false - self.sideloadingProgressView.observedProgress = self.sideloadingProgress - + + sideloadingProgress = progress + sideloadingProgressView.progress = 0 + sideloadingProgressView.isHidden = false + sideloadingProgressView.observedProgress = sideloadingProgress + let operations = [downloadOperation, unzipAppOperation, removeAppExtensionsOperation, installAppOperation].compactMap { $0 } - self.operationQueue.addOperations(operations, waitUntilFinished: false) + operationQueue.addOperations(operations, waitUntilFinished: false) } - - @IBAction func activateApp(_ sender: UIButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - self.activate(installedApp) + + @IBAction func activateApp(_ sender: UIButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let installedApp = dataSource.item(at: indexPath) + activate(installedApp) } - - @IBAction func deactivateApp(_ sender: UIButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - - let installedApp = self.dataSource.item(at: indexPath) - self.deactivate(installedApp) + + @IBAction func deactivateApp(_ sender: UIButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + + let installedApp = dataSource.item(at: indexPath) + deactivate(installedApp) } - - @objc func presentInactiveAppsAlert() - { + + @objc func presentInactiveAppsAlert() { let message: String - - if UserDefaults.standard.activeAppLimitIncludesExtensions - { + + if UserDefaults.standard.activeAppLimitIncludesExtensions { message = NSLocalizedString("Non-developer Apple IDs are limited to 3 apps and app extensions. Inactive apps don't count towards your total, but cannot be opened until activated.", comment: "") - } - else - { + } else { message = NSLocalizedString("Non-developer Apple IDs are limited to 3 apps. Inactive apps are backed up and uninstalled so they don't count towards your total, but will be reinstalled with all their data when activated again.", comment: "") } - + let alertController = UIAlertController(title: NSLocalizedString("What are inactive apps?", comment: ""), message: message, preferredStyle: .alert) alertController.addAction(.ok) - self.present(alertController, animated: true, completion: nil) + present(alertController, animated: true, completion: nil) } - - func updateCell(at indexPath: IndexPath) - { + + func updateCell(at indexPath: IndexPath) { guard let cell = collectionView.cellForItem(at: indexPath) as? InstalledAppCollectionViewCell else { return } - - let installedApp = self.dataSource.item(at: indexPath) - self.dataSource.cellConfigurationHandler(cell, installedApp, indexPath) - + + let installedApp = dataSource.item(at: indexPath) + dataSource.cellConfigurationHandler(cell, installedApp, indexPath) + cell.bannerView.iconImageView.isIndicatingActivity = false } - - func removeAppExtensions(from application: ALTApplication, completion: @escaping (Result) -> Void) - { + + func removeAppExtensions(from application: ALTApplication, completion: @escaping (Result) -> Void) { guard !application.appExtensions.isEmpty else { return completion(.success(())) } - + let firstSentence: String - - if UserDefaults.standard.activeAppLimitIncludesExtensions - { + + if UserDefaults.standard.activeAppLimitIncludesExtensions { firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to 3 active apps and app extensions.", comment: "") - } - else - { + } else { firstSentence = NSLocalizedString("Non-developer Apple IDs are limited to creating 10 App IDs per week.", comment: "") } - + let message = firstSentence + " " + NSLocalizedString("Would you like to remove this app's extensions so they don't count towards your limit?", comment: "") - + let alertController = UIAlertController(title: NSLocalizedString("App Contains Extensions", comment: ""), message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { (action) in + alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: { _ in completion(.failure(OperationError.cancelled)) })) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions", comment: ""), style: .default) { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Keep App Extensions", comment: ""), style: .default) { _ in completion(.success(())) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { (action) in - do - { - for appExtension in application.appExtensions - { + alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove App Extensions", comment: ""), style: .destructive) { _ in + do { + for appExtension in application.appExtensions { try FileManager.default.removeItem(at: appExtension.fileURL) } - + completion(.success(())) - } - catch - { + } catch { completion(.failure(error)) } }) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } } -private extension MyAppsViewController -{ - func open(_ installedApp: InstalledApp) - { +private extension MyAppsViewController { + func open(_ installedApp: InstalledApp) { UIApplication.shared.open(installedApp.openAppURL) { success in guard !success else { return } - + let toastView = ToastView(error: OperationError.openAppFailed(name: installedApp.name)) toastView.show(in: self) } } - - func refresh(_ installedApp: InstalledApp) - { + + func refresh(_ installedApp: InstalledApp) { let previousProgress = AppManager.shared.refreshProgress(for: installedApp) guard previousProgress == nil else { previousProgress?.cancel() return } - - self.refresh([installedApp]) { (results) in + + refresh([installedApp]) { results in // If an error occured, reload the section so the progress bar is no longer visible. - if results.values.contains(where: { $0.error != nil }) - { + if results.values.contains(where: { $0.error != nil }) { DispatchQueue.main.async { self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue]) } } - + print("Finished refreshing with results:", results.map { ($0, $1.error?.localizedDescription ?? "success") }) } } - - func activate(_ installedApp: InstalledApp) - { - func finish(_ result: Result) - { - do - { + + func activate(_ installedApp: InstalledApp) { + func finish(_ result: Result) { + do { let app = try result.get() app.managedObjectContext?.perform { try? app.managedObjectContext?.save() } - } - catch OperationError.cancelled - { + } catch OperationError.cancelled { // Ignore - } - catch - { + } catch { print("Failed to activate app:", error) - + DispatchQueue.main.async { installedApp.isActive = false - + let toastView = ToastView(error: error) toastView.show(in: self) } } } - - if UserDefaults.standard.activeAppsLimit != nil, #available(iOS 13, *) - { + + if UserDefaults.standard.activeAppsLimit != nil, #available(iOS 13, *) { // UserDefaults.standard.activeAppsLimit is only non-nil on iOS 13.3.1 or later, so the #available check is just so we can use Combine. - + guard let app = ALTApplication(fileURL: installedApp.fileURL) else { return finish(.failure(OperationError.invalidApp)) } - + var cancellable: AnyCancellable? cancellable = DatabaseManager.shared.viewContext.registeredObjects.publisher .compactMap { $0 as? InstalledApp } @@ -1084,81 +947,69 @@ private extension MyAppsViewController installedApp.isActive = true cancellable?.cancel() } - + AppManager.shared.deactivateApps(for: app, presentingViewController: self) { result in cancellable?.cancel() installedApp.managedObjectContext?.perform { - switch result - { - case .failure(let error): + switch result { + case let .failure(error): installedApp.isActive = false finish(.failure(error)) - + case .success: installedApp.isActive = true AppManager.shared.activate(installedApp, presentingViewController: self, completionHandler: finish(_:)) } } } - } - else - { + } else { installedApp.isActive = true AppManager.shared.activate(installedApp, presentingViewController: self, completionHandler: finish(_:)) } } - - func deactivate(_ installedApp: InstalledApp, completionHandler: ((Result) -> Void)? = nil) - { + + func deactivate(_ installedApp: InstalledApp, completionHandler: ((Result) -> Void)? = nil) { guard installedApp.isActive else { return } installedApp.isActive = false - - AppManager.shared.deactivate(installedApp, presentingViewController: self) { (result) in - do - { + + AppManager.shared.deactivate(installedApp, presentingViewController: self) { result in + do { let app = try result.get() try? app.managedObjectContext?.save() - + print("Finished deactivating app:", app.bundleIdentifier) - } - catch - { + } catch { print("Failed to activate app:", error) - + DispatchQueue.main.async { installedApp.isActive = true - + let toastView = ToastView(error: error) toastView.show(in: self) } } - + completionHandler?(result) } } - - func remove(_ installedApp: InstalledApp) - { + + func remove(_ installedApp: InstalledApp) { let title = String(format: NSLocalizedString("Remove “%@” from SideStore?", comment: ""), installedApp.name) let message: String - - if UserDefaults.standard.isLegacyDeactivationSupported - { + + if UserDefaults.standard.isLegacyDeactivationSupported { message = NSLocalizedString("You must also delete it from the home screen to fully uninstall the app.", comment: "") - } - else - { + } else { message = NSLocalizedString("This will also erase all backup data for this app.", comment: "") } let alertController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet) alertController.addAction(.cancel) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove", comment: ""), style: .destructive, handler: { (action) in - AppManager.shared.remove(installedApp) { (result) in - switch result - { + alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove", comment: ""), style: .destructive, handler: { _ in + AppManager.shared.remove(installedApp) { result in + switch result { case .success: break - case .failure(let error): + case let .failure(error): DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) @@ -1166,140 +1017,122 @@ private extension MyAppsViewController } } })) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } - - func backup(_ installedApp: InstalledApp) - { + + func backup(_ installedApp: InstalledApp) { let title = NSLocalizedString("Start Backup?", comment: "") let message = NSLocalizedString("This will replace any previous backups. Please leave SideStore open until the backup is complete.", comment: "") let alertController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet) alertController.addAction(.cancel) - + let actionTitle = String(format: NSLocalizedString("Back Up %@", comment: ""), installedApp.name) - alertController.addAction(UIAlertAction(title: actionTitle, style: .default, handler: { (action) in - AppManager.shared.backup(installedApp, presentingViewController: self) { (result) in - do - { + alertController.addAction(UIAlertAction(title: actionTitle, style: .default, handler: { _ in + AppManager.shared.backup(installedApp, presentingViewController: self) { result in + do { let app = try result.get() try? app.managedObjectContext?.save() - + print("Finished backing up app:", app.bundleIdentifier) - } - catch - { + } catch { print("Failed to back up app:", error) - + DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) - + self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue]) } } } - + DispatchQueue.main.async { self.collectionView.reloadSections([Section.activeApps.rawValue, Section.inactiveApps.rawValue]) } })) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } - - func restore(_ installedApp: InstalledApp) - { + + func restore(_ installedApp: InstalledApp) { let message = String(format: NSLocalizedString("This will replace all data you currently have in %@.", comment: ""), installedApp.name) let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to restore this backup?", comment: ""), message: message, preferredStyle: .actionSheet) alertController.addAction(.cancel) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Restore Backup", comment: ""), style: .destructive, handler: { (action) in - AppManager.shared.restore(installedApp, presentingViewController: self) { (result) in - do - { + alertController.addAction(UIAlertAction(title: NSLocalizedString("Restore Backup", comment: ""), style: .destructive, handler: { _ in + AppManager.shared.restore(installedApp, presentingViewController: self) { result in + do { let app = try result.get() try? app.managedObjectContext?.save() - + print("Finished restoring app:", app.bundleIdentifier) - } - catch - { + } catch { print("Failed to restore app:", error) - + DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) } } } - + DispatchQueue.main.async { self.collectionView.reloadSections([Section.activeApps.rawValue]) } })) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } - - func exportBackup(for installedApp: InstalledApp) - { + + func exportBackup(for installedApp: InstalledApp) { guard let backupURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return } - + let documentPicker = UIDocumentPickerViewController(url: backupURL, in: .exportToService) documentPicker.delegate = self - self.present(documentPicker, animated: true, completion: nil) + present(documentPicker, animated: true, completion: nil) } - - func chooseIcon(for installedApp: InstalledApp) - { - self._imagePickerInstalledApp = installedApp - + + func chooseIcon(for installedApp: InstalledApp) { + _imagePickerInstalledApp = installedApp + let imagePicker = UIImagePickerController() imagePicker.delegate = self imagePicker.allowsEditing = true - self.present(imagePicker, animated: true, completion: nil) + present(imagePicker, animated: true, completion: nil) } - - func changeIcon(for installedApp: InstalledApp, to image: UIImage?) - { + + func changeIcon(for installedApp: InstalledApp, to image: UIImage?) { // Remove previous icon from cache. - self.activeAppsDataSource.prefetchItemCache.removeObject(forKey: installedApp) - self.inactiveAppsDataSource.prefetchItemCache.removeObject(forKey: installedApp) - - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in - do - { + activeAppsDataSource.prefetchItemCache.removeObject(forKey: installedApp) + inactiveAppsDataSource.prefetchItemCache.removeObject(forKey: installedApp) + + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + do { let tempApp = context.object(with: installedApp.objectID) as! InstalledApp tempApp.needsResign = true tempApp.hasAlternateIcon = (image != nil) - - if let image = image - { + + if let image = image { guard let icon = image.resizing(toFill: CGSize(width: 256, height: 256)), let iconData = icon.pngData() else { return } - + try iconData.write(to: tempApp.alternateIconURL, options: .atomic) - } - else - { + } else { try FileManager.default.removeItem(at: tempApp.alternateIconURL) } - + try context.save() - - if tempApp.isActive - { + + if tempApp.isActive { DispatchQueue.main.async { self.refresh(installedApp) } } - } - catch - { + } catch { print("Failed to change app icon.", error) - + DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) @@ -1307,16 +1140,14 @@ private extension MyAppsViewController } } } - + @available(iOS 14, *) - func enableJIT(for installedApp: InstalledApp) - { + func enableJIT(for installedApp: InstalledApp) { AppManager.shared.enableJIT(for: installedApp) { result in DispatchQueue.main.async { - switch result - { + switch result { case .success: break - case .failure(let error): + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) } @@ -1325,565 +1156,492 @@ private extension MyAppsViewController } } -private extension MyAppsViewController -{ - @objc func didFetchSource(_ notification: Notification) - { +private extension MyAppsViewController { + @objc func didFetchSource(_: Notification) { DispatchQueue.main.async { - if self.updatesDataSource.fetchedResultsController.fetchedObjects == nil - { - do { try self.updatesDataSource.fetchedResultsController.performFetch() } - catch { print("Error fetching:", error) } + if self.updatesDataSource.fetchedResultsController.fetchedObjects == nil { + do { try self.updatesDataSource.fetchedResultsController.performFetch() } catch { print("Error fetching:", error) } } - + self.update() } } - - @objc func importApp(_ notification: Notification) - { + + @objc func importApp(_ notification: Notification) { // Make sure left UIBarButtonItem has been set. - self.loadViewIfNeeded() - + loadViewIfNeeded() + guard let url = notification.userInfo?[AppDelegate.importAppDeepLinkURLKey] as? URL else { return } - - self.sideloadApp(at: url) { (result) in + + sideloadApp(at: url) { _ in guard url.isFileURL else { return } - - do - { + + do { try FileManager.default.removeItem(at: url) - } - catch - { + } catch { print("Unable to remove imported .ipa.", error) } } } } -extension MyAppsViewController -{ - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { +extension MyAppsViewController { + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let section = Section(rawValue: indexPath.section)! - - switch section - { + + switch section { case .noUpdates: return UICollectionReusableView() case .updates: let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "UpdatesHeader", for: indexPath) as! UpdatesCollectionHeaderView - + UIView.performWithoutAnimation { headerView.button.backgroundColor = UIColor.altPrimary.withAlphaComponent(0.15) headerView.button.setTitle("▾", for: .normal) headerView.button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 28) headerView.button.setTitleColor(.altPrimary, for: .normal) headerView.button.addTarget(self, action: #selector(MyAppsViewController.toggleAppUpdates), for: .primaryActionTriggered) - - if self.isUpdateSectionCollapsed - { + + if self.isUpdateSectionCollapsed { headerView.button.titleLabel?.transform = .identity - } - else - { + } else { headerView.button.titleLabel?.transform = CGAffineTransform.identity.rotated(by: .pi) } - + headerView.isHidden = (self.updatesDataSource.itemCount <= 2) - + headerView.button.layoutIfNeeded() } - + return headerView - + case .activeApps where kind == UICollectionView.elementKindSectionHeader: let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "ActiveAppsHeader", for: indexPath) as! InstalledAppsCollectionHeaderView - + UIView.performWithoutAnimation { headerView.layoutMargins.left = self.view.layoutMargins.left headerView.layoutMargins.right = self.view.layoutMargins.right - - if UserDefaults.standard.activeAppsLimit == nil - { + + if UserDefaults.standard.activeAppsLimit == nil { headerView.textLabel.text = NSLocalizedString("Installed", comment: "") - } - else - { + } else { headerView.textLabel.text = NSLocalizedString("Active", comment: "") } - + headerView.button.isIndicatingActivity = false headerView.button.activityIndicatorView.color = .altPrimary headerView.button.setTitle(NSLocalizedString("Refresh All", comment: ""), for: .normal) headerView.button.addTarget(self, action: #selector(MyAppsViewController.refreshAllApps(_:)), for: .primaryActionTriggered) - + headerView.button.layoutIfNeeded() - - if self.isRefreshingAllApps - { + + if self.isRefreshingAllApps { headerView.button.isIndicatingActivity = true headerView.button.accessibilityLabel = NSLocalizedString("Refreshing", comment: "") headerView.button.accessibilityTraits.remove(.notEnabled) - } - else - { + } else { headerView.button.isIndicatingActivity = false headerView.button.accessibilityLabel = nil } } - + return headerView - + case .inactiveApps where kind == UICollectionView.elementKindSectionHeader: let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "InactiveAppsHeader", for: indexPath) as! InstalledAppsCollectionHeaderView - + UIView.performWithoutAnimation { headerView.layoutMargins.left = self.view.layoutMargins.left headerView.layoutMargins.right = self.view.layoutMargins.right - + headerView.textLabel.text = NSLocalizedString("Inactive", comment: "") headerView.button.setTitle(nil, for: .normal) - - if #available(iOS 13.0, *) - { + + if #available(iOS 13.0, *) { headerView.button.setImage(UIImage(systemName: "questionmark.circle"), for: .normal) } - + headerView.button.addTarget(self, action: #selector(MyAppsViewController.presentInactiveAppsAlert), for: .primaryActionTriggered) } - + return headerView - + case .activeApps, .inactiveApps: let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "InstalledAppsFooter", for: indexPath) as! InstalledAppsCollectionFooterView - + guard let team = DatabaseManager.shared.activeTeam() else { return footerView } - switch team.type - { + switch team.type { case .free: let registeredAppIDs = team.appIDs.count - + let maximumAppIDCount = 10 let remainingAppIDs = max(maximumAppIDCount - registeredAppIDs, 0) - - if remainingAppIDs == 1 - { + + if remainingAppIDs == 1 { footerView.textLabel.text = String(format: NSLocalizedString("1 App ID Remaining", comment: "")) - } - else - { + } else { footerView.textLabel.text = String(format: NSLocalizedString("%@ App IDs Remaining", comment: ""), NSNumber(value: remainingAppIDs)) } - + footerView.textLabel.isHidden = false - + case .individual, .organization, .unknown: footerView.textLabel.isHidden = true @unknown default: break } - + return footerView } } - - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) - { + + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let section = Section.allCases[indexPath.section] - switch section - { + switch section { case .updates: guard let cell = collectionView.cellForItem(at: indexPath) else { break } - self.performSegue(withIdentifier: "showUpdate", sender: cell) - + performSegue(withIdentifier: "showUpdate", sender: cell) + default: break } } } @available(iOS 13.0, *) -extension MyAppsViewController -{ - private func actions(for installedApp: InstalledApp) -> [UIMenuElement] - { +extension MyAppsViewController { + private func actions(for installedApp: InstalledApp) -> [UIMenuElement] { var actions = [UIMenuElement]() - - let openAction = UIAction(title: NSLocalizedString("Open", comment: ""), image: UIImage(systemName: "arrow.up.forward.app")) { (action) in + + let openAction = UIAction(title: NSLocalizedString("Open", comment: ""), image: UIImage(systemName: "arrow.up.forward.app")) { _ in self.open(installedApp) } - + let openMenu = UIMenu(title: "", options: .displayInline, children: [openAction]) - - let refreshAction = UIAction(title: NSLocalizedString("Refresh", comment: ""), image: UIImage(systemName: "arrow.clockwise")) { (action) in + + let refreshAction = UIAction(title: NSLocalizedString("Refresh", comment: ""), image: UIImage(systemName: "arrow.clockwise")) { _ in self.refresh(installedApp) } - - let activateAction = UIAction(title: NSLocalizedString("Activate", comment: ""), image: UIImage(systemName: "checkmark.circle")) { (action) in + + let activateAction = UIAction(title: NSLocalizedString("Activate", comment: ""), image: UIImage(systemName: "checkmark.circle")) { _ in self.activate(installedApp) } - - let deactivateAction = UIAction(title: NSLocalizedString("Deactivate", comment: ""), image: UIImage(systemName: "xmark.circle"), attributes: .destructive) { (action) in + + let deactivateAction = UIAction(title: NSLocalizedString("Deactivate", comment: ""), image: UIImage(systemName: "xmark.circle"), attributes: .destructive) { _ in self.deactivate(installedApp) } - - let removeAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { (action) in + + let removeAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { _ in self.remove(installedApp) } - - let jitAction = UIAction(title: NSLocalizedString("Enable JIT", comment: ""), image: UIImage(systemName: "bolt")) { (action) in + + let jitAction = UIAction(title: NSLocalizedString("Enable JIT", comment: ""), image: UIImage(systemName: "bolt")) { _ in guard #available(iOS 14, *) else { return } self.enableJIT(for: installedApp) } - - let backupAction = UIAction(title: NSLocalizedString("Back Up", comment: ""), image: UIImage(systemName: "doc.on.doc")) { (action) in + + let backupAction = UIAction(title: NSLocalizedString("Back Up", comment: ""), image: UIImage(systemName: "doc.on.doc")) { _ in self.backup(installedApp) } - - let exportBackupAction = UIAction(title: NSLocalizedString("Export Backup", comment: ""), image: UIImage(systemName: "arrow.up.doc")) { (action) in + + let exportBackupAction = UIAction(title: NSLocalizedString("Export Backup", comment: ""), image: UIImage(systemName: "arrow.up.doc")) { _ in self.exportBackup(for: installedApp) } - - let restoreBackupAction = UIAction(title: NSLocalizedString("Restore Backup", comment: ""), image: UIImage(systemName: "arrow.down.doc")) { (action) in + + let restoreBackupAction = UIAction(title: NSLocalizedString("Restore Backup", comment: ""), image: UIImage(systemName: "arrow.down.doc")) { _ in self.restore(installedApp) } - - let chooseIconAction = UIAction(title: NSLocalizedString("Photos", comment: ""), image: UIImage(systemName: "photo")) { (action) in + + let chooseIconAction = UIAction(title: NSLocalizedString("Photos", comment: ""), image: UIImage(systemName: "photo")) { _ in self.chooseIcon(for: installedApp) } - - let removeIconAction = UIAction(title: NSLocalizedString("Remove Custom Icon", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { (action) in + + let removeIconAction = UIAction(title: NSLocalizedString("Remove Custom Icon", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { _ in self.changeIcon(for: installedApp, to: nil) } - + var changeIconActions = [chooseIconAction] - if installedApp.hasAlternateIcon - { + if installedApp.hasAlternateIcon { changeIconActions.append(removeIconAction) } - + let changeIconMenu = UIMenu(title: NSLocalizedString("Change Icon", comment: ""), image: UIImage(systemName: "photo"), children: changeIconActions) - + guard installedApp.bundleIdentifier != StoreApp.altstoreAppID else { #if BETA - return [refreshAction, changeIconMenu] + return [refreshAction, changeIconMenu] #else - return [refreshAction] + return [refreshAction] #endif } - - if installedApp.isActive - { + + if installedApp.isActive { actions.append(openMenu) actions.append(refreshAction) - } - else - { + } else { actions.append(activateAction) } - - if installedApp.isActive, #available(iOS 14, *) - { + + if installedApp.isActive, #available(iOS 14, *) { actions.append(jitAction) } - + #if BETA - actions.append(changeIconMenu) + actions.append(changeIconMenu) #endif - - if installedApp.isActive - { + + if installedApp.isActive { actions.append(backupAction) - } - else if let _ = UTTypeCopyDeclaration(installedApp.installedAppUTI as CFString)?.takeRetainedValue() as NSDictionary?, !UserDefaults.standard.isLegacyDeactivationSupported - { + } else if let _ = UTTypeCopyDeclaration(installedApp.installedAppUTI as CFString)?.takeRetainedValue() as NSDictionary?, !UserDefaults.standard.isLegacyDeactivationSupported { // Allow backing up inactive apps if they are still installed, // but on an iOS version that no longer supports legacy deactivation. // This handles edge case where you can't install more apps until you // delete some, but can't activate inactive apps again to back them up first. actions.append(backupAction) } - - if let backupDirectoryURL = FileManager.default.backupDirectoryURL(for: installedApp) - { + + if let backupDirectoryURL = FileManager.default.backupDirectoryURL(for: installedApp) { var backupExists = false - var outError: NSError? = nil - - self.coordinator.coordinate(readingItemAt: backupDirectoryURL, options: [.withoutChanges], error: &outError) { (backupDirectoryURL) in + var outError: NSError? + + coordinator.coordinate(readingItemAt: backupDirectoryURL, options: [.withoutChanges], error: &outError) { backupDirectoryURL in #if DEBUG - backupExists = true + backupExists = true #else - backupExists = FileManager.default.fileExists(atPath: backupDirectoryURL.path) + backupExists = FileManager.default.fileExists(atPath: backupDirectoryURL.path) #endif } - - if backupExists - { + + if backupExists { actions.append(exportBackupAction) - - if installedApp.isActive - { + + if installedApp.isActive { actions.append(restoreBackupAction) } - } - else if let error = outError - { + } else if let error = outError { print("Unable to check if backup exists:", error) } } - - if installedApp.isActive - { + + if installedApp.isActive { actions.append(deactivateAction) } - + #if DEBUG - - if installedApp.bundleIdentifier != StoreApp.altstoreAppID - { - actions.append(removeAction) - } - + + if installedApp.bundleIdentifier != StoreApp.altstoreAppID { + actions.append(removeAction) + } + #else - - if (UserDefaults.standard.legacySideloadedApps ?? []).contains(installedApp.bundleIdentifier) - { - // Legacy sideloaded app, so can't detect if it's deleted. - actions.append(removeAction) - } - else if !UserDefaults.standard.isLegacyDeactivationSupported && !installedApp.isActive - { - // Inactive apps are actually deleted, so we need another way - // for user to remove them from AltStore. - actions.append(removeAction) - } - + + if (UserDefaults.standard.legacySideloadedApps ?? []).contains(installedApp.bundleIdentifier) { + // Legacy sideloaded app, so can't detect if it's deleted. + actions.append(removeAction) + } else if !UserDefaults.standard.isLegacyDeactivationSupported, !installedApp.isActive { + // Inactive apps are actually deleted, so we need another way + // for user to remove them from AltStore. + actions.append(removeAction) + } + #endif - + return actions } - - override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? + + override func collectionView(_: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point _: CGPoint) -> UIContextMenuConfiguration? { let section = Section(rawValue: indexPath.section)! - switch section - { + switch section { case .updates, .noUpdates: return nil case .activeApps, .inactiveApps: - let installedApp = self.dataSource.item(at: indexPath) - - return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { (suggestedActions) -> UIMenu? in + let installedApp = dataSource.item(at: indexPath) + + return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { _ -> UIMenu? in let actions = self.actions(for: installedApp) - + let menu = UIMenu(title: "", children: actions) return menu } } } - - override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? - { + + override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { guard let indexPath = configuration.identifier as? NSIndexPath else { return nil } guard let cell = collectionView.cellForItem(at: indexPath as IndexPath) as? InstalledAppCollectionViewCell else { return nil } - + let parameters = UIPreviewParameters() parameters.backgroundColor = .clear parameters.visiblePath = UIBezierPath(roundedRect: cell.bannerView.bounds, cornerRadius: cell.bannerView.layer.cornerRadius) - + let preview = UITargetedPreview(view: cell.bannerView, parameters: parameters) return preview } - - override func collectionView(_ collectionView: UICollectionView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? - { - return self.collectionView(collectionView, previewForHighlightingContextMenuWithConfiguration: configuration) + + override func collectionView(_ collectionView: UICollectionView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + self.collectionView(collectionView, previewForHighlightingContextMenuWithConfiguration: configuration) } } -extension MyAppsViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { +extension MyAppsViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let section = Section.allCases[indexPath.section] - switch section - { + switch section { case .noUpdates: let size = CGSize(width: collectionView.bounds.width, height: 44) return size - + case .updates: - let item = self.dataSource.item(at: indexPath) - - if let previousHeight = self.cachedUpdateSizes[item.bundleIdentifier] - { + let item = dataSource.item(at: indexPath) + + if let previousHeight = cachedUpdateSizes[item.bundleIdentifier] { return previousHeight } - + // Manually change cell's width to prevent conflicting with UIView-Encapsulated-Layout-Width constraints. - self.prototypeUpdateCell.frame.size.width = collectionView.bounds.width - - let widthConstraint = self.prototypeUpdateCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) + prototypeUpdateCell.frame.size.width = collectionView.bounds.width + + let widthConstraint = prototypeUpdateCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } - - self.dataSource.cellConfigurationHandler(self.prototypeUpdateCell, item, indexPath) - - let size = self.prototypeUpdateCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - self.cachedUpdateSizes[item.bundleIdentifier] = size + + dataSource.cellConfigurationHandler(prototypeUpdateCell, item, indexPath) + + let size = prototypeUpdateCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + cachedUpdateSizes[item.bundleIdentifier] = size return size case .activeApps, .inactiveApps: return CGSize(width: collectionView.bounds.width, height: 88) } } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize - { + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { let section = Section.allCases[section] - switch section - { + switch section { case .noUpdates: return .zero case .updates: - let height: CGFloat = self.updatesDataSource.itemCount > maximumCollapsedUpdatesCount ? 26 : 0 + let height: CGFloat = updatesDataSource.itemCount > maximumCollapsedUpdatesCount ? 26 : 0 return CGSize(width: collectionView.bounds.width, height: height) - + case .activeApps: return CGSize(width: collectionView.bounds.width, height: 29) - case .inactiveApps where self.inactiveAppsDataSource.itemCount == 0: return .zero + case .inactiveApps where inactiveAppsDataSource.itemCount == 0: return .zero case .inactiveApps: return CGSize(width: collectionView.bounds.width, height: 29) } } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize - { + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { let section = Section.allCases[section] - - func appIDsFooterSize() -> CGSize - { + + func appIDsFooterSize() -> CGSize { guard let _ = DatabaseManager.shared.activeTeam() else { return .zero } - + let indexPath = IndexPath(row: 0, section: section.rawValue) let footerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: indexPath) as! InstalledAppsCollectionFooterView - + let size = footerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) return size } - - switch section - { + + switch section { case .noUpdates: return .zero case .updates: return .zero - - case .activeApps where self.inactiveAppsDataSource.itemCount == 0: return appIDsFooterSize() + + case .activeApps where inactiveAppsDataSource.itemCount == 0: return appIDsFooterSize() case .activeApps: return .zero - - case .inactiveApps where self.inactiveAppsDataSource.itemCount == 0: return .zero + + case .inactiveApps where inactiveAppsDataSource.itemCount == 0: return .zero case .inactiveApps: return appIDsFooterSize() } } - - func collectionView(_ myCV: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets - { + + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { let section = Section.allCases[section] - switch section - { - case .noUpdates where self.updatesDataSource.itemCount != 0: return .zero - case .updates where self.updatesDataSource.itemCount == 0: return .zero + switch section { + case .noUpdates where updatesDataSource.itemCount != 0: return .zero + case .updates where updatesDataSource.itemCount == 0: return .zero default: return UIEdgeInsets(top: 12, left: 0, bottom: 20, right: 0) } } } -extension MyAppsViewController: UICollectionViewDragDelegate -{ - func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] - { - switch Section(rawValue: indexPath.section)! - { +extension MyAppsViewController: UICollectionViewDragDelegate { + func collectionView(_ collectionView: UICollectionView, itemsForBeginning _: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { + switch Section(rawValue: indexPath.section)! { case .updates, .noUpdates: return [] - + case .activeApps, .inactiveApps: guard UserDefaults.standard.activeAppsLimit != nil else { return [] } guard let cell = collectionView.cellForItem(at: indexPath as IndexPath) as? InstalledAppCollectionViewCell else { return [] } - - let item = self.dataSource.item(at: indexPath) + + let item = dataSource.item(at: indexPath) guard item.bundleIdentifier != StoreApp.altstoreAppID else { return [] } - + let dragItem = UIDragItem(itemProvider: NSItemProvider(item: nil, typeIdentifier: nil)) dragItem.localObject = item dragItem.previewProvider = { let parameters = UIDragPreviewParameters() parameters.backgroundColor = .clear parameters.visiblePath = UIBezierPath(roundedRect: cell.bannerView.iconImageView.bounds, cornerRadius: cell.bannerView.iconImageView.layer.cornerRadius) - + let preview = UIDragPreview(view: cell.bannerView.iconImageView, parameters: parameters) return preview } - + return [dragItem] } } - - func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? - { + + func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters? { guard let cell = collectionView.cellForItem(at: indexPath as IndexPath) as? InstalledAppCollectionViewCell else { return nil } - + let parameters = UIDragPreviewParameters() parameters.backgroundColor = .clear parameters.visiblePath = UIBezierPath(roundedRect: cell.bannerView.frame, cornerRadius: cell.bannerView.layer.cornerRadius) - + return parameters } - - func collectionView(_ collectionView: UICollectionView, dragSessionDidEnd session: UIDragSession) - { - let previousDestinationIndexPath = self.dropDestinationIndexPath - self.dropDestinationIndexPath = nil - - if let indexPath = previousDestinationIndexPath - { + + func collectionView(_: UICollectionView, dragSessionDidEnd _: UIDragSession) { + let previousDestinationIndexPath = dropDestinationIndexPath + dropDestinationIndexPath = nil + + if let indexPath = previousDestinationIndexPath { // Access cell directly to prevent UI glitches due to race conditions when refreshing - self.updateCell(at: indexPath) + updateCell(at: indexPath) } } } -extension MyAppsViewController: UICollectionViewDropDelegate -{ - func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool - { - return session.localDragSession != nil +extension MyAppsViewController: UICollectionViewDropDelegate { + func collectionView(_: UICollectionView, canHandle session: UIDropSession) -> Bool { + session.localDragSession != nil } - - func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal - { + + func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath _: IndexPath?) -> UICollectionViewDropProposal { guard let activeAppsLimit = UserDefaults.standard.activeAppsLimit, let installedApp = session.items.first?.localObject as? InstalledApp else { return UICollectionViewDropProposal(operation: .cancel) } - + // Retrieve header attributes for location calculations. guard let activeAppsHeaderAttributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: Section.activeApps.rawValue)), let inactiveAppsHeaderAttributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: Section.inactiveApps.rawValue)) else { return UICollectionViewDropProposal(operation: .cancel) } - - var dropDestinationIndexPath: IndexPath? = nil - - defer - { + + var dropDestinationIndexPath: IndexPath? + + defer { // Animate selection changes. - - if dropDestinationIndexPath != self.dropDestinationIndexPath - { + + if dropDestinationIndexPath != self.dropDestinationIndexPath { let previousIndexPath = self.dropDestinationIndexPath self.dropDestinationIndexPath = dropDestinationIndexPath - + let indexPaths = [previousIndexPath, dropDestinationIndexPath].compactMap { $0 } - + let propertyAnimator = UIViewPropertyAnimator(springTimingParameters: UISpringTimingParameters()) { - for indexPath in indexPaths - { + for indexPath in indexPaths { // Access cell directly so we can animate it correctly. self.updateCell(at: indexPath) } @@ -1891,106 +1649,89 @@ extension MyAppsViewController: UICollectionViewDropDelegate propertyAnimator.startAnimation() } } - + let point = session.location(in: collectionView) - - if installedApp.isActive - { + + if installedApp.isActive { // Deactivating - - if point.y > inactiveAppsHeaderAttributes.frame.minY - { + + if point.y > inactiveAppsHeaderAttributes.frame.minY { // Inactive apps section. return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath) - } - else if point.y > activeAppsHeaderAttributes.frame.minY - { + } else if point.y > activeAppsHeaderAttributes.frame.minY { // Active apps section. return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) - } - else - { + } else { return UICollectionViewDropProposal(operation: .cancel) } - } - else - { + } else { // Activating - + guard point.y > activeAppsHeaderAttributes.frame.minY else { // Above active apps section. return UICollectionViewDropProposal(operation: .cancel) } - + guard point.y < inactiveAppsHeaderAttributes.frame.minY else { // Inactive apps section. return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } - - let activeAppsCount = (self.activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.requiredActiveSlots }.reduce(0, +) + + let activeAppsCount = (activeAppsDataSource.fetchedResultsController.fetchedObjects ?? []).map { $0.requiredActiveSlots }.reduce(0, +) let availableActiveApps = max(activeAppsLimit - activeAppsCount, 0) - - if installedApp.requiredActiveSlots <= availableActiveApps - { + + if installedApp.requiredActiveSlots <= availableActiveApps { // Enough active app slots, so no need to deactivate app first. return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath) - } - else - { + } else { // Not enough active app slots, so we need to deactivate an app. - + // Provided destinationIndexPath is inaccurate. guard let indexPath = collectionView.indexPathForItem(at: point), indexPath.section == Section.activeApps.rawValue else { // Invalid destination index path. return UICollectionViewDropProposal(operation: .cancel) } - - let installedApp = self.dataSource.item(at: indexPath) + + let installedApp = dataSource.item(at: indexPath) guard installedApp.bundleIdentifier != StoreApp.altstoreAppID else { // Can't deactivate AltStore. return UICollectionViewDropProposal(operation: .forbidden, intent: .insertIntoDestinationIndexPath) } - + // This app can be deactivated! dropDestinationIndexPath = indexPath return UICollectionViewDropProposal(operation: .move, intent: .insertIntoDestinationIndexPath) } } } - - func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) - { + + func collectionView(_: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { guard let installedApp = coordinator.session.items.first?.localObject as? InstalledApp else { return } guard let destinationIndexPath = coordinator.destinationIndexPath else { return } - - if installedApp.isActive - { + + if installedApp.isActive { guard destinationIndexPath.section == Section.inactiveApps.rawValue else { return } - self.deactivate(installedApp) - } - else - { + deactivate(installedApp) + } else { guard destinationIndexPath.section == Section.activeApps.rawValue else { return } - - switch coordinator.proposal.intent - { + + switch coordinator.proposal.intent { case .insertIntoDestinationIndexPath: installedApp.isActive = true - - let previousInstalledApp = self.dataSource.item(at: destinationIndexPath) - self.deactivate(previousInstalledApp) { (result) in + + let previousInstalledApp = dataSource.item(at: destinationIndexPath) + deactivate(previousInstalledApp) { result in installedApp.managedObjectContext?.perform { - switch result - { + switch result { case .failure: installedApp.isActive = false case .success: self.activate(installedApp) } } } - + case .insertAtDestinationIndexPath: - self.activate(installedApp) - + activate(installedApp) + case .unspecified: break @unknown default: break } @@ -1998,121 +1739,103 @@ extension MyAppsViewController: UICollectionViewDropDelegate } } -extension MyAppsViewController: NSFetchedResultsControllerDelegate -{ - func controllerWillChangeContent(_ controller: NSFetchedResultsController) - { +extension MyAppsViewController: NSFetchedResultsControllerDelegate { + func controllerWillChangeContent(_ controller: NSFetchedResultsController) { // Responding to NSFetchedResultsController updates before the collection view has // been shown may throw exceptions because the collection view cannot accurately // count the number of items before the update. However, if we manually call // performBatchUpdates _before_ responding to updates, the collection view can get // an accurate pre-update item count. - self.collectionView.performBatchUpdates(nil, completion: nil) - - self.updatesDataSource.controllerWillChangeContent(controller) + collectionView.performBatchUpdates(nil, completion: nil) + + updatesDataSource.controllerWillChangeContent(controller) } - - func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) - { - self.updatesDataSource.controller(controller, didChange: sectionInfo, atSectionIndex: UInt(sectionIndex), for: type) + + func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { + updatesDataSource.controller(controller, didChange: sectionInfo, atSectionIndex: UInt(sectionIndex), for: type) } - - func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) - { - self.updatesDataSource.controller(controller, didChange: anObject, at: indexPath, for: type, newIndexPath: newIndexPath) + + func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { + updatesDataSource.controller(controller, didChange: anObject, at: indexPath, for: type, newIndexPath: newIndexPath) } - - func controllerDidChangeContent(_ controller: NSFetchedResultsController) - { - let previousUpdateCount = self.collectionView.numberOfItems(inSection: Section.updates.rawValue) - let updateCount = Int(self.updatesDataSource.itemCount) - - if previousUpdateCount == 0 && updateCount > 0 - { + + func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + let previousUpdateCount = collectionView.numberOfItems(inSection: Section.updates.rawValue) + let updateCount = Int(updatesDataSource.itemCount) + + if previousUpdateCount == 0 && updateCount > 0 { // Remove "No Updates Available" cell. let change = RSTCellContentChange(type: .delete, currentIndexPath: IndexPath(item: 0, section: Section.noUpdates.rawValue), destinationIndexPath: nil) - self.collectionView.add(change) - } - else if previousUpdateCount > 0 && updateCount == 0 - { + collectionView.add(change) + } else if previousUpdateCount > 0 && updateCount == 0 { // Insert "No Updates Available" cell. let change = RSTCellContentChange(type: .insert, currentIndexPath: nil, destinationIndexPath: IndexPath(item: 0, section: Section.noUpdates.rawValue)) - self.collectionView.add(change) + collectionView.add(change) } - - self.updatesDataSource.controllerDidChangeContent(controller) + + updatesDataSource.controllerDidChangeContent(controller) } } -extension MyAppsViewController: UIDocumentPickerDelegate -{ - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) - { +extension MyAppsViewController: UIDocumentPickerDelegate { + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let fileURL = urls.first else { return } - - switch controller.documentPickerMode - { + + switch controller.documentPickerMode { case .import, .open: - self.sideloadApp(at: fileURL) { (result) in + sideloadApp(at: fileURL) { result in print("Sideloaded app at \(fileURL) with result:", result) } - + case .exportToService, .moveToService: break @unknown default: break } } } -extension MyAppsViewController: UIViewControllerPreviewingDelegate -{ - func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? - { +extension MyAppsViewController: UIViewControllerPreviewingDelegate { + func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { guard - let indexPath = self.collectionView.indexPathForItem(at: location), - let cell = self.collectionView.cellForItem(at: indexPath) + let indexPath = collectionView.indexPathForItem(at: location), + let cell = collectionView.cellForItem(at: indexPath) else { return nil } - + let section = Section.allCases[indexPath.section] - switch section - { + switch section { case .updates: previewingContext.sourceRect = cell.frame - - let app = self.dataSource.item(at: indexPath) - guard let storeApp = app.storeApp else { return nil} - + + let app = dataSource.item(at: indexPath) + guard let storeApp = app.storeApp else { return nil } + let appViewController = AppViewController.makeAppViewController(app: storeApp) return appViewController - + default: return nil } } - - func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) - { + + func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit _: UIViewController) { let point = CGPoint(x: previewingContext.sourceRect.midX, y: previewingContext.sourceRect.midY) - guard let indexPath = self.collectionView.indexPathForItem(at: point), let cell = self.collectionView.cellForItem(at: indexPath) else { return } - - self.performSegue(withIdentifier: "showUpdate", sender: cell) + guard let indexPath = collectionView.indexPathForItem(at: point), let cell = collectionView.cellForItem(at: indexPath) else { return } + + performSegue(withIdentifier: "showUpdate", sender: cell) } } -extension MyAppsViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate -{ - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) - { +extension MyAppsViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { defer { picker.dismiss(animated: true, completion: nil) self._imagePickerInstalledApp = nil } - - guard let image = info[.editedImage] as? UIImage, let installedApp = self._imagePickerInstalledApp else { return } - self.changeIcon(for: installedApp, to: image) + + guard let image = info[.editedImage] as? UIImage, let installedApp = _imagePickerInstalledApp else { return } + changeIcon(for: installedApp, to: image) } - - func imagePickerControllerDidCancel(_ picker: UIImagePickerController) - { + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) - self._imagePickerInstalledApp = nil + _imagePickerInstalledApp = nil } } diff --git a/Sources/SideStore/My Apps/UpdateCollectionViewCell.swift b/Sources/SideStore/My Apps/UpdateCollectionViewCell.swift new file mode 100644 index 00000000..c75c2322 --- /dev/null +++ b/Sources/SideStore/My Apps/UpdateCollectionViewCell.swift @@ -0,0 +1,94 @@ +// +// UpdateCollectionViewCell.swift +// AltStore +// +// Created by Riley Testut on 7/16/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +extension UpdateCollectionViewCell { + enum Mode { + case collapsed + case expanded + } +} + +@objc final class UpdateCollectionViewCell: UICollectionViewCell { + var mode: Mode = .expanded { + didSet { + update() + } + } + + @IBOutlet var bannerView: AppBannerView! + @IBOutlet var versionDescriptionTitleLabel: UILabel! + @IBOutlet var versionDescriptionTextView: CollapsingTextView! + + @IBOutlet private var blurView: UIVisualEffectView! + + private var originalTintColor: UIColor? + + override func awakeFromNib() { + super.awakeFromNib() + + // Prevent temporary unsatisfiable constraint errors due to UIView-Encapsulated-Layout constraints. + contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + contentView.preservesSuperviewLayoutMargins = true + + bannerView.backgroundEffectView.isHidden = true + bannerView.button.setTitle(NSLocalizedString("UPDATE", comment: ""), for: .normal) + + blurView.layer.cornerRadius = 20 + blurView.layer.masksToBounds = true + + update() + } + + override func tintColorDidChange() { + super.tintColorDidChange() + + if tintAdjustmentMode != .dimmed { + originalTintColor = tintColor + } + + update() + } + + override func apply(_: UICollectionViewLayoutAttributes) { + // Animates transition to new attributes. + let animator = UIViewPropertyAnimator(springTimingParameters: UISpringTimingParameters()) { + self.layoutIfNeeded() + } + animator.startAnimation() + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let view = super.hitTest(point, with: event) + + if view == versionDescriptionTextView { + // Forward touches on the text view (but not on the nested "more" button) + // so cell selection works as expected. + return self + } else { + return view + } + } +} + +private extension UpdateCollectionViewCell { + func update() { + switch mode { + case .collapsed: versionDescriptionTextView.isCollapsed = true + case .expanded: versionDescriptionTextView.isCollapsed = false + } + + versionDescriptionTitleLabel.textColor = originalTintColor ?? tintColor + blurView.backgroundColor = originalTintColor ?? tintColor + bannerView.button.progressTintColor = originalTintColor ?? tintColor + + setNeedsLayout() + layoutIfNeeded() + } +} diff --git a/AltStore/My Apps/UpdateCollectionViewCell.xib b/Sources/SideStore/My Apps/UpdateCollectionViewCell.xib similarity index 100% rename from AltStore/My Apps/UpdateCollectionViewCell.xib rename to Sources/SideStore/My Apps/UpdateCollectionViewCell.xib diff --git a/Sources/SideStore/News/NewsCollectionViewCell.swift b/Sources/SideStore/News/NewsCollectionViewCell.swift new file mode 100644 index 00000000..b0227fbf --- /dev/null +++ b/Sources/SideStore/News/NewsCollectionViewCell.swift @@ -0,0 +1,28 @@ +// +// NewsCollectionViewCell.swift +// AltStore +// +// Created by Riley Testut on 8/29/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class NewsCollectionViewCell: UICollectionViewCell { + @IBOutlet var titleLabel: UILabel! + @IBOutlet var captionLabel: UILabel! + @IBOutlet var imageView: UIImageView! + @IBOutlet var contentBackgroundView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + + contentView.preservesSuperviewLayoutMargins = true + + contentBackgroundView.layer.cornerRadius = 30 + contentBackgroundView.clipsToBounds = true + + imageView.layer.cornerRadius = 30 + imageView.clipsToBounds = true + } +} diff --git a/AltStore/News/NewsViewController.swift b/Sources/SideStore/News/NewsViewController.swift similarity index 52% rename from AltStore/News/NewsViewController.swift rename to Sources/SideStore/News/NewsViewController.swift index f7cb37e8..74540d22 100644 --- a/AltStore/News/NewsViewController.swift +++ b/Sources/SideStore/News/NewsViewController.swift @@ -6,521 +6,447 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit import SafariServices +import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI import Nuke -private final class AppBannerFooterView: UICollectionReusableView -{ +private final class AppBannerFooterView: UICollectionReusableView { let bannerView = AppBannerView(frame: .zero) let tapGestureRecognizer = UITapGestureRecognizer(target: nil, action: nil) - - override init(frame: CGRect) - { + + override init(frame: CGRect) { super.init(frame: frame) - - self.addGestureRecognizer(self.tapGestureRecognizer) - - self.bannerView.translatesAutoresizingMaskIntoConstraints = false - self.addSubview(self.bannerView) - + + addGestureRecognizer(tapGestureRecognizer) + + bannerView.translatesAutoresizingMaskIntoConstraints = false + addSubview(bannerView) + NSLayoutConstraint.activate([ - self.bannerView.topAnchor.constraint(equalTo: self.topAnchor), - self.bannerView.bottomAnchor.constraint(equalTo: self.bottomAnchor), - self.bannerView.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor), - self.bannerView.trailingAnchor.constraint(equalTo: self.layoutMarginsGuide.trailingAnchor) + bannerView.topAnchor.constraint(equalTo: topAnchor), + bannerView.bottomAnchor.constraint(equalTo: bottomAnchor), + bannerView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + bannerView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor) ]) } - - required init?(coder aDecoder: NSCoder) { + + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -final class NewsViewController: UICollectionViewController -{ +final class NewsViewController: UICollectionViewController { private lazy var dataSource = self.makeDataSource() private lazy var placeholderView = RSTPlaceholderView(frame: .zero) - + private var prototypeCell: NewsCollectionViewCell! - + private var loadingState: LoadingState = .loading { didSet { - self.update() + update() } } - + // Cache private var cachedCellSizes = [String: CGSize]() - - required init?(coder: NSCoder) - { + + required init?(coder: NSCoder) { super.init(coder: coder) - + NotificationCenter.default.addObserver(self, selector: #selector(NewsViewController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.prototypeCell = NewsCollectionViewCell.instantiate(with: NewsCollectionViewCell.nib!) - self.prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = false - - self.collectionView.dataSource = self.dataSource - self.collectionView.prefetchDataSource = self.dataSource - - self.collectionView.register(NewsCollectionViewCell.nib, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) - self.collectionView.register(AppBannerFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "AppBanner") - - self.registerForPreviewing(with: self, sourceView: self.collectionView) - - self.update() + + prototypeCell = NewsCollectionViewCell.instantiate(with: NewsCollectionViewCell.nib!) + prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = false + + collectionView.dataSource = dataSource + collectionView.prefetchDataSource = dataSource + + collectionView.register(NewsCollectionViewCell.nib, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) + collectionView.register(AppBannerFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "AppBanner") + + registerForPreviewing(with: self, sourceView: collectionView) + + update() } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - self.fetchSource() + + fetchSource() } - - override func viewWillLayoutSubviews() - { + + override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() - - if self.collectionView.contentInset.bottom != 20 - { + + if collectionView.contentInset.bottom != 20 { // Triggers collection view update in iOS 13, which crashes if we do it in viewDidLoad() // since the database might not be loaded yet. - self.collectionView.contentInset.bottom = 20 + collectionView.contentInset.bottom = 20 } } - - @IBAction private func unwindFromSourcesViewController(_ segue: UIStoryboardSegue) - { - self.fetchSource() + + @IBAction private func unwindFromSourcesViewController(_: UIStoryboardSegue) { + fetchSource() } } -private extension NewsViewController -{ - func makeDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource - { +private extension NewsViewController { + func makeDataSource() -> RSTFetchedResultsCollectionViewPrefetchingDataSource { let fetchRequest = NewsItem.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \NewsItem.date, ascending: false), NSSortDescriptor(keyPath: \NewsItem.sortIndex, ascending: true), NSSortDescriptor(keyPath: \NewsItem.sourceIdentifier, ascending: true)] - + let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(NewsItem.objectID), cacheName: nil) - + let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchedResultsController: fetchedResultsController) dataSource.proxy = self - dataSource.cellConfigurationHandler = { (cell, newsItem, indexPath) in + dataSource.cellConfigurationHandler = { cell, newsItem, _ in let cell = cell as! NewsCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right - + cell.titleLabel.text = newsItem.title cell.captionLabel.text = newsItem.caption cell.contentBackgroundView.backgroundColor = newsItem.tintColor - + cell.imageView.image = nil - - if newsItem.imageURL != nil - { + + if newsItem.imageURL != nil { cell.imageView.isIndicatingActivity = true cell.imageView.isHidden = false - } - else - { + } else { cell.imageView.isIndicatingActivity = false cell.imageView.isHidden = true } - + cell.isAccessibilityElement = true cell.accessibilityLabel = (cell.titleLabel.text ?? "") + ". " + (cell.captionLabel.text ?? "") - - if newsItem.storeApp != nil || newsItem.externalURL != nil - { + + if newsItem.storeApp != nil || newsItem.externalURL != nil { cell.accessibilityTraits.insert(.button) - } - else - { + } else { cell.accessibilityTraits.remove(.button) } } - dataSource.prefetchHandler = { (newsItem, indexPath, completionHandler) in + dataSource.prefetchHandler = { newsItem, _, completionHandler in guard let imageURL = newsItem.imageURL else { return nil } - - return RSTAsyncBlockOperation() { (operation) in - ImagePipeline.shared.loadImage(with: imageURL, progress: nil, completion: { (response, error) in + + return RSTAsyncBlockOperation { operation in + ImagePipeline.shared.loadImage(with: imageURL, progress: nil, completion: { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completionHandler(image, nil) - } - else - { + } else { completionHandler(nil, error) } }) } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, error in let cell = cell as! NewsCollectionViewCell cell.imageView.isIndicatingActivity = false cell.imageView.image = image - - if let error = error - { + + if let error = error { print("Error loading image:", error) } } - - dataSource.placeholderView = self.placeholderView - + + dataSource.placeholderView = placeholderView + return dataSource } - func fetchSource() - { - self.loadingState = .loading - - AppManager.shared.fetchSources() { (result) in - do - { - do - { + func fetchSource() { + loadingState = .loading + + AppManager.shared.fetchSources { result in + do { + do { let (_, context) = try result.get() try context.save() - + DispatchQueue.main.async { self.loadingState = .finished(.success(())) } - } - catch let error as AppManager.FetchSourcesError - { + } catch let error as AppManager.FetchSourcesError { try error.managedObjectContext?.save() throw error } - } - catch - { + } catch { DispatchQueue.main.async { - if self.dataSource.itemCount > 0 - { + if self.dataSource.itemCount > 0 { let toastView = ToastView(error: error) toastView.addTarget(nil, action: #selector(TabBarController.presentSources), for: .touchUpInside) toastView.show(in: self) } - + self.loadingState = .finished(.failure(error)) } } } } - - func update() - { - switch self.loadingState - { + + func update() { + switch loadingState { case .loading: - self.placeholderView.textLabel.isHidden = true - self.placeholderView.detailTextLabel.isHidden = false - - self.placeholderView.detailTextLabel.text = NSLocalizedString("Loading...", comment: "") - - self.placeholderView.activityIndicatorView.startAnimating() - - case .finished(.failure(let error)): - self.placeholderView.textLabel.isHidden = false - self.placeholderView.detailTextLabel.isHidden = false - - self.placeholderView.textLabel.text = NSLocalizedString("Unable to Fetch News", comment: "") - self.placeholderView.detailTextLabel.text = error.localizedDescription - - self.placeholderView.activityIndicatorView.stopAnimating() - + placeholderView.textLabel.isHidden = true + placeholderView.detailTextLabel.isHidden = false + + placeholderView.detailTextLabel.text = NSLocalizedString("Loading...", comment: "") + + placeholderView.activityIndicatorView.startAnimating() + + case let .finished(.failure(error)): + placeholderView.textLabel.isHidden = false + placeholderView.detailTextLabel.isHidden = false + + placeholderView.textLabel.text = NSLocalizedString("Unable to Fetch News", comment: "") + placeholderView.detailTextLabel.text = error.localizedDescription + + placeholderView.activityIndicatorView.stopAnimating() + case .finished(.success): - self.placeholderView.textLabel.isHidden = true - self.placeholderView.detailTextLabel.isHidden = true - - self.placeholderView.activityIndicatorView.stopAnimating() + placeholderView.textLabel.isHidden = true + placeholderView.detailTextLabel.isHidden = true + + placeholderView.activityIndicatorView.stopAnimating() } } } -private extension NewsViewController -{ - @objc func handleTapGesture(_ gestureRecognizer: UITapGestureRecognizer) - { +private extension NewsViewController { + @objc func handleTapGesture(_ gestureRecognizer: UITapGestureRecognizer) { guard let footerView = gestureRecognizer.view as? UICollectionReusableView else { return } - - let indexPaths = self.collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) - - guard let indexPath = indexPaths.first(where: { (indexPath) -> Bool in + + let indexPaths = collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) + + guard let indexPath = indexPaths.first(where: { indexPath -> Bool in let supplementaryView = self.collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionFooter, at: indexPath) return supplementaryView == footerView }) else { return } - - let item = self.dataSource.item(at: indexPath) + + let item = dataSource.item(at: indexPath) guard let storeApp = item.storeApp else { return } - + let appViewController = AppViewController.makeAppViewController(app: storeApp) - self.navigationController?.pushViewController(appViewController, animated: true) + navigationController?.pushViewController(appViewController, animated: true) } - - @objc func performAppAction(_ sender: PillButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - let indexPaths = self.collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) - - guard let indexPath = indexPaths.first(where: { (indexPath) -> Bool in + + @objc func performAppAction(_ sender: PillButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + let indexPaths = collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) + + guard let indexPath = indexPaths.first(where: { indexPath -> Bool in let supplementaryView = self.collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionFooter, at: indexPath) return supplementaryView?.frame.contains(point) ?? false }) else { return } - - let app = self.dataSource.item(at: indexPath) + + let app = dataSource.item(at: indexPath) guard let storeApp = app.storeApp else { return } - - if let installedApp = app.storeApp?.installedApp - { - self.open(installedApp) - } - else - { - self.install(storeApp, at: indexPath) + + if let installedApp = app.storeApp?.installedApp { + open(installedApp) + } else { + install(storeApp, at: indexPath) } } - - @objc func install(_ storeApp: StoreApp, at indexPath: IndexPath) - { + + @objc func install(_ storeApp: StoreApp, at indexPath: IndexPath) { let previousProgress = AppManager.shared.installationProgress(for: storeApp) guard previousProgress == nil else { previousProgress?.cancel() return } - - _ = AppManager.shared.install(storeApp, presentingViewController: self) { (result) in + + _ = AppManager.shared.install(storeApp, presentingViewController: self) { result in DispatchQueue.main.async { - switch result - { + switch result { case .failure(OperationError.cancelled): break // Ignore - case .failure(let error): + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) - + case .success: print("Installed app:", storeApp.bundleIdentifier) } - + UIView.performWithoutAnimation { self.collectionView.reloadSections(IndexSet(integer: indexPath.section)) } } } - + UIView.performWithoutAnimation { self.collectionView.reloadSections(IndexSet(integer: indexPath.section)) } } - - func open(_ installedApp: InstalledApp) - { + + func open(_ installedApp: InstalledApp) { UIApplication.shared.open(installedApp.openAppURL) } } -private extension NewsViewController -{ - @objc func importApp(_ notification: Notification) - { - self.presentedViewController?.dismiss(animated: true, completion: nil) +private extension NewsViewController { + @objc func importApp(_: Notification) { + presentedViewController?.dismiss(animated: true, completion: nil) } } -extension NewsViewController -{ - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) - { - let newsItem = self.dataSource.item(at: indexPath) - - if let externalURL = newsItem.externalURL - { +extension NewsViewController { + override func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let newsItem = dataSource.item(at: indexPath) + + if let externalURL = newsItem.externalURL { let safariViewController = SFSafariViewController(url: externalURL) safariViewController.preferredControlTintColor = newsItem.tintColor - self.present(safariViewController, animated: true, completion: nil) - } - else if let storeApp = newsItem.storeApp - { + present(safariViewController, animated: true, completion: nil) + } else if let storeApp = newsItem.storeApp { let appViewController = AppViewController.makeAppViewController(app: storeApp) - self.navigationController?.pushViewController(appViewController, animated: true) + navigationController?.pushViewController(appViewController, animated: true) } } - - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { - let item = self.dataSource.item(at: indexPath) - + + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind _: String, at indexPath: IndexPath) -> UICollectionReusableView { + let item = dataSource.item(at: indexPath) + let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "AppBanner", for: indexPath) as! AppBannerFooterView guard let storeApp = item.storeApp else { return footerView } - - footerView.layoutMargins.left = self.view.layoutMargins.left - footerView.layoutMargins.right = self.view.layoutMargins.right - + + footerView.layoutMargins.left = view.layoutMargins.left + footerView.layoutMargins.right = view.layoutMargins.right + footerView.bannerView.configure(for: storeApp) - + footerView.bannerView.tintColor = storeApp.tintColor footerView.bannerView.button.addTarget(self, action: #selector(NewsViewController.performAppAction(_:)), for: .primaryActionTriggered) footerView.tapGestureRecognizer.addTarget(self, action: #selector(NewsViewController.handleTapGesture(_:))) - + footerView.bannerView.button.isIndicatingActivity = false - - if storeApp.installedApp == nil - { + + if storeApp.installedApp == nil { let buttonTitle = NSLocalizedString("Free", comment: "") footerView.bannerView.button.setTitle(buttonTitle.uppercased(), for: .normal) footerView.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Download %@", comment: ""), storeApp.name) footerView.bannerView.button.accessibilityValue = buttonTitle - + let progress = AppManager.shared.installationProgress(for: storeApp) footerView.bannerView.button.progress = progress - - if let versionDate = storeApp.latestVersion?.date, versionDate > Date() - { + + if let versionDate = storeApp.latestVersion?.date, versionDate > Date() { footerView.bannerView.button.countdownDate = storeApp.versionDate - } - else - { + } else { footerView.bannerView.button.countdownDate = nil } - } - else - { + } else { footerView.bannerView.button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) footerView.bannerView.button.accessibilityLabel = String(format: NSLocalizedString("Open %@", comment: ""), storeApp.name) footerView.bannerView.button.accessibilityValue = nil footerView.bannerView.button.progress = nil footerView.bannerView.button.countdownDate = nil } - + Nuke.loadImage(with: storeApp.iconURL, into: footerView.bannerView.iconImageView) - + return footerView } } -extension NewsViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { - let item = self.dataSource.item(at: indexPath) - - if let previousSize = self.cachedCellSizes[item.identifier] - { +extension NewsViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let item = dataSource.item(at: indexPath) + + if let previousSize = cachedCellSizes[item.identifier] { return previousSize } - - let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) + + let widthConstraint = prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } - - self.dataSource.cellConfigurationHandler(self.prototypeCell, item, indexPath) - - let size = self.prototypeCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - self.cachedCellSizes[item.identifier] = size + + dataSource.cellConfigurationHandler(prototypeCell, item, indexPath) + + let size = prototypeCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + cachedCellSizes[item.identifier] = size return size } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize - { - let item = self.dataSource.item(at: IndexPath(row: 0, section: section)) - - if item.storeApp != nil - { + + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + let item = dataSource.item(at: IndexPath(row: 0, section: section)) + + if item.storeApp != nil { return CGSize(width: 88, height: 88) - } - else - { + } else { return .zero } } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets - { + + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { var insets = UIEdgeInsets(top: 30, left: 0, bottom: 13, right: 0) - - if section == 0 - { + + if section == 0 { insets.top = 10 } - + return insets } } -extension NewsViewController: UIViewControllerPreviewingDelegate -{ - func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? - { - if let indexPath = self.collectionView.indexPathForItem(at: location), let cell = self.collectionView.cellForItem(at: indexPath) - { +extension NewsViewController: UIViewControllerPreviewingDelegate { + func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { + if let indexPath = collectionView.indexPathForItem(at: location), let cell = collectionView.cellForItem(at: indexPath) { // Previewing news item. - + previewingContext.sourceRect = cell.frame - - let newsItem = self.dataSource.item(at: indexPath) - - if let externalURL = newsItem.externalURL - { + + let newsItem = dataSource.item(at: indexPath) + + if let externalURL = newsItem.externalURL { let safariViewController = SFSafariViewController(url: externalURL) safariViewController.preferredControlTintColor = newsItem.tintColor return safariViewController - } - else if let storeApp = newsItem.storeApp - { + } else if let storeApp = newsItem.storeApp { let appViewController = AppViewController.makeAppViewController(app: storeApp) return appViewController } - + return nil - } - else - { + } else { // Previewing app banner (or nothing). - - let indexPaths = self.collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) - - guard let indexPath = indexPaths.first(where: { (indexPath) -> Bool in + + let indexPaths = collectionView.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionFooter) + + guard let indexPath = indexPaths.first(where: { indexPath -> Bool in let layoutAttributes = self.collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionFooter, at: indexPath) return layoutAttributes?.frame.contains(location) ?? false }) else { return nil } - - guard let layoutAttributes = self.collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionFooter, at: indexPath) else { return nil } + + guard let layoutAttributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionFooter, at: indexPath) else { return nil } previewingContext.sourceRect = layoutAttributes.frame - - let item = self.dataSource.item(at: indexPath) + + let item = dataSource.item(at: indexPath) guard let storeApp = item.storeApp else { return nil } - + let appViewController = AppViewController.makeAppViewController(app: storeApp) return appViewController } } - - func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) - { - if let safariViewController = viewControllerToCommit as? SFSafariViewController - { - self.present(safariViewController, animated: true, completion: nil) - } - else - { - self.navigationController?.pushViewController(viewControllerToCommit, animated: true) + + func previewingContext(_: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { + if let safariViewController = viewControllerToCommit as? SFSafariViewController { + present(safariViewController, animated: true, completion: nil) + } else { + navigationController?.pushViewController(viewControllerToCommit, animated: true) } } } diff --git a/AltStore/Operations/AuthenticationOperation.swift b/Sources/SideStore/Operations/AuthenticationOperation.swift similarity index 67% rename from AltStore/Operations/AuthenticationOperation.swift rename to Sources/SideStore/Operations/AuthenticationOperation.swift index db81fb26..5c1d51b6 100644 --- a/AltStore/Operations/AuthenticationOperation.swift +++ b/Sources/SideStore/Operations/AuthenticationOperation.swift @@ -7,21 +7,20 @@ // import Foundation -import RoxasUI import Network +import RoxasUI -import AltStoreCore import AltSign +import SideStoreCore -enum AuthenticationError: LocalizedError -{ +enum AuthenticationError: LocalizedError { case noTeam case noCertificate case teamSelectorError - + case missingPrivateKey case missingCertificate - + var errorDescription: String? { switch self { case .noTeam: return NSLocalizedString("Developer team could not be found.", comment: "") @@ -34,106 +33,96 @@ enum AuthenticationError: LocalizedError } @objc(AuthenticationOperation) -final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, ALTAppleAPISession)> -{ +final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, ALTAppleAPISession)> { let context: AuthenticatedOperationContext - + private weak var presentingViewController: UIViewController? - + private lazy var navigationController: UINavigationController = { let navigationController = self.storyboard.instantiateViewController(withIdentifier: "navigationController") as! UINavigationController - if #available(iOS 13.0, *) - { + if #available(iOS 13.0, *) { navigationController.isModalInPresentation = true } return navigationController }() - + private lazy var storyboard = UIStoryboard(name: "Authentication", bundle: nil) - + private var appleIDEmailAddress: String? private var appleIDPassword: String? private var shouldShowInstructions = false - + private let operationQueue = OperationQueue() - + private var submitCodeAction: UIAlertAction? - - init(context: AuthenticatedOperationContext, presentingViewController: UIViewController?) - { + + init(context: AuthenticatedOperationContext, presentingViewController: UIViewController?) { self.context = context self.presentingViewController = presentingViewController - + super.init() - + self.context.authenticationOperation = self - self.operationQueue.name = "com.altstore.AuthenticationOperation" - self.progress.totalUnitCount = 4 + operationQueue.name = "com.altstore.AuthenticationOperation" + progress.totalUnitCount = 4 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + // Sign In - self.signIn() { (result) in + signIn { result in guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) } - - switch result - { - case .failure(let error): self.finish(.failure(error)) - case .success((let account, let session)): + + switch result { + case let .failure(error): self.finish(.failure(error)) + case let .success((account, session)): self.context.session = session self.progress.completedUnitCount += 1 - + // Fetch Team - self.fetchTeam(for: account, session: session) { (result) in + self.fetchTeam(for: account, session: session) { result in guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) } - - switch result - { - case .failure(let error): self.finish(.failure(error)) - case .success(let team): + + switch result { + case let .failure(error): self.finish(.failure(error)) + case let .success(team): self.context.team = team self.progress.completedUnitCount += 1 - + // Fetch Certificate - self.fetchCertificate(for: team, session: session) { (result) in + self.fetchCertificate(for: team, session: session) { result in guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) } - - switch result - { - case .failure(let error): self.finish(.failure(error)) - case .success(let certificate): + + switch result { + case let .failure(error): self.finish(.failure(error)) + case let .success(certificate): self.context.certificate = certificate self.progress.completedUnitCount += 1 - + // Register Device - self.registerCurrentDevice(for: team, session: session) { (result) in + self.registerCurrentDevice(for: team, session: session) { result in guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) } - - switch result - { - case .failure(let error): self.finish(.failure(error)) + + switch result { + case let .failure(error): self.finish(.failure(error)) case .success: self.progress.completedUnitCount += 1 - + // Save account/team to disk. - self.save(team) { (result) in + self.save(team) { result in guard !self.isCancelled else { return self.finish(.failure(OperationError.cancelled)) } - - switch result - { - case .failure(let error): self.finish(.failure(error)) + + switch result { + case let .failure(error): self.finish(.failure(error)) case .success: // Must cache App IDs _after_ saving account/team to disk. - self.cacheAppIDs(team: team, session: session) { (result) in + self.cacheAppIDs(team: team, session: session) { result in let result = result.map { _ in (team, certificate, session) } self.finish(result) } @@ -148,133 +137,113 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A } } } - - func save(_ altTeam: ALTTeam, completionHandler: @escaping (Result) -> Void) - { + + func save(_ altTeam: ALTTeam, completionHandler: @escaping (Result) -> Void) { let context = DatabaseManager.shared.persistentContainer.newBackgroundContext() context.performAndWait { - do - { + do { let account: Account let team: Team - - if let tempAccount = Account.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Account.identifier), altTeam.account.identifier), in: context) - { + + if let tempAccount = Account.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Account.identifier), altTeam.account.identifier), in: context) { account = tempAccount - } - else - { + } else { account = Account(altTeam.account, context: context) } - - if let tempTeam = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), altTeam.identifier), in: context) - { + + if let tempTeam = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), altTeam.identifier), in: context) { team = tempTeam - } - else - { + } else { team = Team(altTeam, account: account, context: context) } - + account.update(account: altTeam.account) - - if let providedEmailAddress = self.appleIDEmailAddress - { + + if let providedEmailAddress = self.appleIDEmailAddress { // Save the user's provided email address instead of the one associated with their account (which may be outdated). account.appleID = providedEmailAddress } - + team.update(team: altTeam) - + try context.save() - + completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - override func finish(_ result: Result<(ALTTeam, ALTCertificate, ALTAppleAPISession), Error>) - { - guard !self.isFinished else { return } - + + override func finish(_ result: Result<(ALTTeam, ALTCertificate, ALTAppleAPISession), Error>) { + guard !isFinished else { return } + print("Finished authenticating with result:", result.error?.localizedDescription ?? "success") - + let context = DatabaseManager.shared.persistentContainer.newBackgroundContext() context.perform { - do - { + do { let (altTeam, altCertificate, session) = try result.get() - + guard let account = Account.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Account.identifier), altTeam.account.identifier), in: context), let team = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), altTeam.identifier), in: context) else { throw AuthenticationError.noTeam } - + // Account account.isActiveAccount = true - + let otherAccountsFetchRequest = Account.fetchRequest() as NSFetchRequest otherAccountsFetchRequest.predicate = NSPredicate(format: "%K != %@", #keyPath(Account.identifier), account.identifier) - + let otherAccounts = try context.fetch(otherAccountsFetchRequest) - for account in otherAccounts - { + for account in otherAccounts { account.isActiveAccount = false } - + // Team team.isActiveTeam = true - + let otherTeamsFetchRequest = Team.fetchRequest() as NSFetchRequest otherTeamsFetchRequest.predicate = NSPredicate(format: "%K != %@", #keyPath(Team.identifier), team.identifier) - + let otherTeams = try context.fetch(otherTeamsFetchRequest) - for team in otherTeams - { + for team in otherTeams { team.isActiveTeam = false } - + let activeAppsMinimumVersion = OperatingSystemVersion(majorVersion: 13, minorVersion: 3, patchVersion: 1) - if team.type == .free, ProcessInfo.processInfo.isOperatingSystemAtLeast(activeAppsMinimumVersion) - { + if team.type == .free, ProcessInfo.processInfo.isOperatingSystemAtLeast(activeAppsMinimumVersion) { UserDefaults.standard.activeAppsLimit = ALTActiveAppsLimit - } - else - { + } else { UserDefaults.standard.activeAppsLimit = nil } - + // Save try context.save() - + // Update keychain Keychain.shared.appleIDEmailAddress = self.appleIDEmailAddress ?? altTeam.account.appleID // Prefer the user's provided email address over the one associated with their account (which may be outdated). Keychain.shared.appleIDPassword = self.appleIDPassword - + Keychain.shared.signingCertificate = altCertificate.p12Data() Keychain.shared.signingCertificatePassword = altCertificate.machineIdentifier - - self.showInstructionsIfNecessary() { (didShowInstructions) in - + + self.showInstructionsIfNecessary { _ in + let signer = ALTSigner(team: altTeam, certificate: altCertificate) // Refresh screen must go last since a successful refresh will cause the app to quit. - self.showRefreshScreenIfNecessary(signer: signer, session: session) { (didShowRefreshAlert) in + self.showRefreshScreenIfNecessary(signer: signer, session: session) { _ in super.finish(result) - + DispatchQueue.main.async { self.navigationController.dismiss(animated: true, completion: nil) } } } - } - catch - { + } catch { super.finish(result) - + DispatchQueue.main.async { self.navigationController.dismiss(animated: true, completion: nil) } @@ -283,416 +252,341 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A } } -private extension AuthenticationOperation -{ - func present(_ viewController: UIViewController) -> Bool - { - guard let presentingViewController = self.presentingViewController else { return false } - - self.navigationController.view.tintColor = .white - - if self.navigationController.viewControllers.isEmpty - { +private extension AuthenticationOperation { + func present(_ viewController: UIViewController) -> Bool { + guard let presentingViewController = presentingViewController else { return false } + + navigationController.view.tintColor = .white + + if navigationController.viewControllers.isEmpty { guard presentingViewController.presentedViewController == nil else { return false } - - self.navigationController.setViewControllers([viewController], animated: false) - presentingViewController.present(self.navigationController, animated: true, completion: nil) - } - else - { + + navigationController.setViewControllers([viewController], animated: false) + presentingViewController.present(navigationController, animated: true, completion: nil) + } else { viewController.navigationItem.leftBarButtonItem = nil - self.navigationController.pushViewController(viewController, animated: true) + navigationController.pushViewController(viewController, animated: true) } - + return true } } -private extension AuthenticationOperation -{ - func signIn(completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Swift.Error>) -> Void) - { - func authenticate() - { +private extension AuthenticationOperation { + func signIn(completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Swift.Error>) -> Void) { + func authenticate() { DispatchQueue.main.async { let authenticationViewController = self.storyboard.instantiateViewController(withIdentifier: "authenticationViewController") as! AuthenticationViewController - authenticationViewController.authenticationHandler = { (appleID, password, completionHandler) in - self.authenticate(appleID: appleID, password: password) { (result) in + authenticationViewController.authenticationHandler = { appleID, password, completionHandler in + self.authenticate(appleID: appleID, password: password) { result in completionHandler(result) } } - authenticationViewController.completionHandler = { (result) in - if let (account, session, password) = result - { + authenticationViewController.completionHandler = { result in + if let (account, session, password) = result { // We presented the Auth UI and the user signed in. // In this case, we'll assume we should show the instructions again. self.shouldShowInstructions = true - + self.appleIDPassword = password completionHandler(.success((account, session))) - } - else - { + } else { completionHandler(.failure(OperationError.cancelled)) } } - - if !self.present(authenticationViewController) - { + + if !self.present(authenticationViewController) { completionHandler(.failure(OperationError.notAuthenticated)) } } } - - if let appleID = Keychain.shared.appleIDEmailAddress, let password = Keychain.shared.appleIDPassword - { - self.authenticate(appleID: appleID, password: password) { (result) in - switch result - { - case .success((let account, let session)): + + if let appleID = Keychain.shared.appleIDEmailAddress, let password = Keychain.shared.appleIDPassword { + self.authenticate(appleID: appleID, password: password) { result in + switch result { + case let .success((account, session)): self.appleIDPassword = password completionHandler(.success((account, session))) - + case .failure(ALTAppleAPIError.incorrectCredentials), .failure(ALTAppleAPIError.appSpecificPasswordRequired): authenticate() - - case .failure(let error): + + case let .failure(error): completionHandler(.failure(error)) } } - } - else - { + } else { authenticate() } } - - func authenticate(appleID: String, password: String, completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Swift.Error>) -> Void) - { - self.appleIDEmailAddress = appleID - - let fetchAnisetteDataOperation = FetchAnisetteDataOperation(context: self.context) - fetchAnisetteDataOperation.resultHandler = { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let anisetteData): + + func authenticate(appleID: String, password: String, completionHandler: @escaping (Result<(ALTAccount, ALTAppleAPISession), Swift.Error>) -> Void) { + appleIDEmailAddress = appleID + + let fetchAnisetteDataOperation = FetchAnisetteDataOperation(context: context) + fetchAnisetteDataOperation.resultHandler = { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(anisetteData): let verificationHandler: ((@escaping (String?) -> Void) -> Void)? - - if let presentingViewController = self.presentingViewController - { - verificationHandler = { (completionHandler) in + + if let presentingViewController = self.presentingViewController { + verificationHandler = { completionHandler in DispatchQueue.main.async { let alertController = UIAlertController(title: NSLocalizedString("Please enter the 6-digit verification code that was sent to your Apple devices.", comment: ""), message: nil, preferredStyle: .alert) - alertController.addTextField { (textField) in + alertController.addTextField { textField in textField.autocorrectionType = .no textField.autocapitalizationType = .none textField.keyboardType = .numberPad - + NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationOperation.textFieldTextDidChange(_:)), name: UITextField.textDidChangeNotification, object: textField) } - - let submitAction = UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default) { (action) in + + let submitAction = UIAlertAction(title: NSLocalizedString("Continue", comment: ""), style: .default) { _ in let textField = alertController.textFields?.first - + let code = textField?.text ?? "" completionHandler(code) } submitAction.isEnabled = false alertController.addAction(submitAction) self.submitCodeAction = submitAction - - alertController.addAction(UIAlertAction(title: RSTSystemLocalizedString("Cancel"), style: .cancel) { (action) in + + alertController.addAction(UIAlertAction(title: RSTSystemLocalizedString("Cancel"), style: .cancel) { _ in completionHandler(nil) }) - - if self.navigationController.presentingViewController != nil - { + + if self.navigationController.presentingViewController != nil { self.navigationController.present(alertController, animated: true, completion: nil) - } - else - { + } else { presentingViewController.present(alertController, animated: true, completion: nil) } } } - } - else - { + } else { // No view controller to present security code alert, so don't provide verificationHandler. verificationHandler = nil } - + ALTAppleAPI.shared.authenticate(appleID: appleID, password: password, anisetteData: anisetteData, - verificationHandler: verificationHandler) { (account, session, error) in - if let account = account, let session = session - { + verificationHandler: verificationHandler) { account, session, error in + if let account = account, let session = session { completionHandler(.success((account, session))) - } - else - { + } else { completionHandler(.failure(error ?? OperationError.unknown)) } } } } - - self.operationQueue.addOperation(fetchAnisetteDataOperation) + + operationQueue.addOperation(fetchAnisetteDataOperation) } - - func fetchTeam(for account: ALTAccount, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - func selectTeam(from teams: [ALTTeam]) - { - if teams.count <= 1 { - if let team = teams.first { - return completionHandler(.success(team)) - } else { - return completionHandler(.failure(AuthenticationError.noTeam)) - } - } else { - DispatchQueue.main.async { - let selectTeamViewController = self.storyboard.instantiateViewController(withIdentifier: "selectTeamViewController") as! SelectTeamViewController - selectTeamViewController.teams = teams - selectTeamViewController.completionHandler = completionHandler + func fetchTeam(for account: ALTAccount, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + func selectTeam(from teams: [ALTTeam]) { + if teams.count <= 1 { + if let team = teams.first { + return completionHandler(.success(team)) + } else { + return completionHandler(.failure(AuthenticationError.noTeam)) + } + } else { + DispatchQueue.main.async { + let selectTeamViewController = self.storyboard.instantiateViewController(withIdentifier: "selectTeamViewController") as! SelectTeamViewController - if !self.present(selectTeamViewController) - { - return completionHandler(.failure(AuthenticationError.noTeam)) - } - } - } - } + selectTeamViewController.teams = teams + selectTeamViewController.completionHandler = completionHandler - ALTAppleAPI.shared.fetchTeams(for: account, session: session) { (teams, error) in - switch Result(teams, error) - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let teams): - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in - if let activeTeam = DatabaseManager.shared.activeTeam(in: context), let altTeam = teams.first(where: { $0.identifier == activeTeam.identifier }) - { - completionHandler(.success(altTeam)) + if !self.present(selectTeamViewController) { + return completionHandler(.failure(AuthenticationError.noTeam)) } - else - { + } + } + } + + ALTAppleAPI.shared.fetchTeams(for: account, session: session) { teams, error in + switch Result(teams, error) { + case let .failure(error): completionHandler(.failure(error)) + case let .success(teams): + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + if let activeTeam = DatabaseManager.shared.activeTeam(in: context), let altTeam = teams.first(where: { $0.identifier == activeTeam.identifier }) { + completionHandler(.success(altTeam)) + } else { selectTeam(from: teams) } } } } } - - func fetchCertificate(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - func requestCertificate() - { + + func fetchCertificate(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + func requestCertificate() { let machineName = "AltStore - " + UIDevice.current.name - ALTAppleAPI.shared.addCertificate(machineName: machineName, to: team, session: session) { (certificate, error) in - do - { + ALTAppleAPI.shared.addCertificate(machineName: machineName, to: team, session: session) { certificate, error in + do { let certificate = try Result(certificate, error).get() guard let privateKey = certificate.privateKey else { throw AuthenticationError.missingPrivateKey } - - ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { (certificates, error) in - do - { + + ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { certificates, error in + do { let certificates = try Result(certificates, error).get() - + guard let certificate = certificates.first(where: { $0.serialNumber == certificate.serialNumber }) else { throw AuthenticationError.missingCertificate } - + certificate.privateKey = privateKey completionHandler(.success(certificate)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func replaceCertificate(from certificates: [ALTCertificate]) - { + + func replaceCertificate(from certificates: [ALTCertificate]) { guard let certificate = certificates.first(where: { $0.machineName?.starts(with: "AltStore") == true }) ?? certificates.first else { return completionHandler(.failure(AuthenticationError.noCertificate)) } - - ALTAppleAPI.shared.revoke(certificate, for: team, session: session) { (success, error) in - if let error = error, !success - { + + ALTAppleAPI.shared.revoke(certificate, for: team, session: session) { success, error in + if let error = error, !success { completionHandler(.failure(error)) - } - else - { + } else { requestCertificate() } } } - - ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { (certificates, error) in - do - { + + ALTAppleAPI.shared.fetchCertificates(for: team, session: session) { certificates, error in + do { let certificates = try Result(certificates, error).get() - + if let data = Keychain.shared.signingCertificate, let localCertificate = ALTCertificate(p12Data: data, password: nil), - let certificate = certificates.first(where: { $0.serialNumber == localCertificate.serialNumber }) - { + let certificate = certificates.first(where: { $0.serialNumber == localCertificate.serialNumber }) { // We have a certificate stored in the keychain and it hasn't been revoked. localCertificate.machineIdentifier = certificate.machineIdentifier completionHandler(.success(localCertificate)) - } - else if + } else if let serialNumber = Keychain.shared.signingCertificateSerialNumber, let privateKey = Keychain.shared.signingCertificatePrivateKey, - let certificate = certificates.first(where: { $0.serialNumber == serialNumber }) - { + let certificate = certificates.first(where: { $0.serialNumber == serialNumber }) { // LEGACY // We have the private key for one of the certificates, so add it to certificate and use it. certificate.privateKey = privateKey completionHandler(.success(certificate)) - } - else if + } else if let serialNumber = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.certificateID) as? String, let certificate = certificates.first(where: { $0.serialNumber == serialNumber }), let machineIdentifier = certificate.machineIdentifier, FileManager.default.fileExists(atPath: Bundle.main.certificateURL.path), let data = try? Data(contentsOf: Bundle.main.certificateURL), - let localCertificate = ALTCertificate(p12Data: data, password: machineIdentifier) - { + let localCertificate = ALTCertificate(p12Data: data, password: machineIdentifier) { // We have an embedded certificate that hasn't been revoked. localCertificate.machineIdentifier = machineIdentifier completionHandler(.success(localCertificate)) - } - else if certificates.isEmpty - { + } else if certificates.isEmpty { // No certificates, so request a new one. requestCertificate() - } - else - { + } else { // We don't have private keys for any of the certificates, // so we need to revoke one and create a new one. replaceCertificate(from: certificates) } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func registerCurrentDevice(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { + + func registerCurrentDevice(for team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { guard let udid = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.deviceID) as? String else { return completionHandler(.failure(OperationError.unknownUDID)) } - - ALTAppleAPI.shared.fetchDevices(for: team, types: [.iphone, .ipad], session: session) { (devices, error) in - do - { + + ALTAppleAPI.shared.fetchDevices(for: team, types: [.iphone, .ipad], session: session) { devices, error in + do { let devices = try Result(devices, error).get() - - if let device = devices.first(where: { $0.identifier == udid }) - { + + if let device = devices.first(where: { $0.identifier == udid }) { completionHandler(.success(device)) - } - else - { - ALTAppleAPI.shared.registerDevice(name: UIDevice.current.name, identifier: udid, type: .iphone, team: team, session: session) { (device, error) in + } else { + ALTAppleAPI.shared.registerDevice(name: UIDevice.current.name, identifier: udid, type: .iphone, team: team, session: session) { device, error in completionHandler(Result(device, error)) } } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func cacheAppIDs(team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - let fetchAppIDsOperation = FetchAppIDsOperation(context: self.context) - fetchAppIDsOperation.resultHandler = { (result) in - do - { + + func cacheAppIDs(team _: ALTTeam, session _: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + let fetchAppIDsOperation = FetchAppIDsOperation(context: context) + fetchAppIDsOperation.resultHandler = { result in + do { let (_, context) = try result.get() try context.save() - + completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } } - - self.operationQueue.addOperation(fetchAppIDsOperation) + + operationQueue.addOperation(fetchAppIDsOperation) } - - func showInstructionsIfNecessary(completionHandler: @escaping (Bool) -> Void) - { - guard self.shouldShowInstructions else { return completionHandler(false) } - + + func showInstructionsIfNecessary(completionHandler: @escaping (Bool) -> Void) { + guard shouldShowInstructions else { return completionHandler(false) } + DispatchQueue.main.async { let instructionsViewController = self.storyboard.instantiateViewController(withIdentifier: "instructionsViewController") as! InstructionsViewController instructionsViewController.showsBottomButton = true instructionsViewController.completionHandler = { completionHandler(true) } - - if !self.present(instructionsViewController) - { + + if !self.present(instructionsViewController) { completionHandler(false) } } } - - func showRefreshScreenIfNecessary(signer: ALTSigner, session: ALTAppleAPISession, completionHandler: @escaping (Bool) -> Void) - { + + func showRefreshScreenIfNecessary(signer: ALTSigner, session _: ALTAppleAPISession, completionHandler: @escaping (Bool) -> Void) { guard let application = ALTApplication(fileURL: Bundle.main.bundleURL), let provisioningProfile = application.provisioningProfile else { return completionHandler(false) } - + // If we're not using the same certificate used to install AltStore, warn user that they need to refresh. guard !provisioningProfile.certificates.contains(signer.certificate) else { return completionHandler(false) } - -#if DEBUG - completionHandler(false) -#else - DispatchQueue.main.async { - let context = AuthenticatedOperationContext(context: self.context) - context.operations.removeAllObjects() // Prevent deadlock due to endless waiting on previous operations to finish. - - let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController - refreshViewController.context = context - refreshViewController.completionHandler = { _ in - completionHandler(true) + + #if DEBUG + completionHandler(false) + #else + DispatchQueue.main.async { + let context = AuthenticatedOperationContext(context: self.context) + context.operations.removeAllObjects() // Prevent deadlock due to endless waiting on previous operations to finish. + + let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController + refreshViewController.context = context + refreshViewController.completionHandler = { _ in + completionHandler(true) + } + + if !self.present(refreshViewController) { + completionHandler(false) + } } - - if !self.present(refreshViewController) - { - completionHandler(false) - } - } -#endif + #endif } } -extension AuthenticationOperation -{ - @objc func textFieldTextDidChange(_ notification: Notification) - { +extension AuthenticationOperation { + @objc func textFieldTextDidChange(_ notification: Notification) { guard let textField = notification.object as? UITextField else { return } - - self.submitCodeAction?.isEnabled = (textField.text ?? "").count == 6 + + submitCodeAction?.isEnabled = (textField.text ?? "").count == 6 } } diff --git a/AltStore/Operations/BackgroundRefreshAppsOperation.swift b/Sources/SideStore/Operations/BackgroundRefreshAppsOperation.swift similarity index 73% rename from AltStore/Operations/BackgroundRefreshAppsOperation.swift rename to Sources/SideStore/Operations/BackgroundRefreshAppsOperation.swift index 0b3aa209..5bf1975c 100644 --- a/AltStore/Operations/BackgroundRefreshAppsOperation.swift +++ b/Sources/SideStore/Operations/BackgroundRefreshAppsOperation.swift @@ -6,136 +6,118 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import UIKit import CoreData +import UIKit -import AltStoreCore +import SideStoreCore import EmotionalDamage -enum RefreshError: LocalizedError -{ +enum RefreshError: LocalizedError { case noInstalledApps - + var errorDescription: String? { - switch self - { + switch self { case .noInstalledApps: return NSLocalizedString("No active apps require refreshing.", comment: "") } } } -private extension CFNotificationName -{ +private extension CFNotificationName { static let requestAppState = CFNotificationName("com.altstore.RequestAppState" as CFString) static let appIsRunning = CFNotificationName("com.altstore.AppState.Running" as CFString) - - static func requestAppState(for appID: String) -> CFNotificationName - { + + static func requestAppState(for appID: String) -> CFNotificationName { let name = String(CFNotificationName.requestAppState.rawValue) + "." + appID return CFNotificationName(name as CFString) } - - static func appIsRunning(for appID: String) -> CFNotificationName - { + + static func appIsRunning(for appID: String) -> CFNotificationName { let name = String(CFNotificationName.appIsRunning.rawValue) + "." + appID return CFNotificationName(name as CFString) } } -private let ReceivedApplicationState: @convention(c) (CFNotificationCenter?, UnsafeMutableRawPointer?, CFNotificationName?, UnsafeRawPointer?, CFDictionary?) -> Void = -{ (center, observer, name, object, userInfo) in +private let ReceivedApplicationState: @convention(c) (CFNotificationCenter?, UnsafeMutableRawPointer?, CFNotificationName?, UnsafeRawPointer?, CFDictionary?) -> Void = { _, observer, name, _, _ in guard let name = name, let observer = observer else { return } - + let operation = unsafeBitCast(observer, to: BackgroundRefreshAppsOperation.self) operation.receivedApplicationState(notification: name) } @objc(BackgroundRefreshAppsOperation) -final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result]> -{ +final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result]> { let installedApps: [InstalledApp] private let managedObjectContext: NSManagedObjectContext - + var presentsFinishedNotification: Bool = false - + private let refreshIdentifier: String = UUID().uuidString private var runningApplications: Set = [] - - init(installedApps: [InstalledApp]) - { + + init(installedApps: [InstalledApp]) { self.installedApps = installedApps - self.managedObjectContext = installedApps.compactMap({ $0.managedObjectContext }).first ?? DatabaseManager.shared.persistentContainer.newBackgroundContext() - + managedObjectContext = installedApps.compactMap { $0.managedObjectContext }.first ?? DatabaseManager.shared.persistentContainer.newBackgroundContext() + super.init() } - - override func finish(_ result: Result<[String: Result], Error>) - { + + override func finish(_ result: Result<[String: Result], Error>) { super.finish(result) - - self.scheduleFinishedRefreshingNotification(for: result, delay: 0) - - self.managedObjectContext.perform { + + scheduleFinishedRefreshingNotification(for: result, delay: 0) + + managedObjectContext.perform { self.stopListeningForRunningApps() } - + DispatchQueue.main.async { - if UIApplication.shared.applicationState == .background - { - - } + if UIApplication.shared.applicationState == .background {} } - } - - override func main() - { + + override func main() { super.main() - - guard !self.installedApps.isEmpty else { - self.finish(.failure(RefreshError.noInstalledApps)) + + guard !installedApps.isEmpty else { + finish(.failure(RefreshError.noInstalledApps)) return } start_em_proxy(bind_addr: Consts.Proxy.serverURL) - - self.managedObjectContext.perform { + + managedObjectContext.perform { print("Apps to refresh:", self.installedApps.map(\.bundleIdentifier)) - + self.startListeningForRunningApps() - + // Wait for 3 seconds (2 now, 1 later in FindServerOperation) to: // a) give us time to discover AltServers // b) give other processes a chance to respond to requestAppState notification DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { self.managedObjectContext.perform { - let filteredApps = self.installedApps.filter { !self.runningApplications.contains($0.bundleIdentifier) } print("Filtered Apps to Refresh:", filteredApps.map { $0.bundleIdentifier }) - + let group = AppManager.shared.refresh(filteredApps, presentingViewController: nil) - group.beginInstallationHandler = { (installedApp) in + group.beginInstallationHandler = { installedApp in guard installedApp.bundleIdentifier == StoreApp.altstoreAppID else { return } - + // We're starting to install AltStore, which means the app is about to quit. // So, we schedule a "refresh successful" local notification to be displayed after a delay, // but if the app is still running, we cancel the notification. // Then, we schedule another notification and repeat the process. - + // Also since AltServer has already received the app, it can finish installing even if we're no longer running in background. - - if let error = group.context.error - { + + if let error = group.context.error { self.scheduleFinishedRefreshingNotification(for: .failure(error)) - } - else - { + } else { var results = group.results results[installedApp.bundleIdentifier] = .success(installedApp) - + self.scheduleFinishedRefreshingNotification(for: .success(results)) } } - group.completionHandler = { (results) in + group.completionHandler = { results in self.finish(.success(results)) } } @@ -144,122 +126,103 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result], Error>, delay: TimeInterval = 5) - { - func scheduleFinishedRefreshingNotification() - { - self.cancelFinishedRefreshingNotification() - + + func scheduleFinishedRefreshingNotification(for result: Result<[String: Result], Error>, delay: TimeInterval = 5) { + func scheduleFinishedRefreshingNotification() { + cancelFinishedRefreshingNotification() + let content = UNMutableNotificationContent() - + var shouldPresentAlert = false - - do - { + + do { let results = try result.get() shouldPresentAlert = false - - for (_, result) in results - { + + for (_, result) in results { guard case let .failure(error) = result else { continue } throw error } - + content.title = NSLocalizedString("Refreshed Apps", comment: "") content.body = NSLocalizedString("All apps have been refreshed.", comment: "") - } - catch RefreshError.noInstalledApps - { + } catch RefreshError.noInstalledApps { shouldPresentAlert = false - } - catch - { + } catch { print("Failed to refresh apps in background.", error) - + content.title = NSLocalizedString("Failed to Refresh Apps", comment: "") content.body = error.localizedDescription - + shouldPresentAlert = false } - - if shouldPresentAlert - { + + if shouldPresentAlert { let trigger = UNTimeIntervalNotificationTrigger(timeInterval: delay + 1, repeats: false) - - let request = UNNotificationRequest(identifier: self.refreshIdentifier, content: content, trigger: trigger) + + let request = UNNotificationRequest(identifier: refreshIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) - - if delay > 0 - { + + if delay > 0 { DispatchQueue.global().asyncAfter(deadline: .now() + delay) { - UNUserNotificationCenter.current().getPendingNotificationRequests() { (requests) in + UNUserNotificationCenter.current().getPendingNotificationRequests { requests in // If app is still running at this point, we schedule another notification with same identifier. // This prevents the currently scheduled notification from displaying, and starts another countdown timer. // First though, make sure there _is_ still a pending request, otherwise it's been cancelled // and we should stop polling. guard requests.contains(where: { $0.identifier == self.refreshIdentifier }) else { return } - + scheduleFinishedRefreshingNotification() } } } } } - - if self.presentsFinishedNotification - { + + if presentsFinishedNotification { scheduleFinishedRefreshingNotification() - } - + } + // Perform synchronously to ensure app doesn't quit before we've finishing saving to disk. let context = DatabaseManager.shared.persistentContainer.newBackgroundContext() context.performAndWait { _ = RefreshAttempt(identifier: self.refreshIdentifier, result: result, context: context) - - do { try context.save() } - catch { print("Failed to save refresh attempt.", error) } + + do { try context.save() } catch { print("Failed to save refresh attempt.", error) } } } - - func cancelFinishedRefreshingNotification() - { - UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [self.refreshIdentifier]) + + func cancelFinishedRefreshingNotification() { + UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [refreshIdentifier]) } } diff --git a/AltStore/Operations/BackupAppOperation.swift b/Sources/SideStore/Operations/BackupAppOperation.swift similarity index 68% rename from AltStore/Operations/BackupAppOperation.swift rename to Sources/SideStore/Operations/BackupAppOperation.swift index 2cf17266..f7e5f886 100644 --- a/AltStore/Operations/BackupAppOperation.swift +++ b/Sources/SideStore/Operations/BackupAppOperation.swift @@ -8,156 +8,131 @@ import Foundation -import AltStoreCore import AltSign +import SideStoreCore -extension BackupAppOperation -{ - enum Action: String - { +extension BackupAppOperation { + enum Action: String { case backup case restore } } @objc(BackupAppOperation) -class BackupAppOperation: ResultOperation -{ +class BackupAppOperation: ResultOperation { let action: Action let context: InstallAppOperationContext - + private var appName: String? private var timeoutTimer: Timer? - - init(action: Action, context: InstallAppOperationContext) - { + + init(action: Action, context: InstallAppOperationContext) { self.action = action self.context = context - + super.init() } - - override func main() - { + + override func main() { super.main() - - do - { - if let error = self.context.error - { + + do { + if let error = self.context.error { throw error } - - guard let installedApp = self.context.installedApp, let context = installedApp.managedObjectContext else { throw OperationError.invalidParameters } + + guard let installedApp = context.installedApp, let context = installedApp.managedObjectContext else { throw OperationError.invalidParameters } context.perform { - do - { + do { let appName = installedApp.name self.appName = appName - + guard let altstoreApp = InstalledApp.fetchAltStore(in: context) else { throw OperationError.appNotFound } let altstoreOpenURL = altstoreApp.openAppURL - + var returnURLComponents = URLComponents(url: altstoreOpenURL, resolvingAgainstBaseURL: false) returnURLComponents?.host = "appBackupResponse" guard let returnURL = returnURLComponents?.url else { throw OperationError.openAppFailed(name: appName) } - + var openURLComponents = URLComponents() openURLComponents.scheme = installedApp.openAppURL.scheme openURLComponents.host = self.action.rawValue openURLComponents.queryItems = [URLQueryItem(name: "returnURL", value: returnURL.absoluteString)] - + guard let openURL = openURLComponents.url else { throw OperationError.openAppFailed(name: appName) } - + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { let currentTime = CFAbsoluteTimeGetCurrent() - - UIApplication.shared.open(openURL, options: [:]) { (success) in + + UIApplication.shared.open(openURL, options: [:]) { success in let elapsedTime = CFAbsoluteTimeGetCurrent() - currentTime - - if success - { + + if success { self.registerObservers() - } - else if elapsedTime < 0.5 - { + } else if elapsedTime < 0.5 { // Failed too quickly for human to respond to alert, possibly still finalizing installation. // Try again in a couple seconds. - + print("Failed too quickly, retrying after a few seconds...") - + DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { - UIApplication.shared.open(openURL, options: [:]) { (success) in - if success - { + UIApplication.shared.open(openURL, options: [:]) { success in + if success { self.registerObservers() - } - else - { + } else { self.finish(.failure(OperationError.openAppFailed(name: appName))) } } } - } - else - { + } else { self.finish(.failure(OperationError.openAppFailed(name: appName))) } } } - } - catch - { + } catch { self.finish(.failure(error)) } } - } - catch - { - self.finish(.failure(error)) + } catch { + finish(.failure(error)) } } - - override func finish(_ result: Result) - { - let result = result.mapError { (error) -> Error in + + override func finish(_ result: Result) { + let result = result.mapError { error -> Error in let appName = self.appName ?? self.context.bundleIdentifier - - switch (error, self.action) - { - case (let error as NSError, _) where (self.context.error as NSError?) == error: fallthrough + + switch (error, self.action) { + case let (error as NSError, _) where (self.context.error as NSError?) == error: fallthrough case (OperationError.cancelled, _): return error - - case (let error as NSError, .backup): + + case let (error as NSError, .backup): let localizedFailure = String(format: NSLocalizedString("Could not back up “%@”.", comment: ""), appName) return error.withLocalizedFailure(localizedFailure) - - case (let error as NSError, .restore): + + case let (error as NSError, .restore): let localizedFailure = String(format: NSLocalizedString("Could not restore “%@”.", comment: ""), appName) return error.withLocalizedFailure(localizedFailure) } } - - switch result - { - case .success: self.progress.completedUnitCount += 1 + + switch result { + case .success: progress.completedUnitCount += 1 case .failure: break } - + super.finish(result) } } -private extension BackupAppOperation -{ - func registerObservers() - { +private extension BackupAppOperation { + func registerObservers() { var applicationWillReturnObserver: NSObjectProtocol! - applicationWillReturnObserver = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] (notification) in + applicationWillReturnObserver = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] _ in guard let self = self, !self.isFinished else { return } - - self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { [weak self] (timer) in + + self.timeoutTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { [weak self] _ in // Final delay to ensure we don't prematurely return failure // in case timer expired while we were in background, but // are now returning to app with success response. @@ -166,17 +141,17 @@ private extension BackupAppOperation self.finish(.failure(OperationError.timedOut)) } } - + NotificationCenter.default.removeObserver(applicationWillReturnObserver!) } - + var backupResponseObserver: NSObjectProtocol! - backupResponseObserver = NotificationCenter.default.addObserver(forName: AppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] (notification) in + backupResponseObserver = NotificationCenter.default.addObserver(forName: AppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] notification in self?.timeoutTimer?.invalidate() - + let result = notification.userInfo?[AppDelegate.appBackupResultKey] as? Result ?? .failure(OperationError.unknownResult) self?.finish(result) - + NotificationCenter.default.removeObserver(backupResponseObserver!) } } diff --git a/AltStore/Operations/DeactivateAppOperation.swift b/Sources/SideStore/Operations/DeactivateAppOperation.swift similarity index 78% rename from AltStore/Operations/DeactivateAppOperation.swift rename to Sources/SideStore/Operations/DeactivateAppOperation.swift index f650164d..9090eaad 100644 --- a/AltStore/Operations/DeactivateAppOperation.swift +++ b/Sources/SideStore/Operations/DeactivateAppOperation.swift @@ -8,53 +8,49 @@ import Foundation -import AltStoreCore import AltSign -import RoxasUI +import SideStoreCore import minimuxer +import RoxasUI @objc(DeactivateAppOperation) -final class DeactivateAppOperation: ResultOperation -{ +final class DeactivateAppOperation: ResultOperation { let app: InstalledApp let context: OperationContext - - init(app: InstalledApp, context: OperationContext) - { + + init(app: InstalledApp, context: OperationContext) { self.app = app self.context = context - + super.init() } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let installedApp = context.object(with: self.app.objectID) as! InstalledApp let appExtensionProfiles = installedApp.appExtensions.map { $0.resignedBundleIdentifier } let allIdentifiers = [installedApp.resignedBundleIdentifier] + appExtensionProfiles - + for profile in allIdentifiers { do { let res = try remove_provisioning_profile(id: profile) - if case Uhoh.Bad(let code) = res { + if case let Uhoh.Bad(code) = res { self.finish(.failure(minimuxer_to_operation(code: code))) } - } catch Uhoh.Bad(let code) { + } catch let Uhoh.Bad(code) { self.finish(.failure(minimuxer_to_operation(code: code))) } catch { self.finish(.failure(ALTServerError(.unknownResponse))) } } - + self.progress.completedUnitCount += 1 installedApp.isActive = false self.finish(.success(installedApp)) diff --git a/AltStore/Operations/DownloadAppOperation.swift b/Sources/SideStore/Operations/DownloadAppOperation.swift similarity index 62% rename from AltStore/Operations/DownloadAppOperation.swift rename to Sources/SideStore/Operations/DownloadAppOperation.swift index 656be394..211fe1d2 100644 --- a/AltStore/Operations/DownloadAppOperation.swift +++ b/Sources/SideStore/Operations/DownloadAppOperation.swift @@ -9,319 +9,264 @@ import Foundation import RoxasUI -import AltStoreCore import AltSign +import SideStoreCore -private extension DownloadAppOperation -{ - struct DependencyError: ALTLocalizedError - { +private extension DownloadAppOperation { + struct DependencyError: ALTLocalizedError { let dependency: Dependency let error: Error - + var failure: String? { - return String(format: NSLocalizedString("Could not download “%@”.", comment: ""), self.dependency.preferredFilename) + String(format: NSLocalizedString("Could not download “%@”.", comment: ""), dependency.preferredFilename) } - + var underlyingError: Error? { - return self.error + error } } } @objc(DownloadAppOperation) -final class DownloadAppOperation: ResultOperation -{ +final class DownloadAppOperation: ResultOperation { let app: AppProtocol let context: AppOperationContext - + private let bundleIdentifier: String private var sourceURL: URL? private let destinationURL: URL - + private let session = URLSession(configuration: .default) private let temporaryDirectory = FileManager.default.uniqueTemporaryURL() - - init(app: AppProtocol, destinationURL: URL, context: AppOperationContext) - { + + init(app: AppProtocol, destinationURL: URL, context: AppOperationContext) { self.app = app self.context = context - - self.bundleIdentifier = app.bundleIdentifier - self.sourceURL = app.url + + bundleIdentifier = app.bundleIdentifier + sourceURL = app.url self.destinationURL = destinationURL - + super.init() - + // App = 3, Dependencies = 1 - self.progress.totalUnitCount = 4 + progress.totalUnitCount = 4 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - print("Downloading App:", self.bundleIdentifier) - - guard let sourceURL = self.sourceURL else { return self.finish(.failure(OperationError.appNotFound)) } - - self.downloadApp(from: sourceURL) { result in - do - { + + print("Downloading App:", bundleIdentifier) + + guard let sourceURL = sourceURL else { return finish(.failure(OperationError.appNotFound)) } + + downloadApp(from: sourceURL) { result in + do { let application = try result.get() - - if self.context.bundleIdentifier == StoreApp.dolphinAppID, self.context.bundleIdentifier != application.bundleIdentifier - { - if var infoPlist = NSDictionary(contentsOf: application.bundle.infoPlistURL) as? [String: Any] - { + + if self.context.bundleIdentifier == StoreApp.dolphinAppID, self.context.bundleIdentifier != application.bundleIdentifier { + if var infoPlist = NSDictionary(contentsOf: application.bundle.infoPlistURL) as? [String: Any] { // Manually update the app's bundle identifier to match the one specified in the source. // This allows people who previously installed the app to still update and refresh normally. infoPlist[kCFBundleIdentifierKey as String] = StoreApp.dolphinAppID (infoPlist as NSDictionary).write(to: application.bundle.infoPlistURL, atomically: true) } } - + self.downloadDependencies(for: application) { result in - do - { + do { _ = try result.get() - + try FileManager.default.copyItem(at: application.fileURL, to: self.destinationURL, shouldReplace: true) - + guard let copiedApplication = ALTApplication(fileURL: self.destinationURL) else { throw OperationError.invalidApp } self.finish(.success(copiedApplication)) - + self.progress.completedUnitCount += 1 - } - catch - { + } catch { self.finish(.failure(error)) } } - } - catch - { + } catch { self.finish(.failure(error)) } } } - - override func finish(_ result: Result) - { - do - { - try FileManager.default.removeItem(at: self.temporaryDirectory) + + override func finish(_ result: Result) { + do { + try FileManager.default.removeItem(at: temporaryDirectory) + } catch { + print("Failed to remove DownloadAppOperation temporary directory: \(temporaryDirectory).", error) } - catch - { - print("Failed to remove DownloadAppOperation temporary directory: \(self.temporaryDirectory).", error) - } - + super.finish(result) } } -private extension DownloadAppOperation -{ - func downloadApp(from sourceURL: URL, completionHandler: @escaping (Result) -> Void) - { - func finishOperation(_ result: Result) - { - do - { +private extension DownloadAppOperation { + func downloadApp(from sourceURL: URL, completionHandler: @escaping (Result) -> Void) { + func finishOperation(_ result: Result) { + do { let fileURL = try result.get() - + var isDirectory: ObjCBool = false guard FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDirectory) else { throw OperationError.appNotFound } - - try FileManager.default.createDirectory(at: self.temporaryDirectory, withIntermediateDirectories: true, attributes: nil) - + + try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) + let appBundleURL: URL - - if isDirectory.boolValue - { + + if isDirectory.boolValue { // Directory, so assuming this is .app bundle. guard Bundle(url: fileURL) != nil else { throw OperationError.invalidApp } - - appBundleURL = self.temporaryDirectory.appendingPathComponent(fileURL.lastPathComponent) + + appBundleURL = temporaryDirectory.appendingPathComponent(fileURL.lastPathComponent) try FileManager.default.copyItem(at: fileURL, to: appBundleURL) - } - else - { + } else { // File, so assuming this is a .ipa file. - appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: self.temporaryDirectory) + appBundleURL = try FileManager.default.unzipAppBundle(at: fileURL, toDirectory: temporaryDirectory) } - + guard let application = ALTApplication(fileURL: appBundleURL) else { throw OperationError.invalidApp } completionHandler(.success(application)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - - if sourceURL.isFileURL - { + + if sourceURL.isFileURL { finishOperation(.success(sourceURL)) - - self.progress.completedUnitCount += 3 - } - else - { - let downloadTask = self.session.downloadTask(with: sourceURL) { (fileURL, response, error) in - do - { + + progress.completedUnitCount += 3 + } else { + let downloadTask = session.downloadTask(with: sourceURL) { fileURL, response, error in + do { let (fileURL, _) = try Result((fileURL, response), error).get() finishOperation(.success(fileURL)) - + try? FileManager.default.removeItem(at: fileURL) - } - catch - { + } catch { finishOperation(.failure(error)) } } - self.progress.addChild(downloadTask.progress, withPendingUnitCount: 3) - + progress.addChild(downloadTask.progress, withPendingUnitCount: 3) + downloadTask.resume() } } } -private extension DownloadAppOperation -{ - struct AltStorePlist: Decodable - { - private enum CodingKeys: String, CodingKey - { +private extension DownloadAppOperation { + struct AltStorePlist: Decodable { + private enum CodingKeys: String, CodingKey { case dependencies = "ALTDependencies" } var dependencies: [Dependency] } - struct Dependency: Decodable - { + struct Dependency: Decodable { var downloadURL: URL var path: String? - + var preferredFilename: String { - let preferredFilename = self.path.map { ($0 as NSString).lastPathComponent } ?? self.downloadURL.lastPathComponent + let preferredFilename = path.map { ($0 as NSString).lastPathComponent } ?? downloadURL.lastPathComponent return preferredFilename } - - init(from decoder: Decoder) throws - { - enum CodingKeys: String, CodingKey - { + + init(from decoder: Decoder) throws { + enum CodingKeys: String, CodingKey { case downloadURL case path } - + let container = try decoder.container(keyedBy: CodingKeys.self) - + let urlString = try container.decode(String.self, forKey: .downloadURL) let path = try container.decodeIfPresent(String.self, forKey: .path) - + guard let downloadURL = URL(string: urlString) else { throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "downloadURL is not a valid URL.") } - + self.downloadURL = downloadURL self.path = path } } - - func downloadDependencies(for application: ALTApplication, completionHandler: @escaping (Result, Error>) -> Void) - { + + func downloadDependencies(for application: ALTApplication, completionHandler: @escaping (Result, Error>) -> Void) { guard FileManager.default.fileExists(atPath: application.bundle.altstorePlistURL.path) else { return completionHandler(.success([])) } - - do - { + + do { let data = try Data(contentsOf: application.bundle.altstorePlistURL) - + let altstorePlist = try PropertyListDecoder().decode(AltStorePlist.self, from: data) - + var dependencyURLs = Set() var dependencyError: DependencyError? - + let dispatchGroup = DispatchGroup() let progress = Progress(totalUnitCount: Int64(altstorePlist.dependencies.count), parent: self.progress, pendingUnitCount: 1) - - for dependency in altstorePlist.dependencies - { + + for dependency in altstorePlist.dependencies { dispatchGroup.enter() - - self.download(dependency, for: application, progress: progress) { result in - switch result - { - case .failure(let error): dependencyError = error - case .success(let fileURL): dependencyURLs.insert(fileURL) + + download(dependency, for: application, progress: progress) { result in + switch result { + case let .failure(error): dependencyError = error + case let .success(fileURL): dependencyURLs.insert(fileURL) } - + dispatchGroup.leave() } } - + dispatchGroup.notify(qos: .userInitiated, queue: .global()) { - if let dependencyError = dependencyError - { + if let dependencyError = dependencyError { completionHandler(.failure(dependencyError)) - } - else - { + } else { completionHandler(.success(dependencyURLs)) } } - } - catch let error as DecodingError - { + } catch let error as DecodingError { let nsError = (error as NSError).withLocalizedFailure(String(format: NSLocalizedString("Could not download dependencies for %@.", comment: ""), application.name)) completionHandler(.failure(nsError)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - - func download(_ dependency: Dependency, for application: ALTApplication, progress: Progress, completionHandler: @escaping (Result) -> Void) - { - let downloadTask = self.session.downloadTask(with: dependency.downloadURL) { (fileURL, response, error) in - do - { + + func download(_ dependency: Dependency, for application: ALTApplication, progress: Progress, completionHandler: @escaping (Result) -> Void) { + let downloadTask = session.downloadTask(with: dependency.downloadURL) { fileURL, response, error in + do { let (fileURL, _) = try Result((fileURL, response), error).get() defer { try? FileManager.default.removeItem(at: fileURL) } - + let path = dependency.path ?? dependency.preferredFilename let destinationURL = application.fileURL.appendingPathComponent(path) - + let directoryURL = destinationURL.deletingLastPathComponent() - if !FileManager.default.fileExists(atPath: directoryURL.path) - { + if !FileManager.default.fileExists(atPath: directoryURL.path) { try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true) } - + try FileManager.default.copyItem(at: fileURL, to: destinationURL, shouldReplace: true) - + completionHandler(.success(destinationURL)) - } - catch - { + } catch { completionHandler(.failure(DependencyError(dependency: dependency, error: error))) } } progress.addChild(downloadTask.progress, withPendingUnitCount: 1) - + downloadTask.resume() } } diff --git a/AltStore/Operations/EnableJITOperation.swift b/Sources/SideStore/Operations/EnableJITOperation.swift similarity index 68% rename from AltStore/Operations/EnableJITOperation.swift rename to Sources/SideStore/Operations/EnableJITOperation.swift index f89296bf..1ce99e80 100644 --- a/AltStore/Operations/EnableJITOperation.swift +++ b/Sources/SideStore/Operations/EnableJITOperation.swift @@ -6,62 +6,55 @@ // Copyright © 2021 Riley Testut. All rights reserved. // -import UIKit import Combine import minimuxer +import UIKit -import AltStoreCore +import SideStoreCore @available(iOS 14, *) -protocol EnableJITContext -{ +protocol EnableJITContext { var installedApp: InstalledApp? { get } - + var error: Error? { get } } @available(iOS 14, *) -final class EnableJITOperation: ResultOperation -{ +final class EnableJITOperation: ResultOperation { let context: Context - + private var cancellable: AnyCancellable? - - init(context: Context) - { + + init(context: Context) { self.context = context } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) } - + + guard let installedApp = context.installedApp else { return finish(.failure(OperationError.invalidParameters)) } + installedApp.managedObjectContext?.perform { let v = minimuxer_to_operation(code: 1) - + do { var x = try debug_app(app_id: installedApp.resignedBundleIdentifier) switch x { case .Good: self.finish(.success(())) - case .Bad(let code): + case let .Bad(code): self.finish(.failure(minimuxer_to_operation(code: code))) } - } catch Uhoh.Bad(let code) { + } catch let Uhoh.Bad(code) { self.finish(.failure(minimuxer_to_operation(code: code))) } catch { self.finish(.failure(OperationError.unknown)) } - - } } } diff --git a/AltStore/Operations/FetchAnisetteDataOperation.swift b/Sources/SideStore/Operations/FetchAnisetteDataOperation.swift similarity index 81% rename from AltStore/Operations/FetchAnisetteDataOperation.swift rename to Sources/SideStore/Operations/FetchAnisetteDataOperation.swift index 24a4e42c..fbd98b75 100644 --- a/AltStore/Operations/FetchAnisetteDataOperation.swift +++ b/Sources/SideStore/Operations/FetchAnisetteDataOperation.swift @@ -8,44 +8,40 @@ import Foundation -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI @objc(FetchAnisetteDataOperation) -final class FetchAnisetteDataOperation: ResultOperation -{ +final class FetchAnisetteDataOperation: ResultOperation { let context: OperationContext - - init(context: OperationContext) - { + + init(context: OperationContext) { self.context = context } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + let url = AnisetteManager.currentURL DLOG("Anisette URL: %@", url.absoluteString) - - let task = URLSession.shared.dataTask(with: url) { data, response, error in + + let task = URLSession.shared.dataTask(with: url) { data, _, error in guard let data = data, error == nil else { return } - + do { // make sure this JSON is in the format we expect // convert data to json if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: String] { // try to read out a dictionary - //for some reason serial number isn't needed but it doesn't work unless it has a value + // for some reason serial number isn't needed but it doesn't work unless it has a value let formattedJSON: [String: String] = ["machineID": json["X-Apple-I-MD-M"]!, "oneTimePassword": json["X-Apple-I-MD"]!, "localUserID": json["X-Apple-I-MD-LU"]!, "routingInfo": json["X-Apple-I-MD-RINFO"]!, "deviceUniqueIdentifier": json["X-Mme-Device-Id"]!, "deviceDescription": json["X-MMe-Client-Info"]!, "date": json["X-Apple-I-Client-Time"]!, "locale": json["X-Apple-Locale"]!, "timeZone": json["X-Apple-I-TimeZone"]!, "deviceSerialNumber": "1"] - + if let anisette = ALTAnisetteData(json: formattedJSON) { DLOG("Anisette used: %@", formattedJSON) self.finish(.success(anisette)) @@ -55,9 +51,8 @@ final class FetchAnisetteDataOperation: ResultOperation print("Failed to load: \(error.localizedDescription)") self.finish(.failure(error)) } - } - + task.resume() } } diff --git a/AltStore/Operations/FetchAppIDsOperation.swift b/Sources/SideStore/Operations/FetchAppIDsOperation.swift similarity index 75% rename from AltStore/Operations/FetchAppIDsOperation.swift rename to Sources/SideStore/Operations/FetchAppIDsOperation.swift index 2140675d..7d01092a 100644 --- a/AltStore/Operations/FetchAppIDsOperation.swift +++ b/Sources/SideStore/Operations/FetchAppIDsOperation.swift @@ -8,62 +8,55 @@ import Foundation -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI @objc(FetchAppIDsOperation) -final class FetchAppIDsOperation: ResultOperation<([AppID], NSManagedObjectContext)> -{ +final class FetchAppIDsOperation: ResultOperation<([AppID], NSManagedObjectContext)> { let context: AuthenticatedOperationContext let managedObjectContext: NSManagedObjectContext - - init(context: AuthenticatedOperationContext, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) - { + + init(context: AuthenticatedOperationContext, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) { self.context = context self.managedObjectContext = managedObjectContext - + super.init() } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + guard - let team = self.context.team, - let session = self.context.session - else { return self.finish(.failure(OperationError.invalidParameters)) } - - ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in + let team = context.team, + let session = context.session + else { return finish(.failure(OperationError.invalidParameters)) } + + ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { appIDs, error in self.managedObjectContext.perform { - do - { + do { let fetchedAppIDs = try Result(appIDs, error).get() - + guard let team = Team.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Team.identifier), team.identifier), in: self.managedObjectContext) else { throw OperationError.notAuthenticated } - + let fetchedIdentifiers = fetchedAppIDs.map { $0.identifier } - + let deletedAppIDsRequest = AppID.fetchRequest() as NSFetchRequest deletedAppIDsRequest.predicate = NSPredicate(format: "%K == %@ AND NOT (%K IN %@)", #keyPath(AppID.team), team, #keyPath(AppID.identifier), fetchedIdentifiers) - + let deletedAppIDs = try self.managedObjectContext.fetch(deletedAppIDsRequest) deletedAppIDs.forEach { self.managedObjectContext.delete($0) } - + let appIDs = fetchedAppIDs.map { AppID($0, team: team, context: self.managedObjectContext) } self.finish(.success((appIDs, self.managedObjectContext))) - } - catch - { + } catch { self.finish(.failure(error)) } } diff --git a/AltStore/Operations/FetchProvisioningProfilesOperation.swift b/Sources/SideStore/Operations/FetchProvisioningProfilesOperation.swift similarity index 63% rename from AltStore/Operations/FetchProvisioningProfilesOperation.swift rename to Sources/SideStore/Operations/FetchProvisioningProfilesOperation.swift index b543994b..3bf1a07d 100644 --- a/AltStore/Operations/FetchProvisioningProfilesOperation.swift +++ b/Sources/SideStore/Operations/FetchProvisioningProfilesOperation.swift @@ -8,129 +8,112 @@ import Foundation -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI @objc(FetchProvisioningProfilesOperation) -final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioningProfile]> -{ +final class FetchProvisioningProfilesOperation: ResultOperation<[String: ALTProvisioningProfile]> { let context: AppOperationContext - + var additionalEntitlements: [ALTEntitlement: Any]? - + private let appGroupsLock = NSLock() - - init(context: AppOperationContext) - { + + init(context: AppOperationContext) { self.context = context - + super.init() - - self.progress.totalUnitCount = 1 + + progress.totalUnitCount = 1 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + guard - let team = self.context.team, - let session = self.context.session - else { return self.finish(.failure(OperationError.invalidParameters)) } - - guard let app = self.context.app else { return self.finish(.failure(OperationError.appNotFound)) } - - self.progress.totalUnitCount = Int64(1 + app.appExtensions.count) - - self.prepareProvisioningProfile(for: app, parentApp: nil, team: team, session: session) { (result) in - do - { + let team = context.team, + let session = context.session + else { return finish(.failure(OperationError.invalidParameters)) } + + guard let app = context.app else { return finish(.failure(OperationError.appNotFound)) } + + progress.totalUnitCount = Int64(1 + app.appExtensions.count) + + prepareProvisioningProfile(for: app, parentApp: nil, team: team, session: session) { result in + do { self.progress.completedUnitCount += 1 - + let profile = try result.get() - + var profiles = [app.bundleIdentifier: profile] var error: Error? - + let dispatchGroup = DispatchGroup() - - for appExtension in app.appExtensions - { + + for appExtension in app.appExtensions { dispatchGroup.enter() - - self.prepareProvisioningProfile(for: appExtension, parentApp: app, team: team, session: session) { (result) in - switch result - { - case .failure(let e): error = e - case .success(let profile): profiles[appExtension.bundleIdentifier] = profile + + self.prepareProvisioningProfile(for: appExtension, parentApp: app, team: team, session: session) { result in + switch result { + case let .failure(e): error = e + case let .success(profile): profiles[appExtension.bundleIdentifier] = profile } - + dispatchGroup.leave() - + self.progress.completedUnitCount += 1 } } - + dispatchGroup.notify(queue: .global()) { - if let error = error - { + if let error = error { self.finish(.failure(error)) - } - else - { + } else { self.finish(.success(profiles)) } } - } - catch - { + } catch { self.finish(.failure(error)) } } } - - func process(_ result: Result) -> T? - { - switch result - { - case .failure(let error): - self.finish(.failure(error)) + + func process(_ result: Result) -> T? { + switch result { + case let .failure(error): + finish(.failure(error)) return nil - - case .success(let value): - guard !self.isCancelled else { - self.finish(.failure(OperationError.cancelled)) + + case let .success(value): + guard !isCancelled else { + finish(.failure(OperationError.cancelled)) return nil } - + return value } } } -extension FetchProvisioningProfilesOperation -{ - func prepareProvisioningProfile(for app: ALTApplication, parentApp: ALTApplication?, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in - +extension FetchProvisioningProfilesOperation { + func prepareProvisioningProfile(for app: ALTApplication, parentApp: ALTApplication?, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + let preferredBundleID: String? - + // Check if we have already installed this app with this team before. let predicate = NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), app.bundleIdentifier) - if let installedApp = InstalledApp.first(satisfying: predicate, in: context) - { + if let installedApp = InstalledApp.first(satisfying: predicate, in: context) { // Teams match if installedApp.team has same identifier as team, // or if installedApp.team is nil but resignedBundleIdentifier contains the team's identifier. let teamsMatch = installedApp.team?.identifier == team.identifier || (installedApp.team == nil && installedApp.resignedBundleIdentifier.contains(team.identifier)) - + // #if DEBUG // // if app.isAltStoreApp @@ -144,87 +127,70 @@ extension FetchProvisioningProfilesOperation // } // // #else - - if teamsMatch - { + + if teamsMatch { // This app is already installed with the same team, so use the same resigned bundle identifier as before. // This way, if we change the identifier format (again), AltStore will continue to use // the old bundle identifier to prevent it from installing as a new app. preferredBundleID = installedApp.resignedBundleIdentifier - } - else - { + } else { preferredBundleID = nil } - - // #endif - } - else - { + + // #endif + } else { preferredBundleID = nil } - + let bundleID: String - - if let preferredBundleID = preferredBundleID - { + + if let preferredBundleID = preferredBundleID { bundleID = preferredBundleID - } - else - { + } else { // This app isn't already installed, so create the resigned bundle identifier ourselves. // Or, if the app _is_ installed but with a different team, we need to create a new // bundle identifier anyway to prevent collisions with the previous team. let parentBundleID = parentApp?.bundleIdentifier ?? app.bundleIdentifier let updatedParentBundleID: String - - if app.isAltStoreApp - { + + if app.isAltStoreApp { // Use legacy bundle ID format for AltStore (and its extensions). updatedParentBundleID = parentBundleID + "." + team.identifier // Append just team identifier to make it harder to track. - } - else - { + } else { updatedParentBundleID = parentBundleID + "." + team.identifier // Append just team identifier to make it harder to track. } - + bundleID = app.bundleIdentifier.replacingOccurrences(of: parentBundleID, with: updatedParentBundleID) } - + let preferredName: String - - if let parentApp = parentApp - { + + if let parentApp = parentApp { preferredName = parentApp.name + " " + app.name - } - else - { + } else { preferredName = app.name } - + // Register - self.registerAppID(for: app, name: preferredName, bundleIdentifier: bundleID, team: team, session: session) { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let appID): - + self.registerAppID(for: app, name: preferredName, bundleIdentifier: bundleID, team: team, session: session) { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(appID): + // Update features - self.updateFeatures(for: appID, app: app, team: team, session: session) { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let appID): - + self.updateFeatures(for: appID, app: app, team: team, session: session) { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(appID): + // Update app groups - self.updateAppGroups(for: appID, app: app, team: team, session: session) { (result) in - switch result - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let appID): - + self.updateAppGroups(for: appID, app: app, team: team, session: session) { result in + switch result { + case let .failure(error): completionHandler(.failure(error)) + case let .success(appID): + // Fetch Provisioning Profile - self.fetchProvisioningProfile(for: appID, team: team, session: session) { (result) in + self.fetchProvisioningProfile(for: appID, team: team, session: session) { result in completionHandler(result) } } @@ -235,227 +201,175 @@ extension FetchProvisioningProfilesOperation } } } - - func registerAppID(for application: ALTApplication, name: String, bundleIdentifier: String, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { (appIDs, error) in - do - { + + func registerAppID(for application: ALTApplication, name: String, bundleIdentifier: String, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + ALTAppleAPI.shared.fetchAppIDs(for: team, session: session) { appIDs, error in + do { let appIDs = try Result(appIDs, error).get() - - if let appID = appIDs.first(where: { $0.bundleIdentifier.lowercased() == bundleIdentifier.lowercased() }) - { + + if let appID = appIDs.first(where: { $0.bundleIdentifier.lowercased() == bundleIdentifier.lowercased() }) { completionHandler(.success(appID)) - } - else - { + } else { let requiredAppIDs = 1 + application.appExtensions.count let availableAppIDs = max(0, Team.maximumFreeAppIDs - appIDs.count) - + let sortedExpirationDates = appIDs.compactMap { $0.expirationDate }.sorted(by: { $0 < $1 }) - - if team.type == .free - { - if requiredAppIDs > availableAppIDs - { - if let expirationDate = sortedExpirationDates.first - { + + if team.type == .free { + if requiredAppIDs > availableAppIDs { + if let expirationDate = sortedExpirationDates.first { throw OperationError.maximumAppIDLimitReached(application: application, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, nextExpirationDate: expirationDate) - } - else - { + } else { throw ALTAppleAPIError(.maximumAppIDLimitReached) } } } - - ALTAppleAPI.shared.addAppID(withName: name, bundleIdentifier: bundleIdentifier, team: team, session: session) { (appID, error) in - do - { - do - { + + ALTAppleAPI.shared.addAppID(withName: name, bundleIdentifier: bundleIdentifier, team: team, session: session) { appID, error in + do { + do { let appID = try Result(appID, error).get() completionHandler(.success(appID)) - } - catch ALTAppleAPIError.maximumAppIDLimitReached - { - if let expirationDate = sortedExpirationDates.first - { + } catch ALTAppleAPIError.maximumAppIDLimitReached { + if let expirationDate = sortedExpirationDates.first { throw OperationError.maximumAppIDLimitReached(application: application, requiredAppIDs: requiredAppIDs, availableAppIDs: availableAppIDs, nextExpirationDate: expirationDate) - } - else - { + } else { throw ALTAppleAPIError(.maximumAppIDLimitReached) } } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func updateFeatures(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { + + func updateFeatures(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { var entitlements = app.entitlements - for (key, value) in additionalEntitlements ?? [:] - { + for (key, value) in additionalEntitlements ?? [:] { entitlements[key] = value } - - let requiredFeatures = entitlements.compactMap { (entitlement, value) -> (ALTFeature, Any)? in + + let requiredFeatures = entitlements.compactMap { entitlement, value -> (ALTFeature, Any)? in guard let feature = ALTFeature(entitlement: entitlement) else { return nil } return (feature, value) } - + var features = requiredFeatures.reduce(into: [ALTFeature: Any]()) { $0[$1.0] = $1.1 } - - if let applicationGroups = entitlements[.appGroups] as? [String], !applicationGroups.isEmpty - { + + if let applicationGroups = entitlements[.appGroups] as? [String], !applicationGroups.isEmpty { // App uses app groups, so assign `true` to enable the feature. features[.appGroups] = true - } - else - { + } else { // App has no app groups, so assign `false` to disable the feature. features[.appGroups] = false } - + var updateFeatures = false - + // Determine whether the required features are already enabled for the AppID. - for (feature, value) in features - { - if let appIDValue = appID.features[feature] as AnyObject?, (value as AnyObject).isEqual(appIDValue) - { + for (feature, value) in features { + if let appIDValue = appID.features[feature] as AnyObject?, (value as AnyObject).isEqual(appIDValue) { // AppID already has this feature enabled and the values are the same. continue - } - else if appID.features[feature] == nil, let shouldEnableFeature = value as? Bool, !shouldEnableFeature - { + } else if appID.features[feature] == nil, let shouldEnableFeature = value as? Bool, !shouldEnableFeature { // AppID doesn't already have this feature enabled, but we want it disabled anyway. continue - } - else - { + } else { // AppID either doesn't have this feature enabled or the value has changed, // so we need to update it to reflect new values. updateFeatures = true break } } - - if updateFeatures - { + + if updateFeatures { let appID = appID.copy() as! ALTAppID appID.features = features - - ALTAppleAPI.shared.update(appID, team: team, session: session) { (appID, error) in + + ALTAppleAPI.shared.update(appID, team: team, session: session) { appID, error in completionHandler(Result(appID, error)) } - } - else - { + } else { completionHandler(.success(appID)) } } - - func updateAppGroups(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { + + func updateAppGroups(for appID: ALTAppID, app: ALTApplication, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { var entitlements = app.entitlements - for (key, value) in additionalEntitlements ?? [:] - { + for (key, value) in additionalEntitlements ?? [:] { entitlements[key] = value } - + guard var applicationGroups = entitlements[.appGroups] as? [String], !applicationGroups.isEmpty else { // Assigning an App ID to an empty app group array fails, // so just do nothing if there are no app groups. return completionHandler(.success(appID)) } - - if app.isAltStoreApp - { + + if app.isAltStoreApp { // Potentially updating app groups for this specific AltStore. // Find the (unique) AltStore app group, then replace it // with the correct "base" app group ID. // Otherwise, we may append a duplicate team identifier to the end. - if let index = applicationGroups.firstIndex(where: { $0.contains(Bundle.baseAltStoreAppGroupID) }) - { + if let index = applicationGroups.firstIndex(where: { $0.contains(Bundle.baseAltStoreAppGroupID) }) { applicationGroups[index] = Bundle.baseAltStoreAppGroupID - } - else - { + } else { applicationGroups.append(Bundle.baseAltStoreAppGroupID) } } - + // Dispatch onto global queue to prevent appGroupsLock deadlock. DispatchQueue.global().async { - // Ensure we're not concurrently fetching and updating app groups, // which can lead to race conditions such as adding an app group twice. self.appGroupsLock.lock() - - func finish(_ result: Result) - { + + func finish(_ result: Result) { self.appGroupsLock.unlock() completionHandler(result) } - - ALTAppleAPI.shared.fetchAppGroups(for: team, session: session) { (groups, error) in - switch Result(groups, error) - { - case .failure(let error): finish(.failure(error)) - case .success(let fetchedGroups): + + ALTAppleAPI.shared.fetchAppGroups(for: team, session: session) { groups, error in + switch Result(groups, error) { + case let .failure(error): finish(.failure(error)) + case let .success(fetchedGroups): let dispatchGroup = DispatchGroup() - + var groups = [ALTAppGroup]() var errors = [Error]() - - for groupIdentifier in applicationGroups - { + + for groupIdentifier in applicationGroups { let adjustedGroupIdentifier = groupIdentifier + "." + team.identifier - - if let group = fetchedGroups.first(where: { $0.groupIdentifier == adjustedGroupIdentifier }) - { + + if let group = fetchedGroups.first(where: { $0.groupIdentifier == adjustedGroupIdentifier }) { groups.append(group) - } - else - { + } else { dispatchGroup.enter() - + // Not all characters are allowed in group names, so we replace periods with spaces (like Apple does). let name = "AltStore " + groupIdentifier.replacingOccurrences(of: ".", with: " ") - - ALTAppleAPI.shared.addAppGroup(withName: name, groupIdentifier: adjustedGroupIdentifier, team: team, session: session) { (group, error) in - switch Result(group, error) - { - case .success(let group): groups.append(group) - case .failure(let error): errors.append(error) + + ALTAppleAPI.shared.addAppGroup(withName: name, groupIdentifier: adjustedGroupIdentifier, team: team, session: session) { group, error in + switch Result(group, error) { + case let .success(group): groups.append(group) + case let .failure(error): errors.append(error) } - + dispatchGroup.leave() } } } - + dispatchGroup.notify(queue: .global()) { - if let error = errors.first - { + if let error = errors.first { finish(.failure(error)) - } - else - { - ALTAppleAPI.shared.assign(appID, to: Array(groups), team: team, session: session) { (success, error) in + } else { + ALTAppleAPI.shared.assign(appID, to: Array(groups), team: team, session: session) { success, error in let result = Result(success, error) finish(result.map { _ in appID }) } @@ -465,24 +379,21 @@ extension FetchProvisioningProfilesOperation } } } - - func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) - { - ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in - switch Result(profile, error) - { - case .failure(let error): completionHandler(.failure(error)) - case .success(let profile): - + + func fetchProvisioningProfile(for appID: ALTAppID, team: ALTTeam, session: ALTAppleAPISession, completionHandler: @escaping (Result) -> Void) { + ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { profile, error in + switch Result(profile, error) { + case let .failure(error): completionHandler(.failure(error)) + case let .success(profile): + // Delete existing profile - ALTAppleAPI.shared.delete(profile, for: team, session: session) { (success, error) in - switch Result(success, error) - { - case .failure(let error): completionHandler(.failure(error)) + ALTAppleAPI.shared.delete(profile, for: team, session: session) { success, error in + switch Result(success, error) { + case let .failure(error): completionHandler(.failure(error)) case .success: - + // Fetch new provisiong profile - ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { (profile, error) in + ALTAppleAPI.shared.fetchProvisioningProfile(for: appID, deviceType: .iphone, team: team, session: session) { profile, error in completionHandler(Result(profile, error)) } } diff --git a/AltStore/Operations/FetchSourceOperation.swift b/Sources/SideStore/Operations/FetchSourceOperation.swift similarity index 73% rename from AltStore/Operations/FetchSourceOperation.swift rename to Sources/SideStore/Operations/FetchSourceOperation.swift index 14826927..8381c26f 100644 --- a/AltStore/Operations/FetchSourceOperation.swift +++ b/Sources/SideStore/Operations/FetchSourceOperation.swift @@ -6,102 +6,91 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -import AltStoreCore +import SideStoreCore import RoxasUI @objc(FetchSourceOperation) -final class FetchSourceOperation: ResultOperation -{ +final class FetchSourceOperation: ResultOperation { let sourceURL: URL let managedObjectContext: NSManagedObjectContext - + private let session: URLSession - + private lazy var dateFormatter: ISO8601DateFormatter = { let dateFormatter = ISO8601DateFormatter() return dateFormatter }() - - init(sourceURL: URL, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) - { + + init(sourceURL: URL, managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) { self.sourceURL = sourceURL self.managedObjectContext = managedObjectContext - + let configuration = URLSessionConfiguration.default configuration.requestCachePolicy = .reloadIgnoringLocalCacheData configuration.urlCache = nil - - self.session = URLSession(configuration: configuration) + + session = URLSession(configuration: configuration) } - - override func main() - { + + override func main() { super.main() - - let dataTask = self.session.dataTask(with: self.sourceURL) { (data, response, error) in - + + let dataTask = session.dataTask(with: sourceURL) { data, response, error in + let childContext = DatabaseManager.shared.persistentContainer.newBackgroundContext(withParent: self.managedObjectContext) childContext.mergePolicy = NSOverwriteMergePolicy childContext.perform { - do - { + do { let (data, _) = try Result((data, response), error).get() - + let decoder = AltStoreCore.JSONDecoder() - decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in + decoder.dateDecodingStrategy = .custom { decoder -> Date in let container = try decoder.singleValueContainer() let text = try container.decode(String.self) - + // Full ISO8601 Format. self.dateFormatter.formatOptions = [.withFullDate, .withFullTime, .withTimeZone] - if let date = self.dateFormatter.date(from: text) - { + if let date = self.dateFormatter.date(from: text) { return date } - + // Just date portion of ISO8601. self.dateFormatter.formatOptions = [.withFullDate] - if let date = self.dateFormatter.date(from: text) - { + if let date = self.dateFormatter.date(from: text) { return date } - + throw DecodingError.dataCorruptedError(in: container, debugDescription: "Date is in invalid format.") - }) - + } + decoder.managedObjectContext = childContext decoder.sourceURL = self.sourceURL - + let source = try decoder.decode(Source.self, from: data) let identifier = source.identifier - + try childContext.save() - + self.managedObjectContext.perform { - if let source = Source.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Source.identifier), identifier), in: self.managedObjectContext) - { + if let source = Source.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Source.identifier), identifier), in: self.managedObjectContext) { self.finish(.success(source)) - } - else - { + } else { self.finish(.failure(OperationError.noSources)) } } - } - catch - { + } catch { self.managedObjectContext.perform { self.finish(.failure(error)) } } } } - - self.progress.addChild(dataTask.progress, withPendingUnitCount: 1) - + + progress.addChild(dataTask.progress, withPendingUnitCount: 1) + dataTask.resume() } } diff --git a/AltStore/Operations/FetchTrustedSourcesOperation.swift b/Sources/SideStore/Operations/FetchTrustedSourcesOperation.swift similarity index 60% rename from AltStore/Operations/FetchTrustedSourcesOperation.swift rename to Sources/SideStore/Operations/FetchTrustedSourcesOperation.swift index 9fced831..9bc05413 100644 --- a/AltStore/Operations/FetchTrustedSourcesOperation.swift +++ b/Sources/SideStore/Operations/FetchTrustedSourcesOperation.swift @@ -8,58 +8,48 @@ import Foundation -private extension URL -{ +private extension URL { #if STAGING - static let trustedSources = URL(string: "https://raw.githubusercontent.com/SideStore/SideStore/develop/trustedapps.json")! + static let trustedSources = URL(string: "https://raw.githubusercontent.com/SideStore/SideStore/develop/trustedapps.json")! #else - static let trustedSources = URL(string: "https://raw.githubusercontent.com/SideStore/SideStore/develop/trustedapps.json")! + static let trustedSources = URL(string: "https://raw.githubusercontent.com/SideStore/SideStore/develop/trustedapps.json")! #endif } -extension FetchTrustedSourcesOperation -{ - struct TrustedSource: Decodable - { +extension FetchTrustedSourcesOperation { + struct TrustedSource: Decodable { var identifier: String var sourceURL: URL? } - - private struct Response: Decodable - { + + private struct Response: Decodable { var version: Int var sources: [FetchTrustedSourcesOperation.TrustedSource] } } -final class FetchTrustedSourcesOperation: ResultOperation<[FetchTrustedSourcesOperation.TrustedSource]> -{ - override func main() - { +final class FetchTrustedSourcesOperation: ResultOperation<[FetchTrustedSourcesOperation.TrustedSource]> { + override func main() { super.main() - - let dataTask = URLSession.shared.dataTask(with: .trustedSources) { (data, response, error) in - do - { - if let response = response as? HTTPURLResponse - { + + let dataTask = URLSession.shared.dataTask(with: .trustedSources) { data, response, error in + do { + if let response = response as? HTTPURLResponse { guard response.statusCode != 404 else { self.finish(.failure(URLError(.fileDoesNotExist, userInfo: [NSURLErrorKey: URL.trustedSources]))) return } } - + guard let data = data else { throw error! } - + let response = try Foundation.JSONDecoder().decode(Response.self, from: data) self.finish(.success(response.sources)) - } - catch - { + } catch { self.finish(.failure(error)) } } - + dataTask.resume() } } diff --git a/AltStore/Operations/InstallAppOperation.swift b/Sources/SideStore/Operations/InstallAppOperation.swift similarity index 72% rename from AltStore/Operations/InstallAppOperation.swift rename to Sources/SideStore/Operations/InstallAppOperation.swift index 0c268aa1..45dade01 100644 --- a/AltStore/Operations/InstallAppOperation.swift +++ b/Sources/SideStore/Operations/InstallAppOperation.swift @@ -8,149 +8,131 @@ import Foundation import Network -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI @objc(InstallAppOperation) -final class InstallAppOperation: ResultOperation -{ +final class InstallAppOperation: ResultOperation { let context: InstallAppOperationContext - + private var didCleanUp = false - - init(context: InstallAppOperationContext) - { + + init(context: InstallAppOperationContext) { self.context = context - + super.init() - - self.progress.totalUnitCount = 100 + + progress.totalUnitCount = 100 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + guard - let certificate = self.context.certificate, - let resignedApp = self.context.resignedApp - else { return self.finish(.failure(OperationError.invalidParameters)) } - + let certificate = context.certificate, + let resignedApp = context.resignedApp + else { return finish(.failure(OperationError.invalidParameters)) } + let backgroundContext = DatabaseManager.shared.persistentContainer.newBackgroundContext() backgroundContext.perform { - /* App */ let installedApp: InstalledApp - + // Fetch + update rather than insert + resolve merge conflicts to prevent potential context-level conflicts. - if let app = InstalledApp.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), self.context.bundleIdentifier), in: backgroundContext) - { + if let app = InstalledApp.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), self.context.bundleIdentifier), in: backgroundContext) { installedApp = app - } - else - { + } else { installedApp = InstalledApp(resignedApp: resignedApp, originalBundleIdentifier: self.context.bundleIdentifier, certificateSerialNumber: certificate.serialNumber, context: backgroundContext) } - + installedApp.update(resignedApp: resignedApp, certificateSerialNumber: certificate.serialNumber) installedApp.needsResign = false - - if let team = DatabaseManager.shared.activeTeam(in: backgroundContext) - { + + if let team = DatabaseManager.shared.activeTeam(in: backgroundContext) { installedApp.team = team } - + /* App Extensions */ var installedExtensions = Set() - + if let bundle = Bundle(url: resignedApp.fileURL), let directory = bundle.builtInPlugInsURL, let enumerator = FileManager.default.enumerator(at: directory, includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) { - for case let fileURL as URL in enumerator - { + for case let fileURL as URL in enumerator { guard let appExtensionBundle = Bundle(url: fileURL) else { continue } guard let appExtension = ALTApplication(fileURL: appExtensionBundle.bundleURL) else { continue } - + let parentBundleID = self.context.bundleIdentifier let resignedParentBundleID = resignedApp.bundleIdentifier - + let resignedBundleID = appExtension.bundleIdentifier let originalBundleID = resignedBundleID.replacingOccurrences(of: resignedParentBundleID, with: parentBundleID) - + print("`parentBundleID`: \(parentBundleID)") print("`resignedParentBundleID`: \(resignedParentBundleID)") print("`resignedBundleID`: \(resignedBundleID)") print("`originalBundleID`: \(originalBundleID)") - + let installedExtension: InstalledExtension - - if let appExtension = installedApp.appExtensions.first(where: { $0.bundleIdentifier == originalBundleID }) - { + + if let appExtension = installedApp.appExtensions.first(where: { $0.bundleIdentifier == originalBundleID }) { installedExtension = appExtension - } - else - { + } else { installedExtension = InstalledExtension(resignedAppExtension: appExtension, originalBundleIdentifier: originalBundleID, context: backgroundContext) } - + installedExtension.update(resignedAppExtension: appExtension) - + installedExtensions.insert(installedExtension) } } - + installedApp.appExtensions = installedExtensions - + self.context.beginInstallationHandler?(installedApp) - + // Temporary directory and resigned .ipa no longer needed, so delete them now to ensure AltStore doesn't quit before we get the chance to. self.cleanUp() - + var activeProfiles: Set? - if let sideloadedAppsLimit = UserDefaults.standard.activeAppsLimit - { + if let sideloadedAppsLimit = UserDefaults.standard.activeAppsLimit { // When installing these new profiles, AltServer will remove all non-active profiles to ensure we remain under limit. - + let fetchRequest = InstalledApp.activeAppsFetchRequest() fetchRequest.includesPendingChanges = false - + var activeApps = InstalledApp.fetch(fetchRequest, in: backgroundContext) - if !activeApps.contains(installedApp) - { + if !activeApps.contains(installedApp) { let activeAppsCount = activeApps.map { $0.requiredActiveSlots }.reduce(0, +) - + let availableActiveApps = max(sideloadedAppsLimit - activeAppsCount, 0) - if installedApp.requiredActiveSlots <= availableActiveApps - { + if installedApp.requiredActiveSlots <= availableActiveApps { // This app has not been explicitly activated, but there are enough slots available, // so implicitly activate it. installedApp.isActive = true activeApps.append(installedApp) - } - else - { + } else { installedApp.isActive = false } } - activeProfiles = Set(activeApps.flatMap { (installedApp) -> [String] in + activeProfiles = Set(activeApps.flatMap { installedApp -> [String] in let appExtensionProfiles = installedApp.appExtensions.map { $0.resignedBundleIdentifier } return [installedApp.resignedBundleIdentifier] + appExtensionProfiles }) } - + let ns_bundle = NSString(string: installedApp.bundleIdentifier) let ns_bundle_ptr = UnsafeMutablePointer(mutating: ns_bundle.utf8String) - + let res = minimuxer_install_ipa(ns_bundle_ptr) if res == 0 { installedApp.refreshedDate = Date() @@ -161,43 +143,33 @@ final class InstallAppOperation: ResultOperation } } } - - override func finish(_ result: Result) - { - self.cleanUp() - + + override func finish(_ result: Result) { + cleanUp() + // Only remove refreshed IPA when finished. - if let app = self.context.app - { + if let app = context.app { let fileURL = InstalledApp.refreshedIPAURL(for: app) - - do - { + + do { try FileManager.default.removeItem(at: fileURL) - } - catch - { + } catch { print("Failed to remove refreshed .ipa:", error) } } - + super.finish(result) } } -private extension InstallAppOperation -{ - func cleanUp() - { - guard !self.didCleanUp else { return } - self.didCleanUp = true - - do - { - try FileManager.default.removeItem(at: self.context.temporaryDirectory) - } - catch - { +private extension InstallAppOperation { + func cleanUp() { + guard !didCleanUp else { return } + didCleanUp = true + + do { + try FileManager.default.removeItem(at: context.temporaryDirectory) + } catch { print("Failed to remove temporary directory.", error) } } diff --git a/Sources/SideStore/Operations/Operation.swift b/Sources/SideStore/Operations/Operation.swift new file mode 100644 index 00000000..94ff5c49 --- /dev/null +++ b/Sources/SideStore/Operations/Operation.swift @@ -0,0 +1,80 @@ +// +// Operation.swift +// AltStore +// +// Created by Riley Testut on 6/7/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation +import RoxasUI + +class ResultOperation: Operation { + var resultHandler: ((Result) -> Void)? + + @available(*, unavailable) + override func finish() { + super.finish() + } + + func finish(_ result: Result) { + guard !isFinished else { return } + + if isCancelled { + resultHandler?(.failure(OperationError.cancelled)) + } else { + resultHandler?(result) + } + + super.finish() + } +} + +class Operation: RSTOperation, ProgressReporting { + let progress = Progress.discreteProgress(totalUnitCount: 1) + + private var backgroundTaskID: UIBackgroundTaskIdentifier? + + override var isAsynchronous: Bool { + true + } + + override init() { + super.init() + + progress.cancellationHandler = { [weak self] in self?.cancel() } + } + + override func cancel() { + super.cancel() + + if !progress.isCancelled { + progress.cancel() + } + } + + override func main() { + super.main() + + let name = "com.altstore." + NSStringFromClass(type(of: self)) + backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: name) { [weak self] in + guard let backgroundTask = self?.backgroundTaskID else { return } + + self?.cancel() + + UIApplication.shared.endBackgroundTask(backgroundTask) + self?.backgroundTaskID = .invalid + } + } + + override func finish() { + guard !isFinished else { return } + + super.finish() + + if let backgroundTaskID = backgroundTaskID { + UIApplication.shared.endBackgroundTask(backgroundTaskID) + self.backgroundTaskID = .invalid + } + } +} diff --git a/AltStore/Operations/OperationContexts.swift b/Sources/SideStore/Operations/OperationContexts.swift similarity index 67% rename from AltStore/Operations/OperationContexts.swift rename to Sources/SideStore/Operations/OperationContexts.swift index e60178b3..83f85617 100644 --- a/AltStore/Operations/OperationContexts.swift +++ b/Sources/SideStore/Operations/OperationContexts.swift @@ -6,111 +6,102 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation import Network -import AltStoreCore import AltSign +import SideStoreCore -class OperationContext -{ +class OperationContext { var error: Error? - + var presentingViewController: UIViewController? - + let operations: NSHashTable - - init(error: Error? = nil, operations: [Foundation.Operation] = []) - { + + init(error: Error? = nil, operations: [Foundation.Operation] = []) { self.error = error - + self.operations = NSHashTable.weakObjects() - for operation in operations - { + for operation in operations { self.operations.add(operation) } } - - convenience init(context: OperationContext) - { + + convenience init(context: OperationContext) { self.init(error: context.error, operations: context.operations.allObjects) } } -final class AuthenticatedOperationContext: OperationContext -{ +final class AuthenticatedOperationContext: OperationContext { var session: ALTAppleAPISession? - + var team: ALTTeam? var certificate: ALTCertificate? - + weak var authenticationOperation: AuthenticationOperation? - - convenience init(context: AuthenticatedOperationContext) - { + + convenience init(context: AuthenticatedOperationContext) { self.init(error: context.error, operations: context.operations.allObjects) - - self.session = context.session - self.team = context.team - self.certificate = context.certificate - self.authenticationOperation = context.authenticationOperation + + session = context.session + team = context.team + certificate = context.certificate + authenticationOperation = context.authenticationOperation } } @dynamicMemberLookup -class AppOperationContext -{ +class AppOperationContext { let bundleIdentifier: String let authenticatedContext: AuthenticatedOperationContext - + var app: ALTApplication? var provisioningProfiles: [String: ALTProvisioningProfile]? - + var isFinished = false - + var error: Error? { get { - return _error ?? self.authenticatedContext.error + _error ?? self.authenticatedContext.error } set { _error = newValue } } + private var _error: Error? - - init(bundleIdentifier: String, authenticatedContext: AuthenticatedOperationContext) - { + + init(bundleIdentifier: String, authenticatedContext: AuthenticatedOperationContext) { self.bundleIdentifier = bundleIdentifier self.authenticatedContext = authenticatedContext } - - subscript(dynamicMember keyPath: WritableKeyPath) -> T - { - return self.authenticatedContext[keyPath: keyPath] + + subscript(dynamicMember keyPath: WritableKeyPath) -> T { + self.authenticatedContext[keyPath: keyPath] } } -class InstallAppOperationContext: AppOperationContext -{ +class InstallAppOperationContext: AppOperationContext { lazy var temporaryDirectory: URL = { let temporaryDirectory = FileManager.default.uniqueTemporaryURL() - - do { try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) } - catch { self.error = error } - + + do { try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) } catch { self.error = error } + return temporaryDirectory }() - + var resignedApp: ALTApplication? var installedApp: InstalledApp? { didSet { - self.installedAppContext = self.installedApp?.managedObjectContext + installedAppContext = installedApp?.managedObjectContext } } + private var installedAppContext: NSManagedObjectContext? - + var beginInstallationHandler: ((InstalledApp) -> Void)? - + var alternateIconURL: URL? } diff --git a/AltStore/Operations/OperationError.swift b/Sources/SideStore/Operations/OperationError.swift similarity index 89% rename from AltStore/Operations/OperationError.swift rename to Sources/SideStore/Operations/OperationError.swift index 331db175..db16feb1 100644 --- a/AltStore/Operations/OperationError.swift +++ b/Sources/SideStore/Operations/OperationError.swift @@ -6,33 +6,32 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import AltSign +import Foundation -enum OperationError: LocalizedError -{ +enum OperationError: LocalizedError { static let domain = OperationError.unknown._domain - + case unknown case unknownResult case cancelled case timedOut - + case notAuthenticated case appNotFound - + case unknownUDID - + case invalidApp case invalidParameters - + case maximumAppIDLimitReached(application: ALTApplication, requiredAppIDs: Int, availableAppIDs: Int, nextExpirationDate: Date) - + case noSources - + case openAppFailed(name: String) case missingAppGroup - + case noDevice case createService(name: String) case getFromDevice(name: String) @@ -45,7 +44,7 @@ enum OperationError: LocalizedError case functionArguments case profileInstall case noConnection - + var failureReason: String? { switch self { case .unknown: return NSLocalizedString("An unknown error occured.", comment: "") @@ -58,13 +57,13 @@ enum OperationError: LocalizedError case .invalidApp: return NSLocalizedString("The app is invalid.", comment: "") case .invalidParameters: return NSLocalizedString("Invalid parameters.", comment: "") case .noSources: return NSLocalizedString("There are no SideStore sources.", comment: "") - case .openAppFailed(let name): return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), name) + case let .openAppFailed(name): return String(format: NSLocalizedString("SideStore was denied permission to launch %@.", comment: ""), name) case .missingAppGroup: return NSLocalizedString("SideStore's shared app group could not be found.", comment: "") case .maximumAppIDLimitReached: return NSLocalizedString("Cannot register more than 10 App IDs.", comment: "") case .noDevice: return NSLocalizedString("Cannot fetch the device from the muxer", comment: "") - case .createService(let name): return String(format: NSLocalizedString("Cannot start a %@ server on the device.", comment: ""), name) - case .getFromDevice(let name): return String(format: NSLocalizedString("Cannot fetch %@ from the device.", comment: ""), name) - case .setArgument(let name): return String(format: NSLocalizedString("Cannot set %@ on the device.", comment: ""), name) + case let .createService(name): return String(format: NSLocalizedString("Cannot start a %@ server on the device.", comment: ""), name) + case let .getFromDevice(name): return String(format: NSLocalizedString("Cannot fetch %@ from the device.", comment: ""), name) + case let .setArgument(name): return String(format: NSLocalizedString("Cannot set %@ on the device.", comment: ""), name) case .afc: return NSLocalizedString("AFC was unable to manage files on the device", comment: "") case .install: return NSLocalizedString("Unable to install the app from the staging directory", comment: "") case .uninstall: return NSLocalizedString("Unable to uninstall the app", comment: "") @@ -75,44 +74,39 @@ enum OperationError: LocalizedError case .noConnection: return NSLocalizedString("Unable to connect to the device, make sure Wireguard is enabled and you're connected to WiFi", comment: "") } } - + var recoverySuggestion: String? { - switch self - { - case .maximumAppIDLimitReached(let application, let requiredAppIDs, let availableAppIDs, let date): + switch self { + case let .maximumAppIDLimitReached(application, requiredAppIDs, availableAppIDs, date): let baseMessage = NSLocalizedString("Delete sideloaded apps to free up App ID slots.", comment: "") let message: String - - if requiredAppIDs > 1 - { + + if requiredAppIDs > 1 { let availableText: String - - switch availableAppIDs - { + + switch availableAppIDs { case 0: availableText = NSLocalizedString("none are available", comment: "") case 1: availableText = NSLocalizedString("only 1 is available", comment: "") default: availableText = String(format: NSLocalizedString("only %@ are available", comment: ""), NSNumber(value: availableAppIDs)) } - + let prefixMessage = String(format: NSLocalizedString("%@ requires %@ App IDs, but %@.", comment: ""), application.name, NSNumber(value: requiredAppIDs), availableText) message = prefixMessage + " " + baseMessage - } - else - { + } else { let dateComponents = Calendar.current.dateComponents([.day, .hour, .minute], from: Date(), to: date) - + let dateComponentsFormatter = DateComponentsFormatter() dateComponentsFormatter.maximumUnitCount = 1 dateComponentsFormatter.unitsStyle = .full - + let remainingTime = dateComponentsFormatter.string(from: dateComponents)! - + let remainingTimeMessage = String(format: NSLocalizedString("You can register another App ID in %@.", comment: ""), remainingTime) message = baseMessage + " " + remainingTimeMessage } - + return message - + default: return nil } } diff --git a/AltStore/Operations/Patch App/PatchAppOperation.swift b/Sources/SideStore/Operations/Patch App/PatchAppOperation.swift similarity index 54% rename from AltStore/Operations/Patch App/PatchAppOperation.swift rename to Sources/SideStore/Operations/Patch App/PatchAppOperation.swift index efb8d423..4716f1ad 100644 --- a/AltStore/Operations/Patch App/PatchAppOperation.swift +++ b/Sources/SideStore/Operations/Patch App/PatchAppOperation.swift @@ -6,233 +6,215 @@ // Copyright © 2021 Riley Testut. All rights reserved. // -import UIKit -import Combine import AppleArchive +import Combine import System +import UIKit -import AltStoreCore import AltSign +import SideStoreCore import RoxasUI @available(iOS 14, *) -protocol PatchAppContext -{ +protocol PatchAppContext { var bundleIdentifier: String { get } var temporaryDirectory: URL { get } - + var resignedApp: ALTApplication? { get } var error: Error? { get } } -enum PatchAppError: LocalizedError -{ +enum PatchAppError: LocalizedError { case unsupportedOperatingSystemVersion(OperatingSystemVersion) - + var errorDescription: String? { - switch self - { - case .unsupportedOperatingSystemVersion(let osVersion): + switch self { + case let .unsupportedOperatingSystemVersion(osVersion): var osVersionString = "\(osVersion.majorVersion).\(osVersion.minorVersion)" - if osVersion.patchVersion != 0 - { + if osVersion.patchVersion != 0 { osVersionString += ".\(osVersion.patchVersion)" } - + let errorDescription = String(format: NSLocalizedString("The OTA download URL for iOS %@ could not be determined.", comment: ""), osVersionString) return errorDescription } } } -private struct OTAUpdate -{ +private struct OTAUpdate { var url: URL var archivePath: String } @available(iOS 14, *) -final class PatchAppOperation: ResultOperation -{ +final class PatchAppOperation: ResultOperation { let context: PatchAppContext - + var progressHandler: ((Progress, String) -> Void)? - + private let appPatcher = ALTAppPatcher() private lazy var patchDirectory: URL = self.context.temporaryDirectory.appendingPathComponent("Patch", isDirectory: true) - + private var cancellable: AnyCancellable? - - init(context: PatchAppContext) - { + + init(context: PatchAppContext) { self.context = context - + super.init() - - self.progress.totalUnitCount = 100 + + progress.totalUnitCount = 100 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - guard let resignedApp = self.context.resignedApp else { return self.finish(.failure(OperationError.invalidParameters)) } - - self.progressHandler?(self.progress, NSLocalizedString("Downloading iOS firmware...", comment: "")) - - self.cancellable = self.fetchOTAUpdate() + + guard let resignedApp = context.resignedApp else { return finish(.failure(OperationError.invalidParameters)) } + + progressHandler?(progress, NSLocalizedString("Downloading iOS firmware...", comment: "")) + + cancellable = fetchOTAUpdate() .flatMap { self.downloadArchive(from: $0) } .flatMap { self.extractSpotlightFromArchive(at: $0) } .flatMap { self.patch(resignedApp, withBinaryAt: $0) } .tryMap { try FileManager.default.zipAppBundle(at: $0) } - .tryMap { (fileURL) in + .tryMap { fileURL in let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL) - + let destinationURL = InstalledApp.refreshedIPAURL(for: app) try FileManager.default.copyItem(at: fileURL, to: destinationURL, shouldReplace: true) } .receive(on: RunLoop.main) .sink { completion in - switch completion - { - case .failure(let error): self.finish(.failure(error)) + switch completion { + case let .failure(error): self.finish(.failure(error)) case .finished: self.finish(.success(())) } } receiveValue: { _ in } } - - override func cancel() - { + + override func cancel() { super.cancel() - - self.cancellable?.cancel() - self.cancellable = nil + + cancellable?.cancel() + cancellable = nil } } -private let ALTFragmentZipCallback: @convention(c) (UInt32) -> Void = { (percentageComplete) in +private let ALTFragmentZipCallback: @convention(c) (UInt32) -> Void = { percentageComplete in guard let progress = Progress.current() else { return } - - if percentageComplete == 100 && progress.completedUnitCount == 0 - { + + if percentageComplete == 100, progress.completedUnitCount == 0 { // Ignore first percentageComplete, which is always 100. return } - + progress.completedUnitCount = Int64(percentageComplete) } @available(iOS 14, *) -private extension PatchAppOperation -{ - func fetchOTAUpdate() -> AnyPublisher - { +private extension PatchAppOperation { + func fetchOTAUpdate() -> AnyPublisher { Just(()).tryMap { let osVersion = ProcessInfo.processInfo.operatingSystemVersion - switch (osVersion.majorVersion, osVersion.minorVersion) - { + switch (osVersion.majorVersion, osVersion.minorVersion) { case (14, 3): return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2020WinterFCS/patches/001-87330/99E29969-F6B6-422A-B946-70DE2E2D73BE/com_apple_MobileAsset_SoftwareUpdate/67f9e42f5e57a20e0a87eaf81b69dd2a61311d3f.zip")!, - archivePath: "AssetData/payloadv2/payload.042") - + archivePath: "AssetData/payloadv2/payload.042") + case (14, 4): return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2021WinterFCS/patches/001-98606/43AF99A1-F286-43B1-A101-F9F856EA395A/com_apple_MobileAsset_SoftwareUpdate/c4985c32c344beb7b49c61919b4e39d1fd336c90.zip")!, - archivePath: "AssetData/payloadv2/payload.042") - + archivePath: "AssetData/payloadv2/payload.042") + case (14, 5): return OTAUpdate(url: URL(string: "https://updates.cdn-apple.com/2021SpringFCS/patches/061-84483/AB525139-066E-46F8-8E85-DCE802C03BA8/com_apple_MobileAsset_SoftwareUpdate/788573ae93113881db04269acedeecabbaa643e3.zip")!, - archivePath: "AssetData/payloadv2/payload.043") - + archivePath: "AssetData/payloadv2/payload.043") + default: throw PatchAppError.unsupportedOperatingSystemVersion(osVersion) } } .eraseToAnyPublisher() } - - func downloadArchive(from update: OTAUpdate) -> AnyPublisher - { + + func downloadArchive(from update: OTAUpdate) -> AnyPublisher { Just(()).tryMap { #if targetEnvironment(simulator) - throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) + throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) #else - - try FileManager.default.createDirectory(at: self.patchDirectory, withIntermediateDirectories: true, attributes: nil) - - let archiveURL = self.patchDirectory.appendingPathComponent("ota.archive") - try archiveURL.withUnsafeFileSystemRepresentation { archivePath in - guard let fz = fragmentzip_open((update.url.absoluteString as NSString).utf8String!) else { - throw URLError(.cannotConnectToHost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because a connection cannot be made to the host.", comment: ""), - NSURLErrorKey: update.url]) + + try FileManager.default.createDirectory(at: self.patchDirectory, withIntermediateDirectories: true, attributes: nil) + + let archiveURL = self.patchDirectory.appendingPathComponent("ota.archive") + try archiveURL.withUnsafeFileSystemRepresentation { archivePath in + guard let fz = fragmentzip_open((update.url.absoluteString as NSString).utf8String!) else { + throw URLError(.cannotConnectToHost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because a connection cannot be made to the host.", comment: ""), + NSURLErrorKey: update.url]) + } + defer { fragmentzip_close(fz) } + + self.progress.becomeCurrent(withPendingUnitCount: 100) + defer { self.progress.resignCurrent() } + + guard fragmentzip_download_file(fz, update.archivePath, archivePath!, ALTFragmentZipCallback) == 0 else { + throw URLError(.networkConnectionLost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because the network connection was lost.", comment: ""), + NSURLErrorKey: update.url]) + } } - defer { fragmentzip_close(fz) } - - self.progress.becomeCurrent(withPendingUnitCount: 100) - defer { self.progress.resignCurrent() } - - guard fragmentzip_download_file(fz, update.archivePath, archivePath!, ALTFragmentZipCallback) == 0 else { - throw URLError(.networkConnectionLost, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("The connection failed because the network connection was lost.", comment: ""), - NSURLErrorKey: update.url]) - } - } - - print("Downloaded OTA archive.") - return archiveURL - + + print("Downloaded OTA archive.") + return archiveURL + #endif } .mapError { ($0 as NSError).withLocalizedFailure(NSLocalizedString("Could not download OTA archive.", comment: "")) } .eraseToAnyPublisher() } - - func extractSpotlightFromArchive(at archiveURL: URL) -> AnyPublisher - { + + func extractSpotlightFromArchive(at archiveURL: URL) -> AnyPublisher { Just(()).tryMap { #if targetEnvironment(simulator) - throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) + throw PatchAppError.unsupportedOperatingSystemVersion(ProcessInfo.processInfo.operatingSystemVersion) #else - - let spotlightPath = "Applications/Spotlight.app/Spotlight" - let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath) - - guard let readFileStream = ArchiveByteStream.fileStream(path: FilePath(archiveURL.path), mode: .readOnly, options: [], permissions: FilePermissions(rawValue: 0o644)), - let decompressStream = ArchiveByteStream.decompressionStream(readingFrom: readFileStream), - let decodeStream = ArchiveStream.decodeStream(readingFrom: decompressStream), - let readStream = ArchiveStream.extractStream(extractingTo: FilePath(self.patchDirectory.path)) - else { throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: archiveURL]) } - - _ = try ArchiveStream.process(readingFrom: decodeStream, writingTo: readStream) { message, filePath, data in - guard filePath == FilePath(spotlightPath) else { return .skip } - return .ok - } - - print("Extracted Spotlight from OTA archive.") - return spotlightFileURL - + + let spotlightPath = "Applications/Spotlight.app/Spotlight" + let spotlightFileURL = self.patchDirectory.appendingPathComponent(spotlightPath) + + guard let readFileStream = ArchiveByteStream.fileStream(path: FilePath(archiveURL.path), mode: .readOnly, options: [], permissions: FilePermissions(rawValue: 0o644)), + let decompressStream = ArchiveByteStream.decompressionStream(readingFrom: readFileStream), + let decodeStream = ArchiveStream.decodeStream(readingFrom: decompressStream), + let readStream = ArchiveStream.extractStream(extractingTo: FilePath(self.patchDirectory.path)) + else { throw CocoaError(.fileReadCorruptFile, userInfo: [NSURLErrorKey: archiveURL]) } + + _ = try ArchiveStream.process(readingFrom: decodeStream, writingTo: readStream) { _, filePath, _ in + guard filePath == FilePath(spotlightPath) else { return .skip } + return .ok + } + + print("Extracted Spotlight from OTA archive.") + return spotlightFileURL + #endif } .mapError { ($0 as NSError).withLocalizedFailure(NSLocalizedString("Could not extract Spotlight from OTA archive.", comment: "")) } .eraseToAnyPublisher() } - - func patch(_ app: ALTApplication, withBinaryAt patchFileURL: URL) -> AnyPublisher - { + + func patch(_ app: ALTApplication, withBinaryAt patchFileURL: URL) -> AnyPublisher { Just(()).tryMap { // executableURL may be nil, so use infoDictionary instead to determine executable name. // guard let appName = app.bundle.executableURL?.lastPathComponent else { throw OperationError.invalidApp } guard let appName = app.bundle.infoDictionary?[kCFBundleExecutableKey as String] as? String else { throw OperationError.invalidApp } - + let temporaryAppURL = self.patchDirectory.appendingPathComponent("Patched.app", isDirectory: true) try FileManager.default.copyItem(at: app.fileURL, to: temporaryAppURL) - + let appBinaryURL = temporaryAppURL.appendingPathComponent(appName, isDirectory: false) try self.appPatcher.patchAppBinary(at: appBinaryURL, withBinaryAt: patchFileURL) - + print("Patched \(app.name).") return temporaryAppURL } diff --git a/Sources/SideStore/Operations/Patch App/PatchViewController.swift b/Sources/SideStore/Operations/Patch App/PatchViewController.swift new file mode 100644 index 00000000..e8b3a575 --- /dev/null +++ b/Sources/SideStore/Operations/Patch App/PatchViewController.swift @@ -0,0 +1,443 @@ +// +// PatchViewController.swift +// AltStore +// +// Created by Riley Testut on 10/20/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import Combine +import UIKit + +import AltSign +import SideStoreCore +import RoxasUI + +@available(iOS 14.0, *) +extension PatchViewController { + enum Step { + case confirm + case install + case openApp + case patchApp + case reboot + case refresh + case finish + } +} + +@available(iOS 14.0, *) +final class PatchViewController: UIViewController { + var patchApp: AnyApp? + var installedApp: InstalledApp? + + var completionHandler: ((Result) -> Void)? + + private let context = AuthenticatedOperationContext() + + private var currentStep: Step = .confirm { + didSet { + DispatchQueue.main.async { + self.update() + } + } + } + + private var buttonHandler: (() -> Void)? + private var resignedApp: ALTApplication? + + private lazy var temporaryDirectory: URL = FileManager.default.uniqueTemporaryURL() + + private var didEnterBackgroundObservation: NSObjectProtocol? + private weak var cancellableProgress: Progress? + + @IBOutlet private var placeholderView: RSTPlaceholderView! + @IBOutlet private var taskDescriptionLabel: UILabel! + @IBOutlet private var pillButton: PillButton! + @IBOutlet private var cancelBarButtonItem: UIBarButtonItem! + @IBOutlet private var cancelButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + isModalInPresentation = true + + placeholderView.stackView.spacing = 20 + placeholderView.textLabel.textColor = .white + + placeholderView.detailTextLabel.textAlignment = .left + placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6) + + buttonHandler = { [weak self] in + self?.startProcess() + } + + do { + try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) + } catch { + print("Failed to create temporary directory:", error) + } + + update() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + if installedApp != nil { + refreshApp() + } + } +} + +@available(iOS 14.0, *) +private extension PatchViewController { + func update() { + cancelButton.alpha = 0.0 + + switch currentStep { + case .confirm: + guard let app = patchApp else { break } + + if UIDevice.current.isUntetheredJailbreakRequired { + placeholderView.textLabel.text = NSLocalizedString("Jailbreak Requires Untethering", comment: "") + placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak is untethered, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name) + } else { + placeholderView.textLabel.text = NSLocalizedString("Jailbreak Supports Untethering", comment: "") + placeholderView.detailTextLabel.text = String(format: NSLocalizedString("This jailbreak has an untethered version, which means %@ will never expire — even after 7 days or rebooting the device.\n\nInstalling an untethered jailbreak requires a few extra steps, but SideStore will walk you through the process.\n\nWould you like to continue? ", comment: ""), app.name) + } + + pillButton.setTitle(NSLocalizedString("Install Untethered Jailbreak", comment: ""), for: .normal) + + cancelButton.alpha = 1.0 + + case .install: + guard let app = patchApp else { break } + + placeholderView.textLabel.text = String(format: NSLocalizedString("Installing %@ placeholder…", comment: ""), app.name) + placeholderView.detailTextLabel.text = NSLocalizedString("A placeholder app needs to be installed in order to prepare your device for untethering.\n\nThis may take a few moments.", comment: "") + + case .openApp: + placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "") + placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "") + + pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal) + + case .patchApp: + guard let app = patchApp else { break } + + placeholderView.textLabel.text = String(format: NSLocalizedString("Patching %@ placeholder…", comment: ""), app.name) + placeholderView.detailTextLabel.text = NSLocalizedString("This will take a few moments. Please do not turn off the screen or leave the app until patching is complete.", comment: "") + + pillButton.setTitle(NSLocalizedString("Patch Placeholder", comment: ""), for: .normal) + + case .reboot: + placeholderView.textLabel.text = NSLocalizedString("Continue in App", comment: "") + placeholderView.detailTextLabel.text = NSLocalizedString("Please open the placeholder app and follow the instructions to continue jailbreaking your device.", comment: "") + + pillButton.setTitle(NSLocalizedString("Open Placeholder", comment: ""), for: .normal) + + case .refresh: + guard let installedApp = installedApp else { break } + + placeholderView.textLabel.text = String(format: NSLocalizedString("Finish installing %@?", comment: ""), installedApp.name) + placeholderView.detailTextLabel.text = String(format: NSLocalizedString("In order to finish jailbreaking this device, you need to install %@ then follow the instructions in the app.", comment: ""), installedApp.name) + + pillButton.setTitle(String(format: NSLocalizedString("Install %@", comment: ""), installedApp.name), for: .normal) + + case .finish: + guard let installedApp = installedApp else { break } + + placeholderView.textLabel.text = String(format: NSLocalizedString("Finish in %@", comment: ""), installedApp.name) + placeholderView.detailTextLabel.text = String(format: NSLocalizedString("Follow the instructions in %@ to finish jailbreaking this device.", comment: ""), installedApp.name) + + pillButton.setTitle(String(format: NSLocalizedString("Open %@", comment: ""), installedApp.name), for: .normal) + } + } + + func present(_ error: Error, title: String) { + DispatchQueue.main.async { + let nsError = error as NSError + + let alertController = UIAlertController(title: nsError.localizedFailure ?? title, message: error.localizedDescription, preferredStyle: .alert) + alertController.addAction(.ok) + self.present(alertController, animated: true, completion: nil) + + self.setProgress(nil, description: nil) + } + } + + func setProgress(_ progress: Progress?, description: String?) { + DispatchQueue.main.async { + self.pillButton.progress = progress + self.taskDescriptionLabel.text = description ?? " " // Use non-empty string to prevent label resizing itself. + } + } + + func finish(with result: Result) { + do { + try FileManager.default.removeItem(at: temporaryDirectory) + } catch { + print("Failed to remove temporary directory:", error) + } + + if let observation = didEnterBackgroundObservation { + NotificationCenter.default.removeObserver(observation) + } + + completionHandler?(result) + completionHandler = nil + } +} + +@available(iOS 14.0, *) +private extension PatchViewController { + @IBAction func performButtonAction() { + buttonHandler?() + } + + @IBAction func cancel() { + finish(with: .success(())) + + cancellableProgress?.cancel() + } + + @IBAction func installRegularJailbreak() { + guard let app = patchApp else { return } + + let title: String + let message: String + + if UIDevice.current.isUntetheredJailbreakRequired { + title = NSLocalizedString("Untethering Required", comment: "") + message = String(format: NSLocalizedString("%@ can not jailbreak this device unless you untether it first. Are you sure you want to install without untethering?", comment: ""), app.name) + } else { + title = NSLocalizedString("Untethering Recommended", comment: "") + message = String(format: NSLocalizedString("Untethering this jailbreak will prevent %@ from expiring, even after 7 days or rebooting the device. Are you sure you want to install without untethering?", comment: ""), app.name) + } + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("Install Without Untethering", comment: ""), style: .default) { _ in + self.finish(with: .failure(OperationError.cancelled)) + }) + alertController.addAction(.cancel) + present(alertController, animated: true, completion: nil) + } +} + +@available(iOS 14.0, *) +private extension PatchViewController { + func startProcess() { + guard let patchApp = patchApp else { return } + + currentStep = .install + + if let progress = AppManager.shared.installationProgress(for: patchApp) { + // Cancel pending jailbreak app installation so we can start a new one. + progress.cancel() + } + + let appURL = InstalledApp.fileURL(for: patchApp) + let cachedAppURL = temporaryDirectory.appendingPathComponent("Cached.app") + + do { + // Make copy of original app, so we can replace the cached patch app with it later. + try FileManager.default.copyItem(at: appURL, to: cachedAppURL, shouldReplace: true) + } catch { + present(error, title: NSLocalizedString("Could not back up jailbreak app.", comment: "")) + return + } + + var unzippingError: Error? + let refreshGroup = AppManager.shared.install(patchApp, presentingViewController: self, context: context) { result in + do { + _ = try result.get() + + if let unzippingError = unzippingError { + throw unzippingError + } + + // Replace cached patch app with original app so we can resume installing it post-reboot. + try FileManager.default.copyItem(at: cachedAppURL, to: appURL, shouldReplace: true) + + self.openApp() + } catch { + self.present(error, title: String(format: NSLocalizedString("Could not install %@ placeholder.", comment: ""), patchApp.name)) + } + } + refreshGroup.beginInstallationHandler = { installedApp in + do { + // Replace patch app name with correct name. + installedApp.name = patchApp.name + + let ipaURL = installedApp.refreshedIPAURL + let resignedAppURL = try FileManager.default.unzipAppBundle(at: ipaURL, toDirectory: self.temporaryDirectory) + + self.resignedApp = ALTApplication(fileURL: resignedAppURL) + } catch { + print("Error unzipping app bundle:", error) + unzippingError = error + } + } + setProgress(refreshGroup.progress, description: nil) + + cancellableProgress = refreshGroup.progress + } + + func openApp() { + guard let patchApp = patchApp else { return } + + setProgress(nil, description: nil) + currentStep = .openApp + + // This observation is willEnterForeground because patching starts immediately upon return. + didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in + self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } + self.patchApplication() + } + + buttonHandler = { [weak self] in + guard let self = self else { return } + + #if !targetEnvironment(simulator) + + let openURL = InstalledApp.openAppURL(for: patchApp) + UIApplication.shared.open(openURL) { success in + guard !success else { return } + self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name)) + } + + #endif + } + } + + func patchApplication() { + guard let resignedApp = resignedApp else { return } + + currentStep = .patchApp + + buttonHandler = { [weak self] in + self?.patchApplication() + } + + let patchAppOperation = AppManager.shared.patch(resignedApp: resignedApp, presentingViewController: self, context: context) { result in + switch result { + case let .failure(error): self.present(error, title: String(format: NSLocalizedString("Could not patch %@ placeholder.", comment: ""), resignedApp.name)) + case .success: self.rebootDevice() + } + } + patchAppOperation.progressHandler = { progress, description in + self.setProgress(progress, description: description) + } + cancellableProgress = patchAppOperation.progress + } + + func rebootDevice() { + guard let patchApp = patchApp else { return } + + setProgress(nil, description: nil) + currentStep = .reboot + + didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in + self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } + + var patchedApps = UserDefaults.standard.patchedApps ?? [] + if !patchedApps.contains(patchApp.bundleIdentifier) { + patchedApps.append(patchApp.bundleIdentifier) + UserDefaults.standard.patchedApps = patchedApps + } + + self.finish(with: .success(())) + } + + buttonHandler = { [weak self] in + guard let self = self else { return } + + #if !targetEnvironment(simulator) + + let openURL = InstalledApp.openAppURL(for: patchApp) + UIApplication.shared.open(openURL) { success in + guard !success else { return } + self.present(OperationError.openAppFailed(name: patchApp.name), title: String(format: NSLocalizedString("Could not open %@ placeholder.", comment: ""), patchApp.name)) + } + + #endif + } + } + + func refreshApp() { + guard let installedApp = installedApp else { return } + + currentStep = .refresh + + buttonHandler = { [weak self] in + guard let self = self else { return } + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + let tempApp = context.object(with: installedApp.objectID) as! InstalledApp + tempApp.needsResign = true + + let errorTitle = String(format: NSLocalizedString("Could not install %@.", comment: ""), tempApp.name) + + do { + try context.save() + + installedApp.managedObjectContext?.perform { + // Refreshing ensures we don't attempt to patch the app again, + // since that is only checked when installing a new app. + let refreshGroup = AppManager.shared.refresh([installedApp], presentingViewController: self, group: nil) + refreshGroup.completionHandler = { [weak refreshGroup, weak self] results in + guard let self = self else { return } + + do { + guard let (bundleIdentifier, result) = results.first else { throw refreshGroup?.context.error ?? OperationError.unknown } + _ = try result.get() + + if var patchedApps = UserDefaults.standard.patchedApps, let index = patchedApps.firstIndex(of: bundleIdentifier) { + patchedApps.remove(at: index) + UserDefaults.standard.patchedApps = patchedApps + } + + self.finish() + } catch { + self.present(error, title: errorTitle) + } + } + self.setProgress(refreshGroup.progress, description: String(format: NSLocalizedString("Installing %@...", comment: ""), installedApp.name)) + } + } catch { + self.present(error, title: errorTitle) + } + } + } + } + + func finish() { + guard let installedApp = installedApp else { return } + + setProgress(nil, description: nil) + currentStep = .finish + + didEnterBackgroundObservation = NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in + self.didEnterBackgroundObservation.map { NotificationCenter.default.removeObserver($0) } + self.finish(with: .success(())) + } + + installedApp.managedObjectContext?.perform { + let appName = installedApp.name + let openURL = installedApp.openAppURL + + self.buttonHandler = { [weak self] in + guard let self = self else { return } + + #if !targetEnvironment(simulator) + + UIApplication.shared.open(openURL) { success in + guard !success else { return } + self.present(OperationError.openAppFailed(name: appName), title: String(format: NSLocalizedString("Could not open %@.", comment: ""), appName)) + } + + #endif + } + } + } +} diff --git a/AltStore/Operations/RefreshAppOperation.swift b/Sources/SideStore/Operations/RefreshAppOperation.swift similarity index 71% rename from AltStore/Operations/RefreshAppOperation.swift rename to Sources/SideStore/Operations/RefreshAppOperation.swift index 8f09d280..11837db2 100644 --- a/AltStore/Operations/RefreshAppOperation.swift +++ b/Sources/SideStore/Operations/RefreshAppOperation.swift @@ -8,58 +8,53 @@ import Foundation -import AltStoreCore import AltSign -import RoxasUI +import SideStoreCore import minimuxer +import RoxasUI @objc(RefreshAppOperation) -final class RefreshAppOperation: ResultOperation -{ +final class RefreshAppOperation: ResultOperation { let context: AppOperationContext - + // Strong reference to managedObjectContext to keep it alive until we're finished. let managedObjectContext: NSManagedObjectContext - - init(context: AppOperationContext) - { + + init(context: AppOperationContext) { self.context = context - self.managedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext() - + managedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext() + super.init() } - - override func main() - { + + override func main() { super.main() - - do - { - if let error = self.context.error - { + + do { + if let error = context.error { throw error } - - guard let profiles = self.context.provisioningProfiles else { throw OperationError.invalidParameters } - - guard let app = self.context.app else { throw OperationError.appNotFound } - - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + guard let profiles = context.provisioningProfiles else { throw OperationError.invalidParameters } + + guard let app = context.app else { throw OperationError.appNotFound } + + DatabaseManager.shared.persistentContainer.performBackgroundTask { _ in print("Sending refresh app request...") for p in profiles { do { let x = try install_provisioning_profile(plist: p.value.data) - if case .Bad(let code) = x { + if case let .Bad(code) = x { self.finish(.failure(minimuxer_to_operation(code: code))) } - } catch Uhoh.Bad(let code) { + } catch let Uhoh.Bad(code) { self.finish(.failure(minimuxer_to_operation(code: code))) } catch { self.finish(.failure(OperationError.unknown)) } self.progress.completedUnitCount += 1 - + let predicate = NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), app.bundleIdentifier) self.managedObjectContext.perform { guard let installedApp = InstalledApp.first(satisfying: predicate, in: self.managedObjectContext) else { @@ -74,10 +69,8 @@ final class RefreshAppOperation: ResultOperation } } } - } - catch - { - self.finish(.failure(error)) + } catch { + finish(.failure(error)) } } } diff --git a/AltStore/Operations/RefreshGroup.swift b/Sources/SideStore/Operations/RefreshGroup.swift similarity index 61% rename from AltStore/Operations/RefreshGroup.swift rename to Sources/SideStore/Operations/RefreshGroup.swift index 27406257..df5fa948 100644 --- a/AltStore/Operations/RefreshGroup.swift +++ b/Sources/SideStore/Operations/RefreshGroup.swift @@ -6,87 +6,77 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -import AltStoreCore import AltSign +import SideStoreCore -final class RefreshGroup: NSObject -{ +final class RefreshGroup: NSObject { let context: AuthenticatedOperationContext let progress = Progress.discreteProgress(totalUnitCount: 0) - + var completionHandler: (([String: Result]) -> Void)? var beginInstallationHandler: ((InstalledApp) -> Void)? - + private(set) var results = [String: Result]() - + // Keep strong references to managed object contexts // so they don't die out from under us. private(set) var _contexts = Set() - + private var isFinished = false - + private let dispatchGroup = DispatchGroup() private var operations: [Foundation.Operation] = [] - - init(context: AuthenticatedOperationContext = AuthenticatedOperationContext()) - { + + init(context: AuthenticatedOperationContext = AuthenticatedOperationContext()) { self.context = context - + super.init() } - + /// Used to keep track of which operations belong to this group. /// This does _not_ add them to any operation queue. - func add(_ operations: [Foundation.Operation]) - { - for operation in operations - { - self.dispatchGroup.enter() - + func add(_ operations: [Foundation.Operation]) { + for operation in operations { + dispatchGroup.enter() + operation.completionBlock = { [weak self] in self?.dispatchGroup.leave() } } - - if self.operations.isEmpty && !operations.isEmpty - { - self.dispatchGroup.notify(queue: .global()) { [weak self] in + + if self.operations.isEmpty && !operations.isEmpty { + dispatchGroup.notify(queue: .global()) { [weak self] in self?.finish() } } - + self.operations.append(contentsOf: operations) } - - func set(_ result: Result, forAppWithBundleIdentifier bundleIdentifier: String) - { - self.results[bundleIdentifier] = result - - switch result - { + + func set(_ result: Result, forAppWithBundleIdentifier bundleIdentifier: String) { + results[bundleIdentifier] = result + + switch result { case .failure: break - case .success(let installedApp): + case let .success(installedApp): guard let context = installedApp.managedObjectContext else { break } - self._contexts.insert(context) + _contexts.insert(context) } } - - func cancel() - { - self.operations.forEach { $0.cancel() } + + func cancel() { + operations.forEach { $0.cancel() } } } -private extension RefreshGroup -{ - func finish() - { - guard !self.isFinished else { return } - self.isFinished = true - - self.completionHandler?(self.results) +private extension RefreshGroup { + func finish() { + guard !isFinished else { return } + isFinished = true + + completionHandler?(results) } } diff --git a/AltStore/Operations/RemoveAppBackupOperation.swift b/Sources/SideStore/Operations/RemoveAppBackupOperation.swift similarity index 51% rename from AltStore/Operations/RemoveAppBackupOperation.swift rename to Sources/SideStore/Operations/RemoveAppBackupOperation.swift index 24df7ba2..e03587bd 100644 --- a/AltStore/Operations/RemoveAppBackupOperation.swift +++ b/Sources/SideStore/Operations/RemoveAppBackupOperation.swift @@ -9,65 +9,55 @@ import Foundation @objc(RemoveAppBackupOperation) -final class RemoveAppBackupOperation: ResultOperation -{ +final class RemoveAppBackupOperation: ResultOperation { let context: InstallAppOperationContext - + private let coordinator = NSFileCoordinator() private let coordinatorQueue = OperationQueue() - - init(context: InstallAppOperationContext) - { + + init(context: InstallAppOperationContext) { self.context = context - + super.init() - - self.coordinatorQueue.name = "AltStore - RemoveAppBackupOperation Queue" + + coordinatorQueue.name = "AltStore - RemoveAppBackupOperation Queue" } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) } + + guard let installedApp = context.installedApp else { return finish(.failure(OperationError.invalidParameters)) } installedApp.managedObjectContext?.perform { guard let backupDirectoryURL = FileManager.default.backupDirectoryURL(for: installedApp) else { return self.finish(.failure(OperationError.missingAppGroup)) } - + let intent = NSFileAccessIntent.writingIntent(with: backupDirectoryURL, options: [.forDeleting]) - self.coordinator.coordinate(with: [intent], queue: self.coordinatorQueue) { (error) in - do - { - if let error = error - { + self.coordinator.coordinate(with: [intent], queue: self.coordinatorQueue) { error in + do { + if let error = error { throw error } - + try FileManager.default.removeItem(at: intent.url) - + self.finish(.success(())) - } - catch let error as CocoaError where error.code == CocoaError.Code.fileNoSuchFile - { + } catch let error as CocoaError where error.code == CocoaError.Code.fileNoSuchFile { #if DEBUG - - // When debugging, it's expected that app groups don't match, so ignore. - self.finish(.success(())) - + + // When debugging, it's expected that app groups don't match, so ignore. + self.finish(.success(())) + #else - - print("Failed to remove app backup directory:", error) - self.finish(.failure(error)) - + + print("Failed to remove app backup directory:", error) + self.finish(.failure(error)) + #endif - } - catch - { + } catch { print("Failed to remove app backup directory:", error) self.finish(.failure(error)) } diff --git a/AltStore/Operations/RemoveAppOperation.swift b/Sources/SideStore/Operations/RemoveAppOperation.swift similarity index 67% rename from AltStore/Operations/RemoveAppOperation.swift rename to Sources/SideStore/Operations/RemoveAppOperation.swift index 6ec3cba4..0d52fd48 100644 --- a/AltStore/Operations/RemoveAppOperation.swift +++ b/Sources/SideStore/Operations/RemoveAppOperation.swift @@ -8,49 +8,45 @@ import Foundation -import AltStoreCore +import SideStoreCore import minimuxer @objc(RemoveAppOperation) -final class RemoveAppOperation: ResultOperation -{ +final class RemoveAppOperation: ResultOperation { let context: InstallAppOperationContext - - init(context: InstallAppOperationContext) - { + + init(context: InstallAppOperationContext) { self.context = context - + super.init() } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - guard let installedApp = self.context.installedApp else { return self.finish(.failure(OperationError.invalidParameters)) } - + + guard let installedApp = context.installedApp else { return finish(.failure(OperationError.invalidParameters)) } + installedApp.managedObjectContext?.perform { let resignedBundleIdentifier = installedApp.resignedBundleIdentifier - + do { let res = try remove_app(app_id: resignedBundleIdentifier) - if case Uhoh.Bad(let code) = res { + if case let Uhoh.Bad(code) = res { self.finish(.failure(minimuxer_to_operation(code: code))) } - } catch Uhoh.Bad(let code) { + } catch let Uhoh.Bad(code) { self.finish(.failure(minimuxer_to_operation(code: code))) } catch { self.finish(.failure(ALTServerError(.appDeletionFailed))) } - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in self.progress.completedUnitCount += 1 - + let installedApp = context.object(with: installedApp.objectID) as! InstalledApp installedApp.isActive = false self.finish(.success(installedApp)) @@ -58,4 +54,3 @@ final class RemoveAppOperation: ResultOperation } } } - diff --git a/AltStore/Operations/ResignAppOperation.swift b/Sources/SideStore/Operations/ResignAppOperation.swift similarity index 74% rename from AltStore/Operations/ResignAppOperation.swift rename to Sources/SideStore/Operations/ResignAppOperation.swift index 7232cb87..5a3ca7fe 100644 --- a/AltStore/Operations/ResignAppOperation.swift +++ b/Sources/SideStore/Operations/ResignAppOperation.swift @@ -9,65 +9,58 @@ import Foundation import RoxasUI -import AltStoreCore import AltSign +import SideStoreCore @objc(ResignAppOperation) -final class ResignAppOperation: ResultOperation -{ +final class ResignAppOperation: ResultOperation { let context: InstallAppOperationContext - - init(context: InstallAppOperationContext) - { + + init(context: InstallAppOperationContext) { self.context = context - + super.init() - - self.progress.totalUnitCount = 3 + + progress.totalUnitCount = 3 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - + guard - let app = self.context.app, - let profiles = self.context.provisioningProfiles, - let team = self.context.team, - let certificate = self.context.certificate - else { return self.finish(.failure(OperationError.invalidParameters)) } - + let app = context.app, + let profiles = context.provisioningProfiles, + let team = context.team, + let certificate = context.certificate + else { return finish(.failure(OperationError.invalidParameters)) } + // Prepare app bundle let prepareAppProgress = Progress.discreteProgress(totalUnitCount: 2) - self.progress.addChild(prepareAppProgress, withPendingUnitCount: 3) - - let prepareAppBundleProgress = self.prepareAppBundle(for: app, profiles: profiles) { (result) in + progress.addChild(prepareAppProgress, withPendingUnitCount: 3) + + let prepareAppBundleProgress = prepareAppBundle(for: app, profiles: profiles) { result in guard let appBundleURL = self.process(result) else { return } - + print("Resigning App:", self.context.bundleIdentifier) - + // Resign app bundle - let resignProgress = self.resignAppBundle(at: appBundleURL, team: team, certificate: certificate, profiles: Array(profiles.values)) { (result) in + let resignProgress = self.resignAppBundle(at: appBundleURL, team: team, certificate: certificate, profiles: Array(profiles.values)) { result in guard let resignedURL = self.process(result) else { return } - + // Finish - do - { + do { let destinationURL = InstalledApp.refreshedIPAURL(for: app) try FileManager.default.copyItem(at: resignedURL, to: destinationURL, shouldReplace: true) - + // Use appBundleURL since we need an app bundle, not .ipa. guard let resignedApplication = ALTApplication(fileURL: appBundleURL) else { throw OperationError.invalidApp } self.finish(.success(resignedApplication)) - } - catch - { + } catch { self.finish(.failure(error)) } } @@ -75,187 +68,164 @@ final class ResignAppOperation: ResultOperation } prepareAppProgress.addChild(prepareAppBundleProgress, withPendingUnitCount: 1) } - - func process(_ result: Result) -> T? - { - switch result - { - case .failure(let error): - self.finish(.failure(error)) + + func process(_ result: Result) -> T? { + switch result { + case let .failure(error): + finish(.failure(error)) return nil - - case .success(let value): - guard !self.isCancelled else { - self.finish(.failure(OperationError.cancelled)) + + case let .success(value): + guard !isCancelled else { + finish(.failure(OperationError.cancelled)) return nil } - + return value } } } -private extension ResignAppOperation -{ - func prepareAppBundle(for app: ALTApplication, profiles: [String: ALTProvisioningProfile], completionHandler: @escaping (Result) -> Void) -> Progress - { +private extension ResignAppOperation { + func prepareAppBundle(for app: ALTApplication, profiles: [String: ALTProvisioningProfile], completionHandler: @escaping (Result) -> Void) -> Progress { let progress = Progress.discreteProgress(totalUnitCount: 1) - + let bundleIdentifier = app.bundleIdentifier let openURL = InstalledApp.openAppURL(for: app) - + let fileURL = app.fileURL - - func prepare(_ bundle: Bundle, additionalInfoDictionaryValues: [String: Any] = [:]) throws - { + + func prepare(_ bundle: Bundle, additionalInfoDictionaryValues: [String: Any] = [:]) throws { guard let identifier = bundle.bundleIdentifier else { throw ALTError(.missingAppBundle) } guard let profile = profiles[identifier] else { throw ALTError(.missingProvisioningProfile) } guard var infoDictionary = bundle.completeInfoDictionary else { throw ALTError(.missingInfoPlist) } - + infoDictionary[kCFBundleIdentifierKey as String] = profile.bundleIdentifier infoDictionary[Bundle.Info.altBundleID] = identifier infoDictionary[Bundle.Info.devicePairingString] = Bundle.main.object(forInfoDictionaryKey: "ALTPairingFile") as? String - for (key, value) in additionalInfoDictionaryValues - { + for (key, value) in additionalInfoDictionaryValues { infoDictionary[key] = value } - if let appGroups = profile.entitlements[.appGroups] as? [String] - { + if let appGroups = profile.entitlements[.appGroups] as? [String] { infoDictionary[Bundle.Info.appGroups] = appGroups // To keep file providers working, remap the NSExtensionFileProviderDocumentGroup, if there is one. if var extensionInfo = infoDictionary["NSExtension"] as? [String: Any], - let appGroup = extensionInfo["NSExtensionFileProviderDocumentGroup"] as? String, - let localAppGroup = appGroups.filter({ $0.contains(appGroup) }).min(by: { $0.count < $1.count }) - { + let appGroup = extensionInfo["NSExtensionFileProviderDocumentGroup"] as? String, + let localAppGroup = appGroups.filter({ $0.contains(appGroup) }).min(by: { $0.count < $1.count }) { extensionInfo["NSExtensionFileProviderDocumentGroup"] = localAppGroup infoDictionary["NSExtension"] = extensionInfo } } - + // Add app-specific exported UTI so we can check later if this app (extension) is installed or not. let installedAppUTI = ["UTTypeConformsTo": [], "UTTypeDescription": "AltStore Installed App", "UTTypeIconFiles": [], "UTTypeIdentifier": InstalledApp.installedAppUTI(forBundleIdentifier: profile.bundleIdentifier), - "UTTypeTagSpecification": [:]] as [String : Any] - + "UTTypeTagSpecification": [:]] as [String: Any] + var exportedUTIs = infoDictionary[Bundle.Info.exportedUTIs] as? [[String: Any]] ?? [] exportedUTIs.append(installedAppUTI) infoDictionary[Bundle.Info.exportedUTIs] = exportedUTIs - + try (infoDictionary as NSDictionary).write(to: bundle.infoPlistURL) } - + DispatchQueue.global().async { - do - { + do { let appBundleURL = self.context.temporaryDirectory.appendingPathComponent("App.app") try FileManager.default.copyItem(at: fileURL, to: appBundleURL) - + // Become current so we can observe progress from unzipAppBundle(). progress.becomeCurrent(withPendingUnitCount: 1) - + guard let appBundle = Bundle(url: appBundleURL) else { throw ALTError(.missingAppBundle) } guard let infoDictionary = appBundle.completeInfoDictionary else { throw ALTError(.missingInfoPlist) } - + var allURLSchemes = infoDictionary[Bundle.Info.urlTypes] as? [[String: Any]] ?? [] - + let altstoreURLScheme = ["CFBundleTypeRole": "Editor", "CFBundleURLName": bundleIdentifier, - "CFBundleURLSchemes": [openURL.scheme!]] as [String : Any] + "CFBundleURLSchemes": [openURL.scheme!]] as [String: Any] allURLSchemes.append(altstoreURLScheme) - + var additionalValues: [String: Any] = [Bundle.Info.urlTypes: allURLSchemes] - if app.isAltStoreApp - { + if app.isAltStoreApp { guard let udid = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.deviceID) as? String else { throw OperationError.unknownUDID } - guard let pairingFileString = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.devicePairingString) as? String else { throw OperationError.unknownUDID } + guard let pairingFileString = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.devicePairingString) as? String else { throw OperationError.unknownUDID } additionalValues[Bundle.Info.devicePairingString] = pairingFileString additionalValues[Bundle.Info.deviceID] = udid additionalValues[Bundle.Info.serverID] = UserDefaults.standard.preferredServerID - + if let data = Keychain.shared.signingCertificate, let signingCertificate = ALTCertificate(p12Data: data, password: nil), let encryptingPassword = Keychain.shared.signingCertificatePassword { additionalValues[Bundle.Info.certificateID] = signingCertificate.serialNumber - + let encryptedData = signingCertificate.encryptedP12Data(withPassword: encryptingPassword) try encryptedData?.write(to: appBundle.certificateURL, options: .atomic) - } - else - { + } else { // The embedded certificate + certificate identifier are already in app bundle, no need to update them. } - } - else if infoDictionary.keys.contains(Bundle.Info.deviceID), let udid = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.deviceID) as? String - { + } else if infoDictionary.keys.contains(Bundle.Info.deviceID), let udid = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.deviceID) as? String { // There is an ALTDeviceID entry, so assume the app is using AltKit and replace it with the device's UDID. additionalValues[Bundle.Info.deviceID] = udid additionalValues[Bundle.Info.serverID] = UserDefaults.standard.preferredServerID } - + let iconScale = Int(UIScreen.main.scale) - + if let alternateIconURL = self.context.alternateIconURL, case let data = try Data(contentsOf: alternateIconURL), let image = UIImage(data: data), let icon = image.resizing(toFill: CGSize(width: 60 * iconScale, height: 60 * iconScale)), - let iconData = icon.pngData() - { + let iconData = icon.pngData() { let iconName = "AltIcon" let iconURL = appBundleURL.appendingPathComponent(iconName + "@\(iconScale)x.png") try iconData.write(to: iconURL, options: .atomic) - + let iconDictionary = ["CFBundlePrimaryIcon": ["CFBundleIconFiles": [iconName]]] additionalValues["CFBundleIcons"] = iconDictionary } - + // Prepare app try prepare(appBundle, additionalInfoDictionaryValues: additionalValues) - - if let directory = appBundle.builtInPlugInsURL, let enumerator = FileManager.default.enumerator(at: directory, includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) - { - for case let fileURL as URL in enumerator - { + + if let directory = appBundle.builtInPlugInsURL, let enumerator = FileManager.default.enumerator(at: directory, includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) { + for case let fileURL as URL in enumerator { guard let appExtension = Bundle(url: fileURL) else { throw ALTError(.missingAppBundle) } try prepare(appExtension) } } - + completionHandler(.success(appBundleURL)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - + return progress } - - func resignAppBundle(at fileURL: URL, team: ALTTeam, certificate: ALTCertificate, profiles: [ALTProvisioningProfile], completionHandler: @escaping (Result) -> Void) -> Progress - { + + func resignAppBundle(at fileURL: URL, team: ALTTeam, certificate: ALTCertificate, profiles: [ALTProvisioningProfile], completionHandler: @escaping (Result) -> Void) -> Progress { let signer = ALTSigner(team: team, certificate: certificate) - let progress = signer.signApp(at: fileURL, provisioningProfiles: profiles) { (success, error) in - do - { + let progress = signer.signApp(at: fileURL, provisioningProfiles: profiles) { success, error in + do { try Result(success, error).get() - + let ipaURL = try FileManager.default.zipAppBundle(at: fileURL) completionHandler(.success(ipaURL)) - } - catch - { + } catch { completionHandler(.failure(error)) } } - + return progress } } diff --git a/AltStore/Operations/SendAppOperation.swift b/Sources/SideStore/Operations/SendAppOperation.swift similarity index 62% rename from AltStore/Operations/SendAppOperation.swift rename to Sources/SideStore/Operations/SendAppOperation.swift index fb239ba1..5271c5ae 100644 --- a/AltStore/Operations/SendAppOperation.swift +++ b/Sources/SideStore/Operations/SendAppOperation.swift @@ -8,42 +8,38 @@ import Foundation import Network -import AltStoreCore +import SideStoreCore @objc(SendAppOperation) -final class SendAppOperation: ResultOperation<()> -{ +final class SendAppOperation: ResultOperation { let context: InstallAppOperationContext - + private let dispatchQueue = DispatchQueue(label: "com.sidestore.SendAppOperation") - - init(context: InstallAppOperationContext) - { + + init(context: InstallAppOperationContext) { self.context = context - + super.init() - - self.progress.totalUnitCount = 1 + + progress.totalUnitCount = 1 } - - override func main() - { + + override func main() { super.main() - - if let error = self.context.error - { - self.finish(.failure(error)) + + if let error = context.error { + finish(.failure(error)) return } - - guard let resignedApp = self.context.resignedApp else { return self.finish(.failure(OperationError.invalidParameters)) } - + + guard let resignedApp = context.resignedApp else { return finish(.failure(OperationError.invalidParameters)) } + // self.context.resignedApp.fileURL points to the app bundle, but we want the .ipa. - let app = AnyApp(name: resignedApp.name, bundleIdentifier: self.context.bundleIdentifier, url: resignedApp.fileURL) + let app = AnyApp(name: resignedApp.name, bundleIdentifier: context.bundleIdentifier, url: resignedApp.fileURL) let fileURL = InstalledApp.refreshedIPAURL(for: app) - + print("AFC App `fileURL`: \(fileURL.absoluteString)") - + let ns_bundle = NSString(string: app.bundleIdentifier) let ns_bundle_ptr = UnsafeMutablePointer(mutating: ns_bundle.utf8String) @@ -55,14 +51,14 @@ final class SendAppOperation: ResultOperation<()> let res = minimuxer_yeet_app_afc(ns_bundle_ptr, pls, UInt(data.length)) if res == 0 { print("minimuxer_yeet_app_afc `res` == \(res)") - self.progress.completedUnitCount += 1 - self.finish(.success(())) + progress.completedUnitCount += 1 + finish(.success(())) } else { - self.finish(.failure(minimuxer_to_operation(code: res))) + finish(.failure(minimuxer_to_operation(code: res))) } - + } else { - self.finish(.failure(ALTServerError(.underlyingError))) + finish(.failure(ALTServerError(.underlyingError))) } } } diff --git a/AltStore/Operations/UpdatePatronsOperation.swift b/Sources/SideStore/Operations/UpdatePatronsOperation.swift similarity index 67% rename from AltStore/Operations/UpdatePatronsOperation.swift rename to Sources/SideStore/Operations/UpdatePatronsOperation.swift index 8e4064b8..bd1d0f55 100644 --- a/AltStore/Operations/UpdatePatronsOperation.swift +++ b/Sources/SideStore/Operations/UpdatePatronsOperation.swift @@ -6,102 +6,88 @@ // Copyright © 2022 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -import AltStoreCore +import SideStoreCore -private extension URL -{ +private extension URL { #if STAGING - static let patreonInfo = URL(string: "https://f000.backblazeb2.com/file/altstore-staging/altstore/patreon.json")! + static let patreonInfo = URL(string: "https://f000.backblazeb2.com/file/altstore-staging/altstore/patreon.json")! #else - static let patreonInfo = URL(string: "https://cdn.altstore.io/file/altstore/altstore/patreon.json")! + static let patreonInfo = URL(string: "https://cdn.altstore.io/file/altstore/altstore/patreon.json")! #endif } -extension UpdatePatronsOperation -{ - private struct Response: Decodable - { +extension UpdatePatronsOperation { + private struct Response: Decodable { var version: Int var accessToken: String var refreshID: String } } -final class UpdatePatronsOperation: ResultOperation -{ +final class UpdatePatronsOperation: ResultOperation { let context: NSManagedObjectContext - - init(context: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) - { + + init(context: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext()) { self.context = context } - - override func main() - { + + override func main() { super.main() - - let dataTask = URLSession.shared.dataTask(with: .patreonInfo) { (data, response, error) in - do - { - if let response = response as? HTTPURLResponse - { + + let dataTask = URLSession.shared.dataTask(with: .patreonInfo) { data, response, error in + do { + if let response = response as? HTTPURLResponse { guard response.statusCode != 404 else { self.finish(.failure(URLError(.fileDoesNotExist, userInfo: [NSURLErrorKey: URL.patreonInfo]))) return } } - + guard let data = data else { throw error! } - + let response = try AltStoreCore.JSONDecoder().decode(Response.self, from: data) Keychain.shared.patreonCreatorAccessToken = response.accessToken - + let previousRefreshID = UserDefaults.shared.patronsRefreshID guard response.refreshID != previousRefreshID else { self.finish(.success(())) return } - - PatreonAPI.shared.fetchPatrons { (result) in + + PatreonAPI.shared.fetchPatrons { result in self.context.perform { - do - { + do { let patrons = try result.get() let managedPatrons = patrons.map { ManagedPatron(patron: $0, context: self.context) } - + let patronIDs = Set(managedPatrons.map { $0.identifier }) let nonFriendZonePredicate = NSPredicate(format: "NOT (%K IN %@)", #keyPath(ManagedPatron.identifier), patronIDs) - + let nonFriendZonePatrons = ManagedPatron.all(satisfying: nonFriendZonePredicate, in: self.context) - for managedPatron in nonFriendZonePatrons - { + for managedPatron in nonFriendZonePatrons { self.context.delete(managedPatron) } - + try self.context.save() - + UserDefaults.shared.patronsRefreshID = response.refreshID - + self.finish(.success(())) - + print("Updated Friend Zone Patrons!") - } - catch - { + } catch { self.finish(.failure(error)) } } } - } - catch - { + } catch { self.finish(.failure(error)) } } - + dataTask.resume() } } diff --git a/AltStore/Operations/VerifyAppOperation.swift b/Sources/SideStore/Operations/VerifyAppOperation.swift similarity index 59% rename from AltStore/Operations/VerifyAppOperation.swift rename to Sources/SideStore/Operations/VerifyAppOperation.swift index 12d7c73c..56f70a85 100644 --- a/AltStore/Operations/VerifyAppOperation.swift +++ b/Sources/SideStore/Operations/VerifyAppOperation.swift @@ -11,43 +11,39 @@ import Foundation import AltSign import RoxasUI -enum VerificationError: ALTLocalizedError -{ +enum VerificationError: ALTLocalizedError { case privateEntitlements(ALTApplication, entitlements: [String: Any]) case mismatchedBundleIdentifiers(ALTApplication, sourceBundleID: String) case iOSVersionNotSupported(ALTApplication) - + var app: ALTApplication { - switch self - { - case .privateEntitlements(let app, _): return app - case .mismatchedBundleIdentifiers(let app, _): return app - case .iOSVersionNotSupported(let app): return app + switch self { + case let .privateEntitlements(app, _): return app + case let .mismatchedBundleIdentifiers(app, _): return app + case let .iOSVersionNotSupported(app): return app } } - + var failure: String? { - return String(format: NSLocalizedString("“%@” could not be installed.", comment: ""), app.name) + String(format: NSLocalizedString("“%@” could not be installed.", comment: ""), app.name) } - + var failureReason: String? { - switch self - { - case .privateEntitlements(let app, _): + switch self { + case let .privateEntitlements(app, _): return String(format: NSLocalizedString("“%@” requires private permissions.", comment: ""), app.name) - - case .mismatchedBundleIdentifiers(let app, let sourceBundleID): + + case let .mismatchedBundleIdentifiers(app, sourceBundleID): return String(format: NSLocalizedString("The bundle ID “%@” does not match the one specified by the source (“%@”).", comment: ""), app.bundleIdentifier, sourceBundleID) - - case .iOSVersionNotSupported(let app): + + case let .iOSVersionNotSupported(app): let name = app.name - + var version = "iOS \(app.minimumiOSVersion.majorVersion).\(app.minimumiOSVersion.minorVersion)" - if app.minimumiOSVersion.patchVersion > 0 - { + if app.minimumiOSVersion.patchVersion > 0 { version += ".\(app.minimumiOSVersion.patchVersion)" } - + let localizedDescription = String(format: NSLocalizedString("%@ requires %@.", comment: ""), name, version) return localizedDescription } @@ -55,117 +51,101 @@ enum VerificationError: ALTLocalizedError } @objc(VerifyAppOperation) -final class VerifyAppOperation: ResultOperation -{ +final class VerifyAppOperation: ResultOperation { let context: AppOperationContext var verificationHandler: ((VerificationError) -> Bool)? - - init(context: AppOperationContext) - { + + init(context: AppOperationContext) { self.context = context - + super.init() } - - override func main() - { + + override func main() { super.main() - - do - { - if let error = self.context.error - { + + do { + if let error = context.error { throw error } - - guard let app = self.context.app else { throw OperationError.invalidParameters } - - guard app.bundleIdentifier == self.context.bundleIdentifier else { - throw VerificationError.mismatchedBundleIdentifiers(app, sourceBundleID: self.context.bundleIdentifier) + + guard let app = context.app else { throw OperationError.invalidParameters } + + guard app.bundleIdentifier == context.bundleIdentifier else { + throw VerificationError.mismatchedBundleIdentifiers(app, sourceBundleID: context.bundleIdentifier) } - + guard ProcessInfo.processInfo.isOperatingSystemAtLeast(app.minimumiOSVersion) else { throw VerificationError.iOSVersionNotSupported(app) } - - if #available(iOS 13.5, *) - { + + if #available(iOS 13.5, *) { // No psychic paper, so we can ignore private entitlements app.hasPrivateEntitlements = false - } - else - { + } else { // Make sure this goes last, since once user responds to alert we don't do any more app verification. - if let commentStart = app.entitlementsString.range(of: ""), let commentEnd = app.entitlementsString.range(of: "") - { + if let commentStart = app.entitlementsString.range(of: ""), let commentEnd = app.entitlementsString.range(of: "") { // Psychic Paper private entitlements. - + let entitlementsStart = app.entitlementsString.index(after: commentStart.upperBound) let rawEntitlements = String(app.entitlementsString[entitlementsStart ..< commentEnd.lowerBound]) - + let plistTemplate = """ - - - - - %@ - - - """ + + + + + %@ + + + """ let entitlementsPlist = String(format: plistTemplate, rawEntitlements) let entitlements = try PropertyListSerialization.propertyList(from: entitlementsPlist.data(using: .utf8)!, options: [], format: nil) as! [String: Any] - + app.hasPrivateEntitlements = true let error = VerificationError.privateEntitlements(app, entitlements: entitlements) - self.process(error) { (result) in + process(error) { result in self.finish(result.mapError { $0 as Error }) } - + return - } - else - { + } else { app.hasPrivateEntitlements = false } } - - self.finish(.success(())) - } - catch - { - self.finish(.failure(error)) + + finish(.success(())) + } catch { + finish(.failure(error)) } } } -private extension VerifyAppOperation -{ - func process(_ error: VerificationError, completion: @escaping (Result) -> Void) - { - guard let presentingViewController = self.context.presentingViewController else { return completion(.failure(error)) } - +private extension VerifyAppOperation { + func process(_ error: VerificationError, completion: @escaping (Result) -> Void) { + guard let presentingViewController = context.presentingViewController else { return completion(.failure(error)) } + DispatchQueue.main.async { - switch error - { - case .privateEntitlements(_, let entitlements): + switch error { + case let .privateEntitlements(_, entitlements): let permissions = entitlements.keys.sorted().joined(separator: "\n") let message = String(format: NSLocalizedString(""" - You must allow access to these private permissions before continuing: + You must allow access to these private permissions before continuing: - %@ + %@ + + Private permissions allow apps to do more than normally allowed by iOS, including potentially accessing sensitive private data. Make sure to only install apps from sources you trust. + """, comment: ""), permissions) - Private permissions allow apps to do more than normally allowed by iOS, including potentially accessing sensitive private data. Make sure to only install apps from sources you trust. - """, comment: ""), permissions) - let alertController = UIAlertController(title: error.failureReason ?? error.localizedDescription, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Allow Access", comment: ""), style: .destructive) { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Allow Access", comment: ""), style: .destructive) { _ in completion(.success(())) }) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Deny Access", comment: ""), style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Deny Access", comment: ""), style: .default, handler: { _ in completion(.failure(error)) })) presentingViewController.present(alertController, animated: true, completion: nil) - + case .mismatchedBundleIdentifiers: return completion(.failure(error)) case .iOSVersionNotSupported: return completion(.failure(error)) } diff --git a/AltStore/Resources/AltBackup.ipa b/Sources/SideStore/Resources/AltBackup.ipa similarity index 100% rename from AltStore/Resources/AltBackup.ipa rename to Sources/SideStore/Resources/AltBackup.ipa diff --git a/AltStore/AltStore.entitlements b/Sources/SideStore/Resources/AltStore.entitlements similarity index 100% rename from AltStore/AltStore.entitlements rename to Sources/SideStore/Resources/AltStore.entitlements diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/100.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/100.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/100.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/100.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/1024.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/1024.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/1024.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/1024.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/114.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/114.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/114.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/114.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/120.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/120.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/120.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/120.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/144.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/144.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/144.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/144.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/152.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/152.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/152.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/152.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/167.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/167.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/167.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/167.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/180.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/180.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/180.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/180.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/20.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/20.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/20.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/20.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/29.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/29.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/29.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/29.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/40.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/40.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/40.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/40.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/50.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/50.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/50.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/50.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/57.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/57.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/57.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/57.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/58.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/58.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/58.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/58.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/60.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/60.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/60.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/60.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/72.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/72.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/72.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/72.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/76.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/76.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/76.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/76.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/80.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/80.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/80.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/80.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/87.png b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/87.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/87.png rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/87.png diff --git a/AltStore/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Back.imageset/Back@2x.png b/Sources/SideStore/Resources/Assets.xcassets/Back.imageset/Back@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Back.imageset/Back@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/Back.imageset/Back@2x.png diff --git a/AltStore/Resources/Assets.xcassets/Back.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Back.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Back.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Back.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA.png b/Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA.png rename to Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA.png diff --git a/AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@2x.png b/Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@2x.png diff --git a/AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@3x.png b/Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@3x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@3x.png rename to Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/BETA@3x.png diff --git a/AltStore/Resources/Assets.xcassets/BetaBadge.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/BetaBadge.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/BetaBadge.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Colors/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Colors/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png b/Sources/SideStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png diff --git a/AltStore/Resources/Assets.xcassets/Next.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Next.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Next.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Next.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Riley.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Riley.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Riley.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Riley.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Riley.imageset/riley.jpg b/Sources/SideStore/Resources/Assets.xcassets/Riley.imageset/riley.jpg similarity index 100% rename from AltStore/Resources/Assets.xcassets/Riley.imageset/riley.jpg rename to Sources/SideStore/Resources/Assets.xcassets/Riley.imageset/riley.jpg diff --git a/AltStore/Resources/Assets.xcassets/Shane.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Shane.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Shane.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Shane.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Shane.imageset/shane.jpeg b/Sources/SideStore/Resources/Assets.xcassets/Shane.imageset/shane.jpeg similarity index 100% rename from AltStore/Resources/Assets.xcassets/Shane.imageset/shane.jpeg rename to Sources/SideStore/Resources/Assets.xcassets/Shane.imageset/shane.jpeg diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@2x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@2x.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@3x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@3x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@3x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Combined Shape@3x.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Browse.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 10.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 10.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 10.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 10.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 11.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 11.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 11.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 11.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 12.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 12.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 12.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/MyApps.imageset/Group 12.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@2x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@2x.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@3x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@3x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@3x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 6@3x.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 8.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 8.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 8.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/News.imageset/Group 8.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/Contents.json b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/Contents.json similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/Contents.json rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/Contents.json diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@2x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@2x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@2x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@2x.png diff --git a/AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@3x.png b/Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@3x.png similarity index 100% rename from AltStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@3x.png rename to Sources/SideStore/Resources/Assets.xcassets/Tabs/Settings.imageset/noun_Settings_1187813@3x.png diff --git a/AltStore/Base.lproj/LaunchScreen.storyboard b/Sources/SideStore/Resources/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from AltStore/Base.lproj/LaunchScreen.storyboard rename to Sources/SideStore/Resources/Base.lproj/LaunchScreen.storyboard diff --git a/AltStore/Base.lproj/Main.storyboard b/Sources/SideStore/Resources/Base.lproj/Main.storyboard similarity index 100% rename from AltStore/Base.lproj/Main.storyboard rename to Sources/SideStore/Resources/Base.lproj/Main.storyboard diff --git a/AltStore/Info.plist b/Sources/SideStore/Resources/Info.plist similarity index 100% rename from AltStore/Info.plist rename to Sources/SideStore/Resources/Info.plist diff --git a/AltStore/News/NewsCollectionViewCell.xib b/Sources/SideStore/Resources/NewsCollectionViewCell.xib similarity index 100% rename from AltStore/News/NewsCollectionViewCell.xib rename to Sources/SideStore/Resources/NewsCollectionViewCell.xib diff --git a/AltStore/Operations/Patch App/PatchApp.storyboard b/Sources/SideStore/Resources/PatchApp.storyboard similarity index 100% rename from AltStore/Operations/Patch App/PatchApp.storyboard rename to Sources/SideStore/Resources/PatchApp.storyboard diff --git a/AltStore/Settings.bundle/Root.plist b/Sources/SideStore/Resources/Settings.bundle/Root.plist similarity index 100% rename from AltStore/Settings.bundle/Root.plist rename to Sources/SideStore/Resources/Settings.bundle/Root.plist diff --git a/AltStore/Settings.bundle/en.lproj/Root.strings b/Sources/SideStore/Resources/Settings.bundle/en.lproj/Root.strings similarity index 100% rename from AltStore/Settings.bundle/en.lproj/Root.strings rename to Sources/SideStore/Resources/Settings.bundle/en.lproj/Root.strings diff --git a/AltStore/Resources/Silence.m4a b/Sources/SideStore/Resources/Silence.m4a similarity index 100% rename from AltStore/Resources/Silence.m4a rename to Sources/SideStore/Resources/Silence.m4a diff --git a/AltStore/Resources/apps-alpha.json b/Sources/SideStore/Resources/apps-alpha.json similarity index 100% rename from AltStore/Resources/apps-alpha.json rename to Sources/SideStore/Resources/apps-alpha.json diff --git a/AltStore/Resources/apps.json b/Sources/SideStore/Resources/apps.json similarity index 100% rename from AltStore/Resources/apps.json rename to Sources/SideStore/Resources/apps.json diff --git a/AltStore/Resources/tempEnt.plist b/Sources/SideStore/Resources/tempEnt.plist similarity index 100% rename from AltStore/Resources/tempEnt.plist rename to Sources/SideStore/Resources/tempEnt.plist diff --git a/AltStore/SceneDelegate.swift b/Sources/SideStore/SceneDelegate.swift similarity index 80% rename from AltStore/SceneDelegate.swift rename to Sources/SideStore/SceneDelegate.swift index c195f3ea..18ac10fb 100644 --- a/AltStore/SceneDelegate.swift +++ b/Sources/SideStore/SceneDelegate.swift @@ -6,105 +6,90 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import UIKit -import AltStoreCore +import SideStoreCore import EmotionalDamage +import UIKit @available(iOS 13, *) -final class SceneDelegate: UIResponder, UIWindowSceneDelegate -{ +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) - { + func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } - - if let context = connectionOptions.urlContexts.first - { - self.open(context) + + if let context = connectionOptions.urlContexts.first { + open(context) } } - func sceneWillEnterForeground(_ scene: UIScene) - { + func sceneWillEnterForeground(_: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. - + // applicationWillEnterForeground is _not_ called when launching app, // whereas sceneWillEnterForeground _is_ called when launching. // As a result, DatabaseManager might not be started yet, so just return if it isn't // (since all these methods are called separately during app startup). guard DatabaseManager.shared.isStarted else { return } - + AppManager.shared.update() start_em_proxy(bind_addr: Consts.Proxy.serverURL) - + PatreonAPI.shared.refreshPatreonAccount() } - - func sceneDidEnterBackground(_ scene: UIScene) - { + + func sceneDidEnterBackground(_: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. - + guard UIApplication.shared.applicationState == .background else { return } - + // Make sure to update AppDelegate.applicationDidEnterBackground() as well. - + guard let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) else { return } - + let midnightOneMonthAgo = Calendar.current.startOfDay(for: oneMonthAgo) DatabaseManager.shared.purgeLoggedErrors(before: midnightOneMonthAgo) { result in - switch result - { + switch result { case .success: break - case .failure(let error): print("[ALTLog] Failed to purge logged errors before \(midnightOneMonthAgo).", error) + case let .failure(error): print("[ALTLog] Failed to purge logged errors before \(midnightOneMonthAgo).", error) } } - } - - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) - { + + func scene(_: UIScene, openURLContexts URLContexts: Set) { guard let context = URLContexts.first else { return } - self.open(context) + open(context) } } @available(iOS 13.0, *) -private extension SceneDelegate -{ - func open(_ context: UIOpenURLContext) - { - if context.url.isFileURL - { +private extension SceneDelegate { + func open(_ context: UIOpenURLContext) { + if context.url.isFileURL { guard context.url.pathExtension.lowercased() == "ipa" else { return } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: context.url]) } - } - else - { + } else { guard let components = URLComponents(url: context.url, resolvingAgainstBaseURL: false) else { return } guard let host = components.host?.lowercased() else { return } - - switch host - { + + switch host { case "patreon": DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) } - + case "appbackupresponse": let result: Result - - switch context.url.path.lowercased() - { + + switch context.url.path.lowercased() { case "/success": result = .success(()) case "/failure": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name] = $1.value } ?? [:] @@ -113,33 +98,33 @@ private extension SceneDelegate let errorCodeString = queryItems["errorCode"], let errorCode = Int(errorCodeString), let errorDescription = queryItems["errorDescription"] else { return } - + let error = NSError(domain: errorDomain, code: errorCode, userInfo: [NSLocalizedDescriptionKey: errorDescription]) result = .failure(error) - + default: return } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.appBackupDidFinish, object: nil, userInfo: [AppDelegate.appBackupResultKey: result]) } - + case "install": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] guard let downloadURLString = queryItems["url"], let downloadURL = URL(string: downloadURLString) else { return } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: downloadURL]) } - + case "source": let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] guard let sourceURLString = queryItems["url"], let sourceURL = URL(string: sourceURLString) else { return } - + DispatchQueue.main.async { NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL]) } - + default: break } } diff --git a/AltStore/Settings/AboutPatreonHeaderView.xib b/Sources/SideStore/Settings/AboutPatreonHeaderView.xib similarity index 100% rename from AltStore/Settings/AboutPatreonHeaderView.xib rename to Sources/SideStore/Settings/AboutPatreonHeaderView.xib diff --git a/AltStore/Settings/AnisetteManager.swift b/Sources/SideStore/Settings/AnisetteManager.swift similarity index 82% rename from AltStore/Settings/AnisetteManager.swift rename to Sources/SideStore/Settings/AnisetteManager.swift index 4edc4617..e7fe27c3 100644 --- a/AltStore/Settings/AnisetteManager.swift +++ b/Sources/SideStore/Settings/AnisetteManager.swift @@ -8,33 +8,31 @@ import Foundation -public struct AnisetteManager { - +public enum AnisetteManager { /// User defined URL from Settings/UserDefaults static var userURL: String? { var urlString: String? - + if UserDefaults.standard.textServer == false { urlString = UserDefaults.standard.textInputAnisetteURL - } - else { + } else { urlString = UserDefaults.standard.customAnisetteURL } - - + // guard let urlString = UserDefaults.standard.customAnisetteURL, !urlString.isEmpty else { return nil } - + // Test it's a valid URL - + if let urlString = urlString { guard URL(string: urlString) != nil else { - ELOG("UserDefaults has invalid `customAnisetteURL`") - assertionFailure("UserDefaults has invalid `customAnisetteURL`") - return nil + ELOG("UserDefaults has invalid `customAnisetteURL`") + assertionFailure("UserDefaults has invalid `customAnisetteURL`") + return nil } } return urlString } + static var defaultURL: String { guard let url = Bundle.main.object(forInfoDictionaryKey: "ALTAnisetteURL") as? String else { assertionFailure("Info.plist has invalid `ALTAnisetteURL`") @@ -42,9 +40,10 @@ public struct AnisetteManager { } return url } + static var currentURLString: String { userURL ?? defaultURL } // Force unwrap is safe here since we check validity before hand -- @JoeMatt - + /// User url or default from plist if none specified static var currentURL: URL { URL(string: currentURLString)! } } diff --git a/AltStore/Settings/Error Log/ErrorLogTableViewCell.swift b/Sources/SideStore/Settings/Error Log/ErrorLogTableViewCell.swift similarity index 69% rename from AltStore/Settings/Error Log/ErrorLogTableViewCell.swift rename to Sources/SideStore/Settings/Error Log/ErrorLogTableViewCell.swift index 71b67b88..8d423c8a 100644 --- a/AltStore/Settings/Error Log/ErrorLogTableViewCell.swift +++ b/Sources/SideStore/Settings/Error Log/ErrorLogTableViewCell.swift @@ -9,43 +9,38 @@ import UIKit @objc(ErrorLogTableViewCell) -final class ErrorLogTableViewCell: UITableViewCell -{ +final class ErrorLogTableViewCell: UITableViewCell { @IBOutlet var appIconImageView: AppIconImageView! - + @IBOutlet var dateLabel: UILabel! @IBOutlet var errorFailureLabel: UILabel! @IBOutlet var errorCodeLabel: UILabel! @IBOutlet var errorDescriptionTextView: CollapsingTextView! - + @IBOutlet var menuButton: UIButton! - + private var didLayoutSubviews = false - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? - { - let moreButtonFrame = self.convert(self.errorDescriptionTextView.moreButton.frame, from: self.errorDescriptionTextView) + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let moreButtonFrame = convert(errorDescriptionTextView.moreButton.frame, from: errorDescriptionTextView) guard moreButtonFrame.contains(point) else { return super.hitTest(point, with: event) } - + // Pass touches through menuButton so user can press moreButton. - return self.errorDescriptionTextView.moreButton + return errorDescriptionTextView.moreButton } - - override func layoutSubviews() - { + + override func layoutSubviews() { super.layoutSubviews() - - self.didLayoutSubviews = true + + didLayoutSubviews = true } - - override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize - { - if !self.didLayoutSubviews - { + + override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { + if !didLayoutSubviews { // Ensure cell is laid out so it will report correct size. - self.layoutIfNeeded() + layoutIfNeeded() } - + let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority) return size } diff --git a/AltStore/Settings/Error Log/ErrorLogViewController.swift b/Sources/SideStore/Settings/Error Log/ErrorLogViewController.swift similarity index 72% rename from AltStore/Settings/Error Log/ErrorLogViewController.swift rename to Sources/SideStore/Settings/Error Log/ErrorLogViewController.swift index 5c73dbac..46b373a6 100644 --- a/AltStore/Settings/Error Log/ErrorLogViewController.swift +++ b/Sources/SideStore/Settings/Error Log/ErrorLogViewController.swift @@ -6,84 +6,78 @@ // Copyright © 2022 Riley Testut. All rights reserved. // -import UIKit import SafariServices +import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI import Nuke import QuickLook -final class ErrorLogViewController: UITableViewController -{ +final class ErrorLogViewController: UITableViewController { private lazy var dataSource = self.makeDataSource() private var expandedErrorIDs = Set() - + private lazy var timeFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .none dateFormatter.timeStyle = .short return dateFormatter }() - + override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent + .lightContent } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.tableView.dataSource = self.dataSource - self.tableView.prefetchDataSource = self.dataSource + + tableView.dataSource = dataSource + tableView.prefetchDataSource = dataSource } } -private extension ErrorLogViewController -{ - func makeDataSource() -> RSTFetchedResultsTableViewPrefetchingDataSource - { +private extension ErrorLogViewController { + func makeDataSource() -> RSTFetchedResultsTableViewPrefetchingDataSource { let fetchRequest = LoggedError.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \LoggedError.date, ascending: false)] fetchRequest.returnsObjectsAsFaults = false - + let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(LoggedError.localizedDateString), cacheName: nil) - + let dataSource = RSTFetchedResultsTableViewPrefetchingDataSource(fetchedResultsController: fetchedResultsController) dataSource.proxy = self dataSource.rowAnimation = .fade - dataSource.cellConfigurationHandler = { [weak self] (cell, loggedError, indexPath) in + dataSource.cellConfigurationHandler = { [weak self] cell, loggedError, _ in guard let self else { return } - + let cell = cell as! ErrorLogTableViewCell cell.dateLabel.text = self.timeFormatter.string(from: loggedError.date) cell.errorFailureLabel.text = loggedError.localizedFailure ?? NSLocalizedString("Operation Failed", comment: "") - - switch loggedError.domain - { + + switch loggedError.domain { case AltServerErrorDomain: cell.errorCodeLabel?.text = String(format: NSLocalizedString("AltServer Error %@", comment: ""), NSNumber(value: loggedError.code)) case OperationError.domain: cell.errorCodeLabel?.text = String(format: NSLocalizedString("AltStore Error %@", comment: ""), NSNumber(value: loggedError.code)) default: cell.errorCodeLabel?.text = loggedError.error.localizedErrorCode } - + let nsError = loggedError.error as NSError let errorDescription = [nsError.localizedDescription, nsError.localizedRecoverySuggestion].compactMap { $0 }.joined(separator: "\n\n") cell.errorDescriptionTextView.text = errorDescription cell.errorDescriptionTextView.maximumNumberOfLines = 5 cell.errorDescriptionTextView.isCollapsed = !self.expandedErrorIDs.contains(loggedError.objectID) cell.errorDescriptionTextView.moreButton.addTarget(self, action: #selector(ErrorLogViewController.toggleCollapsingCell(_:)), for: .primaryActionTriggered) - + cell.appIconImageView.image = nil cell.appIconImageView.isIndicatingActivity = true cell.appIconImageView.layer.borderColor = UIColor.gray.cgColor - + let displayScale = (self.traitCollection.displayScale == 0.0) ? 1.0 : self.traitCollection.displayScale // 0.0 == "unspecified" cell.appIconImageView.layer.borderWidth = 1.0 / displayScale - - if #available(iOS 14, *) - { + + if #available(iOS 14, *) { let menu = UIMenu(title: "", children: [ UIAction(title: NSLocalizedString("Copy Error Message", comment: ""), image: UIImage(systemName: "doc.on.doc")) { [weak self] _ in self?.copyErrorMessage(for: loggedError) @@ -98,115 +92,95 @@ private extension ErrorLogViewController cell.menuButton.menu = menu } - + // Include errorDescriptionTextView's text in cell summary. cell.accessibilityLabel = [cell.errorFailureLabel.text, cell.dateLabel.text, cell.errorCodeLabel.text, cell.errorDescriptionTextView.text].compactMap { $0 }.joined(separator: ". ") - + // Group all paragraphs together into single accessibility element (otherwise, each paragraph is independently selectable). cell.errorDescriptionTextView.accessibilityLabel = cell.errorDescriptionTextView.text } - dataSource.prefetchHandler = { (loggedError, indexPath, completion) in - RSTAsyncBlockOperation { (operation) in + dataSource.prefetchHandler = { loggedError, _, completion in + RSTAsyncBlockOperation { operation in loggedError.managedObjectContext?.perform { - if let installedApp = loggedError.installedApp - { - installedApp.loadIcon { (result) in - switch result - { - case .failure(let error): completion(nil, error) - case .success(let image): completion(image, nil) + if let installedApp = loggedError.installedApp { + installedApp.loadIcon { result in + switch result { + case let .failure(error): completion(nil, error) + case let .success(image): completion(image, nil) } } - } - else if let storeApp = loggedError.storeApp - { - ImagePipeline.shared.loadImage(with: storeApp.iconURL, progress: nil) { (response, error) in + } else if let storeApp = loggedError.storeApp { + ImagePipeline.shared.loadImage(with: storeApp.iconURL, progress: nil) { response, error in guard !operation.isCancelled else { return operation.finish() } - - if let image = response?.image - { + + if let image = response?.image { completion(image, nil) - } - else - { + } else { completion(nil, error) } } - } - else - { + } else { completion(nil, nil) } } } } - dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in + dataSource.prefetchCompletionHandler = { cell, image, _, _ in let cell = cell as! ErrorLogTableViewCell cell.appIconImageView.image = image cell.appIconImageView.isIndicatingActivity = false } - + let placeholderView = RSTPlaceholderView() placeholderView.textLabel.text = NSLocalizedString("No Errors", comment: "") placeholderView.detailTextLabel.text = NSLocalizedString("Errors that occur when sideloading or refreshing apps will appear here.", comment: "") dataSource.placeholderView = placeholderView - + return dataSource } } -private extension ErrorLogViewController -{ - @IBAction func toggleCollapsingCell(_ sender: UIButton) - { - let point = self.tableView.convert(sender.center, from: sender.superview) - guard let indexPath = self.tableView.indexPathForRow(at: point), let cell = self.tableView.cellForRow(at: indexPath) as? ErrorLogTableViewCell else { return } - - let loggedError = self.dataSource.item(at: indexPath) - - if cell.errorDescriptionTextView.isCollapsed - { - self.expandedErrorIDs.remove(loggedError.objectID) +private extension ErrorLogViewController { + @IBAction func toggleCollapsingCell(_ sender: UIButton) { + let point = tableView.convert(sender.center, from: sender.superview) + guard let indexPath = tableView.indexPathForRow(at: point), let cell = tableView.cellForRow(at: indexPath) as? ErrorLogTableViewCell else { return } + + let loggedError = dataSource.item(at: indexPath) + + if cell.errorDescriptionTextView.isCollapsed { + expandedErrorIDs.remove(loggedError.objectID) + } else { + expandedErrorIDs.insert(loggedError.objectID) } - else - { - self.expandedErrorIDs.insert(loggedError.objectID) - } - - self.tableView.performBatchUpdates { + + tableView.performBatchUpdates { cell.layoutIfNeeded() } } - - @IBAction func showMinimuxerLogs(_ sender: UIBarButtonItem) - { + + @IBAction func showMinimuxerLogs(_: UIBarButtonItem) { // Show minimuxer.log let previewController = QLPreviewController() previewController.dataSource = self let navigationController = UINavigationController(rootViewController: previewController) present(navigationController, animated: true, completion: nil) } - - @IBAction func clearLoggedErrors(_ sender: UIBarButtonItem) - { + + @IBAction func clearLoggedErrors(_ sender: UIBarButtonItem) { let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to clear the error log?", comment: ""), message: nil, preferredStyle: .actionSheet) alertController.popoverPresentationController?.barButtonItem = sender alertController.addAction(.cancel) alertController.addAction(UIAlertAction(title: NSLocalizedString("Clear Error Log", comment: ""), style: .destructive) { _ in self.clearLoggedErrors() }) - self.present(alertController, animated: true) + present(alertController, animated: true) } - - func clearLoggedErrors() - { + + func clearLoggedErrors() { DatabaseManager.shared.purgeLoggedErrors { result in - do - { + do { try result.get() - } - catch - { + } catch { DispatchQueue.main.async { let alertController = UIAlertController(title: NSLocalizedString("Failed to Clear Error Log", comment: ""), message: error.localizedDescription, preferredStyle: .alert) alertController.addAction(.ok) @@ -215,41 +189,36 @@ private extension ErrorLogViewController } } } - - func copyErrorMessage(for loggedError: LoggedError) - { + + func copyErrorMessage(for loggedError: LoggedError) { let nsError = loggedError.error as NSError let errorMessage = [nsError.localizedDescription, nsError.localizedRecoverySuggestion].compactMap { $0 }.joined(separator: "\n\n") - + UIPasteboard.general.string = errorMessage } - - func copyErrorCode(for loggedError: LoggedError) - { + + func copyErrorCode(for loggedError: LoggedError) { let errorCode = loggedError.error.localizedErrorCode UIPasteboard.general.string = errorCode } - - func searchFAQ(for loggedError: LoggedError) - { + + func searchFAQ(for loggedError: LoggedError) { let baseURL = URL(string: "https://faq.altstore.io/getting-started/troubleshooting-guide")! var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)! - + let query = [loggedError.domain, "\(loggedError.code)"].joined(separator: "+") components.queryItems = [URLQueryItem(name: "q", value: query)] - + let safariViewController = SFSafariViewController(url: components.url ?? baseURL) safariViewController.preferredControlTintColor = .altPrimary - self.present(safariViewController, animated: true) + present(safariViewController, animated: true) } } -extension ErrorLogViewController -{ - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) - { - let loggedError = self.dataSource.item(at: indexPath) - +extension ErrorLogViewController { + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let loggedError = dataSource.item(at: indexPath) + let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style) { _ in tableView.deselectRow(at: indexPath, animated: true) @@ -266,57 +235,49 @@ extension ErrorLogViewController self?.searchFAQ(for: loggedError) tableView.deselectRow(at: indexPath, animated: true) }) - self.present(alertController, animated: true) + present(alertController, animated: true) } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? - { + + override func tableView(_: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { _, _, completion in let loggedError = self.dataSource.item(at: indexPath) DatabaseManager.shared.persistentContainer.performBackgroundTask { context in - do - { + do { let loggedError = context.object(with: loggedError.objectID) as! LoggedError context.delete(loggedError) - + try context.save() completion(true) - } - catch - { + } catch { print("[ALTLog] Failed to delete LoggedError \(loggedError.objectID):", error) completion(false) } } } - + let configuration = UISwipeActionsConfiguration(actions: [deleteAction]) configuration.performsFirstActionWithFullSwipe = false return configuration } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? - { + + override func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? { let indexPath = IndexPath(row: 0, section: section) - let loggedError = self.dataSource.item(at: indexPath) - - if Calendar.current.isDateInToday(loggedError.date) - { + let loggedError = dataSource.item(at: indexPath) + + if Calendar.current.isDateInToday(loggedError.date) { return NSLocalizedString("Today", comment: "") - } - else - { + } else { return loggedError.localizedDateString } } } extension ErrorLogViewController: QLPreviewControllerDataSource { - func numberOfPreviewItems(in controller: QLPreviewController) -> Int { - return 1 + func numberOfPreviewItems(in _: QLPreviewController) -> Int { + 1 } - func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { + func previewController(_: QLPreviewController, previewItemAt _: Int) -> QLPreviewItem { let fileURL = FileManager.default.documentsDirectory.appendingPathComponent("minimuxer.log") return fileURL as QLPreviewItem } diff --git a/Sources/SideStore/Settings/InsetGroupTableViewCell.swift b/Sources/SideStore/Settings/InsetGroupTableViewCell.swift new file mode 100644 index 00000000..74e505e6 --- /dev/null +++ b/Sources/SideStore/Settings/InsetGroupTableViewCell.swift @@ -0,0 +1,114 @@ +// +// InsetGroupTableViewCell.swift +// AltStore +// +// Created by Riley Testut on 8/31/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +extension InsetGroupTableViewCell { + @objc enum Style: Int { + case single + case top + case middle + case bottom + } +} + +final class InsetGroupTableViewCell: UITableViewCell { + #if !TARGET_INTERFACE_BUILDER + @IBInspectable var style: Style = .single { + didSet { + self.update() + } + } + #else + @IBInspectable var style: Int = 0 + #endif + + @IBInspectable var isSelectable: Bool = false + + private let separatorView = UIView() + private let insetView = UIView() + + override func awakeFromNib() { + super.awakeFromNib() + + selectionStyle = .none + + separatorView.translatesAutoresizingMaskIntoConstraints = false + separatorView.backgroundColor = UIColor.white.withAlphaComponent(0.25) + addSubview(separatorView) + + insetView.layer.masksToBounds = true + insetView.layer.cornerRadius = 16 + + // Get the preferred background color from Interface Builder. + insetView.backgroundColor = backgroundColor + backgroundColor = nil + + addSubview(insetView, pinningEdgesWith: UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)) + sendSubviewToBack(insetView) + + NSLayoutConstraint.activate([separatorView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 30), + separatorView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -30), + separatorView.bottomAnchor.constraint(equalTo: bottomAnchor), + separatorView.heightAnchor.constraint(equalToConstant: 1)]) + + update() + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if animated { + UIView.animate(withDuration: 0.4) { + self.update() + } + } else { + update() + } + } + + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + super.setHighlighted(highlighted, animated: animated) + + if animated { + UIView.animate(withDuration: 0.4) { + self.update() + } + } else { + update() + } + } +} + +private extension InsetGroupTableViewCell { + func update() { + switch style { + case .single: + insetView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner] + separatorView.isHidden = true + + case .top: + insetView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] + separatorView.isHidden = false + + case .middle: + insetView.layer.maskedCorners = [] + separatorView.isHidden = false + + case .bottom: + insetView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] + separatorView.isHidden = true + } + + if isSelectable && (isHighlighted || isSelected) { + insetView.backgroundColor = UIColor.white.withAlphaComponent(0.55) + } else { + insetView.backgroundColor = UIColor.white.withAlphaComponent(0.25) + } + } +} diff --git a/Sources/SideStore/Settings/LicensesViewController.swift b/Sources/SideStore/Settings/LicensesViewController.swift new file mode 100644 index 00000000..0996a9f5 --- /dev/null +++ b/Sources/SideStore/Settings/LicensesViewController.swift @@ -0,0 +1,48 @@ +// +// LicensesViewController.swift +// AltStore +// +// Created by Riley Testut on 9/6/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class LicensesViewController: UIViewController { + private var _didAppear = false + + @IBOutlet private var textView: UITextView! + + override var preferredStatusBarStyle: UIStatusBarStyle { + .lightContent + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + view.setNeedsLayout() + view.layoutIfNeeded() + + // Fix incorrect initial offset on iPhone SE. + textView.contentOffset.y = 0 + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + _didAppear = true + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + textView.textContainerInset.left = view.layoutMargins.left + textView.textContainerInset.right = view.layoutMargins.right + textView.textContainer.lineFragmentPadding = 0 + + if !_didAppear { + // Fix incorrect initial offset on iPhone SE. + textView.contentOffset.y = 0 + } + } +} diff --git a/Sources/SideStore/Settings/PatreonComponents.swift b/Sources/SideStore/Settings/PatreonComponents.swift new file mode 100644 index 00000000..8dbf5094 --- /dev/null +++ b/Sources/SideStore/Settings/PatreonComponents.swift @@ -0,0 +1,87 @@ +// +// PatreonComponents.swift +// AltStore +// +// Created by Riley Testut on 9/5/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +final class PatronCollectionViewCell: UICollectionViewCell { + @IBOutlet var textLabel: UILabel! +} + +final class PatronsHeaderView: UICollectionReusableView { + let textLabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + + textLabel.font = UIFont.boldSystemFont(ofSize: 17) + textLabel.textColor = .white + addSubview(textLabel, pinningEdgesWith: UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +final class PatronsFooterView: UICollectionReusableView { + let button = UIButton(type: .system) + + override init(frame: CGRect) { + super.init(frame: frame) + + button.translatesAutoresizingMaskIntoConstraints = false + button.activityIndicatorView.style = .medium + button.titleLabel?.textColor = .white + addSubview(button) + + NSLayoutConstraint.activate([button.centerXAnchor.constraint(equalTo: centerXAnchor), + button.centerYAnchor.constraint(equalTo: centerYAnchor)]) + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +final class AboutPatreonHeaderView: UICollectionReusableView { + @IBOutlet var supportButton: UIButton! + @IBOutlet var accountButton: UIButton! + @IBOutlet var textView: UITextView! + + @IBOutlet private var rileyLabel: UILabel! + @IBOutlet private var shaneLabel: UILabel! + + @IBOutlet private var rileyImageView: UIImageView! + @IBOutlet private var shaneImageView: UIImageView! + + override func awakeFromNib() { + super.awakeFromNib() + + textView.clipsToBounds = true + textView.layer.cornerRadius = 20 + textView.textContainer.lineFragmentPadding = 0 + + for imageView in [rileyImageView, shaneImageView].compactMap({ $0 }) { + imageView.clipsToBounds = true + imageView.layer.cornerRadius = imageView.bounds.midY + } + + for button in [supportButton, accountButton].compactMap({ $0 }) { + button.clipsToBounds = true + button.layer.cornerRadius = 16 + } + } + + override func layoutMarginsDidChange() { + super.layoutMarginsDidChange() + + textView.textContainerInset = UIEdgeInsets(top: layoutMargins.left, left: layoutMargins.left, bottom: layoutMargins.right, right: layoutMargins.right) + } +} diff --git a/AltStore/Settings/PatreonViewController.swift b/Sources/SideStore/Settings/PatreonViewController.swift similarity index 63% rename from AltStore/Settings/PatreonViewController.swift rename to Sources/SideStore/Settings/PatreonViewController.swift index 54425868..f7c36a1e 100644 --- a/AltStore/Settings/PatreonViewController.swift +++ b/Sources/SideStore/Settings/PatreonViewController.swift @@ -6,198 +6,173 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit -import SafariServices import AuthenticationServices +import SafariServices +import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI -extension PatreonViewController -{ - private enum Section: Int, CaseIterable - { +extension PatreonViewController { + private enum Section: Int, CaseIterable { case about case patrons } } -final class PatreonViewController: UICollectionViewController -{ +final class PatreonViewController: UICollectionViewController { private lazy var dataSource = self.makeDataSource() private lazy var patronsDataSource = self.makePatronsDataSource() - + private var prototypeAboutHeader: AboutPatreonHeaderView! - + override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent + .lightContent } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - + let aboutHeaderNib = UINib(nibName: "AboutPatreonHeaderView", bundle: nil) - self.prototypeAboutHeader = aboutHeaderNib.instantiate(withOwner: nil, options: nil)[0] as? AboutPatreonHeaderView - - self.collectionView.dataSource = self.dataSource - - self.collectionView.register(aboutHeaderNib, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "AboutHeader") - self.collectionView.register(PatronsHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "PatronsHeader") - //self.collectionView.register(PatronsFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "PatronsFooter") - - //NotificationCenter.default.addObserver(self, selector: #selector(PatreonViewController.didUpdatePatrons(_:)), name: AppManager.didUpdatePatronsNotification, object: nil) - - self.update() + prototypeAboutHeader = aboutHeaderNib.instantiate(withOwner: nil, options: nil)[0] as? AboutPatreonHeaderView + + collectionView.dataSource = dataSource + + collectionView.register(aboutHeaderNib, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "AboutHeader") + collectionView.register(PatronsHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "PatronsHeader") + // self.collectionView.register(PatronsFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "PatronsFooter") + + // NotificationCenter.default.addObserver(self, selector: #selector(PatreonViewController.didUpdatePatrons(_:)), name: AppManager.didUpdatePatronsNotification, object: nil) + + update() } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - //self.fetchPatrons() - - self.update() + + // self.fetchPatrons() + + update() } - - override func viewDidLayoutSubviews() - { + + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - - let layout = self.collectionViewLayout as! UICollectionViewFlowLayout - - var itemWidth = (self.collectionView.bounds.width - (layout.sectionInset.left + layout.sectionInset.right + layout.minimumInteritemSpacing)) / 2 + + let layout = collectionViewLayout as! UICollectionViewFlowLayout + + var itemWidth = (collectionView.bounds.width - (layout.sectionInset.left + layout.sectionInset.right + layout.minimumInteritemSpacing)) / 2 itemWidth.round(.down) - + // TODO: if the intention here is to hide the cells, we should just modify the data source. @JoeMatt layout.itemSize = CGSize(width: 0, height: 0) } } -private extension PatreonViewController -{ - func makeDataSource() -> RSTCompositeCollectionViewDataSource - { +private extension PatreonViewController { + func makeDataSource() -> RSTCompositeCollectionViewDataSource { let aboutDataSource = RSTDynamicCollectionViewDataSource() aboutDataSource.numberOfSectionsHandler = { 1 } aboutDataSource.numberOfItemsHandler = { _ in 0 } - - let dataSource = RSTCompositeCollectionViewDataSource(dataSources: [aboutDataSource, self.patronsDataSource]) + + let dataSource = RSTCompositeCollectionViewDataSource(dataSources: [aboutDataSource, patronsDataSource]) dataSource.proxy = self return dataSource } - - func makePatronsDataSource() -> RSTFetchedResultsCollectionViewDataSource - { + + func makePatronsDataSource() -> RSTFetchedResultsCollectionViewDataSource { let fetchRequest: NSFetchRequest = ManagedPatron.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(ManagedPatron.name), ascending: true, selector: #selector(NSString.caseInsensitiveCompare(_:)))] - + let patronsDataSource = RSTFetchedResultsCollectionViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) - patronsDataSource.cellConfigurationHandler = { (cell, patron, indexPath) in + patronsDataSource.cellConfigurationHandler = { cell, patron, _ in let cell = cell as! PatronCollectionViewCell cell.textLabel.text = patron.name } - + return patronsDataSource } - - func update() - { - self.collectionView.reloadData() + + func update() { + collectionView.reloadData() } - - func prepare(_ headerView: AboutPatreonHeaderView) - { - headerView.layoutMargins = self.view.layoutMargins - + + func prepare(_ headerView: AboutPatreonHeaderView) { + headerView.layoutMargins = view.layoutMargins + headerView.supportButton.addTarget(self, action: #selector(PatreonViewController.openPatreonURL(_:)), for: .primaryActionTriggered) - + let defaultSupportButtonTitle = NSLocalizedString("Become a patron", comment: "") let isPatronSupportButtonTitle = NSLocalizedString("View Patreon", comment: "") - + let defaultText = NSLocalizedString(""" Hello, thank you for using SideStore! - + If you would subscribe to the patreon that would support us and make sure we can continue developing SideStore for you. - + -SideTeam """, comment: "") - + let isPatronText = NSLocalizedString(""" Hey , - + You’re the best. Your account was linked successfully, so you now have access to the beta versions of all of our apps. You can find them all in the Browse tab. - + Thanks for all of your support. Enjoy! - SideTeam """, comment: "") - - if let account = DatabaseManager.shared.patreonAccount(), PatreonAPI.shared.isAuthenticated - { + + if let account = DatabaseManager.shared.patreonAccount(), PatreonAPI.shared.isAuthenticated { headerView.accountButton.addTarget(self, action: #selector(PatreonViewController.signOut(_:)), for: .primaryActionTriggered) headerView.accountButton.setTitle(String(format: NSLocalizedString("Unlink %@", comment: ""), account.name), for: .normal) - - if account.isPatron - { + + if account.isPatron { headerView.supportButton.setTitle(isPatronSupportButtonTitle, for: .normal) - + let font = UIFont.systemFont(ofSize: 16) - + let attributedText = NSMutableAttributedString(string: isPatronText, attributes: [.font: font, .foregroundColor: UIColor.white]) - + let boldedName = NSAttributedString(string: account.firstName ?? account.name, attributes: [.font: UIFont.boldSystemFont(ofSize: font.pointSize), .foregroundColor: UIColor.white]) attributedText.insert(boldedName, at: 4) - + headerView.textView.attributedText = attributedText - } - else - { + } else { headerView.supportButton.setTitle(defaultSupportButtonTitle, for: .normal) headerView.textView.text = defaultText } } - } } -private extension PatreonViewController -{ - @objc func fetchPatrons() - { +private extension PatreonViewController { + @objc func fetchPatrons() { AppManager.shared.updatePatronsIfNeeded() - self.update() + update() } - - @objc func openPatreonURL(_ sender: UIButton) - { + + @objc func openPatreonURL(_: UIButton) { let patreonURL = URL(string: "https://www.patreon.com/SideStore")! - + let safariViewController = SFSafariViewController(url: patreonURL) - safariViewController.preferredControlTintColor = self.view.tintColor - self.present(safariViewController, animated: true, completion: nil) + safariViewController.preferredControlTintColor = view.tintColor + present(safariViewController, animated: true, completion: nil) } - - @IBAction func authenticate(_ sender: UIBarButtonItem) - { - PatreonAPI.shared.authenticate { (result) in - do - { + + @IBAction func authenticate(_: UIBarButtonItem) { + PatreonAPI.shared.authenticate { result in + do { let account = try result.get() try account.managedObjectContext?.save() - + DispatchQueue.main.async { self.update() } - } - catch ASWebAuthenticationSessionError.canceledLogin - { + } catch ASWebAuthenticationSessionError.canceledLogin { // Ignore - } - catch - { + } catch { DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) @@ -205,22 +180,17 @@ private extension PatreonViewController } } } - - @IBAction func signOut(_ sender: UIBarButtonItem) - { - func signOut() - { - PatreonAPI.shared.signOut { (result) in - do - { + + @IBAction func signOut(_: UIBarButtonItem) { + func signOut() { + PatreonAPI.shared.signOut { result in + do { try result.get() - + DispatchQueue.main.async { self.update() } - } - catch - { + } catch { DispatchQueue.main.async { let toastView = ToastView(error: error) toastView.show(in: self) @@ -228,15 +198,14 @@ private extension PatreonViewController } } } - + let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to unlink your Patreon account?", comment: ""), message: NSLocalizedString("You will no longer have access to beta versions of apps.", comment: ""), preferredStyle: .actionSheet) alertController.addAction(UIAlertAction(title: NSLocalizedString("Unlink Patreon Account", comment: ""), style: .destructive) { _ in signOut() }) alertController.addAction(.cancel) - self.present(alertController, animated: true, completion: nil) + present(alertController, animated: true, completion: nil) } - - @objc func didUpdatePatrons(_ notification: Notification) - { + + @objc func didUpdatePatrons(_: Notification) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // Wait short delay before reloading or else footer won't properly update if it's already visible 🤷‍♂️ self.collectionView.reloadData() @@ -244,89 +213,74 @@ private extension PatreonViewController } } -extension PatreonViewController -{ - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { +extension PatreonViewController { + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let section = Section.allCases[indexPath.section] - switch section - { + switch section { case .about: let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "AboutHeader", for: indexPath) as! AboutPatreonHeaderView - self.prepare(headerView) + prepare(headerView) return headerView - + case .patrons: - if kind == UICollectionView.elementKindSectionHeader - { + if kind == UICollectionView.elementKindSectionHeader { let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "PatronsHeader", for: indexPath) as! PatronsHeaderView headerView.textLabel.text = NSLocalizedString("Special thanks to...", comment: "") return headerView - } - else - { + } else { let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "PatronsFooter", for: indexPath) as! PatronsFooterView footerView.button.isIndicatingActivity = false footerView.button.isHidden = false - //footerView.button.addTarget(self, action: #selector(PatreonViewController.fetchPatrons), for: .primaryActionTriggered) - - switch AppManager.shared.updatePatronsResult - { + // footerView.button.addTarget(self, action: #selector(PatreonViewController.fetchPatrons), for: .primaryActionTriggered) + + switch AppManager.shared.updatePatronsResult { case .none: footerView.button.isIndicatingActivity = true case .success?: footerView.button.isHidden = true case .failure?: #if DEBUG - let debug = true + let debug = true #else - let debug = false + let debug = false #endif - - if self.patronsDataSource.itemCount == 0 || debug - { + + if patronsDataSource.itemCount == 0 || debug { // Only show error message if there aren't any cached Patrons (or if this is a debug build). - + footerView.button.isHidden = false footerView.button.setTitle(NSLocalizedString("Error Loading Patrons", comment: ""), for: .normal) - } - else - { + } else { footerView.button.isHidden = true } } - + return footerView } } } } -extension PatreonViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize - { +extension PatreonViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { let section = Section.allCases[section] - switch section - { + switch section { case .about: - let widthConstraint = self.prototypeAboutHeader.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) + let widthConstraint = prototypeAboutHeader.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } - - self.prepare(self.prototypeAboutHeader) - - let size = self.prototypeAboutHeader.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + + prepare(prototypeAboutHeader) + + let size = prototypeAboutHeader.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) return size - + case .patrons: return CGSize(width: 0, height: 0) } } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize - { + + func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { let section = Section.allCases[section] - switch section - { + switch section { case .about: return .zero case .patrons: return CGSize(width: 0, height: 0) } diff --git a/AltStore/Settings/RefreshAttemptsViewController.swift b/Sources/SideStore/Settings/RefreshAttemptsViewController.swift similarity index 83% rename from AltStore/Settings/RefreshAttemptsViewController.swift rename to Sources/SideStore/Settings/RefreshAttemptsViewController.swift index cae2d60c..ed606e48 100644 --- a/AltStore/Settings/RefreshAttemptsViewController.swift +++ b/Sources/SideStore/Settings/RefreshAttemptsViewController.swift @@ -8,67 +8,59 @@ import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI @objc(RefreshAttemptTableViewCell) -private final class RefreshAttemptTableViewCell: UITableViewCell -{ +private final class RefreshAttemptTableViewCell: UITableViewCell { @IBOutlet var successLabel: UILabel! @IBOutlet var dateLabel: UILabel! @IBOutlet var errorDescriptionLabel: UILabel! } -final class RefreshAttemptsViewController: UITableViewController -{ +final class RefreshAttemptsViewController: UITableViewController { private lazy var dataSource = self.makeDataSource() - + private lazy var dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .short dateFormatter.timeStyle = .short return dateFormatter }() - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.tableView.dataSource = self.dataSource + + tableView.dataSource = dataSource } } -private extension RefreshAttemptsViewController -{ - func makeDataSource() -> RSTFetchedResultsTableViewDataSource - { +private extension RefreshAttemptsViewController { + func makeDataSource() -> RSTFetchedResultsTableViewDataSource { let fetchRequest = RefreshAttempt.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \RefreshAttempt.date, ascending: false)] fetchRequest.returnsObjectsAsFaults = false - + let dataSource = RSTFetchedResultsTableViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) - dataSource.cellConfigurationHandler = { [weak self] (cell, attempt, indexPath) in + dataSource.cellConfigurationHandler = { [weak self] cell, attempt, _ in let cell = cell as! RefreshAttemptTableViewCell cell.dateLabel.text = self?.dateFormatter.string(from: attempt.date) cell.errorDescriptionLabel.text = attempt.errorDescription - - if attempt.isSuccess - { + + if attempt.isSuccess { cell.successLabel.text = NSLocalizedString("Success", comment: "") cell.successLabel.textColor = .refreshGreen - } - else - { + } else { cell.successLabel.text = NSLocalizedString("Failure", comment: "") cell.successLabel.textColor = .refreshRed } } - + let placeholderView = RSTPlaceholderView() placeholderView.textLabel.text = NSLocalizedString("No Refresh Attempts", comment: "") placeholderView.detailTextLabel.text = NSLocalizedString("The more you use SideStore, the more often iOS will allow it to refresh apps in the background.", comment: "") dataSource.placeholderView = placeholderView - + return dataSource } } diff --git a/AltStore/Settings/Settings.storyboard b/Sources/SideStore/Settings/Settings.storyboard similarity index 100% rename from AltStore/Settings/Settings.storyboard rename to Sources/SideStore/Settings/Settings.storyboard diff --git a/Sources/SideStore/Settings/SettingsHeaderFooterView.swift b/Sources/SideStore/Settings/SettingsHeaderFooterView.swift new file mode 100644 index 00000000..680fa7a9 --- /dev/null +++ b/Sources/SideStore/Settings/SettingsHeaderFooterView.swift @@ -0,0 +1,34 @@ +// +// SettingsHeaderFooterView.swift +// AltStore +// +// Created by Riley Testut on 8/31/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import RoxasUI + +final class SettingsHeaderFooterView: UITableViewHeaderFooterView { + @IBOutlet var primaryLabel: UILabel! + @IBOutlet var secondaryLabel: UILabel! + @IBOutlet var button: UIButton! + + @IBOutlet private var stackView: UIStackView! + + override func awakeFromNib() { + super.awakeFromNib() + + contentView.layoutMargins = .zero + contentView.preservesSuperviewLayoutMargins = true + + stackView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(stackView) + + NSLayoutConstraint.activate([stackView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + stackView.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor), + stackView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor)]) + } +} diff --git a/AltStore/Settings/SettingsHeaderFooterView.xib b/Sources/SideStore/Settings/SettingsHeaderFooterView.xib similarity index 100% rename from AltStore/Settings/SettingsHeaderFooterView.xib rename to Sources/SideStore/Settings/SettingsHeaderFooterView.xib diff --git a/AltStore/Settings/SettingsViewController.swift b/Sources/SideStore/Settings/SettingsViewController.swift similarity index 62% rename from AltStore/Settings/SettingsViewController.swift rename to Sources/SideStore/Settings/SettingsViewController.swift index 1951ee46..b805cdb4 100644 --- a/AltStore/Settings/SettingsViewController.swift +++ b/Sources/SideStore/Settings/SettingsViewController.swift @@ -6,18 +6,16 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit -import SafariServices -import MessageUI import Intents import IntentsUI +import MessageUI +import SafariServices +import UIKit -import AltStoreCore +import SideStoreCore -extension SettingsViewController -{ - fileprivate enum Section: Int, CaseIterable - { +private extension SettingsViewController { + enum Section: Int, CaseIterable { case signIn case account case patreon @@ -26,30 +24,27 @@ extension SettingsViewController case credits case debug } - - fileprivate enum AppRefreshRow: Int, CaseIterable - { + + enum AppRefreshRow: Int, CaseIterable { case backgroundRefresh - + @available(iOS 14, *) case addToSiri - + static var allCases: [AppRefreshRow] { guard #available(iOS 14, *) else { return [.backgroundRefresh] } return [.backgroundRefresh, .addToSiri] } } - - fileprivate enum CreditsRow: Int, CaseIterable - { + + enum CreditsRow: Int, CaseIterable { case developer case operations case designer case softwareLicenses } - - fileprivate enum DebugRow: Int, CaseIterable - { + + enum DebugRow: Int, CaseIterable { case sendFeedback case refreshAttempts case errorLog @@ -58,273 +53,230 @@ extension SettingsViewController } } -final class SettingsViewController: UITableViewController -{ +final class SettingsViewController: UITableViewController { private var activeTeam: Team? - + private var prototypeHeaderFooterView: SettingsHeaderFooterView! - + private var debugGestureCounter = 0 private weak var debugGestureTimer: Timer? - + @IBOutlet private var accountNameLabel: UILabel! @IBOutlet private var accountEmailLabel: UILabel! @IBOutlet private var accountTypeLabel: UILabel! - + @IBOutlet private var backgroundRefreshSwitch: UISwitch! - + @IBOutlet private var versionLabel: UILabel! - + override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent + .lightContent } - - required init?(coder aDecoder: NSCoder) - { + + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) } - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - + let nib = UINib(nibName: "SettingsHeaderFooterView", bundle: nil) - self.prototypeHeaderFooterView = nib.instantiate(withOwner: nil, options: nil)[0] as? SettingsHeaderFooterView - - self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "HeaderFooterView") - + prototypeHeaderFooterView = nib.instantiate(withOwner: nil, options: nil)[0] as? SettingsHeaderFooterView + + tableView.register(nib, forHeaderFooterViewReuseIdentifier: "HeaderFooterView") + let debugModeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SettingsViewController.handleDebugModeGesture(_:))) debugModeGestureRecognizer.delegate = self debugModeGestureRecognizer.direction = .up debugModeGestureRecognizer.numberOfTouchesRequired = 3 - self.tableView.addGestureRecognizer(debugModeGestureRecognizer) - - if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String - { - self.versionLabel.text = NSLocalizedString(String(format: "SideStore %@", version), comment: "SideStore Version") + tableView.addGestureRecognizer(debugModeGestureRecognizer) + + if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String { + versionLabel.text = NSLocalizedString(String(format: "SideStore %@", version), comment: "SideStore Version") + } else { + versionLabel.text = NSLocalizedString("SideStore", comment: "") } - else - { - self.versionLabel.text = NSLocalizedString("SideStore", comment: "") - } - - self.tableView.contentInset.bottom = 20 - - self.update() - - if #available(iOS 15, *), let appearance = self.tabBarController?.tabBar.standardAppearance - { + + tableView.contentInset.bottom = 20 + + update() + + if #available(iOS 15, *), let appearance = tabBarController?.tabBar.standardAppearance { appearance.stackedLayoutAppearance.normal.badgeBackgroundColor = .altPrimary self.navigationController?.tabBarItem.scrollEdgeAppearance = appearance } } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - self.update() + + update() } } -private extension SettingsViewController -{ - func update() - { - if let team = DatabaseManager.shared.activeTeam() - { - self.accountNameLabel.text = team.name - self.accountEmailLabel.text = team.account.appleID - self.accountTypeLabel.text = team.type.localizedDescription - - self.activeTeam = team +private extension SettingsViewController { + func update() { + if let team = DatabaseManager.shared.activeTeam() { + accountNameLabel.text = team.name + accountEmailLabel.text = team.account.appleID + accountTypeLabel.text = team.type.localizedDescription + + activeTeam = team + } else { + activeTeam = nil } - else - { - self.activeTeam = nil - } - - self.backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled - - if self.isViewLoaded - { - self.tableView.reloadData() + + backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled + + if isViewLoaded { + tableView.reloadData() } } - - func prepare(_ settingsHeaderFooterView: SettingsHeaderFooterView, for section: Section, isHeader: Bool) - { + + func prepare(_ settingsHeaderFooterView: SettingsHeaderFooterView, for section: Section, isHeader: Bool) { settingsHeaderFooterView.primaryLabel.isHidden = !isHeader settingsHeaderFooterView.secondaryLabel.isHidden = isHeader settingsHeaderFooterView.button.isHidden = true - + settingsHeaderFooterView.layoutMargins.bottom = isHeader ? 0 : 8 - - switch section - { + + switch section { case .signIn: - if isHeader - { + if isHeader { settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ACCOUNT", comment: "") - } - else - { + } else { settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Sign in with your Apple ID to download apps from SideStore.", comment: "") } - + case .patreon: - if isHeader - { + if isHeader { settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("PATREON", comment: "") - } - else - { + } else { settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Support the SideStore Team by becoming a patron!", comment: "") } case .account: settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ACCOUNT", comment: "") - + settingsHeaderFooterView.button.setTitle(NSLocalizedString("SIGN OUT", comment: ""), for: .normal) settingsHeaderFooterView.button.addTarget(self, action: #selector(SettingsViewController.signOut(_:)), for: .primaryActionTriggered) settingsHeaderFooterView.button.isHidden = false - + case .appRefresh: - if isHeader - { + if isHeader { settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("REFRESHING APPS", comment: "") - } - else - { + } else { settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Enable Background Refresh to automatically refresh apps in the background when connected to Wi-Fi.", comment: "") } - + case .instructions: break - + case .credits: settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("CREDITS", comment: "") - + case .debug: settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("DEBUG", comment: "") } } - - func preferredHeight(for settingsHeaderFooterView: SettingsHeaderFooterView, in section: Section, isHeader: Bool) -> CGFloat - { + + func preferredHeight(for settingsHeaderFooterView: SettingsHeaderFooterView, in section: Section, isHeader: Bool) -> CGFloat { let widthConstraint = settingsHeaderFooterView.contentView.widthAnchor.constraint(equalToConstant: tableView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } - - self.prepare(settingsHeaderFooterView, for: section, isHeader: isHeader) - + + prepare(settingsHeaderFooterView, for: section, isHeader: isHeader) + let size = settingsHeaderFooterView.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) return size.height } } -private extension SettingsViewController -{ - func signIn() - { - AppManager.shared.authenticate(presentingViewController: self) { (result) in +private extension SettingsViewController { + func signIn() { + AppManager.shared.authenticate(presentingViewController: self) { result in DispatchQueue.main.async { - switch result - { + switch result { case .failure(OperationError.cancelled): // Ignore break - - case .failure(let error): + + case let .failure(error): let toastView = ToastView(error: error) toastView.show(in: self) - + case .success: break } - + self.update() } } } - - @objc func signOut(_ sender: UIBarButtonItem) - { - func signOut() - { - DatabaseManager.shared.signOut { (error) in + + @objc func signOut(_ sender: UIBarButtonItem) { + func signOut() { + DatabaseManager.shared.signOut { error in DispatchQueue.main.async { - if let error = error - { + if let error = error { let toastView = ToastView(error: error) toastView.show(in: self) } - + self.update() } } } - + let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to sign out?", comment: ""), message: NSLocalizedString("You will no longer be able to install or refresh apps once you sign out.", comment: ""), preferredStyle: .actionSheet) alertController.addAction(UIAlertAction(title: NSLocalizedString("Sign Out", comment: ""), style: .destructive) { _ in signOut() }) alertController.addAction(.cancel) - //Fix crash on iPad + // Fix crash on iPad alertController.popoverPresentationController?.barButtonItem = sender - self.present(alertController, animated: true, completion: nil) + present(alertController, animated: true, completion: nil) } - - @IBAction func toggleIsBackgroundRefreshEnabled(_ sender: UISwitch) - { + + @IBAction func toggleIsBackgroundRefreshEnabled(_ sender: UISwitch) { UserDefaults.standard.isBackgroundRefreshEnabled = sender.isOn } - + @available(iOS 14, *) - @IBAction func addRefreshAppsShortcut() - { + @IBAction func addRefreshAppsShortcut() { guard let shortcut = INShortcut(intent: INInteraction.refreshAllApps().intent) else { return } - + let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut) viewController.delegate = self viewController.modalPresentationStyle = .formSheet - self.present(viewController, animated: true, completion: nil) + present(viewController, animated: true, completion: nil) } - - @IBAction func handleDebugModeGesture(_ gestureRecognizer: UISwipeGestureRecognizer) - { - self.debugGestureCounter += 1 - self.debugGestureTimer?.invalidate() - - if self.debugGestureCounter >= 3 - { - self.debugGestureCounter = 0 - + + @IBAction func handleDebugModeGesture(_: UISwipeGestureRecognizer) { + debugGestureCounter += 1 + debugGestureTimer?.invalidate() + + if debugGestureCounter >= 3 { + debugGestureCounter = 0 + UserDefaults.standard.isDebugModeEnabled.toggle() - self.tableView.reloadData() - } - else - { - self.debugGestureTimer = Timer.scheduledTimer(withTimeInterval: 0.4, repeats: false) { [weak self] (timer) in + tableView.reloadData() + } else { + debugGestureTimer = Timer.scheduledTimer(withTimeInterval: 0.4, repeats: false) { [weak self] _ in self?.debugGestureCounter = 0 } } } - - func openTwitter(username: String) - { + + func openTwitter(username: String) { let twitterAppURL = URL(string: "twitter://user?screen_name=" + username)! - UIApplication.shared.open(twitterAppURL, options: [:]) { (success) in - if success - { - if let selectedIndexPath = self.tableView.indexPathForSelectedRow - { + UIApplication.shared.open(twitterAppURL, options: [:]) { success in + if success { + if let selectedIndexPath = self.tableView.indexPathForSelectedRow { self.tableView.deselectRow(at: selectedIndexPath, animated: true) } - } - else - { + } else { let safariURL = URL(string: "https://twitter.com/" + username)! - + let safariViewController = SFSafariViewController(url: safariURL) safariViewController.preferredControlTintColor = .altPrimary self.present(safariViewController, animated: true, completion: nil) @@ -333,12 +285,10 @@ private extension SettingsViewController } } -private extension SettingsViewController -{ - @objc func openPatreonSettings(_ notification: Notification) - { - guard self.presentedViewController == nil else { return } - +private extension SettingsViewController { + @objc func openPatreonSettings(_: Notification) { + guard presentedViewController == nil else { return } + UIView.performWithoutAnimation { self.navigationController?.popViewController(animated: false) self.performSegue(withIdentifier: "showPatreon", sender: nil) @@ -346,163 +296,135 @@ private extension SettingsViewController } } -extension SettingsViewController -{ - override func numberOfSections(in tableView: UITableView) -> Int - { +extension SettingsViewController { + override func numberOfSections(in tableView: UITableView) -> Int { var numberOfSections = super.numberOfSections(in: tableView) - - if !UserDefaults.standard.isDebugModeEnabled - { + + if !UserDefaults.standard.isDebugModeEnabled { numberOfSections -= 1 } - + return numberOfSections } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int - { + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let section = Section.allCases[section] - switch section - { - case .signIn: return (self.activeTeam == nil) ? 1 : 0 - case .account: return (self.activeTeam == nil) ? 0 : 3 + switch section { + case .signIn: return (activeTeam == nil) ? 1 : 0 + case .account: return (activeTeam == nil) ? 0 : 3 case .appRefresh: return AppRefreshRow.allCases.count default: return super.tableView(tableView, numberOfRowsInSection: section.rawValue) } } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = super.tableView(tableView, cellForRowAt: indexPath) - - if #available(iOS 14, *) {} - else if let cell = cell as? InsetGroupTableViewCell, - indexPath.section == Section.appRefresh.rawValue, - indexPath.row == AppRefreshRow.backgroundRefresh.rawValue - { + + if #available(iOS 14, *) {} else if let cell = cell as? InsetGroupTableViewCell, + indexPath.section == Section.appRefresh.rawValue, + indexPath.row == AppRefreshRow.backgroundRefresh.rawValue { // Only one row is visible pre-iOS 14. cell.style = .single } - + return cell } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? - { + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let section = Section.allCases[section] - switch section - { - case .signIn where self.activeTeam != nil: return nil - case .account where self.activeTeam == nil: return nil + switch section { + case .signIn where activeTeam != nil: return nil + case .account where activeTeam == nil: return nil case .signIn, .account, .patreon, .appRefresh, .credits, .debug: let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView - self.prepare(headerView, for: section, isHeader: true) + prepare(headerView, for: section, isHeader: true) return headerView - + case .instructions: return nil } } - - override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? - { + + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { let section = Section.allCases[section] - switch section - { - case .signIn where self.activeTeam != nil: return nil + switch section { + case .signIn where activeTeam != nil: return nil case .signIn, .patreon, .appRefresh: let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView - self.prepare(footerView, for: section, isHeader: false) + prepare(footerView, for: section, isHeader: false) return footerView - + case .account, .credits, .debug, .instructions: return nil } } - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat - { + override func tableView(_: UITableView, heightForHeaderInSection section: Int) -> CGFloat { let section = Section.allCases[section] - switch section - { - case .signIn where self.activeTeam != nil: return 1.0 - case .account where self.activeTeam == nil: return 1.0 + switch section { + case .signIn where activeTeam != nil: return 1.0 + case .account where activeTeam == nil: return 1.0 case .signIn, .account, .patreon, .appRefresh, .credits, .debug: - let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: true) + let height = preferredHeight(for: prototypeHeaderFooterView, in: section, isHeader: true) return height - + case .instructions: return 0.0 } } - - override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat - { + + override func tableView(_: UITableView, heightForFooterInSection section: Int) -> CGFloat { let section = Section.allCases[section] - switch section - { - case .signIn where self.activeTeam != nil: return 1.0 - case .account where self.activeTeam == nil: return 1.0 + switch section { + case .signIn where activeTeam != nil: return 1.0 + case .account where activeTeam == nil: return 1.0 case .signIn, .patreon, .appRefresh: - let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: false) + let height = preferredHeight(for: prototypeHeaderFooterView, in: section, isHeader: false) return height - + case .account, .credits, .debug, .instructions: return 0.0 } } } -extension SettingsViewController -{ - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) - { +extension SettingsViewController { + override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { let section = Section.allCases[indexPath.section] - switch section - { - case .signIn: self.signIn() + switch section { + case .signIn: signIn() case .instructions: break case .appRefresh: let row = AppRefreshRow.allCases[indexPath.row] - switch row - { + switch row { case .backgroundRefresh: break case .addToSiri: guard #available(iOS 14, *) else { return } - self.addRefreshAppsShortcut() + addRefreshAppsShortcut() } - + case .credits: let row = CreditsRow.allCases[indexPath.row] - switch row - { - case .developer: self.openTwitter(username: "sidestore_io") - case .operations: self.openTwitter(username: "sidestore_io") - case .designer: self.openTwitter(username: "lit_ritt") + switch row { + case .developer: openTwitter(username: "sidestore_io") + case .operations: openTwitter(username: "sidestore_io") + case .designer: openTwitter(username: "lit_ritt") case .softwareLicenses: break } - + case .debug: let row = DebugRow.allCases[indexPath.row] - switch row - { + switch row { case .sendFeedback: - if MFMailComposeViewController.canSendMail() - { + if MFMailComposeViewController.canSendMail() { let mailViewController = MFMailComposeViewController() mailViewController.mailComposeDelegate = self mailViewController.setToRecipients(["support@sidestore.io"]) - - if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String - { + + if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String { mailViewController.setSubject("SideStore Beta \(version) Feedback") - } - else - { + } else { mailViewController.setSubject("SideStore Beta Feedback") } - - self.present(mailViewController, animated: true, completion: nil) - } - else - { + + present(mailViewController, animated: true, completion: nil) + } else { let toastView = ToastView(text: NSLocalizedString("Cannot Send Mail", comment: ""), detailText: nil) toastView.show(in: self) } @@ -513,9 +435,10 @@ extension SettingsViewController let alertController = UIAlertController( title: NSLocalizedString("Are you sure to reset the pairing file?", comment: ""), message: NSLocalizedString("You can reset the pairing file when you cannot sideload apps or enable JIT. You need to restart SideStore.", comment: ""), - preferredStyle: UIAlertController.Style.actionSheet) - - alertController.addAction(UIAlertAction(title: NSLocalizedString("Delete and Reset", comment: ""), style: .destructive){ _ in + preferredStyle: UIAlertController.Style.actionSheet + ) + + alertController.addAction(UIAlertAction(title: NSLocalizedString("Delete and Reset", comment: ""), style: .destructive) { _ in if fm.fileExists(atPath: documentsPath.path), let contents = try? String(contentsOf: documentsPath), !contents.isEmpty { try? fm.removeItem(atPath: documentsPath.path) NSLog("Pairing File Reseted") @@ -525,11 +448,11 @@ extension SettingsViewController self.present(dialogMessage, animated: true, completion: nil) }) alertController.addAction(.cancel) - //Fix crash on iPad - alertController.popoverPresentationController?.sourceView = self.tableView - alertController.popoverPresentationController?.sourceRect = self.tableView.rectForRow(at: indexPath) - self.present(alertController, animated: true) - self.tableView.deselectRow(at: indexPath, animated: true) + // Fix crash on iPad + alertController.popoverPresentationController?.sourceView = tableView + alertController.popoverPresentationController?.sourceRect = tableView.rectForRow(at: indexPath) + present(alertController, animated: true) + tableView.deselectRow(at: indexPath, animated: true) case .advancedSettings: // Create the URL that deep links to your app's custom settings. if let url = URL(string: UIApplication.openSettingsURLString) { @@ -540,58 +463,48 @@ extension SettingsViewController } case .refreshAttempts, .errorLog: break } - + default: break } } } -extension SettingsViewController: MFMailComposeViewControllerDelegate -{ - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) - { - if let error = error - { +extension SettingsViewController: MFMailComposeViewControllerDelegate { + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error: Error?) { + if let error = error { let toastView = ToastView(error: error) toastView.show(in: self) } - + controller.dismiss(animated: true, completion: nil) } } -extension SettingsViewController: UIGestureRecognizerDelegate -{ - func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool - { - return true +extension SettingsViewController: UIGestureRecognizerDelegate { + func gestureRecognizer(_: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer) -> Bool { + true } } -extension SettingsViewController: INUIAddVoiceShortcutViewControllerDelegate -{ - func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) - { - if let indexPath = self.tableView.indexPathForSelectedRow - { - self.tableView.deselectRow(at: indexPath, animated: true) +extension SettingsViewController: INUIAddVoiceShortcutViewControllerDelegate { + func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith _: INVoiceShortcut?, error: Error?) { + if let indexPath = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: indexPath, animated: true) } - + controller.dismiss(animated: true, completion: nil) - + guard let error = error else { return } - + let toastView = ToastView(error: error) toastView.show(in: self) } - - func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) - { - if let indexPath = self.tableView.indexPathForSelectedRow - { - self.tableView.deselectRow(at: indexPath, animated: true) + + func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) { + if let indexPath = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: indexPath, animated: true) } - + controller.dismiss(animated: true, completion: nil) } } diff --git a/AltStore/Sources/SourcesViewController.swift b/Sources/SideStore/Sources/SourcesViewController.swift similarity index 72% rename from AltStore/Sources/SourcesViewController.swift rename to Sources/SideStore/Sources/SourcesViewController.swift index 0964aace..290d2367 100644 --- a/AltStore/Sources/SourcesViewController.swift +++ b/Sources/SideStore/Sources/SourcesViewController.swift @@ -6,135 +6,117 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import UIKit import CoreData +import UIKit -import AltStoreCore +import SideStoreCore import RoxasUI -struct SourceError: LocalizedError -{ - enum Code - { +struct SourceError: LocalizedError { + enum Code { case unsupported } - + var code: Code @Managed var source: Source - + var errorDescription: String? { - switch self.code - { - case .unsupported: return String(format: NSLocalizedString("The source “%@” is not supported by this version of SideStore.", comment: ""), self.$source.name) + switch code { + case .unsupported: return String(format: NSLocalizedString("The source “%@” is not supported by this version of SideStore.", comment: ""), $source.name) } } } @objc(SourcesFooterView) -private final class SourcesFooterView: TextCollectionReusableView -{ +private final class SourcesFooterView: TextCollectionReusableView { @IBOutlet var activityIndicatorView: UIActivityIndicatorView! @IBOutlet var textView: UITextView! } -extension SourcesViewController -{ - private enum Section: Int, CaseIterable - { +extension SourcesViewController { + private enum Section: Int, CaseIterable { case added case trusted } } -final class SourcesViewController: UICollectionViewController -{ +final class SourcesViewController: UICollectionViewController { var deepLinkSourceURL: URL? { didSet { - guard let sourceURL = self.deepLinkSourceURL else { return } - self.addSource(url: sourceURL) + guard let sourceURL = deepLinkSourceURL else { return } + addSource(url: sourceURL) } } - + private lazy var dataSource = self.makeDataSource() private lazy var addedSourcesDataSource = self.makeAddedSourcesDataSource() private lazy var trustedSourcesDataSource = self.makeTrustedSourcesDataSource() - + private var fetchTrustedSourcesOperation: FetchTrustedSourcesOperation? private var fetchTrustedSourcesResult: Result? private var _fetchTrustedSourcesContext: NSManagedObjectContext? - - override func viewDidLoad() - { + + override func viewDidLoad() { super.viewDidLoad() - - self.collectionView.dataSource = self.dataSource - + + collectionView.dataSource = dataSource + #if !BETA - // Hide "Add Source" button for public version while in beta. - self.navigationItem.leftBarButtonItem = nil + // Hide "Add Source" button for public version while in beta. + navigationItem.leftBarButtonItem = nil #endif } - - override func viewWillAppear(_ animated: Bool) - { + + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - - if self.deepLinkSourceURL != nil - { - self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true + + if deepLinkSourceURL != nil { + navigationItem.leftBarButtonItem?.isIndicatingActivity = true } - - if self.fetchTrustedSourcesOperation == nil - { - self.fetchTrustedSources() + + if fetchTrustedSourcesOperation == nil { + fetchTrustedSources() } } - - override func viewDidAppear(_ animated: Bool) - { + + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - - if let sourceURL = self.deepLinkSourceURL - { - self.addSource(url: sourceURL) + + if let sourceURL = deepLinkSourceURL { + addSource(url: sourceURL) } } } -private extension SourcesViewController -{ - func makeDataSource() -> RSTCompositeCollectionViewDataSource - { - let dataSource = RSTCompositeCollectionViewDataSource(dataSources: [self.addedSourcesDataSource, self.trustedSourcesDataSource]) +private extension SourcesViewController { + func makeDataSource() -> RSTCompositeCollectionViewDataSource { + let dataSource = RSTCompositeCollectionViewDataSource(dataSources: [addedSourcesDataSource, trustedSourcesDataSource]) dataSource.proxy = self - dataSource.cellConfigurationHandler = { (cell, source, indexPath) in + dataSource.cellConfigurationHandler = { cell, source, indexPath in let tintColor = UIColor.altPrimary - + let cell = cell as! BannerCollectionViewCell cell.layoutMargins.left = self.view.layoutMargins.left cell.layoutMargins.right = self.view.layoutMargins.right cell.tintColor = tintColor - + cell.bannerView.iconImageView.isHidden = true cell.bannerView.buttonLabel.isHidden = true cell.bannerView.button.isIndicatingActivity = false - - switch Section.allCases[indexPath.section] - { + + switch Section.allCases[indexPath.section] { case .added: cell.bannerView.button.isHidden = true - + case .trusted: // Quicker way to determine whether a source is already added than by reading from disk. - if (self.addedSourcesDataSource.fetchedResultsController.fetchedObjects ?? []).contains(where: { $0.identifier == source.identifier }) - { + if (self.addedSourcesDataSource.fetchedResultsController.fetchedObjects ?? []).contains(where: { $0.identifier == source.identifier }) { // Source exists in .added section, so hide the button. cell.bannerView.button.isHidden = true - - if #available(iOS 13.0, *) - { + + if #available(iOS 13.0, *) { let configuation = UIImage.SymbolConfiguration(pointSize: 24) - + let imageAttachment = NSTextAttachment() imageAttachment.image = UIImage(systemName: "checkmark.circle", withConfiguration: configuation)?.withTintColor(.altPrimary) @@ -143,130 +125,118 @@ private extension SourcesViewController cell.bannerView.buttonLabel.textAlignment = .center cell.bannerView.buttonLabel.isHidden = false } - } - else - { + } else { // Source does not exist in .added section, so show the button. cell.bannerView.button.isHidden = false cell.bannerView.buttonLabel.attributedText = nil } - + cell.bannerView.button.setTitle(NSLocalizedString("ADD", comment: ""), for: .normal) cell.bannerView.button.addTarget(self, action: #selector(SourcesViewController.addTrustedSource(_:)), for: .primaryActionTriggered) } - + cell.bannerView.titleLabel.text = source.name cell.bannerView.subtitleLabel.text = source.sourceURL.absoluteString cell.bannerView.subtitleLabel.numberOfLines = 2 - + cell.errorBadge?.isHidden = (source.error == nil) - + let attributedLabel = NSAttributedString(string: source.name + "\n" + source.sourceURL.absoluteString, attributes: [.accessibilitySpeechPunctuation: true]) cell.bannerView.accessibilityAttributedLabel = attributedLabel cell.bannerView.accessibilityTraits.remove(.button) - + // Make sure refresh button is correct size. cell.layoutIfNeeded() } - + return dataSource } - - func makeAddedSourcesDataSource() -> RSTFetchedResultsCollectionViewDataSource - { + + func makeAddedSourcesDataSource() -> RSTFetchedResultsCollectionViewDataSource { let fetchRequest = Source.fetchRequest() as NSFetchRequest fetchRequest.returnsObjectsAsFaults = false fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Source.name, ascending: true), NSSortDescriptor(keyPath: \Source.sourceURL, ascending: true), NSSortDescriptor(keyPath: \Source.identifier, ascending: true)] - + let dataSource = RSTFetchedResultsCollectionViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) return dataSource } - - func makeTrustedSourcesDataSource() -> RSTArrayCollectionViewDataSource - { + + func makeTrustedSourcesDataSource() -> RSTArrayCollectionViewDataSource { let dataSource = RSTArrayCollectionViewDataSource(items: []) return dataSource } } -private extension SourcesViewController -{ - @IBAction func addSource() - { +private extension SourcesViewController { + @IBAction func addSource() { let alertController = UIAlertController(title: NSLocalizedString("Add Source", comment: ""), message: nil, preferredStyle: .alert) - alertController.addTextField { (textField) in + alertController.addTextField { textField in textField.placeholder = "https://apps.altstore.io" textField.textContentType = .URL } alertController.addAction(.cancel) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Add", comment: ""), style: .default) { (action) in + alertController.addAction(UIAlertAction(title: NSLocalizedString("Add", comment: ""), style: .default) { _ in guard let text = alertController.textFields![0].text else { return } guard var sourceURL = URL(string: text) else { return } if sourceURL.scheme == nil { guard let httpsSourceURL = URL(string: "https://" + text) else { return } sourceURL = httpsSourceURL } - + self.navigationItem.leftBarButtonItem?.isIndicatingActivity = true - + self.addSource(url: sourceURL) { _ in self.navigationItem.leftBarButtonItem?.isIndicatingActivity = false } }) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } - - func addSource(url: URL, isTrusted: Bool = false, completionHandler: ((Result) -> Void)? = nil) - { - guard self.view.window != nil else { return } - - if url == self.deepLinkSourceURL - { + + func addSource(url: URL, isTrusted: Bool = false, completionHandler: ((Result) -> Void)? = nil) { + guard view.window != nil else { return } + + if url == deepLinkSourceURL { // Only handle deep link once. - self.deepLinkSourceURL = nil + deepLinkSourceURL = nil } - - func finish(_ result: Result) - { + + func finish(_ result: Result) { DispatchQueue.main.async { - switch result - { + switch result { case .success: break case .failure(OperationError.cancelled): break - case .failure(let error): self.present(error) + case let .failure(error): self.present(error) } - + self.collectionView.reloadSections([Section.trusted.rawValue]) - + completionHandler?(result) } } - + var dependencies: [Foundation.Operation] = [] - if let fetchTrustedSourcesOperation = self.fetchTrustedSourcesOperation - { + if let fetchTrustedSourcesOperation = fetchTrustedSourcesOperation { // Must fetch trusted sources first to determine whether this is a trusted source. // We assume fetchTrustedSources() has already been called before this method. dependencies = [fetchTrustedSourcesOperation] } - - AppManager.shared.fetchSource(sourceURL: url, dependencies: dependencies) { (result) in - do - { + + AppManager.shared.fetchSource(sourceURL: url, dependencies: dependencies) { result in + do { let source = try result.get() let sourceName = source.name let managedObjectContext = source.managedObjectContext - + #if !BETA - guard let trustedSourceIDs = UserDefaults.shared.trustedSourceIDs, trustedSourceIDs.contains(source.identifier) else { throw SourceError(code: .unsupported, source: source) } + guard let trustedSourceIDs = UserDefaults.shared.trustedSourceIDs, trustedSourceIDs.contains(source.identifier) else { throw SourceError(code: .unsupported, source: source) } #endif - + // Hide warning when adding a featured trusted source. let message = isTrusted ? nil : NSLocalizedString("Make sure to only add sources that you trust.", comment: "") - + DispatchQueue.main.async { let alertController = UIAlertController(title: String(format: NSLocalizedString("Would you like to add the source “%@”?", comment: ""), sourceName), message: message, preferredStyle: .alert) @@ -275,112 +245,96 @@ private extension SourcesViewController }) alertController.addAction(UIAlertAction(title: NSLocalizedString("Add Source", comment: ""), style: UIAlertAction.ok.style) { _ in managedObjectContext?.perform { - do - { + do { try managedObjectContext?.save() finish(.success(())) - } - catch - { + } catch { finish(.failure(error)) } } }) self.present(alertController, animated: true, completion: nil) } - } - catch - { + } catch { finish(.failure(error)) } } } - func present(_ error: Error) - { - if let transitionCoordinator = self.transitionCoordinator - { + func present(_ error: Error) { + if let transitionCoordinator = transitionCoordinator { transitionCoordinator.animate(alongsideTransition: nil) { _ in self.present(error) } - + return } - + let nsError = error as NSError let message = nsError.userInfo[NSDebugDescriptionErrorKey] as? String ?? nsError.localizedRecoverySuggestion - + let alertController = UIAlertController(title: error.localizedDescription, message: message, preferredStyle: .alert) alertController.addAction(.ok) - self.present(alertController, animated: true, completion: nil) + present(alertController, animated: true, completion: nil) } - - func fetchTrustedSources() - { - func finish(_ result: Result<[Source], Error>) - { - self.fetchTrustedSourcesResult = result.map { _ in () } - + + func fetchTrustedSources() { + func finish(_ result: Result<[Source], Error>) { + fetchTrustedSourcesResult = result.map { _ in () } + DispatchQueue.main.async { - do - { + do { let sources = try result.get() print("Fetched trusted sources:", sources.map { $0.identifier }) let sectionUpdate = RSTCellContentChange(type: .update, sectionIndex: 0) self.trustedSourcesDataSource.setItems(sources, with: [sectionUpdate]) - } - catch - { + } catch { print("Error fetching trusted sources:", error) - + let sectionUpdate = RSTCellContentChange(type: .update, sectionIndex: 0) self.trustedSourcesDataSource.setItems([], with: [sectionUpdate]) } } } - - self.fetchTrustedSourcesOperation = AppManager.shared.fetchTrustedSources { result in - switch result - { - case .failure(let error): finish(.failure(error)) - case .success(let trustedSources): + + fetchTrustedSourcesOperation = AppManager.shared.fetchTrustedSources { result in + switch result { + case let .failure(error): finish(.failure(error)) + case let .success(trustedSources): // Cache trusted source IDs. UserDefaults.shared.trustedSourceIDs = trustedSources.map { $0.identifier } - + // Don't show sources without a sourceURL. let featuredSourceURLs = trustedSources.compactMap { $0.sourceURL } - + // This context is never saved, but keeps the managed sources alive. let context = DatabaseManager.shared.persistentContainer.newBackgroundSavingViewContext() self._fetchTrustedSourcesContext = context - + let dispatchGroup = DispatchGroup() - + var sourcesByURL = [URL: Source]() var fetchError: Error? - - for sourceURL in featuredSourceURLs - { + + for sourceURL in featuredSourceURLs { dispatchGroup.enter() - + AppManager.shared.fetchSource(sourceURL: sourceURL, managedObjectContext: context) { result in // Serialize access to sourcesByURL. context.performAndWait { - switch result - { - case .failure(let error): fetchError = error - case .success(let source): sourcesByURL[source.sourceURL] = source + switch result { + case let .failure(error): fetchError = error + case let .success(source): sourcesByURL[source.sourceURL] = source } - + dispatchGroup.leave() } } } - + dispatchGroup.notify(queue: .main) { - if let error = fetchError - { + if let error = fetchError { print(error) // 1 error doesn't mean all trusted sources failed to load! Riley, why did you do this??????? // finish(.failure(error)) @@ -391,248 +345,222 @@ private extension SourcesViewController } } } - - @IBAction func addTrustedSource(_ sender: PillButton) - { - let point = self.collectionView.convert(sender.center, from: sender.superview) - guard let indexPath = self.collectionView.indexPathForItem(at: point) else { return } - + + @IBAction func addTrustedSource(_ sender: PillButton) { + let point = collectionView.convert(sender.center, from: sender.superview) + guard let indexPath = collectionView.indexPathForItem(at: point) else { return } + let completedProgress = Progress(totalUnitCount: 1) completedProgress.completedUnitCount = 1 sender.progress = completedProgress - - let source = self.dataSource.item(at: indexPath) - self.addSource(url: source.sourceURL, isTrusted: true) { _ in - //FIXME: Handle cell reuse. + + let source = dataSource.item(at: indexPath) + addSource(url: source.sourceURL, isTrusted: true) { _ in + // FIXME: Handle cell reuse. sender.progress = nil } } - - func remove(_ source: Source) - { + + func remove(_ source: Source) { let alertController = UIAlertController(title: String(format: NSLocalizedString("Are you sure you want to remove the source “%@”?", comment: ""), source.name), message: NSLocalizedString("Any apps you've installed from this source will remain, but they'll no longer receive any app updates.", comment: ""), preferredStyle: .alert) alertController.addAction(UIAlertAction(title: UIAlertAction.cancel.title, style: UIAlertAction.cancel.style, handler: nil)) alertController.addAction(UIAlertAction(title: NSLocalizedString("Remove Source", comment: ""), style: .destructive) { _ in - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let source = context.object(with: source.objectID) as! Source context.delete(source) - - do - { + + do { try context.save() - + DispatchQueue.main.async { self.collectionView.reloadSections([Section.trusted.rawValue]) } - } - catch - { + } catch { DispatchQueue.main.async { self.present(error) } } } }) - - self.present(alertController, animated: true, completion: nil) + + present(alertController, animated: true, completion: nil) } } -extension SourcesViewController -{ - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) - { - self.collectionView.deselectItem(at: indexPath, animated: true) - - let source = self.dataSource.item(at: indexPath) +extension SourcesViewController { + override func collectionView(_: UICollectionView, didSelectItemAt indexPath: IndexPath) { + collectionView.deselectItem(at: indexPath, animated: true) + + let source = dataSource.item(at: indexPath) guard let error = source.error else { return } - - self.present(error) + + present(error) } } -extension SourcesViewController: UICollectionViewDelegateFlowLayout -{ - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { - return CGSize(width: collectionView.bounds.width, height: 80) +extension SourcesViewController: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize { + CGSize(width: collectionView.bounds.width, height: 80) } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize - { + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { let indexPath = IndexPath(row: 0, section: section) let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath) - + // Use this view to calculate the optimal size based on the collection view's width let size = headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, // Width is fixed verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed return size } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize - { + + func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { guard Section(rawValue: section) == .trusted else { return .zero } - + let indexPath = IndexPath(row: 0, section: section) let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: indexPath) - + // Use this view to calculate the optimal size based on the collection view's width let size = headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, // Width is fixed verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed return size } - - override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { + + override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let reuseIdentifier = (kind == UICollectionView.elementKindSectionHeader) ? "Header" : "Footer" - + let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: reuseIdentifier, for: indexPath) as! TextCollectionReusableView - headerView.layoutMargins.left = self.view.layoutMargins.left - headerView.layoutMargins.right = self.view.layoutMargins.right - + headerView.layoutMargins.left = view.layoutMargins.left + headerView.layoutMargins.right = view.layoutMargins.right + let almostRequiredPriority = UILayoutPriority(UILayoutPriority.required.rawValue - 1) // Can't be required or else we can't satisfy constraints when hidden (size = 0). headerView.leadingLayoutConstraint?.priority = almostRequiredPriority headerView.trailingLayoutConstraint?.priority = almostRequiredPriority headerView.topLayoutConstraint?.priority = almostRequiredPriority headerView.bottomLayoutConstraint?.priority = almostRequiredPriority - - switch kind - { + + switch kind { case UICollectionView.elementKindSectionHeader: - switch Section.allCases[indexPath.section] - { + switch Section.allCases[indexPath.section] { case .added: headerView.textLabel.text = NSLocalizedString("Sources control what apps are available to download through SideStore.", comment: "") headerView.textLabel.font = UIFont.preferredFont(forTextStyle: .callout) headerView.textLabel.textAlignment = .natural - + headerView.topLayoutConstraint.constant = 14 headerView.bottomLayoutConstraint.constant = 30 - + case .trusted: - switch self.fetchTrustedSourcesResult - { + switch fetchTrustedSourcesResult { case .failure: headerView.textLabel.text = NSLocalizedString("Error Loading Trusted Sources", comment: "") case .success, .none: headerView.textLabel.text = NSLocalizedString("Trusted Sources", comment: "") } - + let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .callout).withSymbolicTraits(.traitBold)! headerView.textLabel.font = UIFont(descriptor: descriptor, size: 0) headerView.textLabel.textAlignment = .center - + headerView.topLayoutConstraint.constant = 54 headerView.bottomLayoutConstraint.constant = 15 } - + case UICollectionView.elementKindSectionFooter: let footerView = headerView as! SourcesFooterView let font = UIFont.preferredFont(forTextStyle: .subheadline) - - switch self.fetchTrustedSourcesResult - { - case .failure(let error): + + switch fetchTrustedSourcesResult { + case let .failure(error): footerView.textView.font = font footerView.textView.text = error.localizedDescription - + footerView.activityIndicatorView.stopAnimating() footerView.topLayoutConstraint.constant = 0 footerView.textView.textAlignment = .center - + case .success, .none: footerView.textView.delegate = self - + let attributedText = NSMutableAttributedString( string: NSLocalizedString("SideStore has reviewed these sources to make sure they meet our safety standards.\n\nSupport for untrusted sources is currently in beta, but you can help test them out by", comment: ""), attributes: [.font: font, .foregroundColor: UIColor.gray] ) attributedText.mutableString.append(" ") - + let boldedFont = UIFont(descriptor: font.fontDescriptor.withSymbolicTraits(.traitBold)!, size: font.pointSize) let openPatreonURL = URL(string: "https://SideStore.io/patreon")! - + let joinPatreonText = NSAttributedString( string: NSLocalizedString("joining our Patreon.", comment: ""), attributes: [.font: boldedFont, .link: openPatreonURL, .underlineColor: UIColor.clear] ) attributedText.append(joinPatreonText) - + footerView.textView.attributedText = attributedText footerView.textView.textAlignment = .natural - - if self.fetchTrustedSourcesResult != nil - { + + if fetchTrustedSourcesResult != nil { footerView.activityIndicatorView.stopAnimating() footerView.topLayoutConstraint.constant = 20 - } - else - { + } else { footerView.activityIndicatorView.startAnimating() footerView.topLayoutConstraint.constant = 0 } } - + default: break } - + return headerView } } @available(iOS 13, *) -extension SourcesViewController -{ - override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? - { - let source = self.dataSource.item(at: indexPath) +extension SourcesViewController { + override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point _: CGPoint) -> UIContextMenuConfiguration? { + let source = dataSource.item(at: indexPath) - return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { (suggestedActions) -> UIMenu? in - let viewErrorAction = UIAction(title: NSLocalizedString("View Error", comment: ""), image: UIImage(systemName: "exclamationmark.circle")) { (action) in + return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { _ -> UIMenu? in + let viewErrorAction = UIAction(title: NSLocalizedString("View Error", comment: ""), image: UIImage(systemName: "exclamationmark.circle")) { _ in guard let error = source.error else { return } self.present(error) } - - let deleteAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { (action) in + + let deleteAction = UIAction(title: NSLocalizedString("Remove", comment: ""), image: UIImage(systemName: "trash"), attributes: [.destructive]) { _ in self.remove(source) } - - let addAction = UIAction(title: String(format: NSLocalizedString("Add “%@”", comment: ""), source.name), image: UIImage(systemName: "plus")) { (action) in + + let addAction = UIAction(title: String(format: NSLocalizedString("Add “%@”", comment: ""), source.name), image: UIImage(systemName: "plus")) { _ in self.addSource(url: source.sourceURL, isTrusted: true) } - + var actions: [UIAction] = [] - - if source.error != nil - { + + if source.error != nil { actions.append(viewErrorAction) } - - switch Section.allCases[indexPath.section] - { + + switch Section.allCases[indexPath.section] { case .added: - if source.identifier != Source.altStoreIdentifier - { + if source.identifier != Source.altStoreIdentifier { actions.append(deleteAction) } - + case .trusted: - if let cell = collectionView.cellForItem(at: indexPath) as? BannerCollectionViewCell, !cell.bannerView.button.isHidden - { + if let cell = collectionView.cellForItem(at: indexPath) as? BannerCollectionViewCell, !cell.bannerView.button.isHidden { actions.append(addAction) } } - + guard !actions.isEmpty else { return nil } - + let menu = UIMenu(title: "", children: actions) return menu } } - override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? - { + override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { guard let indexPath = configuration.identifier as? NSIndexPath else { return nil } guard let cell = collectionView.cellForItem(at: indexPath as IndexPath) as? BannerCollectionViewCell else { return nil } @@ -644,16 +572,13 @@ extension SourcesViewController return preview } - override func collectionView(_ collectionView: UICollectionView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? - { - return self.collectionView(collectionView, previewForHighlightingContextMenuWithConfiguration: configuration) + override func collectionView(_ collectionView: UICollectionView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + self.collectionView(collectionView, previewForHighlightingContextMenuWithConfiguration: configuration) } } -extension SourcesViewController: UITextViewDelegate -{ - func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool - { - return true +extension SourcesViewController: UITextViewDelegate { + func textView(_: UITextView, shouldInteractWith _: URL, in _: NSRange, interaction _: UITextItemInteraction) -> Bool { + true } } diff --git a/AltStore/TabBarController.swift b/Sources/SideStore/TabBarController.swift similarity index 67% rename from AltStore/TabBarController.swift rename to Sources/SideStore/TabBarController.swift index 91263340..79f3e1bf 100644 --- a/AltStore/TabBarController.swift +++ b/Sources/SideStore/TabBarController.swift @@ -6,13 +6,11 @@ // Copyright © 2019 Riley Testut. All rights reserved. // +import SideStoreCore import UIKit -import AltStoreCore -extension TabBarController -{ - private enum Tab: Int, CaseIterable - { +extension TabBarController { + private enum Tab: Int, CaseIterable { case news case browse case myApps @@ -20,125 +18,104 @@ extension TabBarController } } -final class TabBarController: UITabBarController -{ +final class TabBarController: UITabBarController { private var initialSegue: (identifier: String, sender: Any?)? - + private var _viewDidAppear = false - - required init?(coder aDecoder: NSCoder) - { + + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - + NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil) } - - override func viewDidAppear(_ animated: Bool) - { + + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + _viewDidAppear = true - - if let (identifier, sender) = self.initialSegue - { - self.initialSegue = nil - self.performSegue(withIdentifier: identifier, sender: sender) - } - else if let patchedApps = UserDefaults.standard.patchedApps, !patchedApps.isEmpty - { + + if let (identifier, sender) = initialSegue { + initialSegue = nil + performSegue(withIdentifier: identifier, sender: sender) + } else if let patchedApps = UserDefaults.standard.patchedApps, !patchedApps.isEmpty { // Check if we need to finish installing untethered jailbreak. let activeApps = InstalledApp.fetchActiveApps(in: DatabaseManager.shared.viewContext) guard let patchedApp = activeApps.first(where: { patchedApps.contains($0.bundleIdentifier) }) else { return } - - self.performSegue(withIdentifier: "finishJailbreak", sender: patchedApp) + + performSegue(withIdentifier: "finishJailbreak", sender: patchedApp) } } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) - { + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier else { return } - - switch identifier - { + + switch identifier { case "presentSources": guard let notification = sender as? Notification, let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL else { return } - + let navigationController = segue.destination as! UINavigationController let sourcesViewController = navigationController.viewControllers.first as! SourcesViewController sourcesViewController.deepLinkSourceURL = sourceURL - + case "finishJailbreak": guard let installedApp = sender as? InstalledApp, #available(iOS 14, *) else { return } - + let navigationController = segue.destination as! UINavigationController - + let patchViewController = navigationController.viewControllers.first as! PatchViewController patchViewController.installedApp = installedApp patchViewController.completionHandler = { [weak self] _ in self?.dismiss(animated: true, completion: nil) } - + default: break } } - - override func performSegue(withIdentifier identifier: String, sender: Any?) - { + + override func performSegue(withIdentifier identifier: String, sender: Any?) { guard _viewDidAppear else { - self.initialSegue = (identifier, sender) + initialSegue = (identifier, sender) return } - + super.performSegue(withIdentifier: identifier, sender: sender) } } -extension TabBarController -{ - @objc func presentSources(_ sender: Any) - { - if let presentedViewController = self.presentedViewController - { +extension TabBarController { + @objc func presentSources(_ sender: Any) { + if let presentedViewController = presentedViewController { if let navigationController = presentedViewController as? UINavigationController, - let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController - { + let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController { if let notification = (sender as? Notification), - let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL - { + let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL { sourcesViewController.deepLinkSourceURL = sourceURL - } - else - { + } else { // Don't dismiss SourcesViewController if it's already presented. } - } - else - { + } else { presentedViewController.dismiss(animated: true) { self.presentSources(sender) } } - + return } - - self.performSegue(withIdentifier: "presentSources", sender: sender) + + performSegue(withIdentifier: "presentSources", sender: sender) } } -private extension TabBarController -{ - @objc func openPatreonSettings(_ notification: Notification) - { - self.selectedIndex = Tab.settings.rawValue +private extension TabBarController { + @objc func openPatreonSettings(_: Notification) { + selectedIndex = Tab.settings.rawValue } - - @objc func importApp(_ notification: Notification) - { - self.selectedIndex = Tab.myApps.rawValue + + @objc func importApp(_: Notification) { + selectedIndex = Tab.myApps.rawValue } } diff --git a/AltStore/Types/LoadingState.swift b/Sources/SideStore/Types/LoadingState.swift similarity index 91% rename from AltStore/Types/LoadingState.swift rename to Sources/SideStore/Types/LoadingState.swift index f8b13320..bca461a5 100644 --- a/AltStore/Types/LoadingState.swift +++ b/Sources/SideStore/Types/LoadingState.swift @@ -8,8 +8,7 @@ import Foundation -enum LoadingState -{ +enum LoadingState { case loading case finished(Result) } diff --git a/AltStore/Types/Managed.swift b/Sources/SideStore/Types/Managed.swift similarity index 77% rename from AltStore/Types/Managed.swift rename to Sources/SideStore/Types/Managed.swift index 1bce7bb4..1e8df238 100644 --- a/AltStore/Types/Managed.swift +++ b/Sources/SideStore/Types/Managed.swift @@ -6,44 +6,39 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation @propertyWrapper @dynamicMemberLookup -struct Managed -{ +struct Managed { var wrappedValue: ManagedObject { didSet { self.managedObjectContext = self.wrappedValue.managedObjectContext } } + private var managedObjectContext: NSManagedObjectContext? - + var projectedValue: Managed { - return self + self } - - init(wrappedValue: ManagedObject) - { + + init(wrappedValue: ManagedObject) { self.wrappedValue = wrappedValue self.managedObjectContext = wrappedValue.managedObjectContext } - - subscript(dynamicMember keyPath: KeyPath) -> T - { + + subscript(dynamicMember keyPath: KeyPath) -> T { var result: T! - - if let context = self.managedObjectContext - { + + if let context = managedObjectContext { context.performAndWait { result = self.wrappedValue[keyPath: keyPath] } - } - else - { + } else { result = self.wrappedValue[keyPath: keyPath] } - + return result } } diff --git a/AltStore/Types/ScreenshotProcessor.swift b/Sources/SideStore/Types/ScreenshotProcessor.swift similarity index 69% rename from AltStore/Types/ScreenshotProcessor.swift rename to Sources/SideStore/Types/ScreenshotProcessor.swift index ce1ad8b5..58b372d3 100644 --- a/AltStore/Types/ScreenshotProcessor.swift +++ b/Sources/SideStore/Types/ScreenshotProcessor.swift @@ -8,18 +8,15 @@ import Nuke -struct ScreenshotProcessor: ImageProcessing -{ - func process(image: Image, context: ImageProcessingContext) -> Image? - { +struct ScreenshotProcessor: ImageProcessing { + func process(image: Image, context _: ImageProcessingContext) -> Image? { guard let cgImage = image.cgImage, image.size.width > image.size.height else { return image } - + let rotatedImage = UIImage(cgImage: cgImage, scale: image.scale, orientation: .right) return rotatedImage } } -extension ImageProcessing where Self == ScreenshotProcessor -{ +extension ImageProcessing where Self == ScreenshotProcessor { static var screenshot: Self { Self() } } diff --git a/AltStoreCore/Components/Keychain.swift b/Sources/SideStoreCore/Components/Keychain.swift similarity index 69% rename from AltStoreCore/Components/Keychain.swift rename to Sources/SideStoreCore/Components/Keychain.swift index bb21f913..d91fc06b 100644 --- a/AltStoreCore/Components/Keychain.swift +++ b/Sources/SideStoreCore/Components/Keychain.swift @@ -12,80 +12,72 @@ import KeychainAccess import AltSign @propertyWrapper -public struct KeychainItem -{ +public struct KeychainItem { public let key: String - + public var wrappedValue: Value? { get { - switch Value.self - { - case is Data.Type: return try? Keychain.shared.keychain.getData(self.key) as? Value - case is String.Type: return try? Keychain.shared.keychain.getString(self.key) as? Value + switch Value.self { + case is Data.Type: return try? Keychain.shared.keychain.getData(key) as? Value + case is String.Type: return try? Keychain.shared.keychain.getString(key) as? Value default: return nil } } set { - switch Value.self - { - case is Data.Type: Keychain.shared.keychain[data: self.key] = newValue as? Data - case is String.Type: Keychain.shared.keychain[self.key] = newValue as? String + switch Value.self { + case is Data.Type: Keychain.shared.keychain[data: key] = newValue as? Data + case is String.Type: Keychain.shared.keychain[key] = newValue as? String default: break } } } - - public init(key: String) - { + + public init(key: String) { self.key = key } } -public class Keychain -{ +public class Keychain { public static let shared = Keychain() - + fileprivate let keychain = KeychainAccess.Keychain(service: Bundle.Info.appbundleIdentifier).accessibility(.afterFirstUnlock).synchronizable(true) - + @KeychainItem(key: "appleIDEmailAddress") public var appleIDEmailAddress: String? - + @KeychainItem(key: "appleIDPassword") public var appleIDPassword: String? - + @KeychainItem(key: "signingCertificatePrivateKey") public var signingCertificatePrivateKey: Data? - + @KeychainItem(key: "signingCertificateSerialNumber") public var signingCertificateSerialNumber: String? - + @KeychainItem(key: "signingCertificate") public var signingCertificate: Data? - + @KeychainItem(key: "signingCertificatePassword") public var signingCertificatePassword: String? - + @KeychainItem(key: "patreonAccessToken") public var patreonAccessToken: String? - + @KeychainItem(key: "patreonRefreshToken") public var patreonRefreshToken: String? - + @KeychainItem(key: "patreonCreatorAccessToken") public var patreonCreatorAccessToken: String? - + @KeychainItem(key: "patreonAccountID") public var patreonAccountID: String? - - private init() - { - } - - public func reset() - { - self.appleIDEmailAddress = nil - self.appleIDPassword = nil - self.signingCertificatePrivateKey = nil - self.signingCertificateSerialNumber = nil + + private init() {} + + public func reset() { + appleIDEmailAddress = nil + appleIDPassword = nil + signingCertificatePrivateKey = nil + signingCertificateSerialNumber = nil } } diff --git a/AltStoreCore/Extensions/Date+RelativeDate.swift b/Sources/SideStoreCore/Extensions/Date+RelativeDate.swift similarity index 65% rename from AltStoreCore/Extensions/Date+RelativeDate.swift rename to Sources/SideStoreCore/Extensions/Date+RelativeDate.swift index 62b7251b..a251681c 100644 --- a/AltStoreCore/Extensions/Date+RelativeDate.swift +++ b/Sources/SideStoreCore/Extensions/Date+RelativeDate.swift @@ -8,26 +8,22 @@ import Foundation -public extension Date -{ - func numberOfCalendarDays(since date: Date) -> Int - { +public extension Date { + func numberOfCalendarDays(since date: Date) -> Int { let today = Calendar.current.startOfDay(for: self) let previousDay = Calendar.current.startOfDay(for: date) - + let components = Calendar.current.dateComponents([.day], from: previousDay, to: today) return components.day! } - - func relativeDateString(since date: Date, dateFormatter: DateFormatter) -> String - { - let numberOfDays = self.numberOfCalendarDays(since: date) - - switch numberOfDays - { + + func relativeDateString(since date: Date, dateFormatter: DateFormatter) -> String { + let numberOfDays = numberOfCalendarDays(since: date) + + switch numberOfDays { case 0: return NSLocalizedString("Today", comment: "") case 1: return NSLocalizedString("Yesterday", comment: "") - case 2...7: return String(format: NSLocalizedString("%@ days ago", comment: ""), NSNumber(value: numberOfDays)) + case 2 ... 7: return String(format: NSLocalizedString("%@ days ago", comment: ""), NSNumber(value: numberOfDays)) default: return dateFormatter.string(from: date) } } diff --git a/AltStoreCore/Extensions/FileManager+SharedDirectories.swift b/Sources/SideStoreCore/Extensions/FileManager+SharedDirectories.swift similarity index 50% rename from AltStoreCore/Extensions/FileManager+SharedDirectories.swift rename to Sources/SideStoreCore/Extensions/FileManager+SharedDirectories.swift index d2187981..563586dc 100644 --- a/AltStoreCore/Extensions/FileManager+SharedDirectories.swift +++ b/Sources/SideStoreCore/Extensions/FileManager+SharedDirectories.swift @@ -8,23 +8,21 @@ import Foundation -public extension FileManager -{ +public extension FileManager { var altstoreSharedDirectory: URL? { guard let appGroup = Bundle.main.appGroups.first else { return nil } - - let sharedDirectoryURL = self.containerURL(forSecurityApplicationGroupIdentifier: appGroup) + + let sharedDirectoryURL = containerURL(forSecurityApplicationGroupIdentifier: appGroup) return sharedDirectoryURL } - + var appBackupsDirectory: URL? { - let appBackupsDirectory = self.altstoreSharedDirectory?.appendingPathComponent("Backups", isDirectory: true) + let appBackupsDirectory = altstoreSharedDirectory?.appendingPathComponent("Backups", isDirectory: true) return appBackupsDirectory } - - func backupDirectoryURL(for app: InstalledApp) -> URL? - { - let backupDirectoryURL = self.appBackupsDirectory?.appendingPathComponent(app.bundleIdentifier, isDirectory: true) + + func backupDirectoryURL(for app: InstalledApp) -> URL? { + let backupDirectoryURL = appBackupsDirectory?.appendingPathComponent(app.bundleIdentifier, isDirectory: true) return backupDirectoryURL } } diff --git a/AltStoreCore/Extensions/JSONDecoder+Properties.swift b/Sources/SideStoreCore/Extensions/JSONDecoder+Properties.swift similarity index 73% rename from AltStoreCore/Extensions/JSONDecoder+Properties.swift rename to Sources/SideStoreCore/Extensions/JSONDecoder+Properties.swift index caa3182c..d91e4321 100644 --- a/AltStoreCore/Extensions/JSONDecoder+Properties.swift +++ b/Sources/SideStoreCore/Extensions/JSONDecoder+Properties.swift @@ -6,48 +6,43 @@ // Copyright © 2018 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -public extension CodingUserInfoKey -{ +public extension CodingUserInfoKey { static let managedObjectContext = CodingUserInfoKey(rawValue: "managedObjectContext")! static let sourceURL = CodingUserInfoKey(rawValue: "sourceURL")! } -public final class JSONDecoder: Foundation.JSONDecoder -{ +public final class JSONDecoder: Foundation.JSONDecoder { @DecoderItem(key: .managedObjectContext) public var managedObjectContext: NSManagedObjectContext? - + @DecoderItem(key: .sourceURL) public var sourceURL: URL? } -public extension Decoder -{ - var managedObjectContext: NSManagedObjectContext? { self.userInfo[.managedObjectContext] as? NSManagedObjectContext } - var sourceURL: URL? { self.userInfo[.sourceURL] as? URL } +public extension Decoder { + var managedObjectContext: NSManagedObjectContext? { userInfo[.managedObjectContext] as? NSManagedObjectContext } + var sourceURL: URL? { userInfo[.sourceURL] as? URL } } @propertyWrapper -public struct DecoderItem -{ +public struct DecoderItem { public let key: CodingUserInfoKey - + public var wrappedValue: Value? { get { fatalError("only works on instance properties of classes") } set { fatalError("only works on instance properties of classes") } } - - public init(key: CodingUserInfoKey) - { + + public init(key: CodingUserInfoKey) { self.key = key } - + public static subscript( _enclosingInstance decoder: OuterSelf, - wrapped wrappedKeyPath: ReferenceWritableKeyPath, + wrapped _: ReferenceWritableKeyPath, storage storageKeyPath: ReferenceWritableKeyPath ) -> Value? { get { diff --git a/AltStoreCore/Extensions/UIApplication+AppExtension.swift b/Sources/SideStoreCore/Extensions/UIApplication+AppExtension.swift similarity index 74% rename from AltStoreCore/Extensions/UIApplication+AppExtension.swift rename to Sources/SideStoreCore/Extensions/UIApplication+AppExtension.swift index 7ecebfe5..67205248 100644 --- a/AltStoreCore/Extensions/UIApplication+AppExtension.swift +++ b/Sources/SideStoreCore/Extensions/UIApplication+AppExtension.swift @@ -8,10 +8,9 @@ import UIKit -public extension UIApplication -{ +public extension UIApplication { // Cannot normally use UIApplication.shared from extensions, so we get around this by calling value(forKey:). class var alt_shared: UIApplication? { - return UIApplication.value(forKey: "sharedApplication") as? UIApplication + UIApplication.value(forKey: "sharedApplication") as? UIApplication } } diff --git a/AltStoreCore/Extensions/UIColor+AltStore.swift b/Sources/SideStoreCore/Extensions/UIColor+AltStore.swift similarity index 95% rename from AltStoreCore/Extensions/UIColor+AltStore.swift rename to Sources/SideStoreCore/Extensions/UIColor+AltStore.swift index 74af4c5d..b87d507d 100644 --- a/AltStoreCore/Extensions/UIColor+AltStore.swift +++ b/Sources/SideStoreCore/Extensions/UIColor+AltStore.swift @@ -8,15 +8,14 @@ import UIKit -public extension UIColor -{ +public extension UIColor { private static let colorBundle = Bundle(for: DatabaseManager.self) - + static let altPrimary = UIColor(named: "Primary", in: colorBundle, compatibleWith: nil)! static let deltaPrimary = UIColor(named: "DeltaPrimary", in: colorBundle, compatibleWith: nil) - + static let altPink = UIColor(named: "Pink", in: colorBundle, compatibleWith: nil)! - + static let refreshRed = UIColor(named: "RefreshRed", in: colorBundle, compatibleWith: nil)! static let refreshOrange = UIColor(named: "RefreshOrange", in: colorBundle, compatibleWith: nil)! static let refreshYellow = UIColor(named: "RefreshYellow", in: colorBundle, compatibleWith: nil)! diff --git a/AltStoreCore/Extensions/UIColor+Hex.swift b/Sources/SideStoreCore/Extensions/UIColor+Hex.swift similarity index 81% rename from AltStoreCore/Extensions/UIColor+Hex.swift rename to Sources/SideStoreCore/Extensions/UIColor+Hex.swift index bb6e318e..411661ba 100644 --- a/AltStoreCore/Extensions/UIColor+Hex.swift +++ b/Sources/SideStoreCore/Extensions/UIColor+Hex.swift @@ -8,16 +8,15 @@ import UIKit -public extension UIColor -{ +public extension UIColor { // Borrowed from https://stackoverflow.com/a/26341062 var hexString: String { - let components = self.cgColor.components + let components = cgColor.components let r: CGFloat = components?[0] ?? 0.0 let g: CGFloat = components?[1] ?? 0.0 let b: CGFloat = components?[2] ?? 0.0 - let hexString = String.init(format: "%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255))) + let hexString = String(format: "%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255))) return hexString } } @@ -54,10 +53,10 @@ public extension UIColor { green = (hexNumber & 0x00FF00) >> 8 blue = hexNumber & 0x0000FF case 8: // ARGB (32-bit) - alpha = (hexNumber & 0xFF000000) >> 24 - red = (hexNumber & 0x00FF0000) >> 16 - green = (hexNumber & 0x0000FF00) >> 8 - blue = hexNumber & 0x000000FF + alpha = (hexNumber & 0xFF00_0000) >> 24 + red = (hexNumber & 0x00FF_0000) >> 16 + green = (hexNumber & 0x0000_FF00) >> 8 + blue = hexNumber & 0x0000_00FF default: return nil } @@ -70,4 +69,3 @@ public extension UIColor { ) } } - diff --git a/AltStoreCore/Extensions/UserDefaults+AltStore.swift b/Sources/SideStoreCore/Extensions/UserDefaults+AltStore.swift similarity index 85% rename from AltStoreCore/Extensions/UserDefaults+AltStore.swift rename to Sources/SideStoreCore/Extensions/UserDefaults+AltStore.swift index d780073f..94d17b8d 100644 --- a/AltStoreCore/Extensions/UserDefaults+AltStore.swift +++ b/Sources/SideStoreCore/Extensions/UserDefaults+AltStore.swift @@ -10,65 +10,61 @@ import Foundation import Roxas -public extension UserDefaults -{ +public extension UserDefaults { static let shared: UserDefaults = { guard let appGroup = Bundle.main.appGroups.first else { return .standard } - + let sharedUserDefaults = UserDefaults(suiteName: appGroup)! return sharedUserDefaults }() - + @NSManaged var firstLaunch: Date? @NSManaged var requiresAppGroupMigration: Bool @NSManaged var textServer: Bool @NSManaged var textInputAnisetteURL: String? @NSManaged var customAnisetteURL: String? @NSManaged var preferredServerID: String? - + @NSManaged var isBackgroundRefreshEnabled: Bool @NSManaged var isDebugModeEnabled: Bool @NSManaged var presentedLaunchReminderNotification: Bool - + @NSManaged var legacySideloadedApps: [String]? - + @NSManaged var isLegacyDeactivationSupported: Bool @NSManaged var activeAppLimitIncludesExtensions: Bool - + @NSManaged var localServerSupportsRefreshing: Bool - + @NSManaged var patchedApps: [String]? - + @NSManaged var patronsRefreshID: String? - + @NSManaged var trustedSourceIDs: [String]? - + var activeAppsLimit: Int? { get { - return self._activeAppsLimit?.intValue + _activeAppsLimit?.intValue } set { - if let value = newValue - { - self._activeAppsLimit = NSNumber(value: value) - } - else - { - self._activeAppsLimit = nil + if let value = newValue { + _activeAppsLimit = NSNumber(value: value) + } else { + _activeAppsLimit = nil } } } + @NSManaged @objc(activeAppsLimit) private var _activeAppsLimit: NSNumber? - - class func registerDefaults() - { + + class func registerDefaults() { let ios13_5 = OperatingSystemVersion(majorVersion: 13, minorVersion: 5, patchVersion: 0) let isLegacyDeactivationSupported = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5) let activeAppLimitIncludesExtensions = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5) - + let ios14 = OperatingSystemVersion(majorVersion: 14, minorVersion: 0, patchVersion: 0) let localServerSupportsRefreshing = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14) - + let defaults = [ #keyPath(UserDefaults.isBackgroundRefreshEnabled): true, #keyPath(UserDefaults.isLegacyDeactivationSupported): isLegacyDeactivationSupported, @@ -76,7 +72,7 @@ public extension UserDefaults #keyPath(UserDefaults.localServerSupportsRefreshing): localServerSupportsRefreshing, #keyPath(UserDefaults.requiresAppGroupMigration): true ] - + UserDefaults.standard.register(defaults: defaults) UserDefaults.shared.register(defaults: defaults) } diff --git a/AltStoreCore/Intents/ViewAppIntentHandler.swift b/Sources/SideStoreCore/Intents/ViewAppIntentHandler.swift similarity index 51% rename from AltStoreCore/Intents/ViewAppIntentHandler.swift rename to Sources/SideStoreCore/Intents/ViewAppIntentHandler.swift index 798f2a64..e8b2eb95 100644 --- a/AltStoreCore/Intents/ViewAppIntentHandler.swift +++ b/Sources/SideStoreCore/Intents/ViewAppIntentHandler.swift @@ -6,25 +6,22 @@ // Copyright © 2020 Riley Testut. All rights reserved. // +import SideStoreCore import Intents -import AltStoreCore @available(iOS 14, *) -public class ViewAppIntentHandler: NSObject, ViewAppIntentHandling -{ - public func provideAppOptionsCollection(for intent: ViewAppIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) - { - DatabaseManager.shared.start { (error) in - if let error = error - { +public class ViewAppIntentHandler: NSObject, ViewAppIntentHandling { + public func provideAppOptionsCollection(for _: ViewAppIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + DatabaseManager.shared.start { error in + if let error = error { print("Error starting extension:", error) } - - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in - let apps = InstalledApp.all(in: context).map { (installedApp) in - return App(identifier: installedApp.bundleIdentifier, display: installedApp.name) + + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + let apps = InstalledApp.all(in: context).map { installedApp in + App(identifier: installedApp.bundleIdentifier, display: installedApp.name) } - + let collection = INObjectCollection(items: apps) completion(collection, nil) } diff --git a/AltStoreCore/Model/Account.swift b/Sources/SideStoreCore/Model/Account.swift similarity index 59% rename from AltStoreCore/Model/Account.swift rename to Sources/SideStoreCore/Model/Account.swift index bac611fb..9ea98636 100644 --- a/AltStoreCore/Model/Account.swift +++ b/Sources/SideStoreCore/Model/Account.swift @@ -6,61 +6,55 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation import AltSign @objc(Account) -public class Account: NSManagedObject, Fetchable -{ +public class Account: NSManagedObject, Fetchable { public var localizedName: String { var components = PersonNameComponents() - components.givenName = self.firstName - components.familyName = self.lastName - + components.givenName = firstName + components.familyName = lastName + let name = PersonNameComponentsFormatter.localizedString(from: components, style: .default) return name } - + /* Properties */ @NSManaged public var appleID: String @NSManaged public var identifier: String - + @NSManaged public var firstName: String @NSManaged public var lastName: String - + @NSManaged public var isActiveAccount: Bool - + /* Relationships */ @NSManaged public var teams: Set - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(_ account: ALTAccount, context: NSManagedObjectContext) - { + + public init(_ account: ALTAccount, context: NSManagedObjectContext) { super.init(entity: Account.entity(), insertInto: context) - - self.update(account: account) + + update(account: account) } - - public func update(account: ALTAccount) - { - self.appleID = account.appleID - self.identifier = account.identifier - - self.firstName = account.firstName - self.lastName = account.lastName + + public func update(account: ALTAccount) { + appleID = account.appleID + identifier = account.identifier + + firstName = account.firstName + lastName = account.lastName } } -public extension Account -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "Account") +public extension Account { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "Account") } } diff --git a/AltStoreCore/Model/AppID.swift b/Sources/SideStoreCore/Model/AppID.swift similarity index 56% rename from AltStoreCore/Model/AppID.swift rename to Sources/SideStoreCore/Model/AppID.swift index 1d8607c0..917bc105 100644 --- a/AltStoreCore/Model/AppID.swift +++ b/Sources/SideStoreCore/Model/AppID.swift @@ -6,47 +6,42 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation import AltSign @objc(AppID) -public class AppID: NSManagedObject, Fetchable -{ +public class AppID: NSManagedObject, Fetchable { /* Properties */ @NSManaged public var name: String @NSManaged public var identifier: String @NSManaged public var bundleIdentifier: String @NSManaged public var features: [ALTFeature: Any] @NSManaged public var expirationDate: Date? - + /* Relationships */ @NSManaged public private(set) var team: Team? - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(_ appID: ALTAppID, team: Team, context: NSManagedObjectContext) - { + + public init(_ appID: ALTAppID, team: Team, context: NSManagedObjectContext) { super.init(entity: AppID.entity(), insertInto: context) - - self.name = appID.name - self.identifier = appID.identifier - self.bundleIdentifier = appID.bundleIdentifier - self.features = appID.features - self.expirationDate = appID.expirationDate - + + name = appID.name + identifier = appID.identifier + bundleIdentifier = appID.bundleIdentifier + features = appID.features + expirationDate = appID.expirationDate + self.team = team } } -public extension AppID -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "AppID") +public extension AppID { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "AppID") } } diff --git a/AltStoreCore/Model/AppPermission.swift b/Sources/SideStoreCore/Model/AppPermission.swift similarity index 82% rename from AltStoreCore/Model/AppPermission.swift rename to Sources/SideStoreCore/Model/AppPermission.swift index 2763f95c..b1843de2 100644 --- a/AltStoreCore/Model/AppPermission.swift +++ b/Sources/SideStoreCore/Model/AppPermission.swift @@ -9,21 +9,18 @@ import CoreData import UIKit -public extension ALTAppPermissionType -{ +public extension ALTAppPermissionType { var localizedShortName: String? { - switch self - { + switch self { case .photos: return NSLocalizedString("Photos", comment: "") case .backgroundAudio: return NSLocalizedString("Audio (BG)", comment: "") case .backgroundFetch: return NSLocalizedString("Fetch (BG)", comment: "") default: return nil } } - + var localizedName: String? { - switch self - { + switch self { case .photos: return NSLocalizedString("Photos", comment: "") case .camera: return NSLocalizedString("Camera", comment: "") case .location: return NSLocalizedString("Location", comment: "") @@ -44,10 +41,9 @@ public extension ALTAppPermissionType default: return nil } } - + var icon: UIImage? { - switch self - { + switch self { case .photos: return UIImage(systemName: "photo.on.rectangle.angled") case .camera: return UIImage(systemName: "camera.fill") case .location: return UIImage(systemName: "location.fill") @@ -72,56 +68,46 @@ public extension ALTAppPermissionType } @objc(AppPermission) -public class AppPermission: NSManagedObject, Decodable, Fetchable -{ +public class AppPermission: NSManagedObject, Decodable, Fetchable { /* Properties */ @NSManaged public var type: ALTAppPermissionType @NSManaged public var usageDescription: String - + /* Relationships */ @NSManaged public private(set) var app: StoreApp! - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case type case usageDescription } - - public required init(from decoder: Decoder) throws - { + + public required init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } - + super.init(entity: AppPermission.entity(), insertInto: context) - - do - { + + do { let container = try decoder.container(keyedBy: CodingKeys.self) - self.usageDescription = try container.decode(String.self, forKey: .usageDescription) - + usageDescription = try container.decode(String.self, forKey: .usageDescription) + let rawType = try container.decode(String.self, forKey: .type) - self.type = ALTAppPermissionType(rawValue: rawType) - } - catch - { - if let context = self.managedObjectContext - { + type = ALTAppPermissionType(rawValue: rawType) + } catch { + if let context = managedObjectContext { context.delete(self) } - + throw error } } } -public extension AppPermission -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "AppPermission") +public extension AppPermission { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "AppPermission") } } diff --git a/AltStoreCore/Model/AppVersion.swift b/Sources/SideStoreCore/Model/AppVersion.swift similarity index 65% rename from AltStoreCore/Model/AppVersion.swift rename to Sources/SideStoreCore/Model/AppVersion.swift index 2bbde4a6..980baff8 100644 --- a/AltStoreCore/Model/AppVersion.swift +++ b/Sources/SideStoreCore/Model/AppVersion.swift @@ -9,89 +9,81 @@ import CoreData @objc(AppVersion) -public class AppVersion: NSManagedObject, Decodable, Fetchable -{ +public class AppVersion: NSManagedObject, Decodable, Fetchable { /* Properties */ @NSManaged public var version: String @NSManaged public var date: Date @NSManaged public var localizedDescription: String? - + @NSManaged public var downloadURL: URL @NSManaged public var size: Int64 - + @nonobjc public var minOSVersion: OperatingSystemVersion? { - guard let osVersionString = self._minOSVersion else { return nil } - + guard let osVersionString = _minOSVersion else { return nil } + let osVersion = OperatingSystemVersion(string: osVersionString) return osVersion } + @NSManaged @objc(minOSVersion) private var _minOSVersion: String? - + @nonobjc public var maxOSVersion: OperatingSystemVersion? { - guard let osVersionString = self._maxOSVersion else { return nil } - + guard let osVersionString = _maxOSVersion else { return nil } + let osVersion = OperatingSystemVersion(string: osVersionString) return osVersion } + @NSManaged @objc(maxOSVersion) private var _maxOSVersion: String? - + @NSManaged public var appBundleID: String @NSManaged public var sourceID: String? - + /* Relationships */ @NSManaged public private(set) var app: StoreApp? @NSManaged public private(set) var latestVersionApp: StoreApp? - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case version case date case localizedDescription case downloadURL case size } - - public required init(from decoder: Decoder) throws - { + + public required init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } - + super.init(entity: AppVersion.entity(), insertInto: context) - - do - { + + do { let container = try decoder.container(keyedBy: CodingKeys.self) - - self.version = try container.decode(String.self, forKey: .version) - self.date = try container.decode(Date.self, forKey: .date) - self.localizedDescription = try container.decodeIfPresent(String.self, forKey: .localizedDescription) - - self.downloadURL = try container.decode(URL.self, forKey: .downloadURL) - self.size = try container.decode(Int64.self, forKey: .size) - } - catch - { - if let context = self.managedObjectContext - { + + version = try container.decode(String.self, forKey: .version) + date = try container.decode(Date.self, forKey: .date) + localizedDescription = try container.decodeIfPresent(String.self, forKey: .localizedDescription) + + downloadURL = try container.decode(URL.self, forKey: .downloadURL) + size = try container.decode(Int64.self, forKey: .size) + } catch { + if let context = managedObjectContext { context.delete(self) } - + throw error } } } -public extension AppVersion -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "AppVersion") +public extension AppVersion { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "AppVersion") } - + class func makeAppVersion( version: String, date: Date, @@ -100,8 +92,8 @@ public extension AppVersion size: Int64, appBundleID: String, sourceID: String? = nil, - in context: NSManagedObjectContext) -> AppVersion - { + in context: NSManagedObjectContext + ) -> AppVersion { let appVersion = AppVersion(context: context) appVersion.version = version appVersion.date = date diff --git a/AltStoreCore/Model/DatabaseManager.swift b/Sources/SideStoreCore/Model/DatabaseManager.swift similarity index 69% rename from AltStoreCore/Model/DatabaseManager.swift rename to Sources/SideStoreCore/Model/DatabaseManager.swift index b91a7e8e..595188de 100644 --- a/AltStoreCore/Model/DatabaseManager.swift +++ b/Sources/SideStoreCore/Model/DatabaseManager.swift @@ -11,98 +11,86 @@ import CoreData import AltSign import Roxas -extension CFNotificationName -{ - fileprivate static let willAccessDatabase = CFNotificationName("com.rileytestut.AltStore.WillAccessDatabase" as CFString) +private extension CFNotificationName { + static let willAccessDatabase = CFNotificationName("com.rileytestut.AltStore.WillAccessDatabase" as CFString) } -private let ReceivedWillAccessDatabaseNotification: @convention(c) (CFNotificationCenter?, UnsafeMutableRawPointer?, CFNotificationName?, UnsafeRawPointer?, CFDictionary?) -> Void = { (center, observer, name, object, userInfo) in +private let ReceivedWillAccessDatabaseNotification: @convention(c) (CFNotificationCenter?, UnsafeMutableRawPointer?, CFNotificationName?, UnsafeRawPointer?, CFDictionary?) -> Void = { _, _, _, _, _ in DatabaseManager.shared.receivedWillAccessDatabaseNotification() } -fileprivate class PersistentContainer: RSTPersistentContainer -{ - override class func defaultDirectoryURL() -> URL - { +private class PersistentContainer: RSTPersistentContainer { + override class func defaultDirectoryURL() -> URL { guard let sharedDirectoryURL = FileManager.default.altstoreSharedDirectory else { return super.defaultDirectoryURL() } - + let databaseDirectoryURL = sharedDirectoryURL.appendingPathComponent("Database") try? FileManager.default.createDirectory(at: databaseDirectoryURL, withIntermediateDirectories: true, attributes: nil) return databaseDirectoryURL } - - class func legacyDirectoryURL() -> URL - { - return super.defaultDirectoryURL() + + class func legacyDirectoryURL() -> URL { + super.defaultDirectoryURL() } } -public class DatabaseManager -{ +public class DatabaseManager { public static let shared = DatabaseManager() - + public let persistentContainer: RSTPersistentContainer - + public private(set) var isStarted = false - + private var startCompletionHandlers = [(Error?) -> Void]() private let dispatchQueue = DispatchQueue(label: "io.altstore.DatabaseManager") - + private let coordinator = NSFileCoordinator() private let coordinatorQueue = OperationQueue() - + private var ignoreWillAccessDatabaseNotification = false - - private init() - { - self.persistentContainer = PersistentContainer(name: "AltStore", bundle: Bundle(for: DatabaseManager.self)) - self.persistentContainer.preferredMergePolicy = MergePolicy() - + + private init() { + persistentContainer = PersistentContainer(name: "AltStore", bundle: Bundle(for: DatabaseManager.self)) + persistentContainer.preferredMergePolicy = MergePolicy() + let observer = Unmanaged.passUnretained(self).toOpaque() CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer, ReceivedWillAccessDatabaseNotification, CFNotificationName.willAccessDatabase.rawValue, nil, .deliverImmediately) } } -public extension DatabaseManager -{ - func start(completionHandler: @escaping (Error?) -> Void) - { - func finish(_ error: Error?) - { - self.dispatchQueue.async { - if error == nil - { +public extension DatabaseManager { + func start(completionHandler: @escaping (Error?) -> Void) { + func finish(_ error: Error?) { + dispatchQueue.async { + if error == nil { self.isStarted = true } - + self.startCompletionHandlers.forEach { $0(error) } self.startCompletionHandlers.removeAll() } } - - self.dispatchQueue.async { + + dispatchQueue.async { self.startCompletionHandlers.append(completionHandler) guard self.startCompletionHandlers.count == 1 else { return } - + guard !self.isStarted else { return finish(nil) } - + // Quit any other running AltStore processes to prevent concurrent database access during and after migration. self.ignoreWillAccessDatabaseNotification = true CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), .willAccessDatabase, nil, nil, true) - - self.migrateDatabaseToAppGroupIfNeeded { (result) in - switch result - { - case .failure(let error): finish(error) + + self.migrateDatabaseToAppGroupIfNeeded { result in + switch result { + case let .failure(error): finish(error) case .success: - self.persistentContainer.loadPersistentStores { (description, error) in + self.persistentContainer.loadPersistentStores { _, error in guard error == nil else { return finish(error!) } - - self.prepareDatabase() { (result) in - switch result - { - case .failure(let error): finish(error) + + self.prepareDatabase { result in + switch result { + case let .failure(error): finish(error) case .success: finish(nil) } } @@ -111,319 +99,268 @@ public extension DatabaseManager } } } - - func signOut(completionHandler: @escaping (Error?) -> Void) - { - self.persistentContainer.performBackgroundTask { (context) in - if let account = self.activeAccount(in: context) - { + + func signOut(completionHandler: @escaping (Error?) -> Void) { + persistentContainer.performBackgroundTask { context in + if let account = self.activeAccount(in: context) { account.isActiveAccount = false } - - if let team = self.activeTeam(in: context) - { + + if let team = self.activeTeam(in: context) { team.isActiveTeam = false } - - do - { + + do { try context.save() - + Keychain.shared.reset() - + completionHandler(nil) - } - catch - { + } catch { print("Failed to save when signing out.", error) completionHandler(error) } } } - - func purgeLoggedErrors(before date: Date? = nil, completion: @escaping (Result) -> Void) - { - self.persistentContainer.performBackgroundTask { context in - do - { + + func purgeLoggedErrors(before date: Date? = nil, completion: @escaping (Result) -> Void) { + persistentContainer.performBackgroundTask { context in + do { let predicate = date.map { NSPredicate(format: "%K <= %@", #keyPath(LoggedError.date), $0 as NSDate) } - + let loggedErrors = LoggedError.all(satisfying: predicate, in: context, requestProperties: [\.returnsObjectsAsFaults: true]) loggedErrors.forEach { context.delete($0) } - + try context.save() - + completion(.success(())) - } - catch - { + } catch { completion(.failure(error)) } } } } -public extension DatabaseManager -{ +public extension DatabaseManager { var viewContext: NSManagedObjectContext { - return self.persistentContainer.viewContext + persistentContainer.viewContext } - - func activeAccount(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> Account? - { + + func activeAccount(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> Account? { let predicate = NSPredicate(format: "%K == YES", #keyPath(Account.isActiveAccount)) - + let activeAccount = Account.first(satisfying: predicate, in: context) return activeAccount } - - func activeTeam(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> Team? - { + + func activeTeam(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> Team? { let predicate = NSPredicate(format: "%K == YES", #keyPath(Team.isActiveTeam)) - + let activeTeam = Team.first(satisfying: predicate, in: context) return activeTeam } - - func patreonAccount(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> PatreonAccount? - { + + func patreonAccount(in context: NSManagedObjectContext = DatabaseManager.shared.viewContext) -> PatreonAccount? { guard let patreonAccountID = Keychain.shared.patreonAccountID else { return nil } - + let predicate = NSPredicate(format: "%K == %@", #keyPath(PatreonAccount.identifier), patreonAccountID) - + let patreonAccount = PatreonAccount.first(satisfying: predicate, in: context) return patreonAccount } } -private extension DatabaseManager -{ - func prepareDatabase(completionHandler: @escaping (Result) -> Void) - { - guard !Bundle.isAppExtension() else { return completionHandler(.success(())) } - - let context = self.persistentContainer.newBackgroundContext() +private extension DatabaseManager { + func prepareDatabase(completionHandler: @escaping (Result) -> Void) { + guard !Bundle.isAppExtension else { return completionHandler(.success(())) } + + let context = persistentContainer.newBackgroundContext() context.performAndWait { guard let localApp = ALTApplication(fileURL: Bundle.main.bundleURL) else { return } - + let altStoreSource: Source - - if let source = Source.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Source.identifier), Source.altStoreIdentifier), in: context) - { + + if let source = Source.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Source.identifier), Source.altStoreIdentifier), in: context) { altStoreSource = source - } - else - { + } else { altStoreSource = Source.makeAltStoreSource(in: context) } - + // Make sure to always update source URL to be current. altStoreSource.sourceURL = Source.altStoreSourceURL - + let storeApp: StoreApp - - if let app = StoreApp.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(StoreApp.bundleIdentifier), StoreApp.altstoreAppID), in: context) - { + + if let app = StoreApp.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(StoreApp.bundleIdentifier), StoreApp.altstoreAppID), in: context) { storeApp = app - } - else - { + } else { storeApp = StoreApp.makeAltStoreApp(in: context) storeApp.latestVersion?.version = localApp.version storeApp.source = altStoreSource } - + let serialNumber = Bundle.main.object(forInfoDictionaryKey: Bundle.Info.certificateID) as? String let installedApp: InstalledApp - - if let app = storeApp.installedApp - { + + if let app = storeApp.installedApp { installedApp = app - } - else - { + } else { installedApp = InstalledApp(resignedApp: localApp, originalBundleIdentifier: StoreApp.altstoreAppID, certificateSerialNumber: serialNumber, context: context) installedApp.storeApp = storeApp } - + /* App Extensions */ var installedExtensions = Set() - - for appExtension in localApp.appExtensions - { + + for appExtension in localApp.appExtensions { let resignedBundleID = appExtension.bundleIdentifier let originalBundleID = resignedBundleID.replacingOccurrences(of: localApp.bundleIdentifier, with: StoreApp.altstoreAppID) - + let installedExtension: InstalledExtension - - if let appExtension = installedApp.appExtensions.first(where: { $0.bundleIdentifier == originalBundleID }) - { + + if let appExtension = installedApp.appExtensions.first(where: { $0.bundleIdentifier == originalBundleID }) { installedExtension = appExtension - } - else - { + } else { installedExtension = InstalledExtension(resignedAppExtension: appExtension, originalBundleIdentifier: originalBundleID, context: context) } - + installedExtension.update(resignedAppExtension: appExtension) - + installedExtensions.insert(installedExtension) } - + installedApp.appExtensions = installedExtensions - + let fileURL = installedApp.fileURL - + #if DEBUG - let replaceCachedApp = true + let replaceCachedApp = true #else - let replaceCachedApp = !FileManager.default.fileExists(atPath: fileURL.path) || installedApp.version != localApp.version + let replaceCachedApp = !FileManager.default.fileExists(atPath: fileURL.path) || installedApp.version != localApp.version #endif - - if replaceCachedApp - { - func update(_ bundle: Bundle, bundleID: String) throws - { + + if replaceCachedApp { + func update(_ bundle: Bundle, bundleID: String) throws { let infoPlistURL = bundle.bundleURL.appendingPathComponent("Info.plist") - + guard var infoDictionary = bundle.completeInfoDictionary else { throw ALTError(.missingInfoPlist) } infoDictionary[kCFBundleIdentifierKey as String] = bundleID try (infoDictionary as NSDictionary).write(to: infoPlistURL) } - - FileManager.default.prepareTemporaryURL() { (temporaryFileURL) in - do - { + + FileManager.default.prepareTemporaryURL { temporaryFileURL in + do { try FileManager.default.copyItem(at: Bundle.main.bundleURL, to: temporaryFileURL) - + guard let appBundle = Bundle(url: temporaryFileURL) else { throw ALTError(.invalidApp) } try update(appBundle, bundleID: StoreApp.altstoreAppID) - - if let tempApp = ALTApplication(fileURL: temporaryFileURL) - { - for appExtension in tempApp.appExtensions - { + + if let tempApp = ALTApplication(fileURL: temporaryFileURL) { + for appExtension in tempApp.appExtensions { guard let extensionBundle = Bundle(url: appExtension.fileURL) else { throw ALTError(.invalidApp) } guard let installedExtension = installedExtensions.first(where: { $0.resignedBundleIdentifier == appExtension.bundleIdentifier }) else { throw ALTError(.invalidApp) } try update(extensionBundle, bundleID: installedExtension.bundleIdentifier) } } - + try FileManager.default.copyItem(at: temporaryFileURL, to: fileURL, shouldReplace: true) - } - catch - { + } catch { print("Failed to copy AltStore app bundle to its proper location.", error) } } } - + let cachedRefreshedDate = installedApp.refreshedDate let cachedExpirationDate = installedApp.expirationDate - + // Must go after comparing versions to see if we need to update our cached AltStore app bundle. installedApp.update(resignedApp: localApp, certificateSerialNumber: serialNumber) - - if installedApp.refreshedDate < cachedRefreshedDate - { + + if installedApp.refreshedDate < cachedRefreshedDate { // Embedded provisioning profile has a creation date older than our refreshed date. // This most likely means we've refreshed the app since then, and profile is now outdated, // so use cached dates instead (i.e. not the dates updated from provisioning profile). - + installedApp.refreshedDate = cachedRefreshedDate installedApp.expirationDate = cachedExpirationDate } - - do - { + + do { try context.save() completionHandler(.success(())) - } - catch - { + } catch { completionHandler(.failure(error)) } } } - - func migrateDatabaseToAppGroupIfNeeded(completion: @escaping (Result) -> Void) - { + + func migrateDatabaseToAppGroupIfNeeded(completion: @escaping (Result) -> Void) { guard UserDefaults.shared.requiresAppGroupMigration else { return completion(.success(())) } - func finish(_ result: Result) - { - switch result - { - case .failure(let error): completion(.failure(error)) + func finish(_ result: Result) { + switch result { + case let .failure(error): completion(.failure(error)) case .success: UserDefaults.shared.requiresAppGroupMigration = false completion(.success(())) } } - + let previousDatabaseURL = PersistentContainer.legacyDirectoryURL().appendingPathComponent("AltStore.sqlite") let databaseURL = PersistentContainer.defaultDirectoryURL().appendingPathComponent("AltStore.sqlite") - + let previousAppsDirectoryURL = InstalledApp.legacyAppsDirectoryURL let appsDirectoryURL = InstalledApp.appsDirectoryURL - + let databaseIntent = NSFileAccessIntent.writingIntent(with: databaseURL, options: [.forReplacing]) let appsIntent = NSFileAccessIntent.writingIntent(with: appsDirectoryURL, options: [.forReplacing]) - - self.coordinator.coordinate(with: [databaseIntent, appsIntent], queue: self.coordinatorQueue) { (error) in - do - { - if let error = error - { + + coordinator.coordinate(with: [databaseIntent, appsIntent], queue: coordinatorQueue) { error in + do { + if let error = error { throw error } - + let description = NSPersistentStoreDescription(url: previousDatabaseURL) - + // Disable WAL to remove extra files automatically during migration. description.setOption(["journal_mode": "DELETE"] as NSDictionary, forKey: NSSQLitePragmasOption) - + let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.persistentContainer.managedObjectModel) - + // Migrate database - if FileManager.default.fileExists(atPath: previousDatabaseURL.path) - { - if FileManager.default.fileExists(atPath: databaseURL.path, isDirectory: nil) - { + if FileManager.default.fileExists(atPath: previousDatabaseURL.path) { + if FileManager.default.fileExists(atPath: databaseURL.path, isDirectory: nil) { try FileManager.default.removeItem(at: databaseURL) } - + let previousDatabase = try persistentStoreCoordinator.addPersistentStore(ofType: description.type, configurationName: description.configuration, at: description.url, options: description.options) - + // Pass nil options to prevent later error due to self.persistentContainer using WAL. try persistentStoreCoordinator.migratePersistentStore(previousDatabase, to: databaseURL, options: nil, withType: NSSQLiteStoreType) - + try FileManager.default.removeItem(at: previousDatabaseURL) } - + // Migrate apps - if FileManager.default.fileExists(atPath: previousAppsDirectoryURL.path, isDirectory: nil) - { + if FileManager.default.fileExists(atPath: previousAppsDirectoryURL.path, isDirectory: nil) { _ = try FileManager.default.replaceItemAt(appsDirectoryURL, withItemAt: previousAppsDirectoryURL) } - + finish(.success(())) - } - catch - { + } catch { print("Failed to migrate database to app group:", error) finish(.failure(error)) } } } - - func receivedWillAccessDatabaseNotification() - { + + func receivedWillAccessDatabaseNotification() { defer { self.ignoreWillAccessDatabaseNotification = false } - + // Ignore notifications sent by the current process. - guard !self.ignoreWillAccessDatabaseNotification else { return } - + guard !ignoreWillAccessDatabaseNotification else { return } + exit(104) } } diff --git a/AltStoreCore/Model/InstalledApp.swift b/Sources/SideStoreCore/Model/InstalledApp.swift similarity index 72% rename from AltStoreCore/Model/InstalledApp.swift rename to Sources/SideStoreCore/Model/InstalledApp.swift index 77c49513..70e0191e 100644 --- a/AltStoreCore/Model/InstalledApp.swift +++ b/Sources/SideStoreCore/Model/InstalledApp.swift @@ -6,8 +6,8 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation import AltSign import SemanticVersion @@ -15,186 +15,167 @@ import SemanticVersion // Free developer accounts are limited to only 3 active sideloaded apps at a time as of iOS 13.3.1. public let ALTActiveAppsLimit = 3 -public protocol InstalledAppProtocol: Fetchable -{ +public protocol InstalledAppProtocol: Fetchable { var name: String { get } var bundleIdentifier: String { get } var resignedBundleIdentifier: String { get } var version: String { get } - + var refreshedDate: Date { get } var expirationDate: Date { get } var installedDate: Date { get } } @objc(InstalledApp) -public class InstalledApp: NSManagedObject, InstalledAppProtocol -{ +public class InstalledApp: NSManagedObject, InstalledAppProtocol { /* Properties */ @NSManaged public var name: String @NSManaged public var bundleIdentifier: String @NSManaged public var resignedBundleIdentifier: String @NSManaged public var version: String - + @NSManaged public var refreshedDate: Date @NSManaged public var expirationDate: Date @NSManaged public var installedDate: Date - + @NSManaged public var isActive: Bool @NSManaged public var needsResign: Bool @NSManaged public var hasAlternateIcon: Bool - + @NSManaged public var certificateSerialNumber: String? - + /* Transient */ @NSManaged public var isRefreshing: Bool - + /* Relationships */ @NSManaged public var storeApp: StoreApp? @NSManaged public var team: Team? @NSManaged public var appExtensions: Set - + @NSManaged public private(set) var loggedErrors: NSSet /* Set */ // Use NSSet to avoid eagerly fetching values. - + public var isSideloaded: Bool { - return self.storeApp == nil + storeApp == nil } - + @objc public var hasUpdate: Bool { - if self.storeApp == nil { return false } - if self.storeApp!.latestVersion == nil { return false } - - let currentVersion = SemanticVersion(self.version) - let latestVersion = SemanticVersion(self.storeApp!.latestVersion!.version) - + if storeApp == nil { return false } + if storeApp!.latestVersion == nil { return false } + + let currentVersion = SemanticVersion(version) + let latestVersion = SemanticVersion(storeApp!.latestVersion!.version) + if currentVersion == nil || latestVersion == nil { // One of the versions is not valid SemVer, fall back to comparing the version strings by character - return self.version < self.storeApp!.latestVersion!.version + return version < storeApp!.latestVersion!.version } - + return currentVersion! < latestVersion! } - + public var appIDCount: Int { - return 1 + self.appExtensions.count + 1 + appExtensions.count } - + public var requiredActiveSlots: Int { let requiredActiveSlots = UserDefaults.standard.activeAppLimitIncludesExtensions ? self.appIDCount : 1 return requiredActiveSlots } - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(resignedApp: ALTApplication, originalBundleIdentifier: String, certificateSerialNumber: String?, context: NSManagedObjectContext) - { + + public init(resignedApp: ALTApplication, originalBundleIdentifier: String, certificateSerialNumber: String?, context: NSManagedObjectContext) { super.init(entity: InstalledApp.entity(), insertInto: context) - - self.bundleIdentifier = originalBundleIdentifier - - print("InstalledApp `self.bundleIdentifier`: \(self.bundleIdentifier)") - - self.refreshedDate = Date() - self.installedDate = Date() - - self.expirationDate = self.refreshedDate.addingTimeInterval(60 * 60 * 24 * 7) // Rough estimate until we get real values from provisioning profile. - - self.update(resignedApp: resignedApp, certificateSerialNumber: certificateSerialNumber) + + bundleIdentifier = originalBundleIdentifier + + print("InstalledApp `self.bundleIdentifier`: \(bundleIdentifier)") + + refreshedDate = Date() + installedDate = Date() + + expirationDate = refreshedDate.addingTimeInterval(60 * 60 * 24 * 7) // Rough estimate until we get real values from provisioning profile. + + update(resignedApp: resignedApp, certificateSerialNumber: certificateSerialNumber) } - - public func update(resignedApp: ALTApplication, certificateSerialNumber: String?) - { - self.name = resignedApp.name - - self.resignedBundleIdentifier = resignedApp.bundleIdentifier - self.version = resignedApp.version - + + public func update(resignedApp: ALTApplication, certificateSerialNumber: String?) { + name = resignedApp.name + + resignedBundleIdentifier = resignedApp.bundleIdentifier + version = resignedApp.version + self.certificateSerialNumber = certificateSerialNumber - if let provisioningProfile = resignedApp.provisioningProfile - { - self.update(provisioningProfile: provisioningProfile) + if let provisioningProfile = resignedApp.provisioningProfile { + update(provisioningProfile: provisioningProfile) } } - - public func update(provisioningProfile: ALTProvisioningProfile) - { - self.refreshedDate = provisioningProfile.creationDate - self.expirationDate = provisioningProfile.expirationDate + + public func update(provisioningProfile: ALTProvisioningProfile) { + refreshedDate = provisioningProfile.creationDate + expirationDate = provisioningProfile.expirationDate } - - public func loadIcon(completion: @escaping (Result) -> Void) - { + + public func loadIcon(completion: @escaping (Result) -> Void) { let hasAlternateIcon = self.hasAlternateIcon let alternateIconURL = self.alternateIconURL let fileURL = self.fileURL - + DispatchQueue.global().async { - do - { + do { if hasAlternateIcon, case let data = try Data(contentsOf: alternateIconURL), - let icon = UIImage(data: data) - { + let icon = UIImage(data: data) { return completion(.success(icon)) } - + let application = ALTApplication(fileURL: fileURL) completion(.success(application?.icon)) - } - catch - { + } catch { completion(.failure(error)) } } } } -public extension InstalledApp -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "InstalledApp") +public extension InstalledApp { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "InstalledApp") } - - class func updatesFetchRequest() -> NSFetchRequest - { + + class func updatesFetchRequest() -> NSFetchRequest { let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest fetchRequest.predicate = NSPredicate(format: "%K == YES AND %K == YES", #keyPath(InstalledApp.isActive), #keyPath(InstalledApp.hasUpdate)) return fetchRequest } - - class func activeAppsFetchRequest() -> NSFetchRequest - { + + class func activeAppsFetchRequest() -> NSFetchRequest { let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest fetchRequest.predicate = NSPredicate(format: "%K == YES", #keyPath(InstalledApp.isActive)) print("Active Apps Fetch Request: \(String(describing: fetchRequest.predicate))") return fetchRequest } - - class func fetchAltStore(in context: NSManagedObjectContext) -> InstalledApp? - { + + class func fetchAltStore(in context: NSManagedObjectContext) -> InstalledApp? { let predicate = NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), StoreApp.altstoreAppID) print("Fetch 'AltStore' Predicate: \(String(describing: predicate))") let altStore = InstalledApp.first(satisfying: predicate, in: context) return altStore } - - class func fetchActiveApps(in context: NSManagedObjectContext) -> [InstalledApp] - { + + class func fetchActiveApps(in context: NSManagedObjectContext) -> [InstalledApp] { let activeApps = InstalledApp.fetch(InstalledApp.activeAppsFetchRequest(), in: context) return activeApps } - - class func fetchAppsForRefreshingAll(in context: NSManagedObjectContext) -> [InstalledApp] - { + + class func fetchAppsForRefreshingAll(in context: NSManagedObjectContext) -> [InstalledApp] { var predicate = NSPredicate(format: "%K == YES AND %K != %@", #keyPath(InstalledApp.isActive), #keyPath(InstalledApp.bundleIdentifier), StoreApp.altstoreAppID) print("Fetch Apps for Refreshing All 'AltStore' predicate: \(String(describing: predicate))") - + // if let patreonAccount = DatabaseManager.shared.patreonAccount(in: context), patreonAccount.isPatron, PatreonAPI.shared.isAuthenticated // { // // No additional predicate @@ -204,31 +185,29 @@ public extension InstalledApp // predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, // NSPredicate(format: "%K == nil OR %K == NO", #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.storeApp.isBeta))]) // } - + var installedApps = InstalledApp.all(satisfying: predicate, sortedBy: [NSSortDescriptor(keyPath: \InstalledApp.expirationDate, ascending: true)], in: context) - - if let altStoreApp = InstalledApp.fetchAltStore(in: context) - { + + if let altStoreApp = InstalledApp.fetchAltStore(in: context) { // Refresh AltStore last since it causes app to quit. installedApps.append(altStoreApp) } - + return installedApps } - - class func fetchAppsForBackgroundRefresh(in context: NSManagedObjectContext) -> [InstalledApp] - { + + class func fetchAppsForBackgroundRefresh(in context: NSManagedObjectContext) -> [InstalledApp] { // Date 6 hours before now. let date = Date().addingTimeInterval(-1 * 6 * 60 * 60) - + var predicate = NSPredicate(format: "(%K == YES) AND (%K < %@) AND (%K != %@)", #keyPath(InstalledApp.isActive), #keyPath(InstalledApp.refreshedDate), date as NSDate, #keyPath(InstalledApp.bundleIdentifier), StoreApp.altstoreAppID) print("Active Apps For Background Refresh 'AltStore' predicate: \(String(describing: predicate))") - + // if let patreonAccount = DatabaseManager.shared.patreonAccount(in: context), patreonAccount.isPatron, PatreonAPI.shared.isAuthenticated // { // // No additional predicate @@ -238,116 +217,104 @@ public extension InstalledApp // predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, // NSPredicate(format: "%K == nil OR %K == NO", #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.storeApp.isBeta))]) // } - + var installedApps = InstalledApp.all(satisfying: predicate, sortedBy: [NSSortDescriptor(keyPath: \InstalledApp.expirationDate, ascending: true)], in: context) - - if let altStoreApp = InstalledApp.fetchAltStore(in: context), altStoreApp.refreshedDate < date - { + + if let altStoreApp = InstalledApp.fetchAltStore(in: context), altStoreApp.refreshedDate < date { // Refresh AltStore last since it may cause app to quit. installedApps.append(altStoreApp) } - + return installedApps } } -public extension InstalledApp -{ +public extension InstalledApp { var openAppURL: URL { - let openAppURL = URL(string: "altstore-" + self.bundleIdentifier + "://")! + let openAppURL = URL(string: "altstore-" + bundleIdentifier + "://")! return openAppURL } - - class func openAppURL(for app: AppProtocol) -> URL - { + + class func openAppURL(for app: AppProtocol) -> URL { let openAppURL = URL(string: "altstore-" + app.bundleIdentifier + "://")! return openAppURL } } -public extension InstalledApp -{ +public extension InstalledApp { class var appsDirectoryURL: URL { let baseDirectory = FileManager.default.altstoreSharedDirectory ?? FileManager.default.applicationSupportDirectory let appsDirectoryURL = baseDirectory.appendingPathComponent("Apps") - - do { try FileManager.default.createDirectory(at: appsDirectoryURL, withIntermediateDirectories: true, attributes: nil) } - catch { print("Creating App Directory Error: \(error)") } + + do { try FileManager.default.createDirectory(at: appsDirectoryURL, withIntermediateDirectories: true, attributes: nil) } catch { print("Creating App Directory Error: \(error)") } print("`appsDirectoryURL` is set to: \(appsDirectoryURL.absoluteString)") return appsDirectoryURL } - + class var legacyAppsDirectoryURL: URL { let baseDirectory = FileManager.default.applicationSupportDirectory let appsDirectoryURL = baseDirectory.appendingPathComponent("Apps") print("legacy `appsDirectoryURL` is set to: \(appsDirectoryURL.absoluteString)") return appsDirectoryURL } - - class func fileURL(for app: AppProtocol) -> URL - { - let appURL = self.directoryURL(for: app).appendingPathComponent("App.app") + + class func fileURL(for app: AppProtocol) -> URL { + let appURL = directoryURL(for: app).appendingPathComponent("App.app") return appURL } - - class func refreshedIPAURL(for app: AppProtocol) -> URL - { - let ipaURL = self.directoryURL(for: app).appendingPathComponent("Refreshed.ipa") + + class func refreshedIPAURL(for app: AppProtocol) -> URL { + let ipaURL = directoryURL(for: app).appendingPathComponent("Refreshed.ipa") print("`ipaURL`: \(ipaURL.absoluteString)") return ipaURL } - - class func directoryURL(for app: AppProtocol) -> URL - { + + class func directoryURL(for app: AppProtocol) -> URL { let directoryURL = InstalledApp.appsDirectoryURL.appendingPathComponent(app.bundleIdentifier) - - do { try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) } - catch { print(error) } - + + do { try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) } catch { print(error) } + return directoryURL } - - class func installedAppUTI(forBundleIdentifier bundleIdentifier: String) -> String - { + + class func installedAppUTI(forBundleIdentifier bundleIdentifier: String) -> String { let installedAppUTI = "io.altstore.Installed." + bundleIdentifier return installedAppUTI } - - class func installedBackupAppUTI(forBundleIdentifier bundleIdentifier: String) -> String - { + + class func installedBackupAppUTI(forBundleIdentifier bundleIdentifier: String) -> String { let installedBackupAppUTI = InstalledApp.installedAppUTI(forBundleIdentifier: bundleIdentifier) + ".backup" return installedBackupAppUTI } - - class func alternateIconURL(for app: AppProtocol) -> URL - { - let installedBackupAppUTI = self.directoryURL(for: app).appendingPathComponent("AltIcon.png") + + class func alternateIconURL(for app: AppProtocol) -> URL { + let installedBackupAppUTI = directoryURL(for: app).appendingPathComponent("AltIcon.png") return installedBackupAppUTI } - + var directoryURL: URL { - return InstalledApp.directoryURL(for: self) + InstalledApp.directoryURL(for: self) } - + var fileURL: URL { - return InstalledApp.fileURL(for: self) + InstalledApp.fileURL(for: self) } - + var refreshedIPAURL: URL { - return InstalledApp.refreshedIPAURL(for: self) + InstalledApp.refreshedIPAURL(for: self) } - + var installedAppUTI: String { - return InstalledApp.installedAppUTI(forBundleIdentifier: self.resignedBundleIdentifier) + InstalledApp.installedAppUTI(forBundleIdentifier: resignedBundleIdentifier) } - + var installedBackupAppUTI: String { - return InstalledApp.installedBackupAppUTI(forBundleIdentifier: self.resignedBundleIdentifier) + InstalledApp.installedBackupAppUTI(forBundleIdentifier: resignedBundleIdentifier) } - + var alternateIconURL: URL { - return InstalledApp.alternateIconURL(for: self) + InstalledApp.alternateIconURL(for: self) } } diff --git a/Sources/SideStoreCore/Model/InstalledExtension.swift b/Sources/SideStoreCore/Model/InstalledExtension.swift new file mode 100644 index 00000000..f09c3b6b --- /dev/null +++ b/Sources/SideStoreCore/Model/InstalledExtension.swift @@ -0,0 +1,67 @@ +// +// InstalledExtension.swift +// AltStore +// +// Created by Riley Testut on 1/7/20. +// Copyright © 2020 Riley Testut. All rights reserved. +// + +import CoreData +import Foundation + +import AltSign + +@objc(InstalledExtension) +public class InstalledExtension: NSManagedObject, InstalledAppProtocol { + /* Properties */ + @NSManaged public var name: String + @NSManaged public var bundleIdentifier: String + @NSManaged public var resignedBundleIdentifier: String + @NSManaged public var version: String + + @NSManaged public var refreshedDate: Date + @NSManaged public var expirationDate: Date + @NSManaged public var installedDate: Date + + /* Relationships */ + @NSManaged public var parentApp: InstalledApp? + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { + super.init(entity: entity, insertInto: context) + } + + public init(resignedAppExtension: ALTApplication, originalBundleIdentifier: String, context: NSManagedObjectContext) { + super.init(entity: InstalledExtension.entity(), insertInto: context) + + bundleIdentifier = originalBundleIdentifier + + refreshedDate = Date() + installedDate = Date() + + expirationDate = refreshedDate.addingTimeInterval(60 * 60 * 24 * 7) // Rough estimate until we get real values from provisioning profile. + + update(resignedAppExtension: resignedAppExtension) + } + + public func update(resignedAppExtension: ALTApplication) { + name = resignedAppExtension.name + + resignedBundleIdentifier = resignedAppExtension.bundleIdentifier + version = resignedAppExtension.version + + if let provisioningProfile = resignedAppExtension.provisioningProfile { + update(provisioningProfile: provisioningProfile) + } + } + + public func update(provisioningProfile: ALTProvisioningProfile) { + refreshedDate = provisioningProfile.creationDate + expirationDate = provisioningProfile.expirationDate + } +} + +public extension InstalledExtension { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "InstalledExtension") + } +} diff --git a/AltStoreCore/Model/LoggedError.swift b/Sources/SideStoreCore/Model/LoggedError.swift similarity index 64% rename from AltStoreCore/Model/LoggedError.swift rename to Sources/SideStoreCore/Model/LoggedError.swift index 81835e51..9d4a3a83 100644 --- a/AltStoreCore/Model/LoggedError.swift +++ b/Sources/SideStoreCore/Model/LoggedError.swift @@ -8,10 +8,8 @@ import CoreData -extension LoggedError -{ - public enum Operation: String - { +public extension LoggedError { + enum Operation: String { case install case update case refresh @@ -23,59 +21,56 @@ extension LoggedError } @objc(LoggedError) -public class LoggedError: NSManagedObject, Fetchable -{ +public class LoggedError: NSManagedObject, Fetchable { /* Properties */ @NSManaged public private(set) var date: Date - + @nonobjc public var operation: Operation? { - guard let rawOperation = self._operation else { return nil } - + guard let rawOperation = _operation else { return nil } + let operation = Operation(rawValue: rawOperation) return operation } + @NSManaged @objc(operation) private var _operation: String? - + @NSManaged public private(set) var domain: String @NSManaged public private(set) var code: Int32 @NSManaged public private(set) var userInfo: [String: Any] - + @NSManaged public private(set) var appName: String @NSManaged public private(set) var appBundleID: String - + /* Relationships */ @NSManaged public private(set) var storeApp: StoreApp? @NSManaged public private(set) var installedApp: InstalledApp? - + private static let dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .long dateFormatter.timeStyle = .none return dateFormatter }() - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(error: Error, app: AppProtocol, date: Date = Date(), operation: Operation? = nil, context: NSManagedObjectContext) - { + + public init(error: Error, app: AppProtocol, date: Date = Date(), operation: Operation? = nil, context: NSManagedObjectContext) { super.init(entity: LoggedError.entity(), insertInto: context) - + self.date = date - self._operation = operation?.rawValue - + _operation = operation?.rawValue + let nsError = error as NSError - self.domain = nsError.domain - self.code = Int32(nsError.code) - self.userInfo = nsError.userInfo - - self.appName = app.name - self.appBundleID = app.bundleIdentifier - - switch app - { + domain = nsError.domain + code = Int32(nsError.code) + userInfo = nsError.userInfo + + appName = app.name + appBundleID = app.bundleIdentifier + + switch app { case let storeApp as StoreApp: self.storeApp = storeApp case let installedApp as InstalledApp: self.installedApp = installedApp default: break @@ -83,44 +78,40 @@ public class LoggedError: NSManagedObject, Fetchable } } -public extension LoggedError -{ +public extension LoggedError { var app: AppProtocol { // `as AppProtocol` needed to fix "cannot convert AnyApp to StoreApp" compiler error with Xcode 14. - let app = self.installedApp ?? self.storeApp ?? AnyApp(name: self.appName, bundleIdentifier: self.appBundleID, url: nil) as AppProtocol + let app = installedApp ?? storeApp ?? AnyApp(name: appName, bundleIdentifier: appBundleID, url: nil) as AppProtocol return app } - + var error: Error { - let nsError = NSError(domain: self.domain, code: Int(self.code), userInfo: self.userInfo) + let nsError = NSError(domain: domain, code: Int(code), userInfo: userInfo) return nsError } - + @objc var localizedDateString: String { - let localizedDateString = LoggedError.dateFormatter.string(from: self.date) + let localizedDateString = LoggedError.dateFormatter.string(from: date) return localizedDateString } - + var localizedFailure: String? { - guard let operation = self.operation else { return nil } - switch operation - { - case .install: return String(format: NSLocalizedString("Install %@ Failed", comment: ""), self.appName) - case .update: return String(format: NSLocalizedString("Update %@ Failed", comment: ""), self.appName) - case .refresh: return String(format: NSLocalizedString("Refresh %@ Failed", comment: ""), self.appName) - case .activate: return String(format: NSLocalizedString("Activate %@ Failed", comment: ""), self.appName) - case .deactivate: return String(format: NSLocalizedString("Deactivate %@ Failed", comment: ""), self.appName) - case .backup: return String(format: NSLocalizedString("Backup %@ Failed", comment: ""), self.appName) - case .restore: return String(format: NSLocalizedString("Restore %@ Failed", comment: ""), self.appName) + guard let operation = operation else { return nil } + switch operation { + case .install: return String(format: NSLocalizedString("Install %@ Failed", comment: ""), appName) + case .update: return String(format: NSLocalizedString("Update %@ Failed", comment: ""), appName) + case .refresh: return String(format: NSLocalizedString("Refresh %@ Failed", comment: ""), appName) + case .activate: return String(format: NSLocalizedString("Activate %@ Failed", comment: ""), appName) + case .deactivate: return String(format: NSLocalizedString("Deactivate %@ Failed", comment: ""), appName) + case .backup: return String(format: NSLocalizedString("Backup %@ Failed", comment: ""), appName) + case .restore: return String(format: NSLocalizedString("Restore %@ Failed", comment: ""), appName) } } } -public extension LoggedError -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "LoggedError") +public extension LoggedError { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "LoggedError") } } diff --git a/AltStoreCore/Model/ManagedPatron.swift b/Sources/SideStoreCore/Model/ManagedPatron.swift similarity index 59% rename from AltStoreCore/Model/ManagedPatron.swift rename to Sources/SideStoreCore/Model/ManagedPatron.swift index a482853a..d03c7478 100644 --- a/AltStoreCore/Model/ManagedPatron.swift +++ b/Sources/SideStoreCore/Model/ManagedPatron.swift @@ -9,29 +9,24 @@ import CoreData @objc(ManagedPatron) -public class ManagedPatron: NSManagedObject, Fetchable -{ +public class ManagedPatron: NSManagedObject, Fetchable { @NSManaged public var name: String @NSManaged public var identifier: String - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(patron: Patron, context: NSManagedObjectContext) - { + + public init(patron: Patron, context: NSManagedObjectContext) { super.init(entity: ManagedPatron.entity(), insertInto: context) - - self.name = patron.name - self.identifier = patron.identifier + + name = patron.name + identifier = patron.identifier } } -public extension ManagedPatron -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "Patron") +public extension ManagedPatron { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "Patron") } } diff --git a/AltStoreCore/Model/MergePolicy.swift b/Sources/SideStoreCore/Model/MergePolicy.swift similarity index 77% rename from AltStoreCore/Model/MergePolicy.swift rename to Sources/SideStoreCore/Model/MergePolicy.swift index 08038988..7cdfcd60 100644 --- a/AltStoreCore/Model/MergePolicy.swift +++ b/Sources/SideStoreCore/Model/MergePolicy.swift @@ -10,107 +10,90 @@ import CoreData import Roxas -open class MergePolicy: RSTRelationshipPreservingMergePolicy -{ - open override func resolve(constraintConflicts conflicts: [NSConstraintConflict]) throws - { +open class MergePolicy: RSTRelationshipPreservingMergePolicy { + override open func resolve(constraintConflicts conflicts: [NSConstraintConflict]) throws { guard conflicts.allSatisfy({ $0.databaseObject != nil }) else { - for conflict in conflicts - { - switch conflict.conflictingObjects.first - { + for conflict in conflicts { + switch conflict.conflictingObjects.first { case is StoreApp where conflict.conflictingObjects.count == 2: // Modified cached StoreApp while replacing it with new one, causing context-level conflict. // Most likely, we set up a relationship between the new StoreApp and a NewsItem, // causing cached StoreApp to delete it's NewsItem relationship, resulting in (resolvable) conflict. - - if let previousApp = conflict.conflictingObjects.first(where: { !$0.isInserted }) as? StoreApp - { + + if let previousApp = conflict.conflictingObjects.first(where: { !$0.isInserted }) as? StoreApp { // Delete previous permissions (same as below). - for permission in previousApp.permissions - { + for permission in previousApp.permissions { permission.managedObjectContext?.delete(permission) } - + // Delete previous versions (different than below). - for case let appVersion as AppVersion in previousApp._versions where appVersion.app == nil - { + for case let appVersion as AppVersion in previousApp._versions where appVersion.app == nil { appVersion.managedObjectContext?.delete(appVersion) } } - + case is AppVersion where conflict.conflictingObjects.count == 2: // Occurs first time fetching sources after migrating from pre-AppVersion database model. let conflictingAppVersions = conflict.conflictingObjects.lazy.compactMap { $0 as? AppVersion } - + // Primary AppVersion == AppVersion whose latestVersionApp.latestVersion points back to itself. if let primaryAppVersion = conflictingAppVersions.first(where: { $0.latestVersionApp?.latestVersion == $0 }), - let secondaryAppVersion = conflictingAppVersions.first(where: { $0 != primaryAppVersion }) - { + let secondaryAppVersion = conflictingAppVersions.first(where: { $0 != primaryAppVersion }) { secondaryAppVersion.managedObjectContext?.delete(secondaryAppVersion) print("[ALTLog] Resolving AppVersion context-level conflict. Most likely due to migrating from pre-AppVersion model version.", primaryAppVersion) } - + default: // Unknown context-level conflict. assertionFailure("MergePolicy is only intended to work with database-level conflicts.") } } - + try super.resolve(constraintConflicts: conflicts) - + return } - - for conflict in conflicts - { - switch conflict.databaseObject - { + + for conflict in conflicts { + switch conflict.databaseObject { case let databaseObject as StoreApp: // Delete previous permissions - for permission in databaseObject.permissions - { + for permission in databaseObject.permissions { permission.managedObjectContext?.delete(permission) } - - if let contextApp = conflict.conflictingObjects.first as? StoreApp - { + + if let contextApp = conflict.conflictingObjects.first as? StoreApp { let contextVersions = Set(contextApp._versions.lazy.compactMap { $0 as? AppVersion }.map { $0.version }) - for case let appVersion as AppVersion in databaseObject._versions where !contextVersions.contains(appVersion.version) - { + for case let appVersion as AppVersion in databaseObject._versions where !contextVersions.contains(appVersion.version) { print("[ALTLog] Deleting cached app version: \(appVersion.appBundleID + "_" + appVersion.version), not in:", contextApp.versions.map { $0.appBundleID + "_" + $0.version }) appVersion.managedObjectContext?.delete(appVersion) } } - + case let databaseObject as Source: guard let conflictedObject = conflict.conflictingObjects.first as? Source else { break } let bundleIdentifiers = Set(conflictedObject.apps.map { $0.bundleIdentifier }) let newsItemIdentifiers = Set(conflictedObject.newsItems.map { $0.identifier }) - for app in databaseObject.apps - { - if !bundleIdentifiers.contains(app.bundleIdentifier) - { + for app in databaseObject.apps { + if !bundleIdentifiers.contains(app.bundleIdentifier) { // No longer listed in Source, so remove it from database. app.managedObjectContext?.delete(app) } } - - for newsItem in databaseObject.newsItems - { - if !newsItemIdentifiers.contains(newsItem.identifier) - { + + for newsItem in databaseObject.newsItems { + if !newsItemIdentifiers.contains(newsItem.identifier) { // No longer listed in Source, so remove it from database. newsItem.managedObjectContext?.delete(newsItem) } } - + default: break } } - + try super.resolve(constraintConflicts: conflicts) } } diff --git a/AltStoreCore/Model/NewsItem.swift b/Sources/SideStoreCore/Model/NewsItem.swift similarity index 62% rename from AltStoreCore/Model/NewsItem.swift rename to Sources/SideStoreCore/Model/NewsItem.swift index 22e86eb8..d308715c 100644 --- a/AltStoreCore/Model/NewsItem.swift +++ b/Sources/SideStoreCore/Model/NewsItem.swift @@ -6,34 +6,32 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import UIKit import CoreData +import UIKit @objc(NewsItem) -public class NewsItem: NSManagedObject, Decodable, Fetchable -{ +public class NewsItem: NSManagedObject, Decodable, Fetchable { /* Properties */ @NSManaged public var identifier: String @NSManaged public var date: Date - + @NSManaged public var title: String @NSManaged public var caption: String @NSManaged public var tintColor: UIColor @NSManaged public var sortIndex: Int32 @NSManaged public var isSilent: Bool - + @NSManaged public var imageURL: URL? @NSManaged public var externalURL: URL? - + @NSManaged public var appID: String? @NSManaged public var sourceIdentifier: String? - + /* Relationships */ @NSManaged public var storeApp: StoreApp? @NSManaged public var source: Source? - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case identifier case date case title @@ -44,48 +42,43 @@ public class NewsItem: NSManagedObject, Decodable, Fetchable case appID case notify } - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public required init(from decoder: Decoder) throws - { + + public required init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } - + super.init(entity: NewsItem.entity(), insertInto: context) - + let container = try decoder.container(keyedBy: CodingKeys.self) - self.identifier = try container.decode(String.self, forKey: .identifier) - self.date = try container.decode(Date.self, forKey: .date) - - self.title = try container.decode(String.self, forKey: .title) - self.caption = try container.decode(String.self, forKey: .caption) - - if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor) - { + identifier = try container.decode(String.self, forKey: .identifier) + date = try container.decode(Date.self, forKey: .date) + + title = try container.decode(String.self, forKey: .title) + caption = try container.decode(String.self, forKey: .caption) + + if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor) { guard let tintColor = UIColor(hexString: tintColorHex) else { throw DecodingError.dataCorruptedError(forKey: .tintColor, in: container, debugDescription: "Hex code is invalid.") } - + self.tintColor = tintColor } - - self.imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL) - self.externalURL = try container.decodeIfPresent(URL.self, forKey: .externalURL) - - self.appID = try container.decodeIfPresent(String.self, forKey: .appID) - + + imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL) + externalURL = try container.decodeIfPresent(URL.self, forKey: .externalURL) + + appID = try container.decodeIfPresent(String.self, forKey: .appID) + let notify = try container.decodeIfPresent(Bool.self, forKey: .notify) ?? false - self.isSilent = !notify + isSilent = !notify } } -public extension NewsItem -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "NewsItem") +public extension NewsItem { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "NewsItem") } } diff --git a/AltStoreCore/Model/PatreonAccount.swift b/Sources/SideStoreCore/Model/PatreonAccount.swift similarity index 61% rename from AltStoreCore/Model/PatreonAccount.swift rename to Sources/SideStoreCore/Model/PatreonAccount.swift index 3b2a32b2..733a0241 100644 --- a/AltStoreCore/Model/PatreonAccount.swift +++ b/Sources/SideStoreCore/Model/PatreonAccount.swift @@ -8,50 +8,43 @@ import CoreData -extension PatreonAPI -{ - struct AccountResponse: Decodable - { - struct Data: Decodable - { - struct Attributes: Decodable - { +extension PatreonAPI { + struct AccountResponse: Decodable { + struct Data: Decodable { + struct Attributes: Decodable { var first_name: String? var full_name: String } - + var id: String var attributes: Attributes } - + var data: Data var included: [PatronResponse]? } } @objc(PatreonAccount) -public class PatreonAccount: NSManagedObject, Fetchable -{ +public class PatreonAccount: NSManagedObject, Fetchable { @NSManaged public var identifier: String - + @NSManaged public var name: String @NSManaged public var firstName: String? - + @NSManaged public var isPatron: Bool - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - init(response: PatreonAPI.AccountResponse, context: NSManagedObjectContext) - { + + init(response: PatreonAPI.AccountResponse, context: NSManagedObjectContext) { super.init(entity: PatreonAccount.entity(), insertInto: context) - - self.identifier = response.data.id - self.name = response.data.attributes.full_name - self.firstName = response.data.attributes.first_name - + + identifier = response.data.id + name = response.data.attributes.full_name + firstName = response.data.attributes.first_name + // if let patronResponse = response.included?.first // { // let patron = Patron(response: patronResponse) @@ -61,15 +54,12 @@ public class PatreonAccount: NSManagedObject, Fetchable // { // self.isPatron = false // } - self.isPatron = true + isPatron = true } } -public extension PatreonAccount -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "PatreonAccount") +public extension PatreonAccount { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "PatreonAccount") } } - diff --git a/AltStoreCore/Model/RefreshAttempt.swift b/Sources/SideStoreCore/Model/RefreshAttempt.swift similarity index 57% rename from AltStoreCore/Model/RefreshAttempt.swift rename to Sources/SideStoreCore/Model/RefreshAttempt.swift index 314b8b98..20313561 100644 --- a/AltStoreCore/Model/RefreshAttempt.swift +++ b/Sources/SideStoreCore/Model/RefreshAttempt.swift @@ -9,51 +9,42 @@ import CoreData @objc(RefreshAttempt) -public class RefreshAttempt: NSManagedObject, Fetchable -{ +public class RefreshAttempt: NSManagedObject, Fetchable { @NSManaged public var identifier: String @NSManaged public var date: Date - + @NSManaged public var isSuccess: Bool @NSManaged public var errorDescription: String? - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(identifier: String, result: Result<[String: Result], Error>, context: NSManagedObjectContext) - { + + public init(identifier: String, result: Result<[String: Result], Error>, context: NSManagedObjectContext) { super.init(entity: RefreshAttempt.entity(), insertInto: context) - + self.identifier = identifier - self.date = Date() - - do - { + date = Date() + + do { let results = try result.get() - - for (_, result) in results - { + + for (_, result) in results { guard case let .failure(error) = result else { continue } throw error } - - self.isSuccess = true - self.errorDescription = nil - } - catch - { - self.isSuccess = false - self.errorDescription = error.localizedDescription + + isSuccess = true + errorDescription = nil + } catch { + isSuccess = false + errorDescription = error.localizedDescription } } } -public extension RefreshAttempt -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "RefreshAttempt") +public extension RefreshAttempt { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "RefreshAttempt") } } diff --git a/AltStoreCore/Model/SecureValueTransformer.swift b/Sources/SideStoreCore/Model/SecureValueTransformer.swift similarity index 82% rename from AltStoreCore/Model/SecureValueTransformer.swift rename to Sources/SideStoreCore/Model/SecureValueTransformer.swift index 1a916acd..3c212c12 100644 --- a/AltStoreCore/Model/SecureValueTransformer.swift +++ b/Sources/SideStoreCore/Model/SecureValueTransformer.swift @@ -9,17 +9,15 @@ import Foundation @objc(ALTSecureValueTransformer) -public final class SecureValueTransformer: NSSecureUnarchiveFromDataTransformer -{ +public final class SecureValueTransformer: NSSecureUnarchiveFromDataTransformer { public static let name = NSValueTransformerName(rawValue: "ALTSecureValueTransformer") - - public override static var allowedTopLevelClasses: [AnyClass] { + + override public static var allowedTopLevelClasses: [AnyClass] { let allowedClasses = super.allowedTopLevelClasses + [NSError.self] return allowedClasses } - - public static func register() - { + + public static func register() { let transformer = SecureValueTransformer() ValueTransformer.setValueTransformer(transformer, forName: name) } diff --git a/AltStoreCore/Model/Source.swift b/Sources/SideStoreCore/Model/Source.swift similarity index 66% rename from AltStoreCore/Model/Source.swift rename to Sources/SideStoreCore/Model/Source.swift index 8f1a72a7..103a9075 100644 --- a/AltStoreCore/Model/Source.swift +++ b/Sources/SideStoreCore/Model/Source.swift @@ -9,39 +9,37 @@ import CoreData import UIKit -public extension Source -{ +public extension Source { #if ALPHA - static let altStoreIdentifier = Bundle.Info.appbundleIdentifier + static let altStoreIdentifier = Bundle.Info.appbundleIdentifier #else - static let altStoreIdentifier = Bundle.Info.appbundleIdentifier + static let altStoreIdentifier = Bundle.Info.appbundleIdentifier #endif - + #if STAGING - - #if ALPHA - static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! + + #if ALPHA + static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! + #else + static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! + #endif + #else - static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! - #endif - - #else - - #if ALPHA - static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! - #else - static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! - #endif - + + #if ALPHA + static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! + #else + static let altStoreSourceURL = URL(string: "https://apps.sidestore.io/")! + #endif + #endif } public struct AppPermissionFeed: Codable { let type: String // ALTAppPermissionType let usageDescription: String - - enum CodingKeys: String, CodingKey - { + + enum CodingKeys: String, CodingKey { case type case usageDescription } @@ -52,12 +50,11 @@ public struct AppVersionFeed: Codable { let version: String let date: Date let localizedDescription: String? - + let downloadURL: URL let size: Int64 - - enum CodingKeys: String, CodingKey - { + + enum CodingKeys: String, CodingKey { case version case date case localizedDescription @@ -70,43 +67,39 @@ public struct PlatformURLFeed: Codable { /* Properties */ let platform: Platform let downloadURL: URL - - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case platform case downloadURL } } - public struct StoreAppFeed: Codable { let name: String let bundleIdentifier: String let subtitle: String? - + let developerName: String let localizedDescription: String let size: Int64 - + let iconURL: URL let screenshotURLs: [URL] - + let version: String let versionDate: Date let versionDescription: String? let downloadURL: URL let platformURLs: [PlatformURLFeed]? - + let tintColor: String? // UIColor? let isBeta: Bool - + // let source: Source? let appPermission: [AppPermissionFeed] let versions: [AppVersionFeed] - - enum CodingKeys: String, CodingKey - { + + enum CodingKeys: String, CodingKey { case bundleIdentifier case developerName case downloadURL @@ -130,19 +123,18 @@ public struct StoreAppFeed: Codable { public struct NewsItemFeed: Codable { let identifier: String let date: Date - + let title: String let caption: String - let tintColor: String //UIColor + let tintColor: String // UIColor let notify: Bool - + let imageURL: URL? let externalURL: URL? - + let appID: String? - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case identifier case date case title @@ -155,17 +147,15 @@ public struct NewsItemFeed: Codable { } } - public struct SourceJSON: Codable { let name: String let identifier: String let sourceURL: URL - let userInfo: [String:String]? //[ALTSourceUserInfoKey:String]? + let userInfo: [String: String]? // [ALTSourceUserInfoKey:String]? let apps: [StoreAppFeed] let news: [NewsItemFeed] - - enum CodingKeys: String, CodingKey - { + + enum CodingKeys: String, CodingKey { case name case identifier case sourceURL @@ -173,46 +163,43 @@ public struct SourceJSON: Codable { case apps case news } - } @objc(Source) -public class Source: NSManagedObject, Fetchable, Decodable -{ +public class Source: NSManagedObject, Fetchable, Decodable { /* Properties */ @NSManaged public var name: String @NSManaged public var identifier: String @NSManaged public var sourceURL: URL - + @NSManaged public var error: NSError? - + /* Non-Core Data Properties */ public var userInfo: [ALTSourceUserInfoKey: String]? - + /* Relationships */ @objc(apps) @NSManaged public private(set) var _apps: NSOrderedSet @objc(newsItems) @NSManaged public private(set) var _newsItems: NSOrderedSet - + @nonobjc public var apps: [StoreApp] { get { - return self._apps.array as! [StoreApp] + _apps.array as! [StoreApp] } set { - self._apps = NSOrderedSet(array: newValue) + _apps = NSOrderedSet(array: newValue) } } - + @nonobjc public var newsItems: [NewsItem] { get { - return self._newsItems.array as! [NewsItem] + _newsItems.array as! [NewsItem] } set { - self._newsItems = NSOrderedSet(array: newValue) + _newsItems = NSOrderedSet(array: newValue) } } - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case name case identifier case sourceURL @@ -220,93 +207,77 @@ public class Source: NSManagedObject, Fetchable, Decodable case apps case news } - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public required init(from decoder: Decoder) throws - { + + public required init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } guard let sourceURL = decoder.sourceURL else { preconditionFailure("Decoder must have non-nil sourceURL.") } - + super.init(entity: Source.entity(), insertInto: context) - - do - { + + do { self.sourceURL = sourceURL - + let container = try decoder.container(keyedBy: CodingKeys.self) - self.name = try container.decode(String.self, forKey: .name) - self.identifier = try container.decode(String.self, forKey: .identifier) - + name = try container.decode(String.self, forKey: .name) + identifier = try container.decode(String.self, forKey: .identifier) + let userInfo = try container.decodeIfPresent([String: String].self, forKey: .userInfo) self.userInfo = userInfo?.reduce(into: [:]) { $0[ALTSourceUserInfoKey($1.key)] = $1.value } - + let apps = try container.decodeIfPresent([StoreApp].self, forKey: .apps) ?? [] - let appsByID = Dictionary(apps.map { ($0.bundleIdentifier, $0) }, uniquingKeysWith: { (a, b) in return a }) - - for (index, app) in apps.enumerated() - { - app.sourceIdentifier = self.identifier + let appsByID = Dictionary(apps.map { ($0.bundleIdentifier, $0) }, uniquingKeysWith: { a, _ in a }) + + for (index, app) in apps.enumerated() { + app.sourceIdentifier = identifier app.sortIndex = Int32(index) } - self._apps = NSMutableOrderedSet(array: apps) - + _apps = NSMutableOrderedSet(array: apps) + let newsItems = try container.decodeIfPresent([NewsItem].self, forKey: .news) ?? [] - for (index, item) in newsItems.enumerated() - { - item.sourceIdentifier = self.identifier + for (index, item) in newsItems.enumerated() { + item.sourceIdentifier = identifier item.sortIndex = Int32(index) } - - for newsItem in newsItems - { + + for newsItem in newsItems { guard let appID = newsItem.appID else { continue } - - if let storeApp = appsByID[appID] - { + + if let storeApp = appsByID[appID] { newsItem.storeApp = storeApp - } - else - { + } else { newsItem.storeApp = nil } } - self._newsItems = NSMutableOrderedSet(array: newsItems) - } - catch - { - if let context = self.managedObjectContext - { + _newsItems = NSMutableOrderedSet(array: newsItems) + } catch { + if let context = managedObjectContext { context.delete(self) } - + throw error } } } -public extension Source -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "Source") +public extension Source { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "Source") } - - class func makeAltStoreSource(in context: NSManagedObjectContext) -> Source - { + + class func makeAltStoreSource(in context: NSManagedObjectContext) -> Source { let source = Source(context: context) source.name = "SideStore Offical" source.identifier = Source.altStoreIdentifier source.sourceURL = Source.altStoreSourceURL - + return source } - - class func fetchAltStoreSource(in context: NSManagedObjectContext) -> Source? - { + + class func fetchAltStoreSource(in context: NSManagedObjectContext) -> Source? { let source = Source.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(Source.identifier), Source.altStoreIdentifier), in: context) return source } diff --git a/AltStoreCore/Model/StoreApp.swift b/Sources/SideStoreCore/Model/StoreApp.swift similarity index 66% rename from AltStoreCore/Model/StoreApp.swift rename to Sources/SideStoreCore/Model/StoreApp.swift index 2e38b57d..0c1f6a12 100644 --- a/AltStoreCore/Model/StoreApp.swift +++ b/Sources/SideStoreCore/Model/StoreApp.swift @@ -6,22 +6,21 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation -import Roxas import AltSign +import Roxas -public extension StoreApp -{ +public extension StoreApp { #if ALPHA - static let altstoreAppID = Bundle.Info.appbundleIdentifier + static let altstoreAppID = Bundle.main.Info.appbundleIdentifier #elseif BETA - static let altstoreAppID = Bundle.Info.appbundleIdentifier + static let altstoreAppID = Bundle.main.Info.appbundleIdentifier #else - static let altstoreAppID = Bundle.Info.appbundleIdentifier + static let altstoreAppID = Bundle.main.Info.appbundleIdentifier #endif - + static let dolphinAppID = "me.oatmealdome.dolphinios-njb" } @@ -37,35 +36,27 @@ public final class PlatformURL: NSManagedObject, Decodable { /* Properties */ @NSManaged public private(set) var platform: Platform @NSManaged public private(set) var downloadURL: URL - - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case platform case downloadURL } - - - public init(from decoder: Decoder) throws - { + + public init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } - + // Must initialize with context in order for child context saves to work correctly. super.init(entity: PlatformURL.entity(), insertInto: context) - - do - { + + do { let container = try decoder.container(keyedBy: CodingKeys.self) - self.platform = try container.decode(Platform.self, forKey: .platform) - self.downloadURL = try container.decode(URL.self, forKey: .downloadURL) - } - catch - { - if let context = self.managedObjectContext - { + platform = try container.decode(Platform.self, forKey: .platform) + downloadURL = try container.decode(URL.self, forKey: .downloadURL) + } catch { + if let context = managedObjectContext { context.delete(self) } - + throw error } } @@ -73,134 +64,131 @@ public final class PlatformURL: NSManagedObject, Decodable { extension PlatformURL: Comparable { public static func < (lhs: PlatformURL, rhs: PlatformURL) -> Bool { - return lhs.platform.rawValue < rhs.platform.rawValue + lhs.platform.rawValue < rhs.platform.rawValue } - + public static func > (lhs: PlatformURL, rhs: PlatformURL) -> Bool { - return lhs.platform.rawValue > rhs.platform.rawValue + lhs.platform.rawValue > rhs.platform.rawValue } - + public static func <= (lhs: PlatformURL, rhs: PlatformURL) -> Bool { - return lhs.platform.rawValue <= rhs.platform.rawValue + lhs.platform.rawValue <= rhs.platform.rawValue } - + public static func >= (lhs: PlatformURL, rhs: PlatformURL) -> Bool { - return lhs.platform.rawValue >= rhs.platform.rawValue + lhs.platform.rawValue >= rhs.platform.rawValue } } public typealias PlatformURLs = [PlatformURL] @objc(StoreApp) -public class StoreApp: NSManagedObject, Decodable, Fetchable -{ +public class StoreApp: NSManagedObject, Decodable, Fetchable { /* Properties */ @NSManaged public private(set) var name: String @NSManaged public private(set) var bundleIdentifier: String @NSManaged public private(set) var subtitle: String? - + @NSManaged public private(set) var developerName: String @NSManaged public private(set) var localizedDescription: String @NSManaged @objc(size) internal var _size: Int32 - + @NSManaged public private(set) var iconURL: URL @NSManaged public private(set) var screenshotURLs: [URL] - + @NSManaged @objc(version) internal var _version: String @NSManaged @objc(versionDate) internal var _versionDate: Date @NSManaged @objc(versionDescription) internal var _versionDescription: String? - + @NSManaged @objc(downloadURL) internal var _downloadURL: URL @NSManaged public private(set) var platformURLs: PlatformURLs? @NSManaged public private(set) var tintColor: UIColor? @NSManaged public private(set) var isBeta: Bool - + @objc public internal(set) var sourceIdentifier: String? { get { - self.willAccessValue(forKey: #keyPath(sourceIdentifier)) + willAccessValue(forKey: #keyPath(sourceIdentifier)) defer { self.didAccessValue(forKey: #keyPath(sourceIdentifier)) } - - let sourceIdentifier = self.primitiveSourceIdentifier + + let sourceIdentifier = primitiveSourceIdentifier return sourceIdentifier } set { - self.willChangeValue(forKey: #keyPath(sourceIdentifier)) - self.primitiveSourceIdentifier = newValue - self.didChangeValue(forKey: #keyPath(sourceIdentifier)) - - for version in self.versions - { + willChangeValue(forKey: #keyPath(sourceIdentifier)) + primitiveSourceIdentifier = newValue + didChangeValue(forKey: #keyPath(sourceIdentifier)) + + for version in versions { version.sourceID = newValue } } } + @NSManaged private var primitiveSourceIdentifier: String? - + @NSManaged public var sortIndex: Int32 - + /* Relationships */ @NSManaged public var installedApp: InstalledApp? @NSManaged public var newsItems: Set - + @NSManaged @objc(source) public var _source: Source? @NSManaged @objc(permissions) public var _permissions: NSOrderedSet - + @NSManaged public private(set) var latestVersion: AppVersion? @NSManaged @objc(versions) public private(set) var _versions: NSOrderedSet - + @NSManaged public private(set) var loggedErrors: NSSet /* Set */ // Use NSSet to avoid eagerly fetching values. - + @nonobjc public var source: Source? { set { - self._source = newValue - self.sourceIdentifier = newValue?.identifier + _source = newValue + sourceIdentifier = newValue?.identifier } get { - return self._source + _source } } - + @nonobjc public var permissions: [AppPermission] { - return self._permissions.array as! [AppPermission] + _permissions.array as! [AppPermission] } - + @nonobjc public var versions: [AppVersion] { - return self._versions.array as! [AppVersion] + _versions.array as! [AppVersion] } - + @nonobjc public var size: Int64? { - guard let version = self.latestVersion else { return nil } + guard let version = latestVersion else { return nil } return version.size } - + @nonobjc public var version: String? { - guard let version = self.latestVersion else { return nil } + guard let version = latestVersion else { return nil } return version.version } - + @nonobjc public var versionDescription: String? { - guard let version = self.latestVersion else { return nil } + guard let version = latestVersion else { return nil } return version.localizedDescription } - + @nonobjc public var versionDate: Date? { - guard let version = self.latestVersion else { return nil } + guard let version = latestVersion else { return nil } return version.date } - + @nonobjc public var downloadURL: URL? { guard let version = self.latestVersion else { return nil } return version.downloadURL } - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - private enum CodingKeys: String, CodingKey - { + + private enum CodingKeys: String, CodingKey { case name case bundleIdentifier case developerName @@ -219,128 +207,112 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable case isBeta = "beta" case versions } - - public required init(from decoder: Decoder) throws - { + + public required init(from decoder: Decoder) throws { guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } - + // Must initialize with context in order for child context saves to work correctly. super.init(entity: StoreApp.entity(), insertInto: context) - - do - { + + do { let container = try decoder.container(keyedBy: CodingKeys.self) - self.name = try container.decode(String.self, forKey: .name) - self.bundleIdentifier = try container.decode(String.self, forKey: .bundleIdentifier) - self.developerName = try container.decode(String.self, forKey: .developerName) - self.localizedDescription = try container.decode(String.self, forKey: .localizedDescription) - - self.subtitle = try container.decodeIfPresent(String.self, forKey: .subtitle) - - self.iconURL = try container.decode(URL.self, forKey: .iconURL) - self.screenshotURLs = try container.decodeIfPresent([URL].self, forKey: .screenshotURLs) ?? [] - + name = try container.decode(String.self, forKey: .name) + bundleIdentifier = try container.decode(String.self, forKey: .bundleIdentifier) + developerName = try container.decode(String.self, forKey: .developerName) + localizedDescription = try container.decode(String.self, forKey: .localizedDescription) + + subtitle = try container.decodeIfPresent(String.self, forKey: .subtitle) + + iconURL = try container.decode(URL.self, forKey: .iconURL) + screenshotURLs = try container.decodeIfPresent([URL].self, forKey: .screenshotURLs) ?? [] + let downloadURL = try container.decodeIfPresent(URL.self, forKey: .downloadURL) let platformURLs = try container.decodeIfPresent(PlatformURLs.self.self, forKey: .platformURLs) if let platformURLs = platformURLs { self.platformURLs = platformURLs // Backwards compatibility, use the fiirst (iOS will be first since sorted that way) if let first = platformURLs.sorted().first { - self._downloadURL = first.downloadURL + _downloadURL = first.downloadURL } else { throw DecodingError.dataCorruptedError(forKey: .platformURLs, in: container, debugDescription: "platformURLs has no entries") - } - + } else if let downloadURL = downloadURL { - self._downloadURL = downloadURL + _downloadURL = downloadURL } else { throw DecodingError.dataCorruptedError(forKey: .downloadURL, in: container, debugDescription: "E downloadURL:String or downloadURLs:[[Platform:URL]] key required.") } - - if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor) - { + + if let tintColorHex = try container.decodeIfPresent(String.self, forKey: .tintColor) { guard let tintColor = UIColor(hexString: tintColorHex) else { throw DecodingError.dataCorruptedError(forKey: .tintColor, in: container, debugDescription: "Hex code is invalid.") } - + self.tintColor = tintColor } - - self.isBeta = try container.decodeIfPresent(Bool.self, forKey: .isBeta) ?? false - + + isBeta = try container.decodeIfPresent(Bool.self, forKey: .isBeta) ?? false + let permissions = try container.decodeIfPresent([AppPermission].self, forKey: .permissions) ?? [] - self._permissions = NSOrderedSet(array: permissions) - - if let versions = try container.decodeIfPresent([AppVersion].self, forKey: .versions) - { - //TODO: Throw error if there isn't at least one version. - - for version in versions - { - version.appBundleID = self.bundleIdentifier + _permissions = NSOrderedSet(array: permissions) + + if let versions = try container.decodeIfPresent([AppVersion].self, forKey: .versions) { + // TODO: Throw error if there isn't at least one version. + + for version in versions { + version.appBundleID = bundleIdentifier } - - self.setVersions(versions) - } - else - { + + setVersions(versions) + } else { let version = try container.decode(String.self, forKey: .version) let versionDate = try container.decode(Date.self, forKey: .versionDate) let versionDescription = try container.decodeIfPresent(String.self, forKey: .versionDescription) - + let downloadURL = try container.decode(URL.self, forKey: .downloadURL) let size = try container.decode(Int32.self, forKey: .size) - + let appVersion = AppVersion.makeAppVersion(version: version, date: versionDate, localizedDescription: versionDescription, downloadURL: downloadURL, size: Int64(size), - appBundleID: self.bundleIdentifier, + appBundleID: bundleIdentifier, in: context) - self.setVersions([appVersion]) + setVersions([appVersion]) } - } - catch - { - if let context = self.managedObjectContext - { + } catch { + if let context = managedObjectContext { context.delete(self) } - + throw error } } } -private extension StoreApp -{ - func setVersions(_ versions: [AppVersion]) - { +private extension StoreApp { + func setVersions(_ versions: [AppVersion]) { guard let latestVersion = versions.first else { preconditionFailure("StoreApp must have at least one AppVersion.") } - + self.latestVersion = latestVersion - self._versions = NSOrderedSet(array: versions) - + _versions = NSOrderedSet(array: versions) + // Preserve backwards compatibility by assigning legacy property values. - self._version = latestVersion.version - self._versionDate = latestVersion.date - self._versionDescription = latestVersion.localizedDescription - self._downloadURL = latestVersion.downloadURL - self._size = Int32(latestVersion.size) + _version = latestVersion.version + _versionDate = latestVersion.date + _versionDescription = latestVersion.localizedDescription + _downloadURL = latestVersion.downloadURL + _size = Int32(latestVersion.size) } } -public extension StoreApp -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "StoreApp") +public extension StoreApp { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "StoreApp") } - - class func makeAltStoreApp(in context: NSManagedObjectContext) -> StoreApp - { + + class func makeAltStoreApp(in context: NSManagedObjectContext) -> StoreApp { let app = StoreApp(context: context) app.name = "SideStore" app.bundleIdentifier = StoreApp.altstoreAppID @@ -349,7 +321,7 @@ public extension StoreApp app.iconURL = URL(string: "https://user-images.githubusercontent.com/705880/63392210-540c5980-c37b-11e9-968c-8742fc68ab2e.png")! app.screenshotURLs = [] app.sourceIdentifier = Source.altStoreIdentifier - + let appVersion = AppVersion.makeAppVersion(version: "0.3.0", date: Date(), downloadURL: URL(string: "http://rileytestut.com")!, @@ -358,13 +330,13 @@ public extension StoreApp sourceID: Source.altStoreIdentifier, in: context) app.setVersions([appVersion]) - + print("makeAltStoreApp StoreApp: \(String(describing: app))") - + #if BETA - app.isBeta = true + app.isBeta = true #endif - + return app } } diff --git a/AltStoreCore/Model/Team.swift b/Sources/SideStoreCore/Model/Team.swift similarity index 66% rename from AltStoreCore/Model/Team.swift rename to Sources/SideStoreCore/Model/Team.swift index 212ef69b..87daae8e 100644 --- a/AltStoreCore/Model/Team.swift +++ b/Sources/SideStoreCore/Model/Team.swift @@ -6,16 +6,14 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import CoreData +import Foundation import AltSign -public extension ALTTeamType -{ +public extension ALTTeamType { var localizedDescription: String { - switch self - { + switch self { case .free: return NSLocalizedString("Free Developer Account", comment: "") case .individual: return NSLocalizedString("Developer", comment: "") case .organization: return NSLocalizedString("Organization", comment: "") @@ -25,56 +23,49 @@ public extension ALTTeamType } } -public extension Team -{ +public extension Team { static let maximumFreeAppIDs = 10 } @objc(Team) -public class Team: NSManagedObject, Fetchable -{ +public class Team: NSManagedObject, Fetchable { /* Properties */ @NSManaged public var name: String @NSManaged public var identifier: String @NSManaged public var type: ALTTeamType - + @NSManaged public var isActiveTeam: Bool - + /* Relationships */ @NSManaged public private(set) var account: Account! @NSManaged public var installedApps: Set @NSManaged public private(set) var appIDs: Set - + public var altTeam: ALTTeam? - - private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) - { + + override private init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context) } - - public init(_ team: ALTTeam, account: Account, context: NSManagedObjectContext) - { + + public init(_ team: ALTTeam, account: Account, context: NSManagedObjectContext) { super.init(entity: Team.entity(), insertInto: context) - + self.account = account - - self.update(team: team) + + update(team: team) } - - public func update(team: ALTTeam) - { - self.altTeam = team - - self.name = team.name - self.identifier = team.identifier - self.type = team.type + + public func update(team: ALTTeam) { + altTeam = team + + name = team.name + identifier = team.identifier + type = team.type } } -public extension Team -{ - @nonobjc class func fetchRequest() -> NSFetchRequest - { - return NSFetchRequest(entityName: "Team") +public extension Team { + @nonobjc class func fetchRequest() -> NSFetchRequest { + NSFetchRequest(entityName: "Team") } } diff --git a/Sources/SideStoreCore/Patreon/Benefit.swift b/Sources/SideStoreCore/Patreon/Benefit.swift new file mode 100644 index 00000000..72eb9a47 --- /dev/null +++ b/Sources/SideStoreCore/Patreon/Benefit.swift @@ -0,0 +1,29 @@ +// +// Benefit.swift +// AltStore +// +// Created by Riley Testut on 8/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation + +public enum ALTPatreonBenefitType: String, Codable, Equatable, CaseIterable, Hashable { + case betaAccess = "7585304" + case credits = "8490206" +} + +extension PatreonAPI { + struct BenefitResponse: Decodable { + var id: String + } +} + +public struct Benefit: Hashable { + public var type: ALTPatreonBenefitType + + init?(response: PatreonAPI.BenefitResponse) { + guard let type = ALTPatreonBenefitType(rawValue: response.id) else { return nil } + self.type = type + } +} diff --git a/AltStoreCore/Patreon/Campaign.swift b/Sources/SideStoreCore/Patreon/Campaign.swift similarity index 54% rename from AltStoreCore/Patreon/Campaign.swift rename to Sources/SideStoreCore/Patreon/Campaign.swift index 00153eb9..5ec4cb8f 100644 --- a/AltStoreCore/Patreon/Campaign.swift +++ b/Sources/SideStoreCore/Patreon/Campaign.swift @@ -8,20 +8,16 @@ import Foundation -extension PatreonAPI -{ - struct CampaignResponse: Decodable - { +extension PatreonAPI { + struct CampaignResponse: Decodable { var id: String } } -public struct Campaign -{ +public struct Campaign { public var identifier: String - - init(response: PatreonAPI.CampaignResponse) - { - self.identifier = response.id + + init(response: PatreonAPI.CampaignResponse) { + identifier = response.id } } diff --git a/AltStoreCore/Patreon/PatreonAPI.swift b/Sources/SideStoreCore/Patreon/PatreonAPI.swift similarity index 67% rename from AltStoreCore/Patreon/PatreonAPI.swift rename to Sources/SideStoreCore/Patreon/PatreonAPI.swift index 50219826..6447bc1e 100644 --- a/AltStoreCore/Patreon/PatreonAPI.swift +++ b/Sources/SideStoreCore/Patreon/PatreonAPI.swift @@ -6,159 +6,140 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import AuthenticationServices import CoreData +import Foundation private let clientID = "ZMx0EGUWe4TVWYXNZZwK_fbIK5jHFVWoUf1Qb-sqNXmT-YzAGwDPxxq7ak3_W5Q2" private let clientSecret = "1hktsZB89QyN69cB4R0tu55R4TCPQGXxvebYUUh7Y-5TLSnRswuxs6OUjdJ74IJt" private let campaignID = "2863968" -extension PatreonAPI -{ - enum Error: LocalizedError - { +extension PatreonAPI { + enum Error: LocalizedError { case unknown case notAuthenticated case invalidAccessToken - + var errorDescription: String? { - switch self - { + switch self { case .unknown: return NSLocalizedString("An unknown error occurred.", comment: "") case .notAuthenticated: return NSLocalizedString("No connected Patreon account.", comment: "") case .invalidAccessToken: return NSLocalizedString("Invalid access token.", comment: "") } } } - - enum AuthorizationType - { + + enum AuthorizationType { case none case user case creator } - - enum AnyResponse: Decodable - { + + enum AnyResponse: Decodable { case tier(TierResponse) case benefit(BenefitResponse) - - enum CodingKeys: String, CodingKey - { + + enum CodingKeys: String, CodingKey { case type } - - init(from decoder: Decoder) throws - { + + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - + let type = try container.decode(String.self, forKey: .type) - switch type - { + switch type { case "tier": let tier = try TierResponse(from: decoder) self = .tier(tier) - + case "benefit": let benefit = try BenefitResponse(from: decoder) self = .benefit(benefit) - + default: throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "Unrecognized Patreon response type.") } } } } -public class PatreonAPI: NSObject -{ +public class PatreonAPI: NSObject { public static let shared = PatreonAPI() - + public var isAuthenticated: Bool { - return Keychain.shared.patreonAccessToken != nil + Keychain.shared.patreonAccessToken != nil } - + private var authenticationSession: ASWebAuthenticationSession? - + private let session = URLSession(configuration: .ephemeral) private let baseURL = URL(string: "https://www.patreon.com/")! - - private override init() - { + + override private init() { super.init() } } -public extension PatreonAPI -{ - func authenticate(completion: @escaping (Result) -> Void) - { +public extension PatreonAPI { + func authenticate(completion: @escaping (Result) -> Void) { var components = URLComponents(string: "/oauth2/authorize")! components.queryItems = [URLQueryItem(name: "response_type", value: "code"), URLQueryItem(name: "client_id", value: clientID), URLQueryItem(name: "redirect_uri", value: "https://rileytestut.com/patreon/altstore")] - - let requestURL = components.url(relativeTo: self.baseURL)! - - self.authenticationSession = ASWebAuthenticationSession(url: requestURL, callbackURLScheme: "altstore") { (callbackURL, error) in - do - { + + let requestURL = components.url(relativeTo: baseURL)! + + authenticationSession = ASWebAuthenticationSession(url: requestURL, callbackURLScheme: "altstore") { callbackURL, error in + do { let callbackURL = try Result(callbackURL, error).get() - + guard let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false), let codeQueryItem = components.queryItems?.first(where: { $0.name == "code" }), let code = codeQueryItem.value else { throw Error.unknown } - - self.fetchAccessToken(oauthCode: code) { (result) in - switch result - { - case .failure(let error): completion(.failure(error)) - case .success((let accessToken, let refreshToken)): + + self.fetchAccessToken(oauthCode: code) { result in + switch result { + case let .failure(error): completion(.failure(error)) + case let .success((accessToken, refreshToken)): Keychain.shared.patreonAccessToken = accessToken Keychain.shared.patreonRefreshToken = refreshToken - + self.fetchAccount(completion: completion) } } - } - catch - { + } catch { completion(.failure(error)) } } - - if #available(iOS 13.0, *) - { + + if #available(iOS 13.0, *) { self.authenticationSession?.presentationContextProvider = self } - - self.authenticationSession?.start() + + authenticationSession?.start() } - - func fetchAccount(completion: @escaping (Result) -> Void) - { + + func fetchAccount(completion: @escaping (Result) -> Void) { var components = URLComponents(string: "/api/oauth2/v2/identity")! components.queryItems = [URLQueryItem(name: "include", value: "memberships"), URLQueryItem(name: "fields[user]", value: "first_name,full_name"), URLQueryItem(name: "fields[member]", value: "full_name,patron_status")] - - let requestURL = components.url(relativeTo: self.baseURL)! + + let requestURL = components.url(relativeTo: baseURL)! let request = URLRequest(url: requestURL) - - self.send(request, authorizationType: .user) { (result: Result) in - switch result - { + + send(request, authorizationType: .user) { (result: Result) in + switch result { case .failure(Error.notAuthenticated): - self.signOut() { (result) in + self.signOut { _ in completion(.failure(Error.notAuthenticated)) } - - case .failure(let error): completion(.failure(error)) - case .success(let response): - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in + + case let .failure(error): completion(.failure(error)) + case let .success(response): + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in let account = PatreonAccount(response: response, context: context) Keychain.shared.patreonAccountID = account.identifier completion(.success(account)) @@ -166,256 +147,221 @@ public extension PatreonAPI } } } - - func fetchPatrons(completion: @escaping (Result<[Patron], Swift.Error>) -> Void) - { + + func fetchPatrons(completion: @escaping (Result<[Patron], Swift.Error>) -> Void) { var components = URLComponents(string: "/api/oauth2/v2/campaigns/\(campaignID)/members")! components.queryItems = [URLQueryItem(name: "include", value: "currently_entitled_tiers,currently_entitled_tiers.benefits"), URLQueryItem(name: "fields[tier]", value: "title"), URLQueryItem(name: "fields[member]", value: "full_name,patron_status"), URLQueryItem(name: "page[size]", value: "1000")] - - let requestURL = components.url(relativeTo: self.baseURL)! - - struct Response: Decodable - { + + let requestURL = components.url(relativeTo: baseURL)! + + struct Response: Decodable { var data: [PatronResponse] var included: [AnyResponse] var links: [String: URL]? } - + var allPatrons = [Patron]() - - func fetchPatrons(url: URL) - { + + func fetchPatrons(url: URL) { let request = URLRequest(url: url) - - self.send(request, authorizationType: .creator) { (result: Result) in - switch result - { - case .failure(let error): completion(.failure(error)) - case .success(let response): - let tiers = response.included.compactMap { (response) -> Tier? in - switch response - { - case .tier(let tierResponse): return Tier(response: tierResponse) + + send(request, authorizationType: .creator) { (result: Result) in + switch result { + case let .failure(error): completion(.failure(error)) + case let .success(response): + let tiers = response.included.compactMap { response -> Tier? in + switch response { + case let .tier(tierResponse): return Tier(response: tierResponse) case .benefit: return nil } } - - let tiersByIdentifier = Dictionary(tiers.map { ($0.identifier, $0) }, uniquingKeysWith: { (a, b) in return a }) - - let patrons = response.data.map { (response) -> Patron in + + let tiersByIdentifier = Dictionary(tiers.map { ($0.identifier, $0) }, uniquingKeysWith: { a, _ in a }) + + let patrons = response.data.map { response -> Patron in let patron = Patron(response: response) - - for tierID in response.relationships?.currently_entitled_tiers.data ?? [] - { + + for tierID in response.relationships?.currently_entitled_tiers.data ?? [] { guard let tier = tiersByIdentifier[tierID.id] else { continue } patron.benefits.formUnion(tier.benefits) } - + return patron }.filter { $0.benefits.contains(where: { $0.type == .credits }) } - + allPatrons.append(contentsOf: patrons) - - if let nextURL = response.links?["next"] - { + + if let nextURL = response.links?["next"] { fetchPatrons(url: nextURL) - } - else - { + } else { completion(.success(allPatrons)) } } } } - + fetchPatrons(url: requestURL) } - - func signOut(completion: @escaping (Result) -> Void) - { - DatabaseManager.shared.persistentContainer.performBackgroundTask { (context) in - do - { + + func signOut(completion: @escaping (Result) -> Void) { + DatabaseManager.shared.persistentContainer.performBackgroundTask { context in + do { let accounts = PatreonAccount.all(in: context, requestProperties: [\.returnsObjectsAsFaults: true]) accounts.forEach(context.delete(_:)) - + self.deactivateBetaApps(in: context) - + try context.save() - + Keychain.shared.patreonAccessToken = nil Keychain.shared.patreonRefreshToken = nil Keychain.shared.patreonAccountID = nil - + completion(.success(())) - } - catch - { + } catch { completion(.failure(error)) } } } - - func refreshPatreonAccount() - { + + func refreshPatreonAccount() { guard PatreonAPI.shared.isAuthenticated else { return } - + PatreonAPI.shared.fetchAccount { (result: Result) in - do - { + do { let account = try result.get() - + // if let context = account.managedObjectContext, !account.isPatron // { - // Deactivate all beta apps now that we're no longer a patron. - //self.deactivateBetaApps(in: context) + // Deactivate all beta apps now that we're no longer a patron. + // self.deactivateBetaApps(in: context) // } - + try account.managedObjectContext?.save() - } - catch - { + } catch { print("Failed to fetch Patreon account.", error) } } } } -private extension PatreonAPI -{ - func fetchAccessToken(oauthCode: String, completion: @escaping (Result<(String, String), Swift.Error>) -> Void) - { +private extension PatreonAPI { + func fetchAccessToken(oauthCode: String, completion: @escaping (Result<(String, String), Swift.Error>) -> Void) { let encodedRedirectURI = ("https://rileytestut.com/patreon/altstore" as NSString).addingPercentEncoding(withAllowedCharacters: .alphanumerics)! let encodedOauthCode = (oauthCode as NSString).addingPercentEncoding(withAllowedCharacters: .alphanumerics)! - + let body = "code=\(encodedOauthCode)&grant_type=authorization_code&client_id=\(clientID)&client_secret=\(clientSecret)&redirect_uri=\(encodedRedirectURI)" - - let requestURL = URL(string: "/api/oauth2/token", relativeTo: self.baseURL)! - + + let requestURL = URL(string: "/api/oauth2/token", relativeTo: baseURL)! + var request = URLRequest(url: requestURL) request.httpMethod = "POST" request.httpBody = body.data(using: .utf8) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") - - struct Response: Decodable - { + + struct Response: Decodable { var access_token: String var refresh_token: String } - - self.send(request, authorizationType: .none) { (result: Result) in - switch result - { - case .failure(let error): completion(.failure(error)) - case .success(let response): completion(.success((response.access_token, response.refresh_token))) + + send(request, authorizationType: .none) { (result: Result) in + switch result { + case let .failure(error): completion(.failure(error)) + case let .success(response): completion(.success((response.access_token, response.refresh_token))) } } } - - func refreshAccessToken(completion: @escaping (Result) -> Void) - { + + func refreshAccessToken(completion: @escaping (Result) -> Void) { guard let refreshToken = Keychain.shared.patreonRefreshToken else { return } - + var components = URLComponents(string: "/api/oauth2/token")! components.queryItems = [URLQueryItem(name: "grant_type", value: "refresh_token"), URLQueryItem(name: "refresh_token", value: refreshToken), URLQueryItem(name: "client_id", value: clientID), URLQueryItem(name: "client_secret", value: clientSecret)] - - let requestURL = components.url(relativeTo: self.baseURL)! - + + let requestURL = components.url(relativeTo: baseURL)! + var request = URLRequest(url: requestURL) request.httpMethod = "POST" - - struct Response: Decodable - { + + struct Response: Decodable { var access_token: String var refresh_token: String } - - self.send(request, authorizationType: .none) { (result: Result) in - switch result - { - case .failure(let error): completion(.failure(error)) - case .success(let response): + + send(request, authorizationType: .none) { (result: Result) in + switch result { + case let .failure(error): completion(.failure(error)) + case let .success(response): Keychain.shared.patreonAccessToken = response.access_token Keychain.shared.patreonRefreshToken = response.refresh_token - + completion(.success(())) } } } - - func send(_ request: URLRequest, authorizationType: AuthorizationType, completion: @escaping (Result) -> Void) - { + + func send(_ request: URLRequest, authorizationType: AuthorizationType, completion: @escaping (Result) -> Void) { var request = request - - switch authorizationType - { + + switch authorizationType { case .none: break case .creator: guard let creatorAccessToken = Keychain.shared.patreonCreatorAccessToken else { return completion(.failure(Error.invalidAccessToken)) } request.setValue("Bearer " + creatorAccessToken, forHTTPHeaderField: "Authorization") - + case .user: guard let accessToken = Keychain.shared.patreonAccessToken else { return completion(.failure(Error.notAuthenticated)) } request.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization") } - - let task = self.session.dataTask(with: request) { (data, response, error) in - do - { + + let task = session.dataTask(with: request) { data, response, error in + do { let data = try Result(data, error).get() - - if let response = response as? HTTPURLResponse, response.statusCode == 401 - { - switch authorizationType - { + + if let response = response as? HTTPURLResponse, response.statusCode == 401 { + switch authorizationType { case .creator: completion(.failure(Error.invalidAccessToken)) case .none: completion(.failure(Error.notAuthenticated)) case .user: - self.refreshAccessToken() { (result) in - switch result - { - case .failure(let error): completion(.failure(error)) + self.refreshAccessToken { result in + switch result { + case let .failure(error): completion(.failure(error)) case .success: self.send(request, authorizationType: authorizationType, completion: completion) } } } - + return } - + let response = try JSONDecoder().decode(ResponseType.self, from: data) completion(.success(response)) - } - catch let error - { + } catch { completion(.failure(error)) } } - + task.resume() } - - func deactivateBetaApps(in context: NSManagedObjectContext) - { + + func deactivateBetaApps(in context: NSManagedObjectContext) { let predicate = NSPredicate(format: "%K != %@ AND %K != nil AND %K == YES", #keyPath(InstalledApp.bundleIdentifier), StoreApp.altstoreAppID, #keyPath(InstalledApp.storeApp), #keyPath(InstalledApp.storeApp.isBeta)) - + let installedApps = InstalledApp.all(satisfying: predicate, in: context) installedApps.forEach { $0.isActive = false } } } @available(iOS 13.0, *) -extension PatreonAPI: ASWebAuthenticationPresentationContextProviding -{ - public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor - { - return UIApplication.alt_shared?.keyWindow ?? UIWindow() +extension PatreonAPI: ASWebAuthenticationPresentationContextProviding { + public func presentationAnchor(for _: ASWebAuthenticationSession) -> ASPresentationAnchor { + UIApplication.alt_shared?.keyWindow ?? UIWindow() } } diff --git a/AltStoreCore/Patreon/Patron.swift b/Sources/SideStoreCore/Patreon/Patron.swift similarity index 54% rename from AltStoreCore/Patreon/Patron.swift rename to Sources/SideStoreCore/Patreon/Patron.swift index d716b86c..eee5cc75 100644 --- a/AltStoreCore/Patreon/Patron.swift +++ b/Sources/SideStoreCore/Patreon/Patron.swift @@ -8,71 +8,58 @@ import Foundation -extension PatreonAPI -{ - struct PatronResponse: Decodable - { - struct Attributes: Decodable - { +extension PatreonAPI { + struct PatronResponse: Decodable { + struct Attributes: Decodable { var full_name: String var patron_status: String? } - - struct Relationships: Decodable - { - struct Tiers: Decodable - { - struct TierID: Decodable - { + + struct Relationships: Decodable { + struct Tiers: Decodable { + struct TierID: Decodable { var id: String var type: String } - + var data: [TierID] } - + var currently_entitled_tiers: Tiers } - + var id: String var attributes: Attributes - + var relationships: Relationships? } } -extension Patron -{ - public enum Status: String, Decodable - { +public extension Patron { + enum Status: String, Decodable { case active = "active_patron" case declined = "declined_patron" case former = "former_patron" - case unknown = "unknown" + case unknown } } -public class Patron -{ +public class Patron { public var name: String public var identifier: String - + public var status: Status - + public var benefits: Set = [] - - init(response: PatreonAPI.PatronResponse) - { - self.name = response.attributes.full_name - self.identifier = response.id - - if let status = response.attributes.patron_status - { + + init(response: PatreonAPI.PatronResponse) { + name = response.attributes.full_name + identifier = response.id + + if let status = response.attributes.patron_status { self.status = Status(rawValue: status) ?? .unknown - } - else - { - self.status = .unknown + } else { + status = .unknown } } } diff --git a/Sources/SideStoreCore/Patreon/Tier.swift b/Sources/SideStoreCore/Patreon/Tier.swift new file mode 100644 index 00000000..0048a1fd --- /dev/null +++ b/Sources/SideStoreCore/Patreon/Tier.swift @@ -0,0 +1,43 @@ +// +// Tier.swift +// AltStore +// +// Created by Riley Testut on 8/21/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import Foundation + +extension PatreonAPI { + struct TierResponse: Decodable { + struct Attributes: Decodable { + var title: String + } + + struct Relationships: Decodable { + struct Benefits: Decodable { + var data: [BenefitResponse] + } + + var benefits: Benefits + } + + var id: String + var attributes: Attributes + + var relationships: Relationships + } +} + +public struct Tier { + public var name: String + public var identifier: String + + public var benefits: [Benefit] = [] + + init(response: PatreonAPI.TierResponse) { + name = response.attributes.title + identifier = response.id + benefits = response.relationships.benefits.data.compactMap(Benefit.init(response:)) + } +} diff --git a/AltStoreCore/Protocols/AppProtocol.swift b/Sources/SideStoreCore/Protocols/AppProtocol.swift similarity index 69% rename from AltStoreCore/Protocols/AppProtocol.swift rename to Sources/SideStoreCore/Protocols/AppProtocol.swift index cd76b785..2b46ed7d 100644 --- a/AltStoreCore/Protocols/AppProtocol.swift +++ b/Sources/SideStoreCore/Protocols/AppProtocol.swift @@ -6,47 +6,41 @@ // Copyright © 2019 Riley Testut. All rights reserved. // -import Foundation import AltSign +import Foundation -public protocol AppProtocol -{ +public protocol AppProtocol { var name: String { get } var bundleIdentifier: String { get } var url: URL? { get } } -public struct AnyApp: AppProtocol -{ +public struct AnyApp: AppProtocol { public var name: String public var bundleIdentifier: String public var url: URL? - - public init(name: String, bundleIdentifier: String, url: URL?) - { + + public init(name: String, bundleIdentifier: String, url: URL?) { self.name = name self.bundleIdentifier = bundleIdentifier self.url = url } } -extension ALTApplication: AppProtocol -{ +extension ALTApplication: AppProtocol { public var url: URL? { - return self.fileURL + fileURL } } -extension StoreApp: AppProtocol -{ +extension StoreApp: AppProtocol { public var url: URL? { - return self.downloadURL + downloadURL } } -extension InstalledApp: AppProtocol -{ +extension InstalledApp: AppProtocol { public var url: URL? { - return self.fileURL + fileURL } } diff --git a/AltStoreCore/Protocols/Fetchable.swift b/Sources/SideStoreCore/Protocols/Fetchable.swift similarity index 78% rename from AltStoreCore/Protocols/Fetchable.swift rename to Sources/SideStoreCore/Protocols/Fetchable.swift index 686d1f85..43f1f002 100644 --- a/AltStoreCore/Protocols/Fetchable.swift +++ b/Sources/SideStoreCore/Protocols/Fetchable.swift @@ -10,69 +10,54 @@ import CoreData public typealias FetchRequest = NSFetchRequest -public protocol Fetchable: NSManagedObject -{ -} +public protocol Fetchable: NSManagedObject {} -public extension Fetchable -{ +public extension Fetchable { static func first(satisfying predicate: NSPredicate? = nil, sortedBy sortDescriptors: [NSSortDescriptor]? = nil, in context: NSManagedObjectContext, - requestProperties: [PartialKeyPath: Any?] = [:]) -> Self? - { + requestProperties: [PartialKeyPath: Any?] = [:]) -> Self? { let managedObjects = Self.all(satisfying: predicate, sortedBy: sortDescriptors, in: context, requestProperties: requestProperties, returnFirstResult: true) return managedObjects.first } - + static func all(satisfying predicate: NSPredicate? = nil, sortedBy sortDescriptors: [NSSortDescriptor]? = nil, in context: NSManagedObjectContext, - requestProperties: [PartialKeyPath: Any?] = [:]) -> [Self] - { + requestProperties: [PartialKeyPath: Any?] = [:]) -> [Self] { let managedObjects = Self.all(satisfying: predicate, sortedBy: sortDescriptors, in: context, requestProperties: requestProperties, returnFirstResult: false) return managedObjects } - - static func fetch(_ fetchRequest: NSFetchRequest, in context: NSManagedObjectContext) -> [Self] - { - do - { + + static func fetch(_ fetchRequest: NSFetchRequest, in context: NSManagedObjectContext) -> [Self] { + do { let managedObjects = try context.fetch(fetchRequest) return managedObjects - } - catch - { + } catch { print("Failed to fetch managed objects. Fetch Request: \(fetchRequest). Error: \(error).") return [] } } - - private static func all(satisfying predicate: NSPredicate? = nil, sortedBy sortDescriptors: [NSSortDescriptor]? = nil, in context: NSManagedObjectContext, requestProperties: [PartialKeyPath: Any?], returnFirstResult: Bool) -> [Self] - { - let registeredObjects = context.registeredObjects.lazy.compactMap({ $0 as? Self }).filter({ predicate?.evaluate(with: $0) != false }) - - if let managedObject = registeredObjects.first, returnFirstResult - { + + private static func all(satisfying predicate: NSPredicate? = nil, sortedBy sortDescriptors: [NSSortDescriptor]? = nil, in context: NSManagedObjectContext, requestProperties: [PartialKeyPath: Any?], returnFirstResult: Bool) -> [Self] { + let registeredObjects = context.registeredObjects.lazy.compactMap { $0 as? Self }.filter { predicate?.evaluate(with: $0) != false } + + if let managedObject = registeredObjects.first, returnFirstResult { return [managedObject] } - + let fetchRequest = self.fetchRequest() as! NSFetchRequest fetchRequest.predicate = predicate fetchRequest.sortDescriptors = sortDescriptors fetchRequest.returnsObjectsAsFaults = false - - for (keyPath, value) in requestProperties - { + + for (keyPath, value) in requestProperties { // Still no easy way to cast PartialKeyPath back to usable WritableKeyPath :( guard let objcKeyString = keyPath._kvcKeyPathString else { continue } fetchRequest.setValue(value, forKey: objcKeyString) } - - let fetchedObjects = self.fetch(fetchRequest, in: context) - - if let fetchedObject = fetchedObjects.first, returnFirstResult - { + + let fetchedObjects = fetch(fetchRequest, in: context) + + if let fetchedObject = fetchedObjects.first, returnFirstResult { return [fetchedObject] - } - else - { + } else { return fetchedObjects } } diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/.xccurrentversion b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/.xccurrentversion similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/.xccurrentversion rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/.xccurrentversion diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 11.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 11.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 11.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 11.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 2.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 2.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 2.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 2.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 3.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 3.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 3.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 3.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 4.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 4.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 4.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 4.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 5.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 5.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 5.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 5.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 6.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 6.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 6.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 6.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 7.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 7.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 7.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 7.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 8.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 8.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 8.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 8.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 9.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 9.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 9.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore 9.xcdatamodel/contents diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore.xcdatamodel/contents b/Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore.xcdatamodel/contents similarity index 100% rename from AltStoreCore/Model/AltStore.xcdatamodeld/AltStore.xcdatamodel/contents rename to Sources/SideStoreCore/Resources/AltStore.xcdatamodeld/AltStore.xcdatamodel/contents diff --git a/AltWidget/Assets.xcassets/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/DeltaPrimary.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/DeltaPrimary.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/DeltaPrimary.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/DeltaPrimary.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/Pink.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/Pink.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/Pink.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/Pink.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/Primary.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/Primary.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/Primary.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/Primary.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/RefreshGreen.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/RefreshGreen.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/RefreshGreen.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/RefreshGreen.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/RefreshOrange.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/RefreshOrange.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/RefreshOrange.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/RefreshOrange.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/RefreshRed.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/RefreshRed.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/RefreshRed.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/RefreshRed.colorset/Contents.json diff --git a/AltStoreCore/Resources/Colors.xcassets/RefreshYellow.colorset/Contents.json b/Sources/SideStoreCore/Resources/Colors.xcassets/RefreshYellow.colorset/Contents.json similarity index 100% rename from AltStoreCore/Resources/Colors.xcassets/RefreshYellow.colorset/Contents.json rename to Sources/SideStoreCore/Resources/Colors.xcassets/RefreshYellow.colorset/Contents.json diff --git a/AltStoreCore/Info.plist b/Sources/SideStoreCore/Resources/Info.plist similarity index 100% rename from AltStoreCore/Info.plist rename to Sources/SideStoreCore/Resources/Info.plist diff --git a/AltStoreCore/Intents/ViewApp.intentdefinition b/Sources/SideStoreCore/Resources/Intents/ViewApp.intentdefinition similarity index 100% rename from AltStoreCore/Intents/ViewApp.intentdefinition rename to Sources/SideStoreCore/Resources/Intents/ViewApp.intentdefinition diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore10ToAltStore11.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore10ToAltStore11.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore10ToAltStore11.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore10ToAltStore11.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore2ToAltStore3.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore2ToAltStore3.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore2ToAltStore3.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore2ToAltStore3.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore3ToAltStore4.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore3ToAltStore4.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore3ToAltStore4.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore3ToAltStore4.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore4ToAltStore5.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore4ToAltStore5.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore4ToAltStore5.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore4ToAltStore5.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore5ToAltStore6.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore5ToAltStore6.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore5ToAltStore6.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore5ToAltStore6.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore6ToAltStore7.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore6ToAltStore7.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore6ToAltStore7.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore6ToAltStore7.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore8ToAltStore9.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore8ToAltStore9.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore8ToAltStore9.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore8ToAltStore9.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStore9ToAltStore10.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore9ToAltStore10.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStore9ToAltStore10.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStore9ToAltStore10.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Mapping Models/AltStoreToAltStore2.xcmappingmodel/xcmapping.xml b/Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStoreToAltStore2.xcmappingmodel/xcmapping.xml similarity index 100% rename from AltStoreCore/Model/Migrations/Mapping Models/AltStoreToAltStore2.xcmappingmodel/xcmapping.xml rename to Sources/SideStoreCore/Resources/Migrations/Mapping Models/AltStoreToAltStore2.xcmappingmodel/xcmapping.xml diff --git a/AltStoreCore/Model/Migrations/Policies/InstalledAppPolicy.swift b/Sources/SideStoreCore/Resources/Migrations/Policies/InstalledAppPolicy.swift similarity index 84% rename from AltStoreCore/Model/Migrations/Policies/InstalledAppPolicy.swift rename to Sources/SideStoreCore/Resources/Migrations/Policies/InstalledAppPolicy.swift index 880ae8fe..54bbd525 100644 --- a/AltStoreCore/Model/Migrations/Policies/InstalledAppPolicy.swift +++ b/Sources/SideStoreCore/Resources/Migrations/Policies/InstalledAppPolicy.swift @@ -6,53 +6,45 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import CoreData import AltSign +import CoreData @objc(InstalledAppToInstalledAppMigrationPolicy) -class InstalledAppToInstalledAppMigrationPolicy: NSEntityMigrationPolicy -{ - override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws - { +class InstalledAppToInstalledAppMigrationPolicy: NSEntityMigrationPolicy { + override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager) - + // Entity must be in manager.destinationContext. let entity = NSEntityDescription.entity(forEntityName: "Team", in: manager.destinationContext) - + let fetchRequest = NSFetchRequest() fetchRequest.entity = entity fetchRequest.predicate = NSPredicate(format: "%K == YES", #keyPath(Team.isActiveTeam)) - + let teams = try manager.destinationContext.fetch(fetchRequest) - + // Cannot use NSManagedObject subclasses during migration, so fallback to using KVC instead. dInstance.setValue(teams.first, forKey: #keyPath(InstalledApp.team)) } - + @objc(defaultIsActiveForBundleID:team:) - func defaultIsActive(for bundleID: String, team: NSManagedObject?) -> NSNumber - { + func defaultIsActive(for bundleID: String, team: NSManagedObject?) -> NSNumber { let isActive: Bool - + let activeAppsMinimumVersion = OperatingSystemVersion(majorVersion: 13, minorVersion: 3, patchVersion: 1) - if !ProcessInfo.processInfo.isOperatingSystemAtLeast(activeAppsMinimumVersion) - { + if !ProcessInfo.processInfo.isOperatingSystemAtLeast(activeAppsMinimumVersion) { isActive = true - } - else if let team = team, let type = team.value(forKey: #keyPath(Team.type)) as? Int16, type != ALTTeamType.free.rawValue - { + } else if let team = team, let type = team.value(forKey: #keyPath(Team.type)) as? Int16, type != ALTTeamType.free.rawValue { isActive = true - } - else - { + } else { // AltStore should always be active, but deactivate all other apps. isActive = (bundleID == StoreApp.altstoreAppID) - + // We can assume there is an active app limit, // but will confirm next time user authenticates. UserDefaults.standard.activeAppsLimit = ALTActiveAppsLimit } - + return NSNumber(value: isActive) } } diff --git a/AltStoreCore/Model/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift b/Sources/SideStoreCore/Resources/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift similarity index 76% rename from AltStoreCore/Model/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift rename to Sources/SideStoreCore/Resources/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift index ead50098..f6a0c4d9 100644 --- a/AltStoreCore/Model/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift +++ b/Sources/SideStoreCore/Resources/Migrations/Policies/StoreApp10ToStoreApp11Policy.swift @@ -9,51 +9,49 @@ import CoreData // Can't use NSManagedObject subclasses, so add convenience accessors for KVC. -fileprivate extension NSManagedObject -{ +private extension NSManagedObject { var storeAppBundleID: String? { - let bundleID = self.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String + let bundleID = value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String return bundleID } - + var storeAppSourceID: String? { - let sourceID = self.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String + let sourceID = value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String return sourceID } - + var storeAppVersion: String? { - let version = self.value(forKey: #keyPath(StoreApp._version)) as? String + let version = value(forKey: #keyPath(StoreApp._version)) as? String return version } - + var storeAppVersionDate: Date? { - let versionDate = self.value(forKey: #keyPath(StoreApp._versionDate)) as? Date + let versionDate = value(forKey: #keyPath(StoreApp._versionDate)) as? Date return versionDate } - + var storeAppVersionDescription: String? { - let versionDescription = self.value(forKey: #keyPath(StoreApp._versionDescription)) as? String + let versionDescription = value(forKey: #keyPath(StoreApp._versionDescription)) as? String return versionDescription } - + var storeAppSize: NSNumber? { - let size = self.value(forKey: #keyPath(StoreApp._size)) as? NSNumber + let size = value(forKey: #keyPath(StoreApp._size)) as? NSNumber return size } - + var storeAppDownloadURL: URL? { - let downloadURL = self.value(forKey: #keyPath(StoreApp._downloadURL)) as? URL + let downloadURL = value(forKey: #keyPath(StoreApp._downloadURL)) as? URL return downloadURL } - - func setStoreAppLatestVersion(_ appVersion: NSManagedObject) - { - self.setValue(appVersion, forKey: #keyPath(StoreApp.latestVersion)) - + + func setStoreAppLatestVersion(_ appVersion: NSManagedObject) { + setValue(appVersion, forKey: #keyPath(StoreApp.latestVersion)) + let versions = NSOrderedSet(array: [appVersion]) - self.setValue(versions, forKey: #keyPath(StoreApp._versions)) + setValue(versions, forKey: #keyPath(StoreApp._versions)) } - + class func makeAppVersion(version: String, date: Date, localizedDescription: String?, @@ -61,8 +59,7 @@ fileprivate extension NSManagedObject size: Int64, appBundleID: String, sourceID: String, - in context: NSManagedObjectContext) -> NSManagedObject - { + in context: NSManagedObjectContext) -> NSManagedObject { let appVersion = NSEntityDescription.insertNewObject(forEntityName: AppVersion.entity().name!, into: context) appVersion.setValue(version, forKey: #keyPath(AppVersion.version)) appVersion.setValue(date, forKey: #keyPath(AppVersion.date)) @@ -76,12 +73,10 @@ fileprivate extension NSManagedObject } @objc(StoreApp10ToStoreApp11Policy) -class StoreApp10ToStoreApp11Policy: NSEntityMigrationPolicy -{ - override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws - { +class StoreApp10ToStoreApp11Policy: NSEntityMigrationPolicy { + override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager) - + guard let appBundleID = sInstance.storeAppBundleID, let sourceID = sInstance.storeAppSourceID, let version = sInstance.storeAppVersion, @@ -90,12 +85,12 @@ class StoreApp10ToStoreApp11Policy: NSEntityMigrationPolicy let downloadURL = sInstance.storeAppDownloadURL, let size = sInstance.storeAppSize as? Int64 else { return } - + guard let destinationStoreApp = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first, let context = destinationStoreApp.managedObjectContext else { fatalError("A destination StoreApp and its managedObjectContext must exist.") } - + let appVersion = NSManagedObject.makeAppVersion( version: version, date: versionDate, @@ -104,8 +99,9 @@ class StoreApp10ToStoreApp11Policy: NSEntityMigrationPolicy size: Int64(size), appBundleID: appBundleID, sourceID: sourceID, - in: context) - + in: context + ) + destinationStoreApp.setStoreAppLatestVersion(appVersion) } } diff --git a/AltStoreCore/Model/Migrations/Policies/StoreAppPolicy.swift b/Sources/SideStoreCore/Resources/Migrations/Policies/StoreAppPolicy.swift similarity index 64% rename from AltStoreCore/Model/Migrations/Policies/StoreAppPolicy.swift rename to Sources/SideStoreCore/Resources/Migrations/Policies/StoreAppPolicy.swift index 3cf90c5c..3f5e46ce 100644 --- a/AltStoreCore/Model/Migrations/Policies/StoreAppPolicy.swift +++ b/Sources/SideStoreCore/Resources/Migrations/Policies/StoreAppPolicy.swift @@ -9,17 +9,14 @@ import CoreData @objc(StoreAppToStoreAppMigrationPolicy) -class StoreAppToStoreAppMigrationPolicy: NSEntityMigrationPolicy -{ +class StoreAppToStoreAppMigrationPolicy: NSEntityMigrationPolicy { @objc(migrateIconURL) - func migrateIconURL() -> URL - { - return URL(string: "https://via.placeholder.com/150")! + func migrateIconURL() -> URL { + URL(string: "https://via.placeholder.com/150")! } - + @objc(migrateScreenshotURLs) - func migrateScreenshotURLs() -> NSCopying - { - return [] as NSArray + func migrateScreenshotURLs() -> NSCopying { + [] as NSArray } } diff --git a/Sources/SideStoreCore/Types/ALTAppPermission.swift b/Sources/SideStoreCore/Types/ALTAppPermission.swift new file mode 100644 index 00000000..b94a8357 --- /dev/null +++ b/Sources/SideStoreCore/Types/ALTAppPermission.swift @@ -0,0 +1,69 @@ +// +// ALTAppPermission.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2923 Joseph Mattiello. All rights reserved. +// + +import Foundation + +@objc +public enum ALTAppPermissionType: Int, CaseIterable { + case photos + case camera + case location + case contacts + case reminders + case appleMusic = 6 + case microphone + case speechRecognition + case backgroundAudio + case backgroundFetch + case bluetooth + case network + case calendars + case touchID + case faceID + case siri + case motion + + public var stringValue: String { + switch self { + case .photos: + return "photos" + case .camera: + return "camera" + case .location: + return "location" + case .contacts: + return "contacts" + case .reminders: + return "reminders" + case .appleMusic: + return "music" + case .microphone: + return "microphone" + case .speechRecognition: + return "speech-recognition" + case .backgroundAudio: + return "background-audio" + case .backgroundFetch: + return "background-fetch" + case .bluetooth: + return "bluetooth" + case .network: + return "network" + case .calendars: + return "calendars" + case .touchID: + return "touchid" + case .faceID: + return "faceid" + case .siri: + return "siri" + case .motion: + return "motion" + } + } +} diff --git a/Sources/SideStoreCore/Types/ALTSourceUserInfoKey.swift b/Sources/SideStoreCore/Types/ALTSourceUserInfoKey.swift new file mode 100644 index 00000000..7b885b07 --- /dev/null +++ b/Sources/SideStoreCore/Types/ALTSourceUserInfoKey.swift @@ -0,0 +1,21 @@ +// +// ALTSourceUserInfoKey.swift +// SideStore +// +// Created by Joseph Mattiello on 02/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import Foundation + +@objc +public enum ALTSourceUserInfoKey: Int, CaseIterable { + case patreonAccessToken + + public var stringValue: String { + switch self { + case .patreonAccessToken: + return "patreonAccessToken" + } + } +} diff --git a/AltWidget/AltWidget.swift b/Sources/SideWidget/AltWidget.swift similarity index 72% rename from AltWidget/AltWidget.swift rename to Sources/SideWidget/AltWidget.swift index 29d6a526..e5328b71 100644 --- a/AltWidget/AltWidget.swift +++ b/Sources/SideWidget/AltWidget.swift @@ -6,150 +6,133 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import SwiftUI -import WidgetKit -import UIKit import CoreData +import SwiftUI +import UIKit +import WidgetKit -import AltStoreCore import AltSign +import SideStoreCore import RoxasUIKit -struct AppEntry: TimelineEntry -{ +struct AppEntry: TimelineEntry { var date: Date var relevance: TimelineEntryRelevance? - + var app: AppSnapshot? var isPlaceholder: Bool = false } -struct AppSnapshot -{ +struct AppSnapshot { var name: String var bundleIdentifier: String var expirationDate: Date var refreshedDate: Date - + var tintColor: UIColor? var icon: UIImage? } -extension AppSnapshot -{ +extension AppSnapshot { // Declared in extension so we retain synthesized initializer. - init(installedApp: InstalledApp) - { - self.name = installedApp.name - self.bundleIdentifier = installedApp.bundleIdentifier - self.expirationDate = installedApp.expirationDate - self.refreshedDate = installedApp.refreshedDate - - self.tintColor = installedApp.storeApp?.tintColor - + init(installedApp: InstalledApp) { + name = installedApp.name + bundleIdentifier = installedApp.bundleIdentifier + expirationDate = installedApp.expirationDate + refreshedDate = installedApp.refreshedDate + + tintColor = installedApp.storeApp?.tintColor + let application = ALTApplication(fileURL: installedApp.fileURL) - self.icon = application?.icon?.resizing(toFill: CGSize(width: 180, height: 180)) + icon = application?.icon?.resizing(toFill: CGSize(width: 180, height: 180)) } } -struct Provider: IntentTimelineProvider -{ +struct Provider: IntentTimelineProvider { typealias Intent = ViewAppIntent typealias Entry = AppEntry - - func placeholder(in context: Context) -> AppEntry - { - return AppEntry(date: Date(), app: nil, isPlaceholder: true) + + func placeholder(in _: Context) -> AppEntry { + AppEntry(date: Date(), app: nil, isPlaceholder: true) } - - func getSnapshot(for configuration: ViewAppIntent, in context: Context, completion: @escaping (AppEntry) -> Void) - { - self.prepare { (result) in - do - { + + func getSnapshot(for _: ViewAppIntent, in _: Context, completion: @escaping (AppEntry) -> Void) { + prepare { result in + do { let context = try result.get() let snapshot = InstalledApp.fetchAltStore(in: context).map(AppSnapshot.init) let entry = AppEntry(date: Date(), app: snapshot) completion(entry) - } - catch - { + } catch { print("Error preparing widget snapshot:", error) - + let entry = AppEntry(date: Date(), app: nil) completion(entry) } } } - - func getTimeline(for configuration: ViewAppIntent, in context: Context, completion: @escaping (Timeline) -> Void) { - self.prepare { (result) in + + func getTimeline(for configuration: ViewAppIntent, in _: Context, completion: @escaping (Timeline) -> Void) { + prepare { result in autoreleasepool { - do - { + do { let context = try result.get() - + let installedApp: InstalledApp? - - if let identifier = configuration.app?.identifier - { + + if let identifier = configuration.app?.identifier { let app = InstalledApp.first(satisfying: NSPredicate(format: "%K == %@", #keyPath(InstalledApp.bundleIdentifier), identifier), in: context) installedApp = app - } - else - { + } else { installedApp = InstalledApp.fetchAltStore(in: context) } - + guard let snapshot = installedApp.map(AppSnapshot.init) else { throw ALTError(.invalidApp) } - + let currentDate = Calendar.current.startOfDay(for: Date()) let numberOfDays = snapshot.expirationDate.numberOfCalendarDays(since: currentDate) - + // Generate a timeline consisting of one entry per day. var entries: [AppEntry] = [] - - switch numberOfDays - { + + switch numberOfDays { case ..<0: let entry = AppEntry(date: currentDate, relevance: TimelineEntryRelevance(score: 0.0), app: snapshot) entries.append(entry) - + case 0: let entry = AppEntry(date: currentDate, relevance: TimelineEntryRelevance(score: 1.0), app: snapshot) entries.append(entry) - + default: // To reduce memory consumption, we only generate entries for the next week. This includes: // * 1 for each day the app is valid (up to 7) // * 1 "0 days remaining" // * 1 "Expired" let numberOfEntries = min(numberOfDays, 7) + 2 - - let appEntries = (0 ..< numberOfEntries).map { (dayOffset) -> AppEntry in + + let appEntries = (0 ..< numberOfEntries).map { dayOffset -> AppEntry in let entryDate = Calendar.current.date(byAdding: .day, value: dayOffset, to: currentDate) ?? currentDate.addingTimeInterval(Double(dayOffset) * 60 * 60 * 24) - + let daysSinceRefresh = entryDate.numberOfCalendarDays(since: snapshot.refreshedDate) let totalNumberOfDays = snapshot.expirationDate.numberOfCalendarDays(since: snapshot.refreshedDate) - + let score = (entryDate <= snapshot.expirationDate) ? Float(daysSinceRefresh + 1) / Float(totalNumberOfDays + 1) : 0 // Expired apps have a score of 0. let entry = AppEntry(date: entryDate, relevance: TimelineEntryRelevance(score: score), app: snapshot) return entry } - + entries.append(contentsOf: appEntries) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) - } - catch - { + } catch { print("Error preparing widget timeline:", error) - + let entry = AppEntry(date: Date(), app: nil) let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) @@ -157,16 +140,12 @@ struct Provider: IntentTimelineProvider } } } - - private func prepare(completion: @escaping (Result) -> Void) - { - DatabaseManager.shared.start { (error) in - if let error = error - { + + private func prepare(completion: @escaping (Result) -> Void) { + DatabaseManager.shared.start { error in + if let error = error { completion(.failure(error)) - } - else - { + } else { DatabaseManager.shared.viewContext.perform { completion(.success(DatabaseManager.shared.viewContext)) } @@ -175,14 +154,13 @@ struct Provider: IntentTimelineProvider } } -struct HomeScreenWidget: Widget -{ +struct HomeScreenWidget: Widget { private let kind: String = "AppDetail" - + public var body: some WidgetConfiguration { - return IntentConfiguration(kind: kind, - intent: ViewAppIntent.self, - provider: Provider()) { (entry) in + IntentConfiguration(kind: kind, + intent: ViewAppIntent.self, + provider: Provider()) { entry in WidgetView(entry: entry) } .supportedFamilies([.systemSmall]) @@ -191,56 +169,49 @@ struct HomeScreenWidget: Widget } } -struct TextLockScreenWidget: Widget -{ +struct TextLockScreenWidget: Widget { private let kind: String = "TextLockAppDetail" - + public var body: some WidgetConfiguration { - if #available(iOSApplicationExtension 16, *) - { + if #available(iOSApplicationExtension 16, *) { return IntentConfiguration(kind: kind, intent: ViewAppIntent.self, - provider: Provider()) { (entry) in + provider: Provider()) { entry in ComplicationView(entry: entry, style: .text) } .supportedFamilies([.accessoryCircular]) .configurationDisplayName("AltWidget (Text)") .description("View remaining days until SideStore expires.") - } - else - { + } else { return EmptyWidgetConfiguration() } } } -struct IconLockScreenWidget: Widget -{ +struct IconLockScreenWidget: Widget { private let kind: String = "IconLockAppDetail" - + public var body: some WidgetConfiguration { - if #available(iOSApplicationExtension 16, *) - { + if #available(iOSApplicationExtension 16, *) { return IntentConfiguration(kind: kind, intent: ViewAppIntent.self, - provider: Provider()) { (entry) in + provider: Provider()) { entry in ComplicationView(entry: entry, style: .icon) } .supportedFamilies([.accessoryCircular]) .configurationDisplayName("AltWidget (Icon)") .description("View remaining days until SideStore expires.") - } - else - { + } else { return EmptyWidgetConfiguration() } } } + // -//struct LockScreenWidget: Widget -//{ +// struct LockScreenWidget: Widget +// { // private let kind: String = "LockAppDetail" -// +// // public var body: some WidgetConfiguration { // if #available(iOSApplicationExtension 16, *) // { @@ -258,11 +229,10 @@ struct IconLockScreenWidget: Widget // return EmptyWidgetConfiguration() // } // } -//} +// } @main -struct AltWidgets: WidgetBundle -{ +struct AltWidgets: WidgetBundle { var body: some Widget { HomeScreenWidget() IconLockScreenWidget() diff --git a/AltWidget/ComplicationView.swift b/Sources/SideWidget/ComplicationView.swift similarity index 76% rename from AltWidget/ComplicationView.swift rename to Sources/SideWidget/ComplicationView.swift index 98142c41..3731ec97 100644 --- a/AltWidget/ComplicationView.swift +++ b/Sources/SideWidget/ComplicationView.swift @@ -10,52 +10,45 @@ import SwiftUI import WidgetKit @available(iOS 16, *) -extension ComplicationView -{ - enum Style - { +extension ComplicationView { + enum Style { case text case icon } } @available(iOS 16, *) -struct ComplicationView: View -{ +struct ComplicationView: View { let entry: AppEntry let style: Style - + var body: some View { let refreshedDate = self.entry.app?.refreshedDate ?? .now let expirationDate = self.entry.app?.expirationDate ?? .now - + let totalDays = expirationDate.numberOfCalendarDays(since: refreshedDate) let daysRemaining = expirationDate.numberOfCalendarDays(since: self.entry.date) - + let progress = Double(daysRemaining) / Double(totalDays) - + Gauge(value: progress) { - if daysRemaining < 0 - { + if daysRemaining < 0 { Text("Expired") .font(.system(size: 10, weight: .bold)) - } - else - { - switch self.style - { + } else { + switch self.style { case .text: VStack(spacing: -1) { let fontSize = daysRemaining > 99 ? 18.0 : 20.0 Text("\(daysRemaining)") .font(.system(size: fontSize, weight: .bold, design: .rounded)) - + Text(daysRemaining == 1 ? "DAY" : "DAYS") .font(.caption) } .fixedSize() .offset(y: -1) - + case .icon: ZStack { // Destination @@ -63,17 +56,17 @@ struct ComplicationView: View .resizable() .aspectRatio(1.0, contentMode: .fill) .scaleEffect(x: 0.8, y: 0.8) - + // Source ( daysRemaining > 7 ? - Text("7+") + Text("7+") .font(.system(size: 18, weight: .bold, design: .rounded)) .kerning(-2) : - - Text("\(daysRemaining)") + + Text("\(daysRemaining)") .font(.system(size: 20, weight: .bold, design: .rounded)) - ) + ) .foregroundColor(Color.black) .blendMode(.destinationOut) // Clip text out of image. } @@ -90,44 +83,44 @@ struct ComplicationView_Previews: PreviewProvider { static var previews: some View { let shortRefreshedDate = Calendar.current.date(byAdding: .day, value: -2, to: Date()) ?? Date() let shortExpirationDate = Calendar.current.date(byAdding: .day, value: 7, to: shortRefreshedDate) ?? Date() - + let longRefreshedDate = Calendar.current.date(byAdding: .day, value: -100, to: Date()) ?? Date() let longExpirationDate = Calendar.current.date(byAdding: .day, value: 365, to: longRefreshedDate) ?? Date() - + let expiredDate = shortExpirationDate.addingTimeInterval(1 * 60 * 60 * 24) - + let weekAltstore = AppSnapshot(name: "AltStore", - bundleIdentifier: Bundle.Info.appbundleIdentifier, - expirationDate: shortExpirationDate, - refreshedDate: shortRefreshedDate, - tintColor: .altPrimary, - icon: UIImage(named: "AltStore")) - + bundleIdentifier: Bundle.Info.appbundleIdentifier, + expirationDate: shortExpirationDate, + refreshedDate: shortRefreshedDate, + tintColor: .altPrimary, + icon: UIImage(named: "AltStore")) + let yearAltstore = AppSnapshot(name: "AltStore", - bundleIdentifier: Bundle.Info.appbundleIdentifier, - expirationDate: longExpirationDate, - refreshedDate: longRefreshedDate, - tintColor: .altPrimary, - icon: UIImage(named: "AltStore")) - + bundleIdentifier: Bundle.Info.appbundleIdentifier, + expirationDate: longExpirationDate, + refreshedDate: longRefreshedDate, + tintColor: .altPrimary, + icon: UIImage(named: "AltStore")) + return Group { ComplicationView(entry: AppEntry(date: Date(), app: weekAltstore), style: .icon) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - + ComplicationView(entry: AppEntry(date: expiredDate, app: weekAltstore), style: .icon) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - + ComplicationView(entry: AppEntry(date: longRefreshedDate, app: yearAltstore), style: .icon) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - + ComplicationView(entry: AppEntry(date: Date(), app: weekAltstore), style: .text) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - + ComplicationView(entry: AppEntry(date: expiredDate, app: weekAltstore), style: .text) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - + ComplicationView(entry: AppEntry(date: longRefreshedDate, app: yearAltstore), style: .text) - .previewContext(WidgetPreviewContext(family: .accessoryCircular)) + .previewContext(WidgetPreviewContext(family: .accessoryCircular)) } } } diff --git a/AltWidget/Countdown.swift b/Sources/SideWidget/Countdown.swift similarity index 76% rename from AltWidget/Countdown.swift rename to Sources/SideWidget/Countdown.swift index 0bdf4106..aeebdee3 100644 --- a/AltWidget/Countdown.swift +++ b/Sources/SideWidget/Countdown.swift @@ -9,47 +9,44 @@ import SwiftUI import WidgetKit -struct Countdown: View -{ +struct Countdown: View { var startDate: Date? var endDate: Date? - var currentDate: Date = Date() - + var currentDate: Date = .init() + @Environment(\.font) private var font - + private var numberOfDays: Int { - guard let date = self.endDate else { return 0 } - - let numberOfDays = date.numberOfCalendarDays(since: self.currentDate) + guard let date = endDate else { return 0 } + + let numberOfDays = date.numberOfCalendarDays(since: currentDate) return numberOfDays } - + private var fractionComplete: CGFloat { - guard let startDate = self.startDate, let endDate = self.endDate else { return 1.0 } - + guard let startDate = startDate, let endDate = endDate else { return 1.0 } + let totalNumberOfDays = endDate.numberOfCalendarDays(since: startDate) - let fractionComplete = CGFloat(self.numberOfDays) / CGFloat(totalNumberOfDays) + let fractionComplete = CGFloat(numberOfDays) / CGFloat(totalNumberOfDays) return fractionComplete } - + @ViewBuilder - private func overlay(progress: CGFloat) -> some View - { + private func overlay(progress: CGFloat) -> some View { let strokeStyle = StrokeStyle(lineWidth: 4.0, lineCap: .round, lineJoin: .round) - - if self.numberOfDays > 9 || self.numberOfDays < 0 { + + if numberOfDays > 9 || numberOfDays < 0 { Capsule(style: .continuous) .trim(from: 0.0, to: progress) .stroke(style: strokeStyle) - } - else { + } else { Circle() .trim(from: 0.0, to: progress) .rotation(Angle(degrees: -90), anchor: .center) .stroke(style: strokeStyle) } } - + var body: some View { Text("\(numberOfDays)") .font((font ?? .title).monospacedDigit()) @@ -61,7 +58,7 @@ struct Countdown: View ZStack { overlay(progress: 1.0) .opacity(0.3) - + overlay(progress: fractionComplete) } ) diff --git a/AltWidget/AltWidgetExtension.entitlements b/Sources/SideWidget/Resources/AltWidgetExtension.entitlements similarity index 100% rename from AltWidget/AltWidgetExtension.entitlements rename to Sources/SideWidget/Resources/AltWidgetExtension.entitlements diff --git a/AltWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/AccentColor.colorset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/AltWidget/Assets.xcassets/AltStore.imageset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/AltStore.imageset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Contents.json diff --git a/AltWidget/Assets.xcassets/AltStore.imageset/Group 23_120.png b/Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Group 23_120.png similarity index 100% rename from AltWidget/Assets.xcassets/AltStore.imageset/Group 23_120.png rename to Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Group 23_120.png diff --git a/AltWidget/Assets.xcassets/AltStore.imageset/Group 23_180.png b/Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Group 23_180.png similarity index 100% rename from AltWidget/Assets.xcassets/AltStore.imageset/Group 23_180.png rename to Sources/SideWidget/Resources/Assets.xcassets/AltStore.imageset/Group 23_180.png diff --git a/Sources/AltBackup/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Sources/AltBackup/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/AltWidget/Assets.xcassets/Badge.imageset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/Badge.imageset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/Badge.imageset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/Badge.imageset/Contents.json diff --git a/AltWidget/Assets.xcassets/Badge.imageset/group16Copy2.pdf b/Sources/SideWidget/Resources/Assets.xcassets/Badge.imageset/group16Copy2.pdf similarity index 100% rename from AltWidget/Assets.xcassets/Badge.imageset/group16Copy2.pdf rename to Sources/SideWidget/Resources/Assets.xcassets/Badge.imageset/group16Copy2.pdf diff --git a/Sources/AltBackup/Assets.xcassets/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Sources/AltBackup/Assets.xcassets/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/Contents.json diff --git a/AltWidget/Assets.xcassets/Delta.imageset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/Delta.imageset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/Contents.json diff --git a/AltWidget/Assets.xcassets/Delta.imageset/icon-120.png b/Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/icon-120.png similarity index 100% rename from AltWidget/Assets.xcassets/Delta.imageset/icon-120.png rename to Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/icon-120.png diff --git a/AltWidget/Assets.xcassets/Delta.imageset/icon-180.png b/Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/icon-180.png similarity index 100% rename from AltWidget/Assets.xcassets/Delta.imageset/icon-180.png rename to Sources/SideWidget/Resources/Assets.xcassets/Delta.imageset/icon-180.png diff --git a/AltWidget/Assets.xcassets/SmallIcon.imageset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/SmallIcon.imageset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/SmallIcon.imageset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/SmallIcon.imageset/Contents.json diff --git a/AltWidget/Assets.xcassets/SmallIcon.imageset/altminicon.pdf b/Sources/SideWidget/Resources/Assets.xcassets/SmallIcon.imageset/altminicon.pdf similarity index 100% rename from AltWidget/Assets.xcassets/SmallIcon.imageset/altminicon.pdf rename to Sources/SideWidget/Resources/Assets.xcassets/SmallIcon.imageset/altminicon.pdf diff --git a/AltWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/Sources/SideWidget/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json similarity index 100% rename from AltWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json rename to Sources/SideWidget/Resources/Assets.xcassets/WidgetBackground.colorset/Contents.json diff --git a/AltWidget/Info.plist b/Sources/SideWidget/Resources/Info.plist similarity index 100% rename from AltWidget/Info.plist rename to Sources/SideWidget/Resources/Info.plist diff --git a/AltWidget/WidgetView.swift b/Sources/SideWidget/WidgetView.swift similarity index 81% rename from AltWidget/WidgetView.swift rename to Sources/SideWidget/WidgetView.swift index 6dcfadec..5fee9a03 100644 --- a/AltWidget/WidgetView.swift +++ b/Sources/SideWidget/WidgetView.swift @@ -6,35 +6,33 @@ // Copyright © 2020 Riley Testut. All rights reserved. // -import WidgetKit import SwiftUI +import WidgetKit -import AltStoreCore import AltSign +import SideStoreCore import CoreData -struct WidgetView : View -{ +struct WidgetView: View { var entry: AppEntry - + var body: some View { Group { - if let app = self.entry.app - { + if let app = self.entry.app { let daysRemaining = app.expirationDate.numberOfCalendarDays(since: self.entry.date) - - GeometryReader { (geometry) in + + GeometryReader { geometry in Group { VStack(alignment: .leading) { VStack(alignment: .leading, spacing: 5) { let imageHeight = geometry.size.height * 0.4 - + Image(uiImage: app.icon ?? UIImage()) .resizable() .aspectRatio(CGSize(width: 1, height: 1), contentMode: .fit) .frame(height: imageHeight) .mask(RoundedRectangle(cornerRadius: imageHeight / 5.0, style: .continuous)) - + Text(app.name.uppercased()) .font(.system(size: 12, weight: .semibold, design: .rounded)) .foregroundColor(.white) @@ -42,36 +40,34 @@ struct WidgetView : View .minimumScaleFactor(0.5) } .fixedSize(horizontal: false, vertical: true) - + Spacer(minLength: 0) - + HStack(alignment: .center) { let expirationText: Text = { - switch daysRemaining - { + switch daysRemaining { case ..<0: return Text("Expired") case 1: return Text("1 day") default: return Text("\(daysRemaining) days") } }() - + ( Text("Expires in\n") .font(.system(size: 13, weight: .semibold, design: .rounded)) .foregroundColor(Color.white.opacity(0.45)) + - - expirationText + + expirationText .font(.system(size: 15, weight: .semibold, design: .rounded)) .foregroundColor(.white) ) .lineLimit(2) .lineSpacing(1.0) .minimumScaleFactor(0.5) - + Spacer() - - if daysRemaining >= 0 - { + + if daysRemaining >= 0 { Countdown(startDate: app.refreshedDate, endDate: app.expirationDate, currentDate: self.entry.date) @@ -87,14 +83,11 @@ struct WidgetView : View .padding() } } - } - else - { + } else { VStack { // Put conditional inside VStack, or else an empty view will be returned // if isPlaceholder == false, which messes up layout. - if !entry.isPlaceholder - { + if !entry.isPlaceholder { Text("App Not Found") .font(.system(.body, design: .rounded)) .fontWeight(.semibold) @@ -108,18 +101,16 @@ struct WidgetView : View } } -private extension WidgetView -{ - func backgroundView(icon: UIImage? = nil, tintColor: UIColor? = nil) -> some View - { +private extension WidgetView { + func backgroundView(icon: UIImage? = nil, tintColor: UIColor? = nil) -> some View { let icon = icon ?? UIImage(named: "AltStore")! let tintColor = tintColor ?? .gray - + let imageHeight = 60 as CGFloat let saturation = 1.8 let blurRadius = 5 as CGFloat let tintOpacity = 0.45 - + return ZStack(alignment: .topTrailing) { // Blurred Image GeometryReader { geometry in @@ -131,12 +122,12 @@ private extension WidgetView .saturation(saturation) .blur(radius: blurRadius, opaque: true) .scaleEffect(geometry.size.width / imageHeight, anchor: .center) - + Color(tintColor) .opacity(tintOpacity) } } - + Image("Badge") .resizable() .frame(width: 26, height: 26) @@ -150,44 +141,44 @@ struct WidgetView_Previews: PreviewProvider { let shortRefreshedDate = Calendar.current.date(byAdding: .day, value: -2, to: Date()) ?? Date() let shortExpirationDate = Calendar.current.date(byAdding: .day, value: 7, to: shortRefreshedDate) ?? Date() let expiredExpirationDate = Calendar.current.date(byAdding: .day, value: -155, to: Date()) ?? Date() - + let longRefreshedDate = Calendar.current.date(byAdding: .day, value: -100, to: Date()) ?? Date() let longExpirationDate = Calendar.current.date(byAdding: .day, value: 365, to: longRefreshedDate) ?? Date() - + let altstore = AppSnapshot(name: "AltStore", - bundleIdentifier: Bundle.Info.appbundleIdentifier, - expirationDate: shortExpirationDate, - refreshedDate: shortRefreshedDate, - tintColor: .altPrimary, - icon: UIImage(named: "AltStore")) - + bundleIdentifier: Bundle.Info.appbundleIdentifier, + expirationDate: shortExpirationDate, + refreshedDate: shortRefreshedDate, + tintColor: .altPrimary, + icon: UIImage(named: "AltStore")) + let delta = AppSnapshot(name: "Delta", - bundleIdentifier: "com.rileytestut.Delta", - expirationDate: longExpirationDate, - refreshedDate: longRefreshedDate, - tintColor: .deltaPrimary, - icon: UIImage(named: "Delta")) - + bundleIdentifier: "com.rileytestut.Delta", + expirationDate: longExpirationDate, + refreshedDate: longRefreshedDate, + tintColor: .deltaPrimary, + icon: UIImage(named: "Delta")) + let expiredDelta = AppSnapshot(name: "Delta", bundleIdentifier: "com.rileytestut.Delta", expirationDate: expiredExpirationDate, refreshedDate: shortRefreshedDate, tintColor: .deltaPrimary, icon: UIImage(named: "Delta")) - + return Group { WidgetView(entry: AppEntry(date: Date(), app: altstore)) .previewContext(WidgetPreviewContext(family: .systemSmall)) - + WidgetView(entry: AppEntry(date: Date(), app: delta)) .previewContext(WidgetPreviewContext(family: .systemSmall)) - + WidgetView(entry: AppEntry(date: Date(), app: expiredDelta)) .previewContext(WidgetPreviewContext(family: .systemSmall)) - + WidgetView(entry: AppEntry(date: Date(), app: nil)) .previewContext(WidgetPreviewContext(family: .systemSmall)) - + WidgetView(entry: AppEntry(date: Date(), app: nil, isPlaceholder: true)) .previewContext(WidgetPreviewContext(family: .systemSmall)) } diff --git a/AltStore/Operations/Patch App/fragmentzip.h b/Sources/libfragmentzip/include/fragmentzip.h similarity index 100% rename from AltStore/Operations/Patch App/fragmentzip.h rename to Sources/libfragmentzip/include/fragmentzip.h diff --git a/Dependencies/libfragmentzip b/Sources/libfragmentzip/libfragmentzip-source similarity index 100% rename from Dependencies/libfragmentzip rename to Sources/libfragmentzip/libfragmentzip-source diff --git a/Tests/CargoTests/CargoTests.swift b/Tests/CargoTests/CargoTests.swift new file mode 100644 index 00000000..330765bb --- /dev/null +++ b/Tests/CargoTests/CargoTests.swift @@ -0,0 +1,34 @@ +// +// CargoTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import Cargo + +class CargoTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/EmotionalDamageTests/EmotionalDamageTests.swift b/Tests/EmotionalDamageTests/EmotionalDamageTests.swift new file mode 100644 index 00000000..9e62c6c0 --- /dev/null +++ b/Tests/EmotionalDamageTests/EmotionalDamageTests.swift @@ -0,0 +1,34 @@ +// +// EmotionalDamageTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import EmotionalDamage + +class EmotionalDamageTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/MiniMuxerTests/MiniMuxerTests.swift b/Tests/MiniMuxerTests/MiniMuxerTests.swift new file mode 100644 index 00000000..8d047f3f --- /dev/null +++ b/Tests/MiniMuxerTests/MiniMuxerTests.swift @@ -0,0 +1,34 @@ +// +// MiniMuxerTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import MiniMuxer + +class MiniMuxerTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/SharedTests/SharedTests.swift b/Tests/SharedTests/SharedTests.swift new file mode 100644 index 00000000..923f7ba4 --- /dev/null +++ b/Tests/SharedTests/SharedTests.swift @@ -0,0 +1,34 @@ +// +// SharedTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import Shared + +class SharedTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/SideDaemonTests/SideDaemonTests.swift b/Tests/SideDaemonTests/SideDaemonTests.swift new file mode 100644 index 00000000..75841b13 --- /dev/null +++ b/Tests/SideDaemonTests/SideDaemonTests.swift @@ -0,0 +1,34 @@ +// +// SideDaemonTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import SideDaemon + +class SideDaemonTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/SideStoreCoreTests/SideStoreCoreTests.swift b/Tests/SideStoreCoreTests/SideStoreCoreTests.swift new file mode 100644 index 00000000..3cd9c164 --- /dev/null +++ b/Tests/SideStoreCoreTests/SideStoreCoreTests.swift @@ -0,0 +1,34 @@ +// +// SideStoreCoreTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import SideStoreCore + +class SideStoreCoreTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/SideStoreTests/SideStoreTests.swift b/Tests/SideStoreTests/SideStoreTests.swift new file mode 100644 index 00000000..ec4178dd --- /dev/null +++ b/Tests/SideStoreTests/SideStoreTests.swift @@ -0,0 +1,34 @@ +// +// SideStoreTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import SideStore + +class SideStoreTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/SideWidgetTests/SideWidgetTests.swift b/Tests/SideWidgetTests/SideWidgetTests.swift new file mode 100644 index 00000000..f5730058 --- /dev/null +++ b/Tests/SideWidgetTests/SideWidgetTests.swift @@ -0,0 +1,34 @@ +// +// SideWidgetTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import SideWidget + +class SideWidgetTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/Tests/libfragmentzipTests/libfragmentzipTests.swift b/Tests/libfragmentzipTests/libfragmentzipTests.swift new file mode 100644 index 00000000..16d61e88 --- /dev/null +++ b/Tests/libfragmentzipTests/libfragmentzipTests.swift @@ -0,0 +1,34 @@ +// +// libfragmentzipTests.swift +// SideStore +// +// Created by Joseph Mattiello on 2/28/23. +// Copyright © 2023 Joseph Mattiello. All rights reserved. +// + +import XCTest +@testable import libfragmentzip + +class libfragmentzipTests: XCTestCase { + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +}