Full Code of FLEXTool/FLEX for AI

master eee24be7b7e0 cached
431 files
2.6 MB
710.6k tokens
79 symbols
1 requests
Download .txt
Showing preview only (2,835K chars total). Download the full file or copy to clipboard to get everything.
Repository: FLEXTool/FLEX
Branch: master
Commit: eee24be7b7e0
Files: 431
Total size: 2.6 MB

Directory structure:
gitextract_243iz5jb/

├── .clang-format
├── .github/
│   ├── FUNDING.yml
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .travis.yml
├── .vscode/
│   └── settings.json
├── CONTRIBUTING.md
├── Classes/
│   ├── Core/
│   │   ├── Controllers/
│   │   │   ├── FLEXFilteringTableViewController.h
│   │   │   ├── FLEXFilteringTableViewController.m
│   │   │   ├── FLEXNavigationController.h
│   │   │   ├── FLEXNavigationController.m
│   │   │   ├── FLEXTableViewController.h
│   │   │   └── FLEXTableViewController.m
│   │   ├── FLEXSingleRowSection.h
│   │   ├── FLEXSingleRowSection.m
│   │   ├── FLEXTableViewSection.h
│   │   ├── FLEXTableViewSection.m
│   │   └── Views/
│   │       ├── Carousel/
│   │       │   ├── FLEXCarouselCell.h
│   │       │   ├── FLEXCarouselCell.m
│   │       │   ├── FLEXScopeCarousel.h
│   │       │   └── FLEXScopeCarousel.m
│   │       ├── Cells/
│   │       │   ├── FLEXCodeFontCell.h
│   │       │   ├── FLEXCodeFontCell.m
│   │       │   ├── FLEXKeyValueTableViewCell.h
│   │       │   ├── FLEXKeyValueTableViewCell.m
│   │       │   ├── FLEXMultilineTableViewCell.h
│   │       │   ├── FLEXMultilineTableViewCell.m
│   │       │   ├── FLEXSubtitleTableViewCell.h
│   │       │   ├── FLEXSubtitleTableViewCell.m
│   │       │   ├── FLEXTableViewCell.h
│   │       │   └── FLEXTableViewCell.m
│   │       ├── FLEXTableView.h
│   │       └── FLEXTableView.m
│   ├── Editing/
│   │   ├── ArgumentInputViews/
│   │   │   ├── FLEXArgumentInputColorView.h
│   │   │   ├── FLEXArgumentInputColorView.m
│   │   │   ├── FLEXArgumentInputDateView.h
│   │   │   ├── FLEXArgumentInputDateView.m
│   │   │   ├── FLEXArgumentInputFontView.h
│   │   │   ├── FLEXArgumentInputFontView.m
│   │   │   ├── FLEXArgumentInputFontsPickerView.h
│   │   │   ├── FLEXArgumentInputFontsPickerView.m
│   │   │   ├── FLEXArgumentInputNotSupportedView.h
│   │   │   ├── FLEXArgumentInputNotSupportedView.m
│   │   │   ├── FLEXArgumentInputNumberView.h
│   │   │   ├── FLEXArgumentInputNumberView.m
│   │   │   ├── FLEXArgumentInputObjectView.h
│   │   │   ├── FLEXArgumentInputObjectView.m
│   │   │   ├── FLEXArgumentInputStringView.h
│   │   │   ├── FLEXArgumentInputStringView.m
│   │   │   ├── FLEXArgumentInputStructView.h
│   │   │   ├── FLEXArgumentInputStructView.m
│   │   │   ├── FLEXArgumentInputSwitchView.h
│   │   │   ├── FLEXArgumentInputSwitchView.m
│   │   │   ├── FLEXArgumentInputTextView.h
│   │   │   ├── FLEXArgumentInputTextView.m
│   │   │   ├── FLEXArgumentInputView.h
│   │   │   └── FLEXArgumentInputView.m
│   │   ├── FLEXArgumentInputViewFactory.h
│   │   ├── FLEXArgumentInputViewFactory.m
│   │   ├── FLEXDefaultEditorViewController.h
│   │   ├── FLEXDefaultEditorViewController.m
│   │   ├── FLEXFieldEditorView.h
│   │   ├── FLEXFieldEditorView.m
│   │   ├── FLEXFieldEditorViewController.h
│   │   ├── FLEXFieldEditorViewController.m
│   │   ├── FLEXMethodCallingViewController.h
│   │   ├── FLEXMethodCallingViewController.m
│   │   ├── FLEXVariableEditorViewController.h
│   │   └── FLEXVariableEditorViewController.m
│   ├── ExplorerInterface/
│   │   ├── Bookmarks/
│   │   │   ├── FLEXBookmarkManager.h
│   │   │   ├── FLEXBookmarkManager.m
│   │   │   ├── FLEXBookmarksViewController.h
│   │   │   └── FLEXBookmarksViewController.m
│   │   ├── FLEXExplorerViewController.h
│   │   ├── FLEXExplorerViewController.m
│   │   ├── FLEXViewControllersViewController.h
│   │   ├── FLEXViewControllersViewController.m
│   │   ├── FLEXWindow.h
│   │   ├── FLEXWindow.m
│   │   ├── FLEXWindowManagerController.h
│   │   ├── FLEXWindowManagerController.m
│   │   └── Tabs/
│   │       ├── FLEXTabList.h
│   │       ├── FLEXTabList.m
│   │       ├── FLEXTabsViewController.h
│   │       └── FLEXTabsViewController.m
│   ├── FLEX-Categories.h
│   ├── FLEX-Core.h
│   ├── FLEX-ObjectExploring.h
│   ├── FLEX-Runtime.h
│   ├── FLEX.h
│   ├── GlobalStateExplorers/
│   │   ├── DatabaseBrowser/
│   │   │   ├── FLEXDBQueryRowCell.h
│   │   │   ├── FLEXDBQueryRowCell.m
│   │   │   ├── FLEXDatabaseManager.h
│   │   │   ├── FLEXMultiColumnTableView.h
│   │   │   ├── FLEXMultiColumnTableView.m
│   │   │   ├── FLEXRealmDatabaseManager.h
│   │   │   ├── FLEXRealmDatabaseManager.m
│   │   │   ├── FLEXRealmDefines.h
│   │   │   ├── FLEXSQLResult.h
│   │   │   ├── FLEXSQLResult.m
│   │   │   ├── FLEXSQLiteDatabaseManager.h
│   │   │   ├── FLEXSQLiteDatabaseManager.m
│   │   │   ├── FLEXTableColumnHeader.h
│   │   │   ├── FLEXTableColumnHeader.m
│   │   │   ├── FLEXTableContentViewController.h
│   │   │   ├── FLEXTableContentViewController.m
│   │   │   ├── FLEXTableLeftCell.h
│   │   │   ├── FLEXTableLeftCell.m
│   │   │   ├── FLEXTableListViewController.h
│   │   │   ├── FLEXTableListViewController.m
│   │   │   ├── FLEXTableRowDataViewController.h
│   │   │   ├── FLEXTableRowDataViewController.m
│   │   │   └── LICENSE
│   │   ├── FLEXAPNSViewController.h
│   │   ├── FLEXAPNSViewController.m
│   │   ├── FLEXAddressExplorerCoordinator.h
│   │   ├── FLEXAddressExplorerCoordinator.m
│   │   ├── FLEXCookiesViewController.h
│   │   ├── FLEXCookiesViewController.m
│   │   ├── FLEXLiveObjectsController.h
│   │   ├── FLEXLiveObjectsController.m
│   │   ├── FLEXObjectListViewController.h
│   │   ├── FLEXObjectListViewController.m
│   │   ├── FLEXObjectRef.h
│   │   ├── FLEXObjectRef.m
│   │   ├── FLEXWebViewController.h
│   │   ├── FLEXWebViewController.m
│   │   ├── FileBrowser/
│   │   │   ├── FLEXActivityViewController.h
│   │   │   ├── FLEXActivityViewController.m
│   │   │   ├── FLEXFileBrowserController.h
│   │   │   ├── FLEXFileBrowserController.m
│   │   │   ├── FLEXFileBrowserSearchOperation.h
│   │   │   └── FLEXFileBrowserSearchOperation.m
│   │   ├── Globals/
│   │   │   ├── FLEXGlobalsEntry.h
│   │   │   ├── FLEXGlobalsEntry.m
│   │   │   ├── FLEXGlobalsSection.h
│   │   │   ├── FLEXGlobalsSection.m
│   │   │   ├── FLEXGlobalsViewController.h
│   │   │   └── FLEXGlobalsViewController.m
│   │   ├── Keychain/
│   │   │   ├── FLEXKeychain.h
│   │   │   ├── FLEXKeychain.m
│   │   │   ├── FLEXKeychainQuery.h
│   │   │   ├── FLEXKeychainQuery.m
│   │   │   ├── FLEXKeychainViewController.h
│   │   │   ├── FLEXKeychainViewController.m
│   │   │   └── SSKeychain_LICENSE
│   │   ├── RuntimeBrowser/
│   │   │   ├── DataSources/
│   │   │   │   ├── FLEXRuntimeClient.h
│   │   │   │   ├── FLEXRuntimeClient.m
│   │   │   │   ├── FLEXRuntimeController.h
│   │   │   │   ├── FLEXRuntimeController.m
│   │   │   │   ├── FLEXRuntimeExporter.h
│   │   │   │   └── FLEXRuntimeExporter.m
│   │   │   ├── FLEXKBToolbarButton.h
│   │   │   ├── FLEXKBToolbarButton.m
│   │   │   ├── FLEXKeyPathSearchController.h
│   │   │   ├── FLEXKeyPathSearchController.m
│   │   │   ├── FLEXKeyboardToolbar.h
│   │   │   ├── FLEXKeyboardToolbar.m
│   │   │   ├── FLEXObjcRuntimeViewController.h
│   │   │   ├── FLEXObjcRuntimeViewController.m
│   │   │   ├── FLEXRuntimeBrowserToolbar.h
│   │   │   ├── FLEXRuntimeBrowserToolbar.m
│   │   │   ├── FLEXRuntimeKeyPath.h
│   │   │   ├── FLEXRuntimeKeyPath.m
│   │   │   ├── FLEXRuntimeKeyPathTokenizer.h
│   │   │   ├── FLEXRuntimeKeyPathTokenizer.m
│   │   │   ├── FLEXSearchToken.h
│   │   │   └── FLEXSearchToken.m
│   │   └── SystemLog/
│   │       ├── ActivityStreamAPI.h
│   │       ├── FLEXASLLogController.h
│   │       ├── FLEXASLLogController.m
│   │       ├── FLEXLogController.h
│   │       ├── FLEXOSLogController.h
│   │       ├── FLEXOSLogController.m
│   │       ├── FLEXSystemLogCell.h
│   │       ├── FLEXSystemLogCell.m
│   │       ├── FLEXSystemLogMessage.h
│   │       ├── FLEXSystemLogMessage.m
│   │       ├── FLEXSystemLogViewController.h
│   │       ├── FLEXSystemLogViewController.m
│   │       └── LLVM_LICENSE.TXT
│   ├── Info.plist
│   ├── Manager/
│   │   ├── FLEXManager+Extensibility.h
│   │   ├── FLEXManager+Extensibility.m
│   │   ├── FLEXManager+Networking.h
│   │   ├── FLEXManager+Networking.m
│   │   ├── FLEXManager.h
│   │   ├── FLEXManager.m
│   │   └── Private/
│   │       └── FLEXManager+Private.h
│   ├── Network/
│   │   ├── FLEXFirebaseTransaction.mm
│   │   ├── FLEXHTTPTransactionDetailController.h
│   │   ├── FLEXHTTPTransactionDetailController.m
│   │   ├── FLEXMITMDataSource.h
│   │   ├── FLEXMITMDataSource.m
│   │   ├── FLEXNetworkCurlLogger.h
│   │   ├── FLEXNetworkCurlLogger.m
│   │   ├── FLEXNetworkMITMViewController.h
│   │   ├── FLEXNetworkMITMViewController.m
│   │   ├── FLEXNetworkRecorder.h
│   │   ├── FLEXNetworkRecorder.m
│   │   ├── FLEXNetworkSettingsController.h
│   │   ├── FLEXNetworkSettingsController.m
│   │   ├── FLEXNetworkTransaction.h
│   │   ├── FLEXNetworkTransaction.m
│   │   ├── FLEXNetworkTransactionCell.h
│   │   ├── FLEXNetworkTransactionCell.m
│   │   ├── Firestore.h
│   │   ├── OSCache/
│   │   │   ├── LICENSE.md
│   │   │   ├── OSCache.h
│   │   │   └── OSCache.m
│   │   └── PonyDebugger/
│   │       ├── FLEXNetworkObserver.h
│   │       ├── FLEXNetworkObserver.m
│   │       └── LICENSE
│   ├── ObjectExplorers/
│   │   ├── FLEXObjectExplorer.h
│   │   ├── FLEXObjectExplorer.m
│   │   ├── FLEXObjectExplorerFactory.h
│   │   ├── FLEXObjectExplorerFactory.m
│   │   ├── FLEXObjectExplorerViewController.h
│   │   ├── FLEXObjectExplorerViewController.m
│   │   └── Sections/
│   │       ├── FLEXCollectionContentSection.h
│   │       ├── FLEXCollectionContentSection.m
│   │       ├── FLEXColorPreviewSection.h
│   │       ├── FLEXColorPreviewSection.m
│   │       ├── FLEXDefaultsContentSection.h
│   │       ├── FLEXDefaultsContentSection.m
│   │       ├── FLEXMetadataSection.h
│   │       ├── FLEXMetadataSection.m
│   │       ├── FLEXMutableListSection.h
│   │       ├── FLEXMutableListSection.m
│   │       ├── FLEXObjectInfoSection.h
│   │       └── Shortcuts/
│   │           ├── FLEXBlockShortcuts.h
│   │           ├── FLEXBlockShortcuts.m
│   │           ├── FLEXBundleShortcuts.h
│   │           ├── FLEXBundleShortcuts.m
│   │           ├── FLEXClassShortcuts.h
│   │           ├── FLEXClassShortcuts.m
│   │           ├── FLEXImageShortcuts.h
│   │           ├── FLEXImageShortcuts.m
│   │           ├── FLEXLayerShortcuts.h
│   │           ├── FLEXLayerShortcuts.m
│   │           ├── FLEXNSDataShortcuts.h
│   │           ├── FLEXNSDataShortcuts.m
│   │           ├── FLEXNSStringShortcuts.h
│   │           ├── FLEXNSStringShortcuts.m
│   │           ├── FLEXShortcut.h
│   │           ├── FLEXShortcut.m
│   │           ├── FLEXShortcutsFactory+Defaults.h
│   │           ├── FLEXShortcutsFactory+Defaults.m
│   │           ├── FLEXShortcutsSection.h
│   │           ├── FLEXShortcutsSection.m
│   │           ├── FLEXUIAppShortcuts.h
│   │           ├── FLEXUIAppShortcuts.m
│   │           ├── FLEXViewControllerShortcuts.h
│   │           ├── FLEXViewControllerShortcuts.m
│   │           ├── FLEXViewShortcuts.h
│   │           ├── FLEXViewShortcuts.m
│   │           ├── FLEXWindowShortcuts.h
│   │           └── FLEXWindowShortcuts.m
│   ├── Toolbar/
│   │   ├── FLEXExplorerToolbar.h
│   │   ├── FLEXExplorerToolbar.m
│   │   ├── FLEXExplorerToolbarItem.h
│   │   └── FLEXExplorerToolbarItem.m
│   ├── Utility/
│   │   ├── APPLE_LICENSE
│   │   ├── Categories/
│   │   │   ├── CALayer+FLEX.h
│   │   │   ├── CALayer+FLEX.m
│   │   │   ├── FLEXRuntime+Compare.h
│   │   │   ├── FLEXRuntime+Compare.m
│   │   │   ├── FLEXRuntime+UIKitHelpers.h
│   │   │   ├── FLEXRuntime+UIKitHelpers.m
│   │   │   ├── NSArray+FLEX.h
│   │   │   ├── NSArray+FLEX.m
│   │   │   ├── NSDateFormatter+FLEX.h
│   │   │   ├── NSDateFormatter+FLEX.m
│   │   │   ├── NSObject+FLEX_Reflection.h
│   │   │   ├── NSObject+FLEX_Reflection.m
│   │   │   ├── NSTimer+FLEX.h
│   │   │   ├── NSTimer+FLEX.m
│   │   │   ├── NSUserDefaults+FLEX.h
│   │   │   ├── NSUserDefaults+FLEX.m
│   │   │   ├── Private/
│   │   │   │   ├── Cocoa+FLEXShortcuts.h
│   │   │   │   ├── Cocoa+FLEXShortcuts.m
│   │   │   │   ├── NSDictionary+ObjcRuntime.h
│   │   │   │   ├── NSDictionary+ObjcRuntime.m
│   │   │   │   ├── NSMapTable+FLEX_Subscripting.h
│   │   │   │   ├── NSMapTable+FLEX_Subscripting.m
│   │   │   │   ├── NSString+FLEX.h
│   │   │   │   ├── NSString+FLEX.m
│   │   │   │   ├── NSString+ObjcRuntime.h
│   │   │   │   ├── NSString+ObjcRuntime.m
│   │   │   │   ├── UIView+FLEX_Layout.h
│   │   │   │   └── UIView+FLEX_Layout.m
│   │   │   ├── UIBarButtonItem+FLEX.h
│   │   │   ├── UIBarButtonItem+FLEX.m
│   │   │   ├── UIFont+FLEX.h
│   │   │   ├── UIFont+FLEX.m
│   │   │   ├── UIGestureRecognizer+Blocks.h
│   │   │   ├── UIGestureRecognizer+Blocks.m
│   │   │   ├── UIMenu+FLEX.h
│   │   │   ├── UIMenu+FLEX.m
│   │   │   ├── UIPasteboard+FLEX.h
│   │   │   ├── UIPasteboard+FLEX.m
│   │   │   ├── UITextField+Range.h
│   │   │   └── UITextField+Range.m
│   │   ├── FLEXAlert.h
│   │   ├── FLEXAlert.m
│   │   ├── FLEXColor.h
│   │   ├── FLEXColor.m
│   │   ├── FLEXHeapEnumerator.h
│   │   ├── FLEXHeapEnumerator.m
│   │   ├── FLEXMacros.h
│   │   ├── FLEXResources.h
│   │   ├── FLEXResources.m
│   │   ├── FLEXUtility.h
│   │   ├── FLEXUtility.m
│   │   ├── Keyboard/
│   │   │   ├── FLEXKeyboardHelpViewController.h
│   │   │   ├── FLEXKeyboardHelpViewController.m
│   │   │   ├── FLEXKeyboardShortcutManager.h
│   │   │   └── FLEXKeyboardShortcutManager.m
│   │   └── Runtime/
│   │       ├── FLEXRuntimeUtility.h
│   │       ├── FLEXRuntimeUtility.m
│   │       ├── Objc/
│   │       │   ├── FLEXObjcInternal.h
│   │       │   ├── FLEXObjcInternal.mm
│   │       │   ├── FLEXRuntimeConstants.h
│   │       │   ├── FLEXRuntimeConstants.m
│   │       │   ├── FLEXRuntimeSafety.h
│   │       │   ├── FLEXRuntimeSafety.m
│   │       │   ├── FLEXSwiftInternal.h
│   │       │   ├── FLEXSwiftInternal.mm
│   │       │   ├── FLEXTypeEncodingParser.h
│   │       │   ├── FLEXTypeEncodingParser.m
│   │       │   └── Reflection/
│   │       │       ├── FLEXBlockDescription.h
│   │       │       ├── FLEXBlockDescription.m
│   │       │       ├── FLEXClassBuilder.h
│   │       │       ├── FLEXClassBuilder.m
│   │       │       ├── FLEXIvar.h
│   │       │       ├── FLEXIvar.m
│   │       │       ├── FLEXMetadataExtras.h
│   │       │       ├── FLEXMetadataExtras.m
│   │       │       ├── FLEXMethod.h
│   │       │       ├── FLEXMethod.m
│   │       │       ├── FLEXMethodBase.h
│   │       │       ├── FLEXMethodBase.m
│   │       │       ├── FLEXMirror.h
│   │       │       ├── FLEXMirror.m
│   │       │       ├── FLEXProperty.h
│   │       │       ├── FLEXProperty.m
│   │       │       ├── FLEXPropertyAttributes.h
│   │       │       ├── FLEXPropertyAttributes.m
│   │       │       ├── FLEXProtocol.h
│   │       │       ├── FLEXProtocol.m
│   │       │       ├── FLEXProtocolBuilder.h
│   │       │       └── FLEXProtocolBuilder.m
│   │       ├── flex_fishhook.c
│   │       └── flex_fishhook.h
│   └── ViewHierarchy/
│       ├── FLEXHierarchyViewController.h
│       ├── FLEXHierarchyViewController.m
│       ├── FLEXImagePreviewViewController.h
│       ├── FLEXImagePreviewViewController.m
│       ├── SnapshotExplorer/
│       │   ├── FHSRangeSlider.h
│       │   ├── FHSRangeSlider.m
│       │   ├── FHSSnapshotView.h
│       │   ├── FHSSnapshotView.m
│       │   ├── FHSView.h
│       │   ├── FHSView.m
│       │   ├── FHSViewController.h
│       │   ├── FHSViewController.m
│       │   ├── FHSViewSnapshot.h
│       │   ├── FHSViewSnapshot.m
│       │   └── Scene/
│       │       ├── FHSSnapshotNodes.h
│       │       ├── FHSSnapshotNodes.m
│       │       ├── SceneKit+Snapshot.h
│       │       └── SceneKit+Snapshot.m
│       └── TreeExplorer/
│           ├── FLEXHierarchyTableViewCell.h
│           ├── FLEXHierarchyTableViewCell.m
│           ├── FLEXHierarchyTableViewController.h
│           └── FLEXHierarchyTableViewController.m
├── Example/
│   ├── FLEXample/
│   │   ├── App/
│   │   │   ├── Commit.swift
│   │   │   ├── CommitListViewController.h
│   │   │   ├── CommitListViewController.m
│   │   │   ├── Person.h
│   │   │   └── Person.m
│   │   ├── AppDelegate.swift
│   │   ├── MiscNetworkRequests.h
│   │   ├── MiscNetworkRequests.m
│   │   ├── SceneDelegate.swift
│   │   └── Supporting Files/
│   │       ├── Assets.xcassets/
│   │       │   ├── AppIcon.appiconset/
│   │       │   │   └── Contents.json
│   │       │   └── Contents.json
│   │       ├── Base.lproj/
│   │       │   └── LaunchScreen.storyboard
│   │       ├── Bundle/
│   │       │   ├── dogs.realm
│   │       │   └── image
│   │       ├── FLEXample-Bridging-Header.h
│   │       ├── Info.plist
│   │       └── Preview Content/
│   │           └── Preview Assets.xcassets/
│   │               └── Contents.json
│   ├── FLEXample-Cocoapods.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── FLEXample.xcscheme
│   ├── FLEXample-SPM.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── FLEXample.xcscheme
│   ├── Podfile
│   └── Realm/
│       ├── Dog.h
│       ├── Dog.m
│       ├── Owner.h
│       └── Owner.m
├── FLEX.podspec
├── FLEX.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── FLEX.xcscheme
│           └── FLEXTests.xcscheme
├── FLEXTests/
│   ├── FLEXTests.m
│   ├── FLEXTestsMethodsList.m
│   ├── FLEXTypeEncodingParserTests.m
│   ├── Info.plist
│   └── Supporting Files/
│       ├── FLEXNewRootClass.h
│       └── FLEXNewRootClass.m
├── Graphics/
│   ├── FLEX-Icons.sketch
│   ├── filetypes/
│   │   └── old/
│   │       ├── audio.pxm
│   │       ├── binary.pxm
│   │       ├── html.pxm
│   │       ├── js.pxm
│   │       ├── json.pxm
│   │       ├── plist.pxm
│   │       ├── text.pxm
│   │       ├── textplain.pxm
│   │       └── video.pxm
│   ├── image_to_code.py
│   ├── images_to_hex.sh
│   └── iterate_hex_to_pasteboard.sh
├── LICENSE
├── Package.swift
├── README.md
├── SM/
│   └── Surfile
└── generate-spm-headers.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
BasedOnStyle:  WebKit
AccessModifierOffset: -2
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackParameters: true
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Linux
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerBinding: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
MaxEmptyLinesToKeep: 3
NamespaceIndentation: None
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 60
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerBindsToType: false
SpaceAfterControlStatementKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles:  false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
Standard: Auto
TabWidth: 4
UseTab: Never

...


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [NSExceptional]


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Report a bug in FLEX
title: ''
labels: bug
assignees: ''

---

### Environment
- Platform+version: **iOS 14** <!--- Change to match your platform and version -->
- FLEX version: **9.9.9** <!--- Change to the version of FLEX you're using -->
<!--- FLEXing / libFLEX users: please include FLEXing and libFLEX versions separately -->

### Bug Report

Here, you can provide a description of the bug. Some tips:

- Please do not paste an entire crash log. Upload the crash log to something like [ghostbin.co](https://ghostbin.co/) or another paste service. Alternatively, you can cut out the relevant stack trace and paste that inside a ` ```code block``` `
- If the bug is more complex than "this button is broken" or a crash, consider including a sample project. For example, if your app's requests aren't showing up in the network history page.
- Providing steps to reproduce is always helpful!
- If you want to include a screenshot or GIF, consider modifying the default markdown for uploaded images to use this code to make the image smaller on desktop:
  ```
  <img width="50%" src=your-image-url >
  ```

This template is a suggestion. You may format your issue however you want, but generally you should at least include your iOS version and FLEX version.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest a new feature for FLEX
title: ''
labels: enhancement
assignees: ''

---




================================================
FILE: .gitignore
================================================
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
.DS_Store
/Example/Pods
Podfile.lock
IDEWorkspaceChecks.plist
*.xcworkspace
.build


================================================
FILE: .travis.yml
================================================
language: objective-c
xcode_workspace: FLEX.xcworkspace
xcode_sdk: iphonesimulator
before_install:
    - gem install xcpretty
matrix:
    include:
        - xcode_scheme: UICatalog
        - xcode_scheme: FLEX
script:
    - set -o pipefail
    - xcodebuild -workspace $TRAVIS_XCODE_WORKSPACE -scheme $TRAVIS_XCODE_SCHEME -sdk $TRAVIS_XCODE_SDK build | xcpretty

================================================
FILE: .vscode/settings.json
================================================
{
    "search.exclude": {
        "Classes/Headers": true
    }
}


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to FLEX #

We welcome contributions! Please open a pull request with your changes. 


================================================
FILE: Classes/Core/Controllers/FLEXFilteringTableViewController.h
================================================
//
//  FLEXFilteringTableViewController.h
//  FLEX
//
//  Created by Tanner on 3/9/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewController.h"

#pragma mark - FLEXTableViewFiltering
@protocol FLEXTableViewFiltering <FLEXSearchResultsUpdating>

/// An array of visible, "filtered" sections. For example,
/// if you have 3 sections in \c allSections and the user searches
/// for something that matches rows in only one section, then
/// this property would only contain that on matching section.
@property (nonatomic, copy) NSArray<FLEXTableViewSection *> *sections;
/// An array of all possible sections. Empty sections are to be removed
/// and the resulting array stored in the \c section property. Setting
/// this property should immediately set \c sections to \c nonemptySections 
///
/// Do not manually initialize this property, it will be
/// initialized for you using the result of \c makeSections.
@property (nonatomic, copy) NSArray<FLEXTableViewSection *> *allSections;

/// This computed property should filter \c allSections for assignment to \c sections
@property (nonatomic, readonly, copy) NSArray<FLEXTableViewSection *> *nonemptySections;

/// This should be able to re-initialize \c allSections
- (NSArray<FLEXTableViewSection *> *)makeSections;

@end


#pragma mark - FLEXFilteringTableViewController
/// A table view which implements \c UITableView* methods using arrays of
/// \c FLEXTableViewSection objects provied by a special delegate.
@interface FLEXFilteringTableViewController : FLEXTableViewController <FLEXTableViewFiltering>

/// Stores the current search query.
@property (nonatomic, copy) NSString *filterText;

/// This property is set to \c self by default.
///
/// This property is used to power almost all of the table view's data source
/// and delegate methods automatically, including row and section filtering
/// when the user searches, 3D Touch context menus, row selection, etc.
///
/// Setting this property will also set \c searchDelegate to that object.
@property (nonatomic, weak) id<FLEXTableViewFiltering> filterDelegate;

/// Defaults to \c NO. If enabled, all filtering will be done by calling
/// \c onBackgroundQueue:thenOnMainQueue: with the UI updated on the main queue.
@property (nonatomic) BOOL filterInBackground;

/// Defaults to \c NO. If enabled, one • will be supplied as an index title for each section.
@property (nonatomic) BOOL wantsSectionIndexTitles;

/// Recalculates the non-empty sections and reloads the table view.
///
/// Subclasses may override to perform additional reloading logic,
/// such as calling \c -reloadSections if needed. Be sure to call
/// \c super after any logic that would affect the appearance of 
/// the table view, since the table view is reloaded last.
///
/// Called at the end of this class's implementation of \c updateSearchResults:
- (void)reloadData;

/// Invoke this method to call \c -reloadData on each section
/// in \c self.filterDelegate.allSections.
- (void)reloadSections;

#pragma mark FLEXTableViewFiltering

@property (nonatomic, copy) NSArray<FLEXTableViewSection *> *sections;
@property (nonatomic, copy) NSArray<FLEXTableViewSection *> *allSections;

/// Subclasses can override to hide specific sections under certain conditions
/// if using \c self as the \c filterDelegate, as is the default.
///
/// For example, the object explorer hides the description section when searching.
@property (nonatomic, readonly, copy) NSArray<FLEXTableViewSection *> *nonemptySections;

/// If using \c self as the \c filterDelegate, as is the default,
/// subclasses should override to provide the sections for the table view.
- (NSArray<FLEXTableViewSection *> *)makeSections;

@end


================================================
FILE: Classes/Core/Controllers/FLEXFilteringTableViewController.m
================================================
//
//  FLEXFilteringTableViewController.m
//  FLEX
//
//  Created by Tanner on 3/9/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXFilteringTableViewController.h"
#import "FLEXTableViewSection.h"
#import "NSArray+FLEX.h"
#import "FLEXMacros.h"

@interface FLEXFilteringTableViewController ()

@end

@implementation FLEXFilteringTableViewController
@synthesize allSections = _allSections;

#pragma mark - View controller lifecycle

- (void)loadView {
    [super loadView];
    
    if (!self.filterDelegate) {
        self.filterDelegate = self;
    } else {
        [self _registerCellsForReuse];
    }
}

- (void)_registerCellsForReuse {
    for (FLEXTableViewSection *section in self.filterDelegate.allSections) {
        if (section.cellRegistrationMapping) {
            [self.tableView registerCells:section.cellRegistrationMapping];
        }
    }
}


#pragma mark - Public

- (void)setFilterDelegate:(id<FLEXTableViewFiltering>)filterDelegate {
    _filterDelegate = filterDelegate;
    filterDelegate.allSections = [filterDelegate makeSections];
    
    if (self.isViewLoaded) {
        [self _registerCellsForReuse];
    }
}

- (void)reloadData {
    [self reloadData:self.nonemptySections];
}

- (void)reloadData:(NSArray *)nonemptySections {
    // Recalculate displayed sections
    self.filterDelegate.sections = nonemptySections;

    // Refresh table view
    if (self.isViewLoaded) {
        [self.tableView reloadData];
    }
}

- (void)reloadSections {
    for (FLEXTableViewSection *section in self.filterDelegate.allSections) {
        [section reloadData];
    }
}


#pragma mark - Search

- (void)updateSearchResults:(NSString *)newText {
    NSArray *(^filter)(void) = ^NSArray *{
        self.filterText = newText;

        // Sections will adjust data based on this property
        for (FLEXTableViewSection *section in self.filterDelegate.allSections) {
            section.filterText = newText;
        }
        
        return nil;
    };
    
    if (self.filterInBackground) {
        [self onBackgroundQueue:filter thenOnMainQueue:^(NSArray *unused) {
            if ([self.searchText isEqualToString:newText]) {
                [self reloadData];
            }
        }];
    } else {
        filter();
        [self reloadData];
    }
}


#pragma mark Filtering

- (NSArray<FLEXTableViewSection *> *)nonemptySections {
    return [self.filterDelegate.allSections flex_filtered:^BOOL(FLEXTableViewSection *section, NSUInteger idx) {
        return section.numberOfRows > 0;
    }];
}

- (NSArray<FLEXTableViewSection *> *)makeSections {
    return @[];
}

- (void)setAllSections:(NSArray<FLEXTableViewSection *> *)allSections {
    _allSections = allSections.copy;
    // Only display nonempty sections
    self.sections = self.nonemptySections;
}

- (void)setSections:(NSArray<FLEXTableViewSection *> *)sections {
    // Allow sections to reload a portion of the table view at will
    [sections enumerateObjectsUsingBlock:^(FLEXTableViewSection *s, NSUInteger idx, BOOL *stop) {
        [s setTable:self.tableView section:idx];
    }];
    _sections = sections.copy;
}


#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.filterDelegate.sections.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.filterDelegate.sections[section].numberOfRows;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return self.filterDelegate.sections[section].title;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *reuse = [self.filterDelegate.sections[indexPath.section] reuseIdentifierForRow:indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuse forIndexPath:indexPath];
    [self.filterDelegate.sections[indexPath.section] configureCell:cell forRow:indexPath.row];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    if (self.wantsSectionIndexTitles) {
        return [NSArray flex_forEachUpTo:self.filterDelegate.sections.count map:^id(NSUInteger i) {
            return @"⦁";
        }];
    }
    
    return nil;
}


#pragma mark - UITableViewDelegate

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self.filterDelegate.sections[indexPath.section] canSelectRow:indexPath.row];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    FLEXTableViewSection *section = self.filterDelegate.sections[indexPath.section];

    void (^action)(UIViewController *) = [section didSelectRowAction:indexPath.row];
    UIViewController *details = [section viewControllerToPushForRow:indexPath.row];

    if (action) {
        action(self);
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    } else if (details) {
        [self.navigationController pushViewController:details animated:YES];
    } else {
        [NSException raise:NSInternalInconsistencyException
                    format:@"Row is selectable but has no action or view controller"];
    }
}

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
    [self.filterDelegate.sections[indexPath.section] didPressInfoButtonAction:indexPath.row](self);
}

- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point __IOS_AVAILABLE(13.0) {
    FLEXTableViewSection *section = self.filterDelegate.sections[indexPath.section];
    NSString *title = [section menuTitleForRow:indexPath.row];
    NSArray<UIMenuElement *> *menuItems = [section menuItemsForRow:indexPath.row sender:self];
    
    if (menuItems.count) {
        return [UIContextMenuConfiguration
            configurationWithIdentifier:nil
            previewProvider:nil
            actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
                return [UIMenu menuWithTitle:title children:menuItems];
            }
        ];
    }
    
    return nil;
}

@end


================================================
FILE: Classes/Core/Controllers/FLEXNavigationController.h
================================================
//
//  FLEXNavigationController.h
//  FLEX
//
//  Created by Tanner on 1/30/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface FLEXNavigationController : UINavigationController

+ (instancetype)withRootViewController:(UIViewController *)rootVC;

@end

@interface UINavigationController (FLEXObjectExploring)

/// Push an object explorer view controller onto the navigation stack
- (void)pushExplorerForObject:(id)object;
/// Push an object explorer view controller onto the navigation stack
- (void)pushExplorerForObject:(id)object animated:(BOOL)animated;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Core/Controllers/FLEXNavigationController.m
================================================
//
//  FLEXNavigationController.m
//  FLEX
//
//  Created by Tanner on 1/30/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXNavigationController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXTabList.h"

@interface UINavigationController (Private) <UIGestureRecognizerDelegate>
- (void)_gestureRecognizedInteractiveHide:(UIGestureRecognizer *)sender;
@end
@interface UIPanGestureRecognizer (Private)
- (void)_setDelegate:(id)delegate;
@end

@interface FLEXNavigationController ()
@property (nonatomic, readonly) BOOL toolbarWasHidden;
@property (nonatomic) BOOL waitingToAddTab;
@property (nonatomic, readonly) BOOL canShowToolbar;
@property (nonatomic) BOOL didSetupPendingDismissButtons;
@property (nonatomic) UISwipeGestureRecognizer *navigationBarSwipeGesture;
@end

@implementation FLEXNavigationController

+ (instancetype)withRootViewController:(UIViewController *)rootVC {
    FLEXNavigationController *nav = [[self alloc] initWithRootViewController:rootVC];
    return nav;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.waitingToAddTab = YES;
    
    // Add gesture to reveal toolbar if hidden
    UITapGestureRecognizer *navbarTapGesture = [[UITapGestureRecognizer alloc]
        initWithTarget:self action:@selector(handleNavigationBarTap:)
    ];
    
    // Don't cancel touches to work around bug on versions of iOS prior to 13
    navbarTapGesture.cancelsTouchesInView = NO;
    [self.navigationBar addGestureRecognizer:navbarTapGesture];
    
    // Add gesture to dismiss if not presented with a sheet style
    if (@available(iOS 13, *)) {
        switch (self.modalPresentationStyle) {
            case UIModalPresentationAutomatic:
            case UIModalPresentationPageSheet:
            case UIModalPresentationFormSheet:
                break;
                
            default:
                [self addNavigationBarSwipeGesture];
                break;
        }
    } else {
        [self addNavigationBarSwipeGesture];
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    if (@available(iOS 15.0, *)) {
        UISheetPresentationController *presenter = self.sheetPresentationController;
        presenter.detents = @[
            UISheetPresentationControllerDetent.mediumDetent,
            UISheetPresentationControllerDetent.largeDetent,
        ];
        presenter.prefersScrollingExpandsWhenScrolledToEdge = NO;
        presenter.selectedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
        presenter.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
    }
    
    if (self.beingPresented && !self.didSetupPendingDismissButtons) {
        for (UIViewController *vc in self.viewControllers) {
            [self addNavigationBarItemsToViewController:vc.navigationItem];
        }
        
        self.didSetupPendingDismissButtons = YES;
    }
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    if (self.waitingToAddTab) {
        // Only add new tab if we're presented properly
        if ([self.presentingViewController isKindOfClass:[FLEXExplorerViewController class]]) {
            // New navigation controllers always add themselves as new tabs,
            // tabs are closed by FLEXExplorerViewController
            [FLEXTabList.sharedList addTab:self];
            self.waitingToAddTab = NO;
        }
    }
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [super pushViewController:viewController animated:animated];
    [self addNavigationBarItemsToViewController:viewController.navigationItem];
}

- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
    // Workaround for UIActivityViewController trying to dismiss us for some reason
    if (![self.viewControllers.lastObject.presentedViewController isKindOfClass:UIActivityViewController.self]) {
        [super dismissViewControllerAnimated:flag completion:completion];
    }
}

- (void)dismissAnimated {
    // Tabs are only closed if the done button is pressed; this
    // allows you to leave a tab open by dragging down to dismiss
    if ([self.presentingViewController isKindOfClass:[FLEXExplorerViewController class]]) {
        [FLEXTabList.sharedList closeTab:self];        
    }
    
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

- (BOOL)canShowToolbar {
    return self.topViewController.toolbarItems.count > 0;
}

- (void)addNavigationBarItemsToViewController:(UINavigationItem *)navigationItem {
    if (!self.presentingViewController) {
        return;
    }
    
    // Check if a done item already exists
    for (UIBarButtonItem *item in navigationItem.rightBarButtonItems) {
        if (item.style == UIBarButtonItemStyleDone) {
            return;
        }
    }
    
    // Give root view controllers a Done button if it does not already have one
    UIBarButtonItem *done = [[UIBarButtonItem alloc]
        initWithBarButtonSystemItem:UIBarButtonSystemItemDone
        target:self
        action:@selector(dismissAnimated)
    ];
    
    // Prepend the button if other buttons exist already
    NSArray *existingItems = navigationItem.rightBarButtonItems;
    if (existingItems.count) {
        navigationItem.rightBarButtonItems = [@[done] arrayByAddingObjectsFromArray:existingItems];
    } else {
        navigationItem.rightBarButtonItem = done;
    }
    
    // Keeps us from calling this method again on
    // the same view controllers in -viewWillAppear:
    self.didSetupPendingDismissButtons = YES;
}

- (void)addNavigationBarSwipeGesture {
    UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]
        initWithTarget:self action:@selector(handleNavigationBarSwipe:)
    ];
    swipe.direction = UISwipeGestureRecognizerDirectionDown;
    swipe.delegate = self;
    self.navigationBarSwipeGesture = swipe;
    [self.navigationBar addGestureRecognizer:swipe];
}

- (void)handleNavigationBarSwipe:(UISwipeGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateRecognized) {
        [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    }
}
     
- (void)handleNavigationBarTap:(UIGestureRecognizer *)sender {
    // Don't reveal the toolbar if we were just tapping a button
    CGPoint location = [sender locationInView:self.navigationBar];
    UIView *hitView = [self.navigationBar hitTest:location withEvent:nil];
    if ([hitView isKindOfClass:[UIControl class]]) {
        return;
    }

    if (sender.state == UIGestureRecognizerStateRecognized) {
        if (self.toolbarHidden && self.canShowToolbar) {
            [self setToolbarHidden:NO animated:YES];
        }
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)g1 shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)g2 {
    if (g1 == self.navigationBarSwipeGesture && g2 == self.barHideOnSwipeGestureRecognizer) {
        return YES;
    }
    
    return NO;
}

- (void)_gestureRecognizedInteractiveHide:(UIPanGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateRecognized) {
        BOOL show = self.canShowToolbar;
        CGFloat yTranslation = [sender translationInView:self.view].y;
        CGFloat yVelocity = [sender velocityInView:self.view].y;
        if (yVelocity > 2000) {
            [self setToolbarHidden:YES animated:YES];
        } else if (show && yTranslation > 20 && yVelocity > 250) {
            [self setToolbarHidden:NO animated:YES];
        } else if (yTranslation < -20) {
            [self setToolbarHidden:YES animated:YES];
        }
    }
}

@end

@implementation UINavigationController (FLEXObjectExploring)

- (void)pushExplorerForObject:(id)object {
    [self pushExplorerForObject:object animated:YES];
}

- (void)pushExplorerForObject:(id)object animated:(BOOL)animated {
    UIViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:object];
    if (explorer) {
        [self pushViewController:explorer animated:animated];
    }
}

@end


================================================
FILE: Classes/Core/Controllers/FLEXTableViewController.h
================================================
//
//  FLEXTableViewController.h
//  FLEX
//
//  Created by Tanner on 7/5/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "FLEXTableView.h"
@class FLEXScopeCarousel, FLEXWindow, FLEXTableViewSection;

typedef CGFloat FLEXDebounceInterval;
/// No delay, all events delivered
extern CGFloat const kFLEXDebounceInstant;
/// Small delay which makes UI seem smoother by avoiding rapid events
extern CGFloat const kFLEXDebounceFast;
/// Slower than Fast, faster than ExpensiveIO
extern CGFloat const kFLEXDebounceForAsyncSearch;
/// The least frequent, at just over once per second; for I/O or other expensive operations
extern CGFloat const kFLEXDebounceForExpensiveIO;

@protocol FLEXSearchResultsUpdating <NSObject>
/// A method to handle search query update events.
///
/// \c searchBarDebounceInterval is used to reduce the frequency at which this
/// method is called. This method is also called when the search bar becomes
/// the first responder, and when the selected search bar scope index changes.
- (void)updateSearchResults:(NSString *)newText;
@end

@interface FLEXTableViewController : UITableViewController <
    UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate
>

/// A grouped table view. Inset on iOS 13.
///
/// Simply calls into \c initWithStyle:
- (id)init;

/// Subclasses may override to configure the controller before \c viewDidLoad:
- (id)initWithStyle:(UITableViewStyle)style;

@property (nonatomic) FLEXTableView *tableView;

/// If your subclass conforms to \c FLEXSearchResultsUpdating
/// then this property is assigned to \c self automatically.
///
/// Setting \c filterDelegate will also set this property to that object.
@property (nonatomic, weak) id<FLEXSearchResultsUpdating> searchDelegate;

/// Defaults to NO.
///
/// Setting this to YES will initialize the carousel and the view.
@property (nonatomic) BOOL showsCarousel;
/// A horizontally scrolling list with functionality similar to
/// that of a search bar's scope bar. You'd want to use this when
/// you have potentially more than 4 scope options.
@property (nonatomic) FLEXScopeCarousel *carousel;

/// Defaults to NO.
///
/// Setting this to YES will initialize searchController and the view.
@property (nonatomic) BOOL showsSearchBar;
/// Defaults to NO.
///
/// Setting this to YES will make the search bar appear whenever the view appears.
/// Otherwise, iOS will only show the search bar when you scroll up.
@property (nonatomic) BOOL showSearchBarInitially;
/// Defaults to NO.
///
/// Setting this to YES will make the search bar activate whenever the view appears.
@property (nonatomic) BOOL activatesSearchBarAutomatically;

/// nil unless showsSearchBar is set to YES.
///
/// self is used as the default search results updater and delegate.
/// The search bar will not dim the background or hide the navigation bar by default.
/// On iOS 11 and up, the search bar will appear in the navigation bar below the title.
@property (nonatomic) UISearchController *searchController;
/// Used to initialize the search controller. Defaults to nil.
@property (nonatomic) UIViewController *searchResultsController;
/// Defaults to "Fast"
///
/// Determines how often search bar results will be "debounced."
/// Empty query events are always sent instantly. Query events will
/// be sent when the user has not changed the query for this interval.
@property (nonatomic) FLEXDebounceInterval searchBarDebounceInterval;
/// Whether the search bar stays at the top of the view while scrolling.
///
/// Calls into self.navigationItem.hidesSearchBarWhenScrolling.
/// Do not change self.navigationItem.hidesSearchBarWhenScrolling directly,
/// or it will not be respsected. Use this instead.
/// Defaults to NO.
@property (nonatomic) BOOL pinSearchBar;
/// By default, we will show the search bar's cancel button when
/// search becomes active and hide it when search is dismissed.
///
/// Do not set the showsCancelButton property on the searchController's
/// searchBar manually. Set this property after turning on showsSearchBar.
///
/// Does nothing pre-iOS 13, safe to call on any version.
@property (nonatomic) BOOL automaticallyShowsSearchBarCancelButton;

/// If using the scope bar, self.searchController.searchBar.selectedScopeButtonIndex.
/// Otherwise, this is the selected index of the carousel, or NSNotFound if using neither.
@property (nonatomic) NSInteger selectedScope;
/// self.searchController.searchBar.text
@property (nonatomic, readonly, copy) NSString *searchText;

/// A totally optional delegate to forward search results updater calls to.
/// If a delegate is set, updateSearchResults: is not called on this view controller.
@property (nonatomic, weak) id<FLEXSearchResultsUpdating> searchResultsUpdater;

/// self.view.window as a \c FLEXWindow
@property (nonatomic, readonly) FLEXWindow *window;

/// Convenient for doing some async processor-intensive searching
/// in the background before updating the UI back on the main queue.
- (void)onBackgroundQueue:(NSArray *(^)(void))backgroundBlock thenOnMainQueue:(void(^)(NSArray *))mainBlock;

/// Adds up to 3 additional items to the toolbar in right-to-left order.
///
/// That is, the first item in the given array will be the rightmost item behind
/// any existing toolbar items. By default, buttons for bookmarks and tabs are shown.
///
/// If you wish to have more control over how the buttons are arranged or which
/// buttons are displayed, you can access the properties for the pre-existing
/// toolbar items directly and manually set \c self.toolbarItems by overriding
/// the \c setupToolbarItems method below.
- (void)addToolbarItems:(NSArray<UIBarButtonItem *> *)items;

/// Subclasses may override. You should not need to call this method directly.
- (void)setupToolbarItems;

@property (nonatomic, readonly) UIBarButtonItem *shareToolbarItem;
@property (nonatomic, readonly) UIBarButtonItem *bookmarksToolbarItem;
@property (nonatomic, readonly) UIBarButtonItem *openTabsToolbarItem;

/// Whether or not to display the "share" icon in the middle of the toolbar. NO by default.
///
/// Turning this on after you have added custom toolbar items will
/// push off the leftmost toolbar item and shift the others leftward.
@property (nonatomic) BOOL showsShareToolbarItem;
/// Called when the share button is pressed.
/// Default implementation does nothign. Subclasses may override.
- (void)shareButtonPressed:(UIBarButtonItem *)sender;

/// Subclasses may call this to opt-out of all toolbar related behavior.
/// This is necessary if you want to disable the gesture which reveals the toolbar.
- (void)disableToolbar;

@end


================================================
FILE: Classes/Core/Controllers/FLEXTableViewController.m
================================================
//
//  FLEXTableViewController.m
//  FLEX
//
//  Created by Tanner on 7/5/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXBookmarksViewController.h"
#import "FLEXTabsViewController.h"
#import "FLEXScopeCarousel.h"
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "FLEXResources.h"
#import "UIBarButtonItem+FLEX.h"
#import <objc/runtime.h>

@interface Block : NSObject
- (void)invoke;
@end

CGFloat const kFLEXDebounceInstant = 0.f;
CGFloat const kFLEXDebounceFast = 0.05;
CGFloat const kFLEXDebounceForAsyncSearch = 0.15;
CGFloat const kFLEXDebounceForExpensiveIO = 0.5;

@interface FLEXTableViewController ()
@property (nonatomic) NSTimer *debounceTimer;
@property (nonatomic) BOOL didInitiallyRevealSearchBar;
@property (nonatomic) UITableViewStyle style;

@property (nonatomic) BOOL hasAppeared;
@property (nonatomic, readonly) UIView *tableHeaderViewContainer;

@property (nonatomic, readonly) BOOL manuallyDeactivateSearchOnDisappear;

@property (nonatomic) UIBarButtonItem *middleToolbarItem;
@property (nonatomic) UIBarButtonItem *middleLeftToolbarItem;
@property (nonatomic) UIBarButtonItem *leftmostToolbarItem;
@end

@implementation FLEXTableViewController
@dynamic tableView;
@synthesize showsShareToolbarItem = _showsShareToolbarItem;
@synthesize tableHeaderViewContainer = _tableHeaderViewContainer;
@synthesize automaticallyShowsSearchBarCancelButton = _automaticallyShowsSearchBarCancelButton;

#pragma mark - Initialization

- (id)init {
    if (@available(iOS 13.0, *)) {
        self = [self initWithStyle:UITableViewStyleInsetGrouped];
    } else {
        self = [self initWithStyle:UITableViewStyleGrouped];
    }
    
    return self;
}

- (id)initWithStyle:(UITableViewStyle)style {
    self = [super initWithStyle:style];
    
    if (self) {
        _searchBarDebounceInterval = kFLEXDebounceFast;
        _showSearchBarInitially = YES;
        _style = style;
        _manuallyDeactivateSearchOnDisappear = (
            NSProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11
        );
        
        // We will be our own search delegate if we implement this method
        if ([self respondsToSelector:@selector(updateSearchResults:)]) {
            self.searchDelegate = (id)self;
        }
    }
    
    return self;
}


#pragma mark - Public

- (FLEXWindow *)window {
    return (id)self.view.window;
}

- (void)setShowsSearchBar:(BOOL)showsSearchBar {
    if (_showsSearchBar == showsSearchBar) return;
    _showsSearchBar = showsSearchBar;
    
    if (showsSearchBar) {
        UIViewController *results = self.searchResultsController;
        self.searchController = [[UISearchController alloc] initWithSearchResultsController:results];
        self.searchController.searchBar.placeholder = @"Filter";
        self.searchController.searchResultsUpdater = (id)self;
        self.searchController.delegate = (id)self;
        if (@available(iOS 9.1, *)) {
            self.searchController.obscuresBackgroundDuringPresentation = NO;
        } else {
            self.searchController.dimsBackgroundDuringPresentation = NO;
        }
        self.searchController.hidesNavigationBarDuringPresentation = NO;
        /// Not necessary in iOS 13; remove this when iOS 13 is the minimum deployment target
        self.searchController.searchBar.delegate = self;

        self.automaticallyShowsSearchBarCancelButton = YES;

        if (@available(iOS 13, *)) {
            self.searchController.automaticallyShowsScopeBar = NO;
        }
        
        [self addSearchController:self.searchController];
    } else {
        // Search already shown and just set to NO, so remove it
        [self removeSearchController:self.searchController];
    }
}

- (void)setShowsCarousel:(BOOL)showsCarousel {
    if (_showsCarousel == showsCarousel) return;
    _showsCarousel = showsCarousel;
    
    if (showsCarousel) {
        _carousel = ({ weakify(self)
            
            FLEXScopeCarousel *carousel = [FLEXScopeCarousel new];
            carousel.selectedIndexChangedAction = ^(NSInteger idx) { strongify(self);
                [self.searchDelegate updateSearchResults:self.searchText];
            };

            // UITableView won't update the header size unless you reset the header view
            [carousel registerBlockForDynamicTypeChanges:^(FLEXScopeCarousel *_) { strongify(self);
                [self layoutTableHeaderIfNeeded];
            }];

            carousel;
        });
        [self addCarousel:_carousel];
    } else {
        // Carousel already shown and just set to NO, so remove it
        [self removeCarousel:_carousel];
    }
}

- (NSInteger)selectedScope {
    if (self.searchController.searchBar.showsScopeBar) {
        return self.searchController.searchBar.selectedScopeButtonIndex;
    } else if (self.showsCarousel) {
        return self.carousel.selectedIndex;
    } else {
        return 0;
    }
}

- (void)setSelectedScope:(NSInteger)selectedScope {
    if (self.searchController.searchBar.showsScopeBar) {
        self.searchController.searchBar.selectedScopeButtonIndex = selectedScope;
    } else if (self.showsCarousel) {
        self.carousel.selectedIndex = selectedScope;
    }

    [self.searchDelegate updateSearchResults:self.searchText];
}

- (NSString *)searchText {
    return self.searchController.searchBar.text;
}

- (BOOL)automaticallyShowsSearchBarCancelButton {
    if (@available(iOS 13, *)) {
        return self.searchController.automaticallyShowsCancelButton;
    }

    return _automaticallyShowsSearchBarCancelButton;
}

- (void)setAutomaticallyShowsSearchBarCancelButton:(BOOL)value {
    if (@available(iOS 13, *)) {
        self.searchController.automaticallyShowsCancelButton = value;
    }

    _automaticallyShowsSearchBarCancelButton = value;
}

- (void)onBackgroundQueue:(NSArray *(^)(void))backgroundBlock thenOnMainQueue:(void(^)(NSArray *))mainBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSArray *items = backgroundBlock();
        dispatch_async(dispatch_get_main_queue(), ^{
            mainBlock(items);
        });
    });
}

- (void)setsShowsShareToolbarItem:(BOOL)showsShareToolbarItem {
    _showsShareToolbarItem = showsShareToolbarItem;
    if (self.isViewLoaded) {
        [self setupToolbarItems];
    }
}

- (void)disableToolbar {
    self.navigationController.toolbarHidden = YES;
    self.navigationController.hidesBarsOnSwipe = NO;
    self.toolbarItems = nil;
}


#pragma mark - View Controller Lifecycle

- (void)loadView {
    self.view = [FLEXTableView style:self.style];
    self.tableView.dataSource = self;
    self.tableView.delegate = self;
    
    self.tableView.estimatedRowHeight = 10;
    
    _shareToolbarItem = FLEXBarButtonItemSystem(Action, self, @selector(shareButtonPressed:));
    _bookmarksToolbarItem = [UIBarButtonItem
        flex_itemWithImage:FLEXResources.bookmarksIcon target:self action:@selector(showBookmarks)
    ];
    _openTabsToolbarItem = [UIBarButtonItem
        flex_itemWithImage:FLEXResources.openTabsIcon target:self action:@selector(showTabSwitcher)
    ];
    
    self.leftmostToolbarItem = UIBarButtonItem.flex_fixedSpace;
    self.middleLeftToolbarItem = UIBarButtonItem.flex_fixedSpace;
    self.middleToolbarItem = UIBarButtonItem.flex_fixedSpace;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
    
    // Toolbar
    self.navigationController.toolbarHidden = self.toolbarItems.count > 0;
    self.navigationController.hidesBarsOnSwipe = YES;

    // On iOS 13, the root view controller shows it's search bar no matter what.
    // Turning this off avoids some weird flash the navigation bar does when we
    // toggle navigationItem.hidesSearchBarWhenScrolling on and off. The flash
    // will still happen on subsequent view controllers, but we can at least
    // avoid it for the root view controller
    if (@available(iOS 13, *)) {
        if (self.navigationController.viewControllers.firstObject == self) {
            _showSearchBarInitially = NO;
        }
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    if (@available(iOS 11.0, *)) {
        // When going back, make the search bar reappear instead of hiding
        if ((self.pinSearchBar || self.showSearchBarInitially) && !self.didInitiallyRevealSearchBar) {
            self.navigationItem.hidesSearchBarWhenScrolling = NO;
        }
    }
    
    // Make the keyboard seem to appear faster
    if (self.activatesSearchBarAutomatically) {
        [self makeKeyboardAppearNow];
    }

    [self setupToolbarItems];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // Allow scrolling to collapse the search bar, only if we don't want it pinned
    if (@available(iOS 11.0, *)) {
        if (self.showSearchBarInitially && !self.pinSearchBar && !self.didInitiallyRevealSearchBar) {
            // All this mumbo jumbo is necessary to work around a bug in iOS 13 up to 13.2
            // wherein quickly toggling navigationItem.hidesSearchBarWhenScrolling to make
            // the search bar appear initially results in a bugged search bar that
            // becomes transparent and floats over the screen as you scroll
            [UIView animateWithDuration:0.2 animations:^{
                self.navigationItem.hidesSearchBarWhenScrolling = YES;
                [self.navigationController.view setNeedsLayout];
                [self.navigationController.view layoutIfNeeded];
            }];
        }
    }
    
    if (self.activatesSearchBarAutomatically) {
        // Keyboard has appeared, now we call this as we soon present our search bar
        [self removeDummyTextField];
        
        // Activate the search bar
        dispatch_async(dispatch_get_main_queue(), ^{
            // This doesn't work unless it's wrapped in this dispatch_async call
            [self.searchController.searchBar becomeFirstResponder];
        });
    }

    // We only want to reveal the search bar when the view controller first appears.
    self.didInitiallyRevealSearchBar = YES;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    if (self.manuallyDeactivateSearchOnDisappear && self.searchController.isActive) {
        self.searchController.active = NO;
    }
}

- (void)didMoveToParentViewController:(UIViewController *)parent {
    [super didMoveToParentViewController:parent];
    // Reset this since we are re-appearing under a new
    // parent view controller and need to show it again
    self.didInitiallyRevealSearchBar = NO;
}


#pragma mark - Toolbar, Public

- (void)setupToolbarItems {
    if (!self.isViewLoaded) {
        return;
    }
    
    self.toolbarItems = @[
        self.leftmostToolbarItem,
        UIBarButtonItem.flex_flexibleSpace,
        self.middleLeftToolbarItem,
        UIBarButtonItem.flex_flexibleSpace,
        self.middleToolbarItem,
        UIBarButtonItem.flex_flexibleSpace,
        self.bookmarksToolbarItem,
        UIBarButtonItem.flex_flexibleSpace,
        self.openTabsToolbarItem,
    ];
    
    for (UIBarButtonItem *item in self.toolbarItems) {
        [item _setWidth:60];
        // This does not work for anything but fixed spaces for some reason
        // item.width = 60;
    }
    
    // Disable tabs entirely when not presented by FLEXExplorerViewController
    UIViewController *presenter = self.navigationController.presentingViewController;
    if (![presenter isKindOfClass:[FLEXExplorerViewController class]]) {
        self.openTabsToolbarItem.enabled = NO;
    }
}

- (void)addToolbarItems:(NSArray<UIBarButtonItem *> *)items {
    if (self.showsShareToolbarItem) {
        // Share button is in the middle, skip middle button
        if (items.count > 0) {
            self.middleLeftToolbarItem = items[0];
        }
        if (items.count > 1) {
            self.leftmostToolbarItem = items[1];
        }
    } else {
        // Add buttons right-to-left
        if (items.count > 0) {
            self.middleToolbarItem = items[0];
        }
        if (items.count > 1) {
            self.middleLeftToolbarItem = items[1];
        }
        if (items.count > 2) {
            self.leftmostToolbarItem = items[2];
        }
    }
    
    [self setupToolbarItems];
}

- (void)setShowsShareToolbarItem:(BOOL)showShare {
    if (_showsShareToolbarItem != showShare) {
        _showsShareToolbarItem = showShare;
        
        if (showShare) {
            // Push out leftmost item
            self.leftmostToolbarItem = self.middleLeftToolbarItem;
            self.middleLeftToolbarItem = self.middleToolbarItem;
            
            // Use share for middle
            self.middleToolbarItem = self.shareToolbarItem;
        } else {
            // Remove share, shift custom items rightward
            self.middleToolbarItem = self.middleLeftToolbarItem;
            self.middleLeftToolbarItem = self.leftmostToolbarItem;
            self.leftmostToolbarItem = UIBarButtonItem.flex_fixedSpace;
        }
    }
    
    [self setupToolbarItems];
}

- (void)shareButtonPressed:(UIBarButtonItem *)sender {

}


#pragma mark - Private

- (void)debounce:(void(^)(void))block {
    [self.debounceTimer invalidate];
    
    self.debounceTimer = [NSTimer
        scheduledTimerWithTimeInterval:self.searchBarDebounceInterval
        target:block
        selector:@selector(invoke)
        userInfo:nil
        repeats:NO
    ];
}

- (void)layoutTableHeaderIfNeeded {
    if (self.showsCarousel) {
        self.carousel.frame = FLEXRectSetHeight(
            self.carousel.frame, self.carousel.intrinsicContentSize.height
        );
    }
    
    self.tableView.tableHeaderView = self.tableView.tableHeaderView;
}

- (void)addCarousel:(FLEXScopeCarousel *)carousel {
    if (@available(iOS 11.0, *)) {
        self.tableView.tableHeaderView = carousel;
    } else {
        carousel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
        
        CGRect frame = self.tableHeaderViewContainer.frame;
        CGRect subviewFrame = carousel.frame;
        subviewFrame.origin.y = 0;
        
        // Put the carousel below the search bar if it's already there
        if (self.showsSearchBar) {
            carousel.frame = subviewFrame = FLEXRectSetY(
                subviewFrame, self.searchController.searchBar.frame.size.height
            );
            frame.size.height += carousel.intrinsicContentSize.height;
        } else {
            frame.size.height = carousel.intrinsicContentSize.height;
        }
        
        self.tableHeaderViewContainer.frame = frame;
        [self.tableHeaderViewContainer addSubview:carousel];
    }
    
    [self layoutTableHeaderIfNeeded];
}

- (void)removeCarousel:(FLEXScopeCarousel *)carousel {
    [carousel removeFromSuperview];
    
    if (@available(iOS 11.0, *)) {
        self.tableView.tableHeaderView = nil;
    } else {
        if (self.showsSearchBar) {
            [self removeSearchController:self.searchController];
            [self addSearchController:self.searchController];
        } else {
            self.tableView.tableHeaderView = nil;
            _tableHeaderViewContainer = nil;
        }
    }
}

- (void)addSearchController:(UISearchController *)controller {
    if (@available(iOS 11.0, *)) {
        self.navigationItem.searchController = controller;
    } else {
        controller.searchBar.autoresizingMask |= UIViewAutoresizingFlexibleBottomMargin;
        [self.tableHeaderViewContainer addSubview:controller.searchBar];
        CGRect subviewFrame = controller.searchBar.frame;
        CGRect frame = self.tableHeaderViewContainer.frame;
        frame.size.width = MAX(frame.size.width, subviewFrame.size.width);
        frame.size.height = subviewFrame.size.height;
        
        // Move the carousel down if it's already there
        if (self.showsCarousel) {
            self.carousel.frame = FLEXRectSetY(
                self.carousel.frame, subviewFrame.size.height
            );
            frame.size.height += self.carousel.frame.size.height;
        }
        
        self.tableHeaderViewContainer.frame = frame;
        [self layoutTableHeaderIfNeeded];
    }
}

- (void)removeSearchController:(UISearchController *)controller {
    if (@available(iOS 11.0, *)) {
        self.navigationItem.searchController = nil;
    } else {
        [controller.searchBar removeFromSuperview];
        
        if (self.showsCarousel) {
//            self.carousel.frame = FLEXRectRemake(CGPointZero, self.carousel.frame.size);
            [self removeCarousel:self.carousel];
            [self addCarousel:self.carousel];
        } else {
            self.tableView.tableHeaderView = nil;
            _tableHeaderViewContainer = nil;
        }
    }
}

- (UIView *)tableHeaderViewContainer {
    if (!_tableHeaderViewContainer) {
        _tableHeaderViewContainer = [UIView new];
        self.tableView.tableHeaderView = self.tableHeaderViewContainer;
    }
    
    return _tableHeaderViewContainer;
}

- (void)showBookmarks {
    UINavigationController *nav = [[UINavigationController alloc]
        initWithRootViewController:[FLEXBookmarksViewController new]
    ];
    [self presentViewController:nav animated:YES completion:nil];
}

- (void)showTabSwitcher {
    UINavigationController *nav = [[UINavigationController alloc]
        initWithRootViewController:[FLEXTabsViewController new]
    ];
    [self presentViewController:nav animated:YES completion:nil];
}


#pragma mark - Search Bar

#pragma mark Faster keyboard

static UITextField *kDummyTextField = nil;

/// Make the keyboard appear instantly. We use this to make the
/// keyboard appear faster when the search bar is set to appear initially.
/// You must call \c -removeDummyTextField before your search bar is to appear.
- (void)makeKeyboardAppearNow {
    if (!kDummyTextField) {
        kDummyTextField = [UITextField new];
        kDummyTextField.autocorrectionType = UITextAutocorrectionTypeNo;
    }
    
    kDummyTextField.inputAccessoryView = self.searchController.searchBar.inputAccessoryView;
    [UIApplication.sharedApplication.keyWindow addSubview:kDummyTextField];
    [kDummyTextField becomeFirstResponder];
}

- (void)removeDummyTextField {
    if (kDummyTextField.superview) {
        [kDummyTextField removeFromSuperview];
    }
}

#pragma mark UISearchResultsUpdating

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
    [self.debounceTimer invalidate];
    NSString *text = searchController.searchBar.text;
    
    void (^updateSearchResults)(void) = ^{
        if (self.searchResultsUpdater) {
            [self.searchResultsUpdater updateSearchResults:text];
        } else {
            [self.searchDelegate updateSearchResults:text];
        }
    };
    
    // Only debounce if we want to, and if we have a non-empty string
    // Empty string events are sent instantly
    if (text.length && self.searchBarDebounceInterval > kFLEXDebounceInstant) {
        [self debounce:updateSearchResults];
    } else {
        updateSearchResults();
    }
}


#pragma mark UISearchControllerDelegate

- (void)willPresentSearchController:(UISearchController *)searchController {
    // Manually show cancel button for < iOS 13
    if (!@available(iOS 13, *) && self.automaticallyShowsSearchBarCancelButton) {
        [searchController.searchBar setShowsCancelButton:YES animated:YES];
    }
}

- (void)willDismissSearchController:(UISearchController *)searchController {
    // Manually hide cancel button for < iOS 13
    if (!@available(iOS 13, *) && self.automaticallyShowsSearchBarCancelButton) {
        [searchController.searchBar setShowsCancelButton:NO animated:YES];
    }
}


#pragma mark UISearchBarDelegate

/// Not necessary in iOS 13; remove this when iOS 13 is the deployment target
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
    [self updateSearchResultsForSearchController:self.searchController];
}


#pragma mark Table View

/// Not having a title in the first section looks weird with a rounded-corner table view style
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (@available(iOS 13, *)) {
        if (self.style == UITableViewStyleInsetGrouped) {
            return @" ";
        }
    }

    return nil; // For plain/gropued style
}

@end


================================================
FILE: Classes/Core/FLEXSingleRowSection.h
================================================
//
//  FLEXSingleRowSection.h
//  FLEX
//
//  Created by Tanner Bennett on 9/25/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewSection.h"

NS_ASSUME_NONNULL_BEGIN

/// A section providing a specific single row.
///
/// You may optionally provide a view controller to push when the row
/// is selected, or an action to perform when it is selected.
/// Which one is used first is up to the table view data source.
@interface FLEXSingleRowSection : FLEXTableViewSection

/// @param reuseIdentifier if nil, kFLEXDefaultCell is used.
+ (instancetype)title:(nullable NSString *)sectionTitle
                reuse:(nullable NSString *)reuseIdentifier
                 cell:(void(^)(__kindof UITableViewCell *cell))cellConfiguration;

@property (nullable, nonatomic) UIViewController *pushOnSelection;
@property (nullable, nonatomic) void (^selectionAction)(UIViewController *host);
/// Called to determine whether the single row should display itself or not.
@property (nonatomic) BOOL (^filterMatcher)(NSString *filterText);

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Core/FLEXSingleRowSection.m
================================================
//
//  FLEXSingleRowSection.m
//  FLEX
//
//  Created by Tanner Bennett on 9/25/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXSingleRowSection.h"
#import "FLEXTableView.h"

@interface FLEXSingleRowSection ()
@property (nonatomic, readonly) NSString *reuseIdentifier;
@property (nonatomic, readonly) void (^cellConfiguration)(__kindof UITableViewCell *cell);

@property (nonatomic) NSString *lastTitle;
@property (nonatomic) NSString *lastSubitle;
@end

@implementation FLEXSingleRowSection

#pragma mark - Public

+ (instancetype)title:(NSString *)title
                reuse:(NSString *)reuse
                 cell:(void (^)(__kindof UITableViewCell *))config {
    return [[self alloc] initWithTitle:title reuse:reuse cell:config];
}

- (id)initWithTitle:(NSString *)sectionTitle
              reuse:(NSString *)reuseIdentifier
               cell:(void (^)(__kindof UITableViewCell *))cellConfiguration {
    NSParameterAssert(cellConfiguration);
    
    self = [super init];
    if (self) {
        _title = sectionTitle;
        _reuseIdentifier = reuseIdentifier ?: kFLEXDefaultCell;
        _cellConfiguration = cellConfiguration;
    }

    return self;
}

#pragma mark - Overrides

- (NSInteger)numberOfRows {
    if (self.filterMatcher && self.filterText.length) {
        return self.filterMatcher(self.filterText) ? 1 : 0;
    }
    
    return 1;
}

- (BOOL)canSelectRow:(NSInteger)row {
    return self.pushOnSelection || self.selectionAction;
}

- (void (^)(__kindof UIViewController *))didSelectRowAction:(NSInteger)row {
    return self.selectionAction;
}

- (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
    return self.pushOnSelection;
}

- (NSString *)reuseIdentifierForRow:(NSInteger)row {
    return self.reuseIdentifier;
}

- (void)configureCell:(__kindof UITableViewCell *)cell forRow:(NSInteger)row {
    cell.textLabel.text = nil;
    cell.detailTextLabel.text = nil;
    cell.accessoryType = UITableViewCellAccessoryNone;
    
    self.cellConfiguration(cell);
    self.lastTitle = cell.textLabel.text;
    self.lastSubitle = cell.detailTextLabel.text;
}

- (NSString *)titleForRow:(NSInteger)row {
    return self.lastTitle;
}

- (NSString *)subtitleForRow:(NSInteger)row {
    return self.lastSubitle;
}

@end


================================================
FILE: Classes/Core/FLEXTableViewSection.h
================================================
//
//  FLEXTableViewSection.h
//  FLEX
//
//  Created by Tanner on 1/29/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "NSArray+FLEX.h"
@class FLEXTableView;

NS_ASSUME_NONNULL_BEGIN

#pragma mark FLEXTableViewSection

/// An abstract base class for table view sections.
///
/// Many properties or methods here return nil or some logical equivalent by default.
/// Even so, most of the methods with defaults are intended to be overriden by subclasses.
/// Some methods are not implemented at all and MUST be implemented by a subclass.
@interface FLEXTableViewSection : NSObject {
    @protected
    /// Unused by default, use if you want
    NSString *_title;
    
    @private
    __weak UITableView *_tableView;
    NSInteger _sectionIndex;
}

#pragma mark - Data

/// A title to be displayed for the custom section.
/// Subclasses may override or use the \c _title ivar.
@property (nonatomic, readonly, nullable, copy) NSString *title;
/// The number of rows in this section. Subclasses must override.
/// This should not change until \c filterText is changed or \c reloadData is called.
@property (nonatomic, readonly) NSInteger numberOfRows;
/// A map of reuse identifiers to \c UITableViewCell (sub)class objects.
/// Subclasses \e may override this as necessary, but are not required to.
/// See \c FLEXTableView.h for more information.
/// @return nil by default.
@property (nonatomic, readonly, nullable) NSDictionary<NSString *, Class> *cellRegistrationMapping;

/// The section should filter itself based on the contents of this property
/// as it is set. If it is set to nil or an empty string, it should not filter.
/// Subclasses should override or observe this property and react to changes.
///
/// It is common practice to use two arrays for the underlying model:
/// One to hold all rows, and one to hold unfiltered rows. When \c setFilterText:
/// is called, call \c super to store the new value, and re-filter your model accordingly.
@property (nonatomic, nullable) NSString *filterText;

/// Provides an avenue for the section to refresh data or change the number of rows.
///
/// This is called before reloading the table view itself. If your section pulls data
/// from an external data source, this is a good place to refresh that data entirely.
/// If your section does not, then it might be simpler for you to just override
/// \c setFilterText: to call \c super and call \c reloadData.
- (void)reloadData;

/// Like \c reloadData, but optionally reloads the table view section
/// associated with this section object, if any. Do not override.
/// Do not call outside of the main thread.
- (void)reloadData:(BOOL)updateTable;

/// Provide a table view and section index to allow the section to efficiently reload
/// its own section of the table when something changes it. The table reference is
/// held weakly, and subclasses cannot access it or the index. Call this method again
/// if the section numbers have changed since you last called it.
- (void)setTable:(UITableView *)tableView section:(NSInteger)index;

#pragma mark - Row Selection

/// Whether the given row should be selectable, such as if tapping the cell
/// should take the user to a new screen or trigger an action.
/// Subclasses \e may override this as necessary, but are not required to.
/// @return \c NO by default
- (BOOL)canSelectRow:(NSInteger)row;

/// An action "future" to be triggered when the row is selected, if the row
/// supports being selected as indicated by \c canSelectRow:. Subclasses
/// must implement this in accordance with how they implement \c canSelectRow:
/// if they do not implement \c viewControllerToPushForRow:
/// @return This returns \c nil if no view controller is provided by
/// \c viewControllerToPushForRow: — otherwise it pushes that view controller
/// onto \c host.navigationController
- (nullable void(^)(__kindof UIViewController *host))didSelectRowAction:(NSInteger)row;

/// A view controller to display when the row is selected, if the row
/// supports being selected as indicated by \c canSelectRow:. Subclasses
/// must implement this in accordance with how they implement \c canSelectRow:
/// if they do not implement \c didSelectRowAction:
/// @return \c nil by default
- (nullable UIViewController *)viewControllerToPushForRow:(NSInteger)row;

/// Called when the accessory view's detail button is pressed.
/// @return \c nil by default.
- (nullable void(^)(__kindof UIViewController *host))didPressInfoButtonAction:(NSInteger)row;

#pragma mark - Context Menus

/// By default, this is the title of the row.
/// @return The title of the context menu, if any.
- (nullable NSString *)menuTitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0));
/// Protected, not intended for public use. \c menuTitleForRow:
/// already includes the value returned from this method.
/// 
/// By default, this returns \c @"". Subclasses may override to
/// provide a detailed description of the target of the context menu.
- (NSString *)menuSubtitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0));
/// The context menu items, if any. Subclasses may override.
/// By default, only inludes items for \c copyMenuItemsForRow:.
- (nullable NSArray<UIMenuElement *> *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13.0));
/// Subclasses may override to return a list of copiable items.
///
/// Every two elements in the list compose a key-value pair, where the key
/// should be a description of what will be copied, and the values should be
/// the strings to copy. Return an empty string as a value to show a disabled action.
- (nullable NSArray<NSString *> *)copyMenuItemsForRow:(NSInteger)row API_AVAILABLE(ios(13.0));

#pragma mark - Cell Configuration

/// Provide a reuse identifier for the given row. Subclasses should override.
///
/// Custom reuse identifiers should be specified in \c cellRegistrationMapping.
/// You may return any of the identifiers in \c FLEXTableView.h
/// without including them in the \c cellRegistrationMapping.
/// @return \c kFLEXDefaultCell by default.
- (NSString *)reuseIdentifierForRow:(NSInteger)row;
/// Configure a cell for the given row. Subclasses must override.
- (void)configureCell:(__kindof UITableViewCell *)cell forRow:(NSInteger)row;

#pragma mark - External Convenience

/// For use by whatever view controller uses your section. Not required.
/// @return An optional title.
- (nullable NSString *)titleForRow:(NSInteger)row;
/// For use by whatever view controller uses your section. Not required.
/// @return An optional subtitle.
- (nullable NSString *)subtitleForRow:(NSInteger)row;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Core/FLEXTableViewSection.m
================================================
//
//  FLEXTableViewSection.m
//  FLEX
//
//  Created by Tanner on 1/29/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewSection.h"
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "UIMenu+FLEX.h"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"

@implementation FLEXTableViewSection

- (NSInteger)numberOfRows {
    return 0;
}

- (void)reloadData { }

- (void)reloadData:(BOOL)updateTable {
    [self reloadData];
    if (updateTable) {
        NSIndexSet *index = [NSIndexSet indexSetWithIndex:_sectionIndex];
        [_tableView reloadSections:index withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)setTable:(UITableView *)tableView section:(NSInteger)index {
    _tableView = tableView;
    _sectionIndex = index;
}

- (NSDictionary<NSString *,Class> *)cellRegistrationMapping {
    return nil;
}

- (BOOL)canSelectRow:(NSInteger)row { return NO; }

- (void (^)(__kindof UIViewController *))didSelectRowAction:(NSInteger)row {
    UIViewController *toPush = [self viewControllerToPushForRow:row];
    if (toPush) {
        return ^(UIViewController *host) {
            [host.navigationController pushViewController:toPush animated:YES];
        };
    }

    return nil;
}

- (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
    return nil;
}

- (void (^)(__kindof UIViewController *))didPressInfoButtonAction:(NSInteger)row {
    return nil;
}

- (NSString *)reuseIdentifierForRow:(NSInteger)row {
    return kFLEXDefaultCell;
}

- (NSString *)menuTitleForRow:(NSInteger)row {
    NSString *title = [self titleForRow:row];
    NSString *subtitle = [self menuSubtitleForRow:row];
    
    if (subtitle.length) {
        return [NSString stringWithFormat:@"%@\n\n%@", title, subtitle];
    }
    
    return title;
}

- (NSString *)menuSubtitleForRow:(NSInteger)row {
    return @"";
}

- (NSArray<UIMenuElement *> *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13.0)) {
    NSArray<NSString *> *copyItems = [self copyMenuItemsForRow:row];
    NSAssert(copyItems.count % 2 == 0, @"copyMenuItemsForRow: should return an even list");
    
    if (copyItems.count) {
        NSInteger numberOfActions = copyItems.count / 2;
        BOOL collapseMenu = numberOfActions > 4;
        UIImage *copyIcon = [UIImage systemImageNamed:@"doc.on.doc"];
        
        NSMutableArray *actions = [NSMutableArray new];
        
        for (NSInteger i = 0; i < copyItems.count; i += 2) {
            NSString *key = copyItems[i], *value = copyItems[i+1];
            NSString *title = collapseMenu ? key : [@"Copy " stringByAppendingString:key];
            
            UIAction *copy = [UIAction
                actionWithTitle:title
                image:copyIcon
                identifier:nil
                handler:^(__kindof UIAction *action) {
                    UIPasteboard.generalPasteboard.string = value;
                }
            ];
            if (!value.length) {
                copy.attributes = UIMenuElementAttributesDisabled;
            }
            
            [actions addObject:copy];
        }
        
        UIMenu *copyMenu = [UIMenu
            flex_inlineMenuWithTitle:@"Copy…" 
            image:copyIcon
            children:actions
        ];
        
        if (collapseMenu) {
            return @[[copyMenu flex_collapsed]];
        } else {
            return @[copyMenu];
        }
    }
    
    return @[];
}

- (NSArray<NSString *> *)copyMenuItemsForRow:(NSInteger)row {
    return nil;
}

- (NSString *)titleForRow:(NSInteger)row { return nil; }
- (NSString *)subtitleForRow:(NSInteger)row { return nil; }

@end

#pragma clang diagnostic pop


================================================
FILE: Classes/Core/Views/Carousel/FLEXCarouselCell.h
================================================
//
//  FLEXCarouselCell.h
//  FLEX
//
//  Created by Tanner Bennett on 7/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface FLEXCarouselCell : UICollectionViewCell

@property (nonatomic, copy) NSString *title;

@end


================================================
FILE: Classes/Core/Views/Carousel/FLEXCarouselCell.m
================================================
//
//  FLEXCarouselCell.m
//  FLEX
//
//  Created by Tanner Bennett on 7/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXCarouselCell.h"
#import "FLEXColor.h"
#import "UIView+FLEX_Layout.h"

@interface FLEXCarouselCell ()
@property (nonatomic, readonly) UILabel *titleLabel;
@property (nonatomic, readonly) UIView *selectionIndicatorStripe;
@property (nonatomic) BOOL constraintsInstalled;
@end

@implementation FLEXCarouselCell

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _titleLabel = [UILabel new];
        _selectionIndicatorStripe = [UIView new];

        self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
        self.selectionIndicatorStripe.backgroundColor = self.tintColor;
        if (@available(iOS 10, *)) {
            self.titleLabel.adjustsFontForContentSizeCategory = YES;
        }

        [self.contentView addSubview:self.titleLabel];
        [self.contentView addSubview:self.selectionIndicatorStripe];

        [self installConstraints];

        [self updateAppearance];
    }

    return self;
}

- (void)updateAppearance {
    self.selectionIndicatorStripe.hidden = !self.selected;

    if (self.selected) {
        self.titleLabel.textColor = self.tintColor;
    } else {
        self.titleLabel.textColor = FLEXColor.deemphasizedTextColor;
    }
}

#pragma mark Public

- (NSString *)title {
    return self.titleLabel.text;
}

- (void)setTitle:(NSString *)title {
    self.titleLabel.text = title;
    [self.titleLabel sizeToFit];
    [self setNeedsLayout];
}

#pragma mark Overrides

- (void)prepareForReuse {
    [super prepareForReuse];
    [self updateAppearance];
}

- (void)installConstraints {
    CGFloat stripeHeight = 2;

    self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.selectionIndicatorStripe.translatesAutoresizingMaskIntoConstraints = NO;

    UIView *superview = self.contentView;
    [self.titleLabel flex_pinEdgesToSuperviewWithInsets:UIEdgeInsetsMake(10, 15, 8 + stripeHeight, 15)];

    [self.selectionIndicatorStripe.leadingAnchor constraintEqualToAnchor:superview.leadingAnchor].active = YES;
    [self.selectionIndicatorStripe.bottomAnchor constraintEqualToAnchor:superview.bottomAnchor].active = YES;
    [self.selectionIndicatorStripe.trailingAnchor constraintEqualToAnchor:superview.trailingAnchor].active = YES;
    [self.selectionIndicatorStripe.heightAnchor constraintEqualToConstant:stripeHeight].active = YES;
}

- (void)setSelected:(BOOL)selected {
    super.selected = selected;
    [self updateAppearance];
}

@end


================================================
FILE: Classes/Core/Views/Carousel/FLEXScopeCarousel.h
================================================
//
//  FLEXScopeCarousel.h
//  FLEX
//
//  Created by Tanner Bennett on 7/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

/// Only use on iOS 10 and up. Requires iOS 10 APIs for calculating row sizes.
@interface FLEXScopeCarousel : UIControl

@property (nonatomic, copy) NSArray<NSString *> *items;
@property (nonatomic) NSInteger selectedIndex;
@property (nonatomic) void(^selectedIndexChangedAction)(NSInteger idx);

- (void)registerBlockForDynamicTypeChanges:(void(^)(FLEXScopeCarousel *))handler;

@end


================================================
FILE: Classes/Core/Views/Carousel/FLEXScopeCarousel.m
================================================
//
//  FLEXScopeCarousel.m
//  FLEX
//
//  Created by Tanner Bennett on 7/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXScopeCarousel.h"
#import "FLEXCarouselCell.h"
#import "FLEXColor.h"
#import "FLEXMacros.h"
#import "UIView+FLEX_Layout.h"

const CGFloat kCarouselItemSpacing = 0;
NSString * const kCarouselCellReuseIdentifier = @"kCarouselCellReuseIdentifier";

@interface FLEXScopeCarousel () <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (nonatomic, readonly) UICollectionView *collectionView;
@property (nonatomic, readonly) FLEXCarouselCell *sizingCell;

@property (nonatomic, readonly) id dynamicTypeObserver;
@property (nonatomic, readonly) NSMutableArray *dynamicTypeHandlers;

@property (nonatomic) BOOL constraintsInstalled;
@end

@implementation FLEXScopeCarousel

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = FLEXColor.primaryBackgroundColor;
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        self.translatesAutoresizingMaskIntoConstraints = YES;
        _dynamicTypeHandlers = [NSMutableArray new];
        
        CGSize itemSize = CGSizeZero;
        if (@available(iOS 10.0, *)) {
            itemSize = UICollectionViewFlowLayoutAutomaticSize;
        }

        // Collection view layout
        UICollectionViewFlowLayout *layout = ({
            UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
            layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
            layout.sectionInset = UIEdgeInsetsZero;
            layout.minimumLineSpacing = kCarouselItemSpacing;
            layout.itemSize = itemSize;
            layout.estimatedItemSize = itemSize;
            layout;
        });

        // Collection view
        _collectionView = ({
            UICollectionView *cv = [[UICollectionView alloc]
                initWithFrame:CGRectZero
                collectionViewLayout:layout
            ];
            cv.showsHorizontalScrollIndicator = NO;
            cv.backgroundColor = UIColor.clearColor;
            cv.delegate = self;
            cv.dataSource = self;
            [cv registerClass:[FLEXCarouselCell class] forCellWithReuseIdentifier:kCarouselCellReuseIdentifier];

            [self addSubview:cv];
            cv;
        });


        // Sizing cell
        _sizingCell = [FLEXCarouselCell new];
        self.sizingCell.title = @"NSObject";

        // Dynamic type
        weakify(self);
        _dynamicTypeObserver = [NSNotificationCenter.defaultCenter
            addObserverForName:UIContentSizeCategoryDidChangeNotification
            object:nil queue:nil usingBlock:^(NSNotification *note) { strongify(self)
                [self.collectionView setNeedsLayout];
                [self setNeedsUpdateConstraints];

                // Notify observers
                for (void (^block)(FLEXScopeCarousel *) in self.dynamicTypeHandlers) {
                    block(self);
                }
            }
        ];
    }

    return self;
}

- (void)dealloc {
    [NSNotificationCenter.defaultCenter removeObserver:self.dynamicTypeObserver];
}

#pragma mark - Overrides

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGFloat width = 1.f / UIScreen.mainScreen.scale;

    // Draw hairline
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, FLEXColor.hairlineColor.CGColor);
    CGContextSetLineWidth(context, width);
    CGContextMoveToPoint(context, 0, rect.size.height - width);
    CGContextAddLineToPoint(context, rect.size.width, rect.size.height - width);
    CGContextStrokePath(context);
}

+ (BOOL)requiresConstraintBasedLayout {
    return YES;
}

- (void)updateConstraints {
    if (!self.constraintsInstalled) {
        self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.collectionView flex_pinEdgesToSuperview];
        
        self.constraintsInstalled = YES;
    }
    
    [super updateConstraints];
}

- (CGSize)intrinsicContentSize {
    return CGSizeMake(
        UIViewNoIntrinsicMetric,
        [self.sizingCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height
    );
}

#pragma mark - Public

- (void)setItems:(NSArray<NSString *> *)items {
    NSParameterAssert(items.count);

    _items = items.copy;

    // Refresh list, select first item initially
    [self.collectionView reloadData];
    self.selectedIndex = 0;
}

- (void)setSelectedIndex:(NSInteger)idx {
    NSParameterAssert(idx < self.items.count);

    _selectedIndex = idx;
    NSIndexPath *path = [NSIndexPath indexPathForItem:idx inSection:0];
    [self.collectionView selectItemAtIndexPath:path
                                      animated:YES
                                scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
    [self collectionView:self.collectionView didSelectItemAtIndexPath:path];
}

- (void)registerBlockForDynamicTypeChanges:(void (^)(FLEXScopeCarousel *))handler {
    [self.dynamicTypeHandlers addObject:handler];
}

#pragma mark - UICollectionView

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//    if (@available(iOS 10.0, *)) {
//        return UICollectionViewFlowLayoutAutomaticSize;
//    }
    
    self.sizingCell.title = self.items[indexPath.item];
    return [self.sizingCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.items.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    FLEXCarouselCell *cell = (id)[collectionView dequeueReusableCellWithReuseIdentifier:kCarouselCellReuseIdentifier
                                                                           forIndexPath:indexPath];
    cell.title = self.items[indexPath.row];
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    _selectedIndex = indexPath.item; // In case self.selectedIndex didn't trigger this call

    if (self.selectedIndexChangedAction) {
        self.selectedIndexChangedAction(indexPath.row);
    }

    // TODO: dynamically choose a scroll position. Very wide items should
    // get "Left" while smaller items should not scroll at all, unless
    // they are only partially on the screen, in which case they
    // should get "HorizontallyCentered" to bring them onto the screen.
    // For now, everything goes to the left, as this has a similar effect.
    [collectionView scrollToItemAtIndexPath:indexPath
                           atScrollPosition:UICollectionViewScrollPositionLeft
                                   animated:YES];
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXCodeFontCell.h
================================================
//
//  FLEXCodeFontCell.h
//  FLEX
//
//  Created by Tanner on 12/27/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXMultilineTableViewCell.h"

NS_ASSUME_NONNULL_BEGIN

@interface FLEXCodeFontCell : FLEXMultilineDetailTableViewCell

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Core/Views/Cells/FLEXCodeFontCell.m
================================================
//
//  FLEXCodeFontCell.m
//  FLEX
//
//  Created by Tanner on 12/27/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXCodeFontCell.h"
#import "UIFont+FLEX.h"

@implementation FLEXCodeFontCell

- (void)postInit {
    [super postInit];
    
    self.titleLabel.font = UIFont.flex_codeFont;
    self.subtitleLabel.font = UIFont.flex_codeFont;

    self.titleLabel.adjustsFontSizeToFitWidth = YES;
    self.titleLabel.minimumScaleFactor = 0.9;
    self.subtitleLabel.adjustsFontSizeToFitWidth = YES;
    self.subtitleLabel.minimumScaleFactor = 0.75;
    
    // Disable mutli-line pre iOS 11
    if (@available(iOS 11, *)) {
        self.subtitleLabel.numberOfLines = 5;
    } else {
        self.titleLabel.numberOfLines = 1;
        self.subtitleLabel.numberOfLines = 1;
    }
}

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.h
================================================
//
//  FLEXKeyValueTableViewCell.h
//  FLEX
//
//  Created by Tanner Bennett on 1/23/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewCell.h"

@interface FLEXKeyValueTableViewCell : FLEXTableViewCell

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.m
================================================
//
//  FLEXKeyValueTableViewCell.m
//  FLEX
//
//  Created by Tanner Bennett on 1/23/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXKeyValueTableViewCell.h"

@implementation FLEXKeyValueTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    return [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
}

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXMultilineTableViewCell.h
================================================
//
//  FLEXMultilineTableViewCell.h
//  FLEX
//
//  Created by Ryan Olson on 2/13/15.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewCell.h"

/// A cell with both labels set to be multi-line capable.
@interface FLEXMultilineTableViewCell : FLEXTableViewCell

+ (CGFloat)preferredHeightWithAttributedText:(NSAttributedString *)attributedText
                                    maxWidth:(CGFloat)contentViewWidth
                                       style:(UITableViewStyle)style
                              showsAccessory:(BOOL)showsAccessory;

@end

/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleSubtitle
@interface FLEXMultilineDetailTableViewCell : FLEXMultilineTableViewCell

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXMultilineTableViewCell.m
================================================
//
//  FLEXMultilineTableViewCell.m
//  FLEX
//
//  Created by Ryan Olson on 2/13/15.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXMultilineTableViewCell.h"
#import "UIView+FLEX_Layout.h"
#import "FLEXUtility.h"

@interface FLEXMultilineTableViewCell ()
@property (nonatomic, readonly) UILabel *_titleLabel;
@property (nonatomic, readonly) UILabel *_subtitleLabel;
@property (nonatomic) BOOL constraintsUpdated;
@end

@implementation FLEXMultilineTableViewCell

- (void)postInit {
    [super postInit];
    
    self.titleLabel.numberOfLines = 0;
    self.subtitleLabel.numberOfLines = 0;
}

+ (UIEdgeInsets)labelInsets {
    return UIEdgeInsetsMake(10.0, 16.0, 10.0, 8.0);
}

+ (CGFloat)preferredHeightWithAttributedText:(NSAttributedString *)attributedText
                                    maxWidth:(CGFloat)contentViewWidth
                                       style:(UITableViewStyle)style
                              showsAccessory:(BOOL)showsAccessory {
    CGFloat labelWidth = contentViewWidth;

    // Content view inset due to accessory view observed on iOS 8.1 iPhone 6.
    if (showsAccessory) {
        labelWidth -= 34.0;
    }

    UIEdgeInsets labelInsets = [self labelInsets];
    labelWidth -= (labelInsets.left + labelInsets.right);

    CGSize constrainSize = CGSizeMake(labelWidth, CGFLOAT_MAX);
    CGRect boundingBox = [attributedText
        boundingRectWithSize:constrainSize
        options:NSStringDrawingUsesLineFragmentOrigin
        context:nil
    ];
    CGFloat preferredLabelHeight = FLEXFloor(boundingBox.size.height);
    CGFloat preferredCellHeight = preferredLabelHeight + labelInsets.top + labelInsets.bottom + 1.0;

    return preferredCellHeight;
}

@end


@implementation FLEXMultilineDetailTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    return [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.h
================================================
//
//  FLEXSubtitleTableViewCell.h
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewCell.h"

/// A cell initialized with \c UITableViewCellStyleSubtitle
@interface FLEXSubtitleTableViewCell : FLEXTableViewCell

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.m
================================================
//
//  FLEXSubtitleTableViewCell.m
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXSubtitleTableViewCell.h"

@implementation FLEXSubtitleTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    return [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXTableViewCell.h
================================================
//
//  FLEXTableViewCell.h
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface FLEXTableViewCell : UITableViewCell

/// Use this instead of .textLabel
@property (nonatomic, readonly) UILabel *titleLabel;
/// Use this instead of .detailTextLabel
@property (nonatomic, readonly) UILabel *subtitleLabel;

/// Subclasses can override this instead of initializers to
/// perform additional initialization without lots of boilerplate.
/// Remember to call super!
- (void)postInit;

@end


================================================
FILE: Classes/Core/Views/Cells/FLEXTableViewCell.m
================================================
//
//  FLEXTableViewCell.m
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewCell.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "FLEXTableView.h"

@interface UITableView (Internal)
// Exists at least since iOS 5
- (BOOL)_canPerformAction:(SEL)action forCell:(UITableViewCell *)cell sender:(id)sender;
- (void)_performAction:(SEL)action forCell:(UITableViewCell *)cell sender:(id)sender;
@end

@interface UITableViewCell (Internal)
// Exists at least since iOS 5
@property (nonatomic, readonly) FLEXTableView *_tableView;
@end

@implementation FLEXTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self postInit];
    }

    return self;
}

- (void)postInit {
    UIFont *cellFont = UIFont.flex_defaultTableCellFont;
    self.titleLabel.font = cellFont;
    self.subtitleLabel.font = cellFont;
    self.subtitleLabel.textColor = FLEXColor.deemphasizedTextColor;
    
    self.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
    self.subtitleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
    
    self.titleLabel.numberOfLines = 1;
    self.subtitleLabel.numberOfLines = 1;
}

- (UILabel *)titleLabel {
    return self.textLabel;
}

- (UILabel *)subtitleLabel {
    return self.detailTextLabel;
}

@end


================================================
FILE: Classes/Core/Views/FLEXTableView.h
================================================
//
//  FLEXTableView.h
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

#pragma mark Reuse identifiers

typedef NSString * FLEXTableViewCellReuseIdentifier;

/// A regular \c FLEXTableViewCell initialized with \c UITableViewCellStyleDefault
extern FLEXTableViewCellReuseIdentifier const kFLEXDefaultCell;
/// A \c FLEXSubtitleTableViewCell initialized with \c UITableViewCellStyleSubtitle
extern FLEXTableViewCellReuseIdentifier const kFLEXDetailCell;
/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleDefault
extern FLEXTableViewCellReuseIdentifier const kFLEXMultilineCell;
/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleSubtitle
extern FLEXTableViewCellReuseIdentifier const kFLEXMultilineDetailCell;
/// A \c FLEXTableViewCell initialized with \c UITableViewCellStyleValue1
extern FLEXTableViewCellReuseIdentifier const kFLEXKeyValueCell;
/// A \c FLEXSubtitleTableViewCell which uses monospaced fonts for both labels
extern FLEXTableViewCellReuseIdentifier const kFLEXCodeFontCell;

#pragma mark - FLEXTableView
@interface FLEXTableView : UITableView

+ (instancetype)flexDefaultTableView;
+ (instancetype)groupedTableView;
+ (instancetype)plainTableView;
+ (instancetype)style:(UITableViewStyle)style;

/// You do not need to register classes for any of the default reuse identifiers above
/// (annotated as \c FLEXTableViewCellReuseIdentifier types) unless you wish to provide
/// a custom cell for any of those reuse identifiers. By default, \c FLEXTableViewCell,
/// \c FLEXSubtitleTableViewCell, and \c FLEXMultilineTableViewCell are used, respectively.
///
/// @param registrationMapping A map of reuse identifiers to \c UITableViewCell (sub)class objects.
- (void)registerCells:(NSDictionary<NSString *, Class> *)registrationMapping;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Core/Views/FLEXTableView.m
================================================
//
//  FLEXTableView.m
//  FLEX
//
//  Created by Tanner on 4/17/19.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "FLEXSubtitleTableViewCell.h"
#import "FLEXMultilineTableViewCell.h"
#import "FLEXKeyValueTableViewCell.h"
#import "FLEXCodeFontCell.h"

FLEXTableViewCellReuseIdentifier const kFLEXDefaultCell = @"kFLEXDefaultCell";
FLEXTableViewCellReuseIdentifier const kFLEXDetailCell = @"kFLEXDetailCell";
FLEXTableViewCellReuseIdentifier const kFLEXMultilineCell = @"kFLEXMultilineCell";
FLEXTableViewCellReuseIdentifier const kFLEXMultilineDetailCell = @"kFLEXMultilineDetailCell";
FLEXTableViewCellReuseIdentifier const kFLEXKeyValueCell = @"kFLEXKeyValueCell";
FLEXTableViewCellReuseIdentifier const kFLEXCodeFontCell = @"kFLEXCodeFontCell";

#pragma mark Private

@interface UITableView (Private)
- (CGFloat)_heightForHeaderInSection:(NSInteger)section;
- (NSString *)_titleForHeaderInSection:(NSInteger)section;
@end

@implementation FLEXTableView

+ (instancetype)flexDefaultTableView {
    if (@available(iOS 13.0, *)) {
        return [[self alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
    } else {
        return [[self alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
    }
}

#pragma mark - Initialization

+ (id)groupedTableView {
    if (@available(iOS 13.0, *)) {
        return [[self alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
    } else {
        return [[self alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
    }
}

+ (id)plainTableView {
    return [[self alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
}

+ (id)style:(UITableViewStyle)style {
    return [[self alloc] initWithFrame:CGRectZero style:style];
}

- (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    self = [super initWithFrame:frame style:style];
    if (self) {
        [self registerCells:@{
            kFLEXDefaultCell : [FLEXTableViewCell class],
            kFLEXDetailCell : [FLEXSubtitleTableViewCell class],
            kFLEXMultilineCell : [FLEXMultilineTableViewCell class],
            kFLEXMultilineDetailCell : [FLEXMultilineDetailTableViewCell class],
            kFLEXKeyValueCell : [FLEXKeyValueTableViewCell class],
            kFLEXCodeFontCell : [FLEXCodeFontCell class],
        }];
    }

    return self;
}


#pragma mark - Public

- (void)registerCells:(NSDictionary<NSString*, Class> *)registrationMapping {
    [registrationMapping enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, Class cellClass, BOOL *stop) {
        [self registerClass:cellClass forCellReuseIdentifier:identifier];
    }];
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.h
================================================
//
//  FLEXArgumentInputColorView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/30/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputColorView : FLEXArgumentInputView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.m
================================================
//
//  FLEXArgumentInputColorView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/30/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputColorView.h"
#import "FLEXUtility.h"
#import "FLEXRuntimeUtility.h"

@protocol FLEXColorComponentInputViewDelegate;

@interface FLEXColorComponentInputView : UIView

@property (nonatomic) UISlider *slider;
@property (nonatomic) UILabel *valueLabel;

@property (nonatomic, weak) id <FLEXColorComponentInputViewDelegate> delegate;

@end

@protocol FLEXColorComponentInputViewDelegate <NSObject>

- (void)colorComponentInputViewValueDidChange:(FLEXColorComponentInputView *)colorComponentInputView;

@end


@implementation FLEXColorComponentInputView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.slider = [UISlider new];
        [self.slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSubview:self.slider];
        
        self.valueLabel = [UILabel new];
        self.valueLabel.backgroundColor = self.backgroundColor;
        self.valueLabel.font = [UIFont systemFontOfSize:14.0];
        self.valueLabel.textAlignment = NSTextAlignmentRight;
        [self addSubview:self.valueLabel];
        
        [self updateValueLabel];
    }
    return self;
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.slider.backgroundColor = backgroundColor;
    self.valueLabel.backgroundColor = backgroundColor;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    const CGFloat kValueLabelWidth = 50.0;
    
    [self.slider sizeToFit];
    CGFloat sliderWidth = self.bounds.size.width - kValueLabelWidth;
    self.slider.frame = CGRectMake(0, 0, sliderWidth, self.slider.frame.size.height);
    
    [self.valueLabel sizeToFit];
    CGFloat valueLabelOriginX = CGRectGetMaxX(self.slider.frame);
    CGFloat valueLabelOriginY = FLEXFloor((self.slider.frame.size.height - self.valueLabel.frame.size.height) / 2.0);
    self.valueLabel.frame = CGRectMake(valueLabelOriginX, valueLabelOriginY, kValueLabelWidth, self.valueLabel.frame.size.height);
}

- (void)sliderChanged:(id)sender {
    [self.delegate colorComponentInputViewValueDidChange:self];
    [self updateValueLabel];
}

- (void)updateValueLabel {
    self.valueLabel.text = [NSString stringWithFormat:@"%.3f", self.slider.value];
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat height = [self.slider sizeThatFits:size].height;
    return CGSizeMake(size.width, height);
}

@end

@interface FLEXColorPreviewBox : UIView

@property (nonatomic) UIColor *color;

@property (nonatomic) UIView *colorOverlayView;

@end

@implementation FLEXColorPreviewBox

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.layer.borderWidth = 1.0;
        self.layer.borderColor = UIColor.blackColor.CGColor;
        self.backgroundColor = [UIColor colorWithPatternImage:[[self class] backgroundPatternImage]];
        
        self.colorOverlayView = [[UIView alloc] initWithFrame:self.bounds];
        self.colorOverlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        self.colorOverlayView.backgroundColor = UIColor.clearColor;
        [self addSubview:self.colorOverlayView];
    }
    return self;
}

- (void)setColor:(UIColor *)color {
    self.colorOverlayView.backgroundColor = color;
}

- (UIColor *)color {
    return self.colorOverlayView.backgroundColor;
}

+ (UIImage *)backgroundPatternImage {
    const CGFloat kSquareDimension = 5.0;
    CGSize squareSize = CGSizeMake(kSquareDimension, kSquareDimension);
    CGSize imageSize = CGSizeMake(2.0 * kSquareDimension, 2.0 * kSquareDimension);
    
    UIGraphicsBeginImageContextWithOptions(imageSize, YES, UIScreen.mainScreen.scale);
    
    [UIColor.whiteColor setFill];
    UIRectFill(CGRectMake(0, 0, imageSize.width, imageSize.height));
    
    [UIColor.grayColor setFill];
    UIRectFill(CGRectMake(squareSize.width, 0, squareSize.width, squareSize.height));
    UIRectFill(CGRectMake(0, squareSize.height, squareSize.width, squareSize.height));
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}

@end

@interface FLEXArgumentInputColorView () <FLEXColorComponentInputViewDelegate>

@property (nonatomic) FLEXColorPreviewBox *colorPreviewBox;
@property (nonatomic) UILabel *hexLabel;
@property (nonatomic) FLEXColorComponentInputView *alphaInput;
@property (nonatomic) FLEXColorComponentInputView *redInput;
@property (nonatomic) FLEXColorComponentInputView *greenInput;
@property (nonatomic) FLEXColorComponentInputView *blueInput;

@end

@implementation FLEXArgumentInputColorView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.colorPreviewBox = [FLEXColorPreviewBox new];
        [self addSubview:self.colorPreviewBox];
        
        self.hexLabel = [UILabel new];
        self.hexLabel.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.9];
        self.hexLabel.textAlignment = NSTextAlignmentCenter;
        self.hexLabel.font = [UIFont systemFontOfSize:12.0];
        [self addSubview:self.hexLabel];
        
        self.alphaInput = [FLEXColorComponentInputView new];
        self.alphaInput.slider.minimumTrackTintColor = UIColor.blackColor;
        self.alphaInput.delegate = self;
        [self addSubview:self.alphaInput];
        
        self.redInput = [FLEXColorComponentInputView new];
        self.redInput.slider.minimumTrackTintColor = UIColor.redColor;
        self.redInput.delegate = self;
        [self addSubview:self.redInput];
        
        self.greenInput = [FLEXColorComponentInputView new];
        self.greenInput.slider.minimumTrackTintColor = UIColor.greenColor;
        self.greenInput.delegate = self;
        [self addSubview:self.greenInput];
        
        self.blueInput = [FLEXColorComponentInputView new];
        self.blueInput.slider.minimumTrackTintColor = UIColor.blueColor;
        self.blueInput.delegate = self;
        [self addSubview:self.blueInput];
    }
    return self;
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.alphaInput.backgroundColor = backgroundColor;
    self.redInput.backgroundColor = backgroundColor;
    self.greenInput.backgroundColor = backgroundColor;
    self.blueInput.backgroundColor = backgroundColor;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat runningOriginY = 0;
    CGSize constrainSize = CGSizeMake(self.bounds.size.width, CGFLOAT_MAX);
    
    self.colorPreviewBox.frame = CGRectMake(0, runningOriginY, self.bounds.size.width, [[self class] colorPreviewBoxHeight]);
    runningOriginY = CGRectGetMaxY(self.colorPreviewBox.frame) + [[self class] inputViewVerticalPadding];
    
    [self.hexLabel sizeToFit];
    const CGFloat kLabelVerticalOutsetAmount = 0.0;
    const CGFloat kLabelHorizontalOutsetAmount = 2.0;
    UIEdgeInsets labelOutset = UIEdgeInsetsMake(-kLabelVerticalOutsetAmount, -kLabelHorizontalOutsetAmount, -kLabelVerticalOutsetAmount, -kLabelHorizontalOutsetAmount);
    self.hexLabel.frame = UIEdgeInsetsInsetRect(self.hexLabel.frame, labelOutset);
    CGFloat hexLabelOriginX = self.colorPreviewBox.layer.borderWidth;
    CGFloat hexLabelOriginY = CGRectGetMaxY(self.colorPreviewBox.frame) - self.colorPreviewBox.layer.borderWidth - self.hexLabel.frame.size.height;
    self.hexLabel.frame = CGRectMake(hexLabelOriginX, hexLabelOriginY, self.hexLabel.frame.size.width, self.hexLabel.frame.size.height);
    
    NSArray<FLEXColorComponentInputView *> *colorComponentInputViews = @[self.alphaInput, self.redInput, self.greenInput, self.blueInput];
    for (FLEXColorComponentInputView *inputView in colorComponentInputViews) {
        CGSize fitSize = [inputView sizeThatFits:constrainSize];
        inputView.frame = CGRectMake(0, runningOriginY, fitSize.width, fitSize.height);
        runningOriginY = CGRectGetMaxY(inputView.frame) + [[self class] inputViewVerticalPadding];
    }
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue isKindOfClass:[UIColor class]]) {
        [self updateWithColor:inputValue];
    } else if ([inputValue isKindOfClass:[NSValue class]]) {
        const char *type = [inputValue objCType];
        if (strcmp(type, @encode(CGColorRef)) == 0) {
            CGColorRef colorRef;
            [inputValue getValue:&colorRef];
            UIColor *color = [[UIColor alloc] initWithCGColor:colorRef];
            [self updateWithColor:color];
        }
    } else {
        [self updateWithColor:UIColor.clearColor];
    }
}

- (id)inputValue {
    return [UIColor colorWithRed:self.redInput.slider.value green:self.greenInput.slider.value blue:self.blueInput.slider.value alpha:self.alphaInput.slider.value];
}

- (void)colorComponentInputViewValueDidChange:(FLEXColorComponentInputView *)colorComponentInputView {
    [self updateColorPreview];
}

- (void)updateWithColor:(UIColor *)color {
    CGFloat red, green, blue, white, alpha;
    if ([color getRed:&red green:&green blue:&blue alpha:&alpha]) {
        self.alphaInput.slider.value = alpha;
        [self.alphaInput updateValueLabel];
        self.redInput.slider.value = red;
        [self.redInput updateValueLabel];
        self.greenInput.slider.value = green;
        [self.greenInput updateValueLabel];
        self.blueInput.slider.value = blue;
        [self.blueInput updateValueLabel];
    } else if ([color getWhite:&white alpha:&alpha]) {
        self.alphaInput.slider.value = alpha;
        [self.alphaInput updateValueLabel];
        self.redInput.slider.value = white;
        [self.redInput updateValueLabel];
        self.greenInput.slider.value = white;
        [self.greenInput updateValueLabel];
        self.blueInput.slider.value = white;
        [self.blueInput updateValueLabel];
    }
    [self updateColorPreview];
}

- (void)updateColorPreview {
    self.colorPreviewBox.color = self.inputValue;
    unsigned char redByte = self.redInput.slider.value * 255;
    unsigned char greenByte = self.greenInput.slider.value * 255;
    unsigned char blueByte = self.blueInput.slider.value * 255;
    self.hexLabel.text = [NSString stringWithFormat:@"#%02X%02X%02X", redByte, greenByte, blueByte];
    [self setNeedsLayout];
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat height = 0;
    height += [[self class] colorPreviewBoxHeight];
    height += [[self class] inputViewVerticalPadding];
    height += [self.alphaInput sizeThatFits:size].height;
    height += [[self class] inputViewVerticalPadding];
    height += [self.redInput sizeThatFits:size].height;
    height += [[self class] inputViewVerticalPadding];
    height += [self.greenInput sizeThatFits:size].height;
    height += [[self class] inputViewVerticalPadding];
    height += [self.blueInput sizeThatFits:size].height;
    return CGSizeMake(size.width, height);
}

+ (CGFloat)inputViewVerticalPadding {
    return 10.0;
}

+ (CGFloat)colorPreviewBoxHeight {
    return 40.0;
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);

    // We don't care if currentValue is a color or not; we will default to +clearColor
    return (strcmp(type, @encode(CGColorRef)) == 0) || (strcmp(type, FLEXEncodeClass(UIColor)) == 0);
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.h
================================================
//
//  FLEXArgumentInputDataView.h
//  Flipboard
//
//  Created by Daniel Rodriguez Troitino on 2/14/15.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputDateView : FLEXArgumentInputView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.m
================================================
//
//  FLEXArgumentInputDataView.m
//  Flipboard
//
//  Created by Daniel Rodriguez Troitino on 2/14/15.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputDateView.h"
#import "FLEXRuntimeUtility.h"

@interface FLEXArgumentInputDateView ()

@property (nonatomic) UIDatePicker *datePicker;

@end

@implementation FLEXArgumentInputDateView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.datePicker = [UIDatePicker new];
        self.datePicker.datePickerMode = UIDatePickerModeDateAndTime;
        // Using UTC, because that's what the NSDate description prints
        self.datePicker.calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
        self.datePicker.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
        [self addSubview:self.datePicker];
    }
    return self;
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue isKindOfClass:[NSDate class]]) {
        self.datePicker.date = inputValue;
    }
}

- (id)inputValue {
    return self.datePicker.date;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.datePicker.frame = self.bounds;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat height = [self.datePicker sizeThatFits:size].height;
    return CGSizeMake(size.width, height);
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    return strcmp(type, FLEXEncodeClass(NSDate)) == 0;
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.h
================================================
//
//  FLEXArgumentInputFontView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/28/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputFontView : FLEXArgumentInputView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.m
================================================
//
//  FLEXArgumentInputFontView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/28/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputFontView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXArgumentInputFontsPickerView.h"

@interface FLEXArgumentInputFontView ()

@property (nonatomic) FLEXArgumentInputView *fontNameInput;
@property (nonatomic) FLEXArgumentInputView *pointSizeInput;

@end

@implementation FLEXArgumentInputFontView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.fontNameInput = [[FLEXArgumentInputFontsPickerView alloc] initWithArgumentTypeEncoding:FLEXEncodeClass(NSString)];
        self.fontNameInput.targetSize = FLEXArgumentInputViewSizeSmall;
        self.fontNameInput.title = @"Font Name:";
        [self addSubview:self.fontNameInput];
        
        self.pointSizeInput = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:@encode(CGFloat)];
        self.pointSizeInput.targetSize = FLEXArgumentInputViewSizeSmall;
        self.pointSizeInput.title = @"Point Size:";
        [self addSubview:self.pointSizeInput];
    }
    return self;
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.fontNameInput.backgroundColor = backgroundColor;
    self.pointSizeInput.backgroundColor = backgroundColor;
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue isKindOfClass:[UIFont class]]) {
        UIFont *font = (UIFont *)inputValue;
        self.fontNameInput.inputValue = font.fontName;
        self.pointSizeInput.inputValue = @(font.pointSize);
    }
}

- (id)inputValue {
    CGFloat pointSize = 0;
    if ([self.pointSizeInput.inputValue isKindOfClass:[NSValue class]]) {
        NSValue *pointSizeValue = (NSValue *)self.pointSizeInput.inputValue;
        if (strcmp([pointSizeValue objCType], @encode(CGFloat)) == 0) {
            [pointSizeValue getValue:&pointSize];
        }
    }
    return [UIFont fontWithName:self.fontNameInput.inputValue size:pointSize];
}

- (BOOL)inputViewIsFirstResponder {
    return [self.fontNameInput inputViewIsFirstResponder] || [self.pointSizeInput inputViewIsFirstResponder];
}


#pragma mark - Layout and Sizing

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat runningOriginY = self.topInputFieldVerticalLayoutGuide;
    
    CGSize fontNameFitSize = [self.fontNameInput sizeThatFits:self.bounds.size];
    self.fontNameInput.frame = CGRectMake(0, runningOriginY, fontNameFitSize.width, fontNameFitSize.height);
    runningOriginY = CGRectGetMaxY(self.fontNameInput.frame) + [[self class] verticalPaddingBetweenFields];
    
    CGSize pointSizeFitSize = [self.pointSizeInput sizeThatFits:self.bounds.size];
    self.pointSizeInput.frame = CGRectMake(0, runningOriginY, pointSizeFitSize.width, pointSizeFitSize.height);
}

+ (CGFloat)verticalPaddingBetweenFields {
    return 10.0;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize fitSize = [super sizeThatFits:size];
    
    CGSize constrainSize = CGSizeMake(size.width, CGFLOAT_MAX);
    
    CGFloat height = fitSize.height;
    height += [self.fontNameInput sizeThatFits:constrainSize].height;
    height += [[self class] verticalPaddingBetweenFields];
    height += [self.pointSizeInput sizeThatFits:constrainSize].height;
    
    return CGSizeMake(fitSize.width, height);
}


#pragma mark -

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    return strcmp(type, FLEXEncodeClass(UIFont)) == 0;
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.h
================================================
//
//  FLEXArgumentInputFontsPickerView.h
//  FLEX
//
//  Created by 啟倫 陳 on 2014/7/27.
//  Copyright (c) 2014年 f. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputFontsPickerView : FLEXArgumentInputTextView <UIPickerViewDataSource, UIPickerViewDelegate>
@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.m
================================================
//
//  FLEXArgumentInputFontsPickerView.m
//  FLEX
//
//  Created by 啟倫 陳 on 2014/7/27.
//  Copyright (c) 2014年 f. All rights reserved.
//

#import "FLEXArgumentInputFontsPickerView.h"
#import "FLEXRuntimeUtility.h"

@interface FLEXArgumentInputFontsPickerView ()

@property (nonatomic) NSMutableArray<NSString *> *availableFonts;

@end


@implementation FLEXArgumentInputFontsPickerView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.targetSize = FLEXArgumentInputViewSizeSmall;
        [self createAvailableFonts];
        self.inputTextView.inputView = [self createFontsPicker];
    }
    return self;
}

- (void)setInputValue:(id)inputValue {
    self.inputTextView.text = inputValue;
    if ([self.availableFonts indexOfObject:inputValue] == NSNotFound) {
        [self.availableFonts insertObject:inputValue atIndex:0];
    }
    [(UIPickerView *)self.inputTextView.inputView selectRow:[self.availableFonts indexOfObject:inputValue] inComponent:0 animated:NO];
}

- (id)inputValue {
    return self.inputTextView.text.length > 0 ? [self.inputTextView.text copy] : nil;
}

#pragma mark - private

- (UIPickerView*)createFontsPicker {
    UIPickerView *fontsPicker = [UIPickerView new];
    fontsPicker.dataSource = self;
    fontsPicker.delegate = self;
    
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
    // Deprecated in iOS 13; from then on, selection is always shown
    fontsPicker.showsSelectionIndicator = YES;
    #pragma clang diagnostic pop

    return fontsPicker;
}

- (void)createAvailableFonts {
    NSMutableArray<NSString *> *unsortedFontsArray = [NSMutableArray new];
    for (NSString *eachFontFamily in UIFont.familyNames) {
        for (NSString *eachFontName in [UIFont fontNamesForFamilyName:eachFontFamily]) {
            [unsortedFontsArray addObject:eachFontName];
        }
    }
    self.availableFonts = [NSMutableArray arrayWithArray:[unsortedFontsArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]];
}

#pragma mark - UIPickerViewDataSource

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 1;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return self.availableFonts.count;
}

#pragma mark - UIPickerViewDelegate

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
    UILabel *fontLabel;
    if (!view) {
        fontLabel = [UILabel new];
        fontLabel.backgroundColor = UIColor.clearColor;
        fontLabel.textAlignment = NSTextAlignmentCenter;
    } else {
        fontLabel = (UILabel*)view;
    }
    UIFont *font = [UIFont fontWithName:self.availableFonts[row] size:15.0];
    NSDictionary<NSString *, id> *attributesDictionary = [NSDictionary<NSString *, id> dictionaryWithObject:font forKey:NSFontAttributeName];
    NSAttributedString *attributesString = [[NSAttributedString alloc] initWithString:self.availableFonts[row] attributes:attributesDictionary];
    fontLabel.attributedText = attributesString;
    [fontLabel sizeToFit];
    return fontLabel;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    self.inputTextView.text = self.availableFonts[row];
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.h
================================================
//
//  FLEXArgumentInputNotSupportedView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/18/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputNotSupportedView : FLEXArgumentInputTextView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.m
================================================
//
//  FLEXArgumentInputNotSupportedView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/18/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputNotSupportedView.h"
#import "FLEXColor.h"

@implementation FLEXArgumentInputNotSupportedView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputTextView.userInteractionEnabled = NO;
        self.inputTextView.backgroundColor = [FLEXColor secondaryGroupedBackgroundColorWithAlpha:0.5];
        self.inputPlaceholderText = @"nil  (type not supported)";
        self.targetSize = FLEXArgumentInputViewSizeSmall;
    }
    return self;
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.h
================================================
//
//  FLEXArgumentInputNumberView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputNumberView : FLEXArgumentInputTextView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.m
================================================
//
//  FLEXArgumentInputNumberView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputNumberView.h"
#import "FLEXRuntimeUtility.h"

@implementation FLEXArgumentInputNumberView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputTextView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
        self.targetSize = FLEXArgumentInputViewSizeSmall;
    }
    
    return self;
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue respondsToSelector:@selector(stringValue)]) {
        self.inputTextView.text = [inputValue stringValue];
    }
}

- (id)inputValue {
    return [FLEXRuntimeUtility valueForNumberWithObjCType:self.typeEncoding.UTF8String fromInputString:self.inputTextView.text];
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    
    static NSArray<NSString *> *supportedTypes = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        supportedTypes = @[
            @FLEXEncodeClass(NSNumber),
            @FLEXEncodeClass(NSDecimalNumber),
            @(@encode(char)),
            @(@encode(int)),
            @(@encode(short)),
            @(@encode(long)),
            @(@encode(long long)),
            @(@encode(unsigned char)),
            @(@encode(unsigned int)),
            @(@encode(unsigned short)),
            @(@encode(unsigned long)),
            @(@encode(unsigned long long)),
            @(@encode(float)),
            @(@encode(double)),
            @(@encode(long double))
        ];
    });
    
    return type && [supportedTypes containsObject:@(type)];
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.h
================================================
//
//  FLEXArgumentInputObjectView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputObjectView : FLEXArgumentInputTextView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.m
================================================
//
//  FLEXArgumentInputJSONObjectView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputObjectView.h"
#import "FLEXRuntimeUtility.h"

static const CGFloat kSegmentInputMargin = 10;

typedef NS_ENUM(NSUInteger, FLEXArgInputObjectType) {
    FLEXArgInputObjectTypeJSON,
    FLEXArgInputObjectTypeAddress
};

@interface FLEXArgumentInputObjectView ()

@property (nonatomic) UISegmentedControl *objectTypeSegmentControl;
@property (nonatomic) FLEXArgInputObjectType inputType;

@end

@implementation FLEXArgumentInputObjectView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        // Start with the numbers and punctuation keyboard since quotes, curly braces, or
        // square brackets are likely to be the first characters type for the JSON.
        self.inputTextView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
        self.targetSize = FLEXArgumentInputViewSizeLarge;

        self.objectTypeSegmentControl = [[UISegmentedControl alloc] initWithItems:@[@"Value", @"Address"]];
        [self.objectTypeSegmentControl addTarget:self action:@selector(didChangeType) forControlEvents:UIControlEventValueChanged];
        self.objectTypeSegmentControl.selectedSegmentIndex = 0;
        [self addSubview:self.objectTypeSegmentControl];

        self.inputType = [[self class] preferredDefaultTypeForObjCType:typeEncoding withCurrentValue:nil];
        self.objectTypeSegmentControl.selectedSegmentIndex = self.inputType;
    }

    return self;
}

- (void)didChangeType {
    self.inputType = self.objectTypeSegmentControl.selectedSegmentIndex;

    if (super.inputValue) {
        // Trigger an update to the text field to show
        // the address of the stored object we were given,
        // or to show a JSON representation of the object
        [self populateTextAreaFromValue:super.inputValue];
    } else {
        // Clear the text field
        [self populateTextAreaFromValue:nil];
    }
}

- (void)setInputType:(FLEXArgInputObjectType)inputType {
    if (_inputType == inputType) return;

    _inputType = inputType;

    // Resize input view
    switch (inputType) {
        case FLEXArgInputObjectTypeJSON:
            self.targetSize = FLEXArgumentInputViewSizeLarge;
            break;
        case FLEXArgInputObjectTypeAddress:
            self.targetSize = FLEXArgumentInputViewSizeSmall;
            break;
    }

    // Change placeholder
    switch (inputType) {
        case FLEXArgInputObjectTypeJSON:
            self.inputPlaceholderText =
            @"You can put any valid JSON here, such as a string, number, array, or dictionary:"
            "\n\"This is a string\""
            "\n1234"
            "\n{ \"name\": \"Bob\", \"age\": 47 }"
            "\n["
            "\n   1, 2, 3"
            "\n]";
            break;
        case FLEXArgInputObjectTypeAddress:
            self.inputPlaceholderText = @"0x0000deadb33f";
            break;
    }

    [self setNeedsLayout];
    [self.superview setNeedsLayout];
}

- (void)setInputValue:(id)inputValue {
    super.inputValue = inputValue;
    [self populateTextAreaFromValue:inputValue];
}

- (id)inputValue {
    switch (self.inputType) {
        case FLEXArgInputObjectTypeJSON:
            return [FLEXRuntimeUtility objectValueFromEditableJSONString:self.inputTextView.text];
        case FLEXArgInputObjectTypeAddress: {
            NSScanner *scanner = [NSScanner scannerWithString:self.inputTextView.text];

            unsigned long long objectPointerValue;
            if ([scanner scanHexLongLong:&objectPointerValue]) {
                return (__bridge id)(void *)objectPointerValue;
            }

            return nil;
        }
    }
}

- (void)populateTextAreaFromValue:(id)value {
    if (!value) {
        self.inputTextView.text = nil;
    } else {
        if (self.inputType == FLEXArgInputObjectTypeJSON) {
            self.inputTextView.text = [FLEXRuntimeUtility editableJSONStringForObject:value];
        } else if (self.inputType == FLEXArgInputObjectTypeAddress) {
            self.inputTextView.text = [NSString stringWithFormat:@"%p", value];
        }
    }

    // Delegate methods are not called for programmatic changes
    [self textViewDidChange:self.inputTextView];
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize fitSize = [super sizeThatFits:size];
    fitSize.height += [self.objectTypeSegmentControl sizeThatFits:size].height + kSegmentInputMargin;

    return fitSize;
}

- (void)layoutSubviews {
    CGFloat segmentHeight = [self.objectTypeSegmentControl sizeThatFits:self.frame.size].height;
    self.objectTypeSegmentControl.frame = CGRectMake(
        0.0,
        // Our segmented control is taking the position
        // of the text view, as far as super is concerned,
        // and we override this property to be different
        super.topInputFieldVerticalLayoutGuide,
        self.frame.size.width,
        segmentHeight
    );

    [super layoutSubviews];
}

- (CGFloat)topInputFieldVerticalLayoutGuide {
    // Our text view is offset from the segmented control
    CGFloat segmentHeight = [self.objectTypeSegmentControl sizeThatFits:self.frame.size].height;
    return segmentHeight + super.topInputFieldVerticalLayoutGuide + kSegmentInputMargin;
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    // Must be object type
    return type[0] == FLEXTypeEncodingObjcObject || type[0] == FLEXTypeEncodingObjcClass;
}

+ (FLEXArgInputObjectType)preferredDefaultTypeForObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type[0] == FLEXTypeEncodingObjcObject || type[0] == FLEXTypeEncodingObjcClass);

    if (value) {
        // If there's a current value, it must be serializable to JSON
        // to display the JSON editor. Otherwise display the address field.
        if ([FLEXRuntimeUtility editableJSONStringForObject:value]) {
            return FLEXArgInputObjectTypeJSON;
        } else {
            return FLEXArgInputObjectTypeAddress;
        }
    } else {
        // Otherwise, see if we have more type information than just 'id'.
        // If we do, make sure the encoding is something serializable to JSON.
        // Properties and ivars keep more detailed type encoding information than method arguments.
        if (strcmp(type, @encode(id)) != 0) {
            BOOL isJSONSerializableType = NO;

            // Parse class name out of the string,
            // which is in the form `@"ClassName"`
            Class cls = NSClassFromString(({
                NSString *className = nil;
                NSScanner *scan = [NSScanner scannerWithString:@(type)];
                NSCharacterSet *allowed = [NSCharacterSet
                    characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$"
                ];

                // Skip over the @" then scan the name
                if ([scan scanString:@"@\"" intoString:nil]) {
                    [scan scanCharactersFromSet:allowed intoString:&className];
                }

                className;
            }));

            // Note: we can't use @encode(NSString) here because that drops
            // the class information and just goes to @encode(id).
            NSArray<Class> *jsonTypes = @[
                [NSString class],
                [NSNumber class],
                [NSArray class],
                [NSDictionary class],
            ];

            // Look for matching types
            for (Class jsonClass in jsonTypes) {
                if ([cls isSubclassOfClass:jsonClass]) {
                    isJSONSerializableType = YES;
                    break;
                }
            }

            if (isJSONSerializableType) {
                return FLEXArgInputObjectTypeJSON;
            } else {
                return FLEXArgInputObjectTypeAddress;
            }
        } else {
            return FLEXArgInputObjectTypeAddress;
        }
    }
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.h
================================================
//
//  FLEXArgumentInputStringView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/28/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputStringView : FLEXArgumentInputTextView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.m
================================================
//
//  FLEXArgumentInputStringView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/28/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputStringView.h"
#import "FLEXRuntimeUtility.h"

@implementation FLEXArgumentInputStringView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        FLEXTypeEncoding type = typeEncoding[0];
        if (type == FLEXTypeEncodingConst) {
            // A crash here would mean an invalid type encoding string
            type = typeEncoding[1];
        }

        // Selectors don't need a multi-line text box
        if (type == FLEXTypeEncodingSelector) {
            self.targetSize = FLEXArgumentInputViewSizeSmall;
        } else {
            self.targetSize = FLEXArgumentInputViewSizeLarge;
        }
    }
    return self;
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue isKindOfClass:[NSString class]]) {
        self.inputTextView.text = inputValue;
    } else if ([inputValue isKindOfClass:[NSValue class]]) {
        NSValue *value = (id)inputValue;
        NSParameterAssert(strlen(value.objCType) == 1);

        // C-String or SEL from NSValue
        FLEXTypeEncoding type = value.objCType[0];
        if (type == FLEXTypeEncodingConst) {
            // A crash here would mean an invalid type encoding string
            type = value.objCType[1];
        }

        if (type == FLEXTypeEncodingCString) {
            self.inputTextView.text = @((const char *)value.pointerValue);
        } else if (type == FLEXTypeEncodingSelector) {
            self.inputTextView.text = NSStringFromSelector((SEL)value.pointerValue);
        }
    }
}

- (id)inputValue {
    NSString *text = self.inputTextView.text;
    // Interpret empty string as nil. We loose the ability to set empty string as a string value,
    // but we accept that tradeoff in exchange for not having to type quotes for every string.
    if (!text.length) {
        return nil;
    }

    // Case: C-strings and SELs
    if (self.typeEncoding.length <= 2) {
        FLEXTypeEncoding type = [self.typeEncoding characterAtIndex:0];
        if (type == FLEXTypeEncodingConst) {
            // A crash here would mean an invalid type encoding string
            type = [self.typeEncoding characterAtIndex:1];
        }

        if (type == FLEXTypeEncodingCString || type == FLEXTypeEncodingSelector) {
            const char *encoding = self.typeEncoding.UTF8String;
            SEL selector = NSSelectorFromString(text);
            return [NSValue valueWithBytes:&selector objCType:encoding];
        }
    }

    // Case: NSStrings
    return self.inputTextView.text.copy;
}

// TODO: Support using object address for strings, as in the object arg view.

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    unsigned long len = strlen(type);

    BOOL isConst = type[0] == FLEXTypeEncodingConst;
    NSInteger i = isConst ? 1 : 0;

    BOOL typeIsString = strcmp(type, FLEXEncodeClass(NSString)) == 0;
    BOOL typeIsCString = len <= 2 && type[i] == FLEXTypeEncodingCString;
    BOOL typeIsSEL = len <= 2 && type[i] == FLEXTypeEncodingSelector;
    BOOL valueIsString = [value isKindOfClass:[NSString class]];

    BOOL typeIsPrimitiveString = typeIsSEL || typeIsCString;
    BOOL typeIsSupported = typeIsString || typeIsCString || typeIsSEL;

    BOOL valueIsNSValueWithCorrectType = NO;
    if ([value isKindOfClass:[NSValue class]]) {
        NSValue *v = (id)value;
        len = strlen(v.objCType);
        if (len == 1) {
            FLEXTypeEncoding type = v.objCType[i];
            if (type == FLEXTypeEncodingCString && typeIsCString) {
                valueIsNSValueWithCorrectType = YES;
            } else if (type == FLEXTypeEncodingSelector && typeIsSEL) {
                valueIsNSValueWithCorrectType = YES;
            }
        }
    }

    if (!value && typeIsSupported) {
        return YES;
    }

    if (typeIsString && valueIsString) {
        return YES;
    }

    // Primitive strings can be input as NSStrings or NSValues
    if (typeIsPrimitiveString && (valueIsString || valueIsNSValueWithCorrectType)) {
        return YES;
    }

    return NO;
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.h
================================================
//
//  FLEXArgumentInputStructView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputStructView : FLEXArgumentInputView

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.m
================================================
//
//  FLEXArgumentInputStructView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputStructView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXTypeEncodingParser.h"

@interface FLEXArgumentInputStructView ()

@property (nonatomic) NSArray<FLEXArgumentInputView *> *argumentInputViews;

@end

@implementation FLEXArgumentInputStructView

static NSMutableDictionary<NSString *, NSArray<NSString *> *> *structFieldNameRegistrar = nil;
+ (void)initialize {
    if (self == [FLEXArgumentInputStructView class]) {
        structFieldNameRegistrar = [NSMutableDictionary new];
        [self registerDefaultFieldNames];
    }
}

+ (void)registerDefaultFieldNames {
    NSDictionary *defaults = @{
        @(@encode(CGRect)):             @[@"CGPoint origin", @"CGSize size"],
        @(@encode(CGPoint)):            @[@"CGFloat x", @"CGFloat y"],
        @(@encode(CGSize)):             @[@"CGFloat width", @"CGFloat height"],
        @(@encode(CGVector)):           @[@"CGFloat dx", @"CGFloat dy"],
        @(@encode(UIEdgeInsets)):       @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"],
        @(@encode(UIOffset)):           @[@"CGFloat horizontal", @"CGFloat vertical"],
        @(@encode(NSRange)):            @[@"NSUInteger location", @"NSUInteger length"],
        @(@encode(CATransform3D)):      @[@"CGFloat m11", @"CGFloat m12", @"CGFloat m13", @"CGFloat m14",
                                          @"CGFloat m21", @"CGFloat m22", @"CGFloat m23", @"CGFloat m24",
                                          @"CGFloat m31", @"CGFloat m32", @"CGFloat m33", @"CGFloat m34",
                                          @"CGFloat m41", @"CGFloat m42", @"CGFloat m43", @"CGFloat m44"],
        @(@encode(CGAffineTransform)):  @[@"CGFloat a", @"CGFloat b",
                                          @"CGFloat c", @"CGFloat d",
                                          @"CGFloat tx", @"CGFloat ty"],
    };
    
    [structFieldNameRegistrar addEntriesFromDictionary:defaults];
    
    if (@available(iOS 11.0, *)) {
        structFieldNameRegistrar[@(@encode(NSDirectionalEdgeInsets))] = @[
            @"CGFloat top", @"CGFloat leading", @"CGFloat bottom", @"CGFloat trailing"
        ];
    }
}

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        NSMutableArray<FLEXArgumentInputView *> *inputViews = [NSMutableArray new];
        NSArray<NSString *> *customTitles = [[self class] customFieldTitlesForTypeEncoding:typeEncoding];
        [FLEXRuntimeUtility enumerateTypesInStructEncoding:typeEncoding usingBlock:^(NSString *structName,
                                                                                     const char *fieldTypeEncoding,
                                                                                     NSString *prettyTypeEncoding,
                                                                                     NSUInteger fieldIndex,
                                                                                     NSUInteger fieldOffset) {
            
            FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:fieldTypeEncoding];
            inputView.targetSize = FLEXArgumentInputViewSizeSmall;
            
            if (fieldIndex < customTitles.count) {
                inputView.title = customTitles[fieldIndex];
            } else {
                inputView.title = [NSString stringWithFormat:@"%@ field %lu (%@)",
                    structName, (unsigned long)fieldIndex, prettyTypeEncoding
                ];
            }

            [inputViews addObject:inputView];
            [self addSubview:inputView];
        }];
        self.argumentInputViews = inputViews;
    }
    return self;
}


#pragma mark - Superclass Overrides

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    for (FLEXArgumentInputView *inputView in self.argumentInputViews) {
        inputView.backgroundColor = backgroundColor;
    }
}

- (void)setInputValue:(id)inputValue {
    if ([inputValue isKindOfClass:[NSValue class]]) {
        const char *structTypeEncoding = [inputValue objCType];
        if (strcmp(self.typeEncoding.UTF8String, structTypeEncoding) == 0) {
            NSUInteger valueSize = 0;
            
            if (FLEXGetSizeAndAlignment(structTypeEncoding, &valueSize, NULL)) {
                void *unboxedValue = malloc(valueSize);
                [inputValue getValue:unboxedValue];
                [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName,
                                                                                                   const char *fieldTypeEncoding,
                                                                                                   NSString *prettyTypeEncoding,
                                                                                                   NSUInteger fieldIndex,
                                                                                                   NSUInteger fieldOffset) {
                    
                    void *fieldPointer = unboxedValue + fieldOffset;
                    FLEXArgumentInputView *inputView = self.argumentInputViews[fieldIndex];
                    
                    if (fieldTypeEncoding[0] == FLEXTypeEncodingObjcObject || fieldTypeEncoding[0] == FLEXTypeEncodingObjcClass) {
                        inputView.inputValue = (__bridge id)fieldPointer;
                    } else {
                        NSValue *boxedField = [FLEXRuntimeUtility valueForPrimitivePointer:fieldPointer objCType:fieldTypeEncoding];
                        inputView.inputValue = boxedField;
                    }
                }];
                free(unboxedValue);
            }
        }
    }
}

- (id)inputValue {
    NSValue *boxedStruct = nil;
    const char *structTypeEncoding = self.typeEncoding.UTF8String;
    NSUInteger structSize = 0;
    
    if (FLEXGetSizeAndAlignment(structTypeEncoding, &structSize, NULL)) {
        void *unboxedStruct = malloc(structSize);
        [FLEXRuntimeUtility enumerateTypesInStructEncoding:structTypeEncoding usingBlock:^(NSString *structName,
                                                                                           const char *fieldTypeEncoding,
                                                                                           NSString *prettyTypeEncoding,
                                                                                           NSUInteger fieldIndex,
                                                                                           NSUInteger fieldOffset) {
            
            void *fieldPointer = unboxedStruct + fieldOffset;
            FLEXArgumentInputView *inputView = self.argumentInputViews[fieldIndex];
            
            if (fieldTypeEncoding[0] == FLEXTypeEncodingObjcObject || fieldTypeEncoding[0] == FLEXTypeEncodingObjcClass) {
                // Object fields
                memcpy(fieldPointer, (__bridge void *)inputView.inputValue, sizeof(id));
            } else {
                // Boxed primitive/struct fields
                id inputValue = inputView.inputValue;
                if ([inputValue isKindOfClass:[NSValue class]] && strcmp([inputValue objCType], fieldTypeEncoding) == 0) {
                    [inputValue getValue:fieldPointer];
                }
            }
        }];
        
        boxedStruct = [NSValue value:unboxedStruct withObjCType:structTypeEncoding];
        free(unboxedStruct);
    }
    
    return boxedStruct;
}

- (BOOL)inputViewIsFirstResponder {
    BOOL isFirstResponder = NO;
    for (FLEXArgumentInputView *inputView in self.argumentInputViews) {
        if ([inputView inputViewIsFirstResponder]) {
            isFirstResponder = YES;
            break;
        }
    }
    return isFirstResponder;
}


#pragma mark - Layout and Sizing

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat runningOriginY = self.topInputFieldVerticalLayoutGuide;
    
    for (FLEXArgumentInputView *inputView in self.argumentInputViews) {
        CGSize inputFitSize = [inputView sizeThatFits:self.bounds.size];
        inputView.frame = CGRectMake(0, runningOriginY, inputFitSize.width, inputFitSize.height);
        runningOriginY = CGRectGetMaxY(inputView.frame) + [[self class] verticalPaddingBetweenFields];
    }
}

+ (CGFloat)verticalPaddingBetweenFields {
    return 10.0;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize fitSize = [super sizeThatFits:size];
    
    CGSize constrainSize = CGSizeMake(size.width, CGFLOAT_MAX);
    CGFloat height = fitSize.height;
    
    for (FLEXArgumentInputView *inputView in self.argumentInputViews) {
        height += [inputView sizeThatFits:constrainSize].height;
        height += [[self class] verticalPaddingBetweenFields];
    }
    
    return CGSizeMake(fitSize.width, height);
}


#pragma mark - Class Helpers

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    if (type[0] == FLEXTypeEncodingStructBegin) {
        return FLEXGetSizeAndAlignment(type, nil, nil);
    }

    return NO;
}

+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
    NSParameterAssert(typeEncoding); NSParameterAssert(names);
    structFieldNameRegistrar[typeEncoding] = names;
}

+ (NSArray<NSString *> *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding {
    return structFieldNameRegistrar[@(typeEncoding)];
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.h
================================================
//
//  FLEXArgumentInputSwitchView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputSwitchView : FLEXArgumentInputView

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.m
================================================
//
//  FLEXArgumentInputSwitchView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputSwitchView.h"

@interface FLEXArgumentInputSwitchView ()

@property (nonatomic) UISwitch *inputSwitch;

@end

@implementation FLEXArgumentInputSwitchView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputSwitch = [UISwitch new];
        [self.inputSwitch addTarget:self action:@selector(switchValueDidChange:) forControlEvents:UIControlEventValueChanged];
        [self.inputSwitch sizeToFit];
        [self addSubview:self.inputSwitch];
    }
    return self;
}


#pragma mark Input/Output

- (void)setInputValue:(id)inputValue {
    BOOL on = NO;
    if ([inputValue isKindOfClass:[NSNumber class]]) {
        NSNumber *number = (NSNumber *)inputValue;
        on = [number boolValue];
    } else if ([inputValue isKindOfClass:[NSValue class]]) {
        NSValue *value = (NSValue *)inputValue;
        if (strcmp([value objCType], @encode(BOOL)) == 0) {
            [value getValue:&on];
        }
    }
    self.inputSwitch.on = on;
}

- (id)inputValue {
    BOOL isOn = [self.inputSwitch isOn];
    NSValue *boxedBool = [NSValue value:&isOn withObjCType:@encode(BOOL)];
    return boxedBool;
}

- (void)switchValueDidChange:(id)sender {
    [self.delegate argumentInputViewValueDidChange:self];
}


#pragma mark - Layout and Sizing

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.inputSwitch.frame = CGRectMake(0, self.topInputFieldVerticalLayoutGuide, self.inputSwitch.frame.size.width, self.inputSwitch.frame.size.height);
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize fitSize = [super sizeThatFits:size];
    fitSize.height += self.inputSwitch.frame.size.height;
    return fitSize;
}


#pragma mark - Class Helpers

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    NSParameterAssert(type);
    // Only BOOLs. Current value is irrelevant.
    return strcmp(type, @encode(BOOL)) == 0;
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h
================================================
//
//  FLEXArgumentInputTextView.h
//  FLEXInjected
//
//  Created by Ryan Olson on 6/15/14.
//
//

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputTextView : FLEXArgumentInputView <UITextViewDelegate>

// For subclass eyes only

@property (nonatomic, readonly) UITextView *inputTextView;
@property (nonatomic) NSString *inputPlaceholderText;

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.m
================================================
//
//  FLEXArgumentInputTextView.m
//  FLEXInjected
//
//  Created by Ryan Olson on 6/15/14.
//
//

#import "FLEXColor.h"
#import "FLEXArgumentInputTextView.h"
#import "FLEXUtility.h"

@interface FLEXArgumentInputTextView ()

@property (nonatomic) UITextView *inputTextView;
@property (nonatomic) UILabel *placeholderLabel;
@property (nonatomic, readonly) NSUInteger numberOfInputLines;

@end

@implementation FLEXArgumentInputTextView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputTextView = [UITextView new];
        self.inputTextView.font = [[self class] inputFont];
        self.inputTextView.backgroundColor = FLEXColor.secondaryGroupedBackgroundColor;
        self.inputTextView.layer.cornerRadius = 10.f;
        self.inputTextView.contentInset = UIEdgeInsetsMake(0, 5, 0, 0);
        self.inputTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
        self.inputTextView.autocorrectionType = UITextAutocorrectionTypeNo;
        self.inputTextView.delegate = self;
        self.inputTextView.inputAccessoryView = [self createToolBar];
        if (@available(iOS 11, *)) {
            self.inputTextView.smartQuotesType = UITextSmartQuotesTypeNo;
            [self.inputTextView.layer setValue:@YES forKey:@"continuousCorners"];
        } else {
            self.inputTextView.layer.borderWidth = 1.f;
            self.inputTextView.layer.borderColor = FLEXColor.borderColor.CGColor;
        }

        self.placeholderLabel = [UILabel new];
        self.placeholderLabel.font = self.inputTextView.font;
        self.placeholderLabel.textColor = FLEXColor.deemphasizedTextColor;
        self.placeholderLabel.numberOfLines = 0;

        [self addSubview:self.inputTextView];
        [self.inputTextView addSubview:self.placeholderLabel];

    }
    return self;
}

#pragma mark - Private

- (UIToolbar *)createToolBar {
    UIToolbar *toolBar = [UIToolbar new];
    [toolBar sizeToFit];
    UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc]
        initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
        target:nil action:nil
    ];
    UIBarButtonItem *pasteItem = [[UIBarButtonItem alloc]
        initWithTitle:@"Paste" style:UIBarButtonItemStyleDone
        target:self.inputTextView action:@selector(paste:)
    ];
    UIBarButtonItem *doneItem = [[UIBarButtonItem alloc]
        initWithBarButtonSystemItem:UIBarButtonSystemItemDone
        target:self.inputTextView action:@selector(resignFirstResponder)
    ];
    toolBar.items = @[spaceItem, pasteItem, doneItem];
    return toolBar;
}

- (void)setInputPlaceholderText:(NSString *)placeholder {
    self.placeholderLabel.text = placeholder;
    if (placeholder.length) {
        if (!self.inputTextView.text.length) {
            self.placeholderLabel.hidden = NO;
        } else {
            self.placeholderLabel.hidden = YES;
        }
    } else {
        self.placeholderLabel.hidden = YES;
    }

    [self setNeedsLayout];
}

- (NSString *)inputPlaceholderText {
    return self.placeholderLabel.text;
}


#pragma mark - Superclass Overrides

- (BOOL)inputViewIsFirstResponder {
    return self.inputTextView.isFirstResponder;
}


#pragma mark - Layout and Sizing

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.inputTextView.frame = CGRectMake(0, self.topInputFieldVerticalLayoutGuide, self.bounds.size.width, [self inputTextViewHeight]);
    // Placeholder label is positioned by insetting then origin
    // by the content inset then the text container inset
    CGSize s = self.inputTextView.frame.size;
    self.placeholderLabel.frame = CGRectMake(0, 0, s.width, s.height);
    self.placeholderLabel.frame = UIEdgeInsetsInsetRect(
        UIEdgeInsetsInsetRect(self.placeholderLabel.frame, self.inputTextView.contentInset),
        self.inputTextView.textContainerInset
    );
}

- (NSUInteger)numberOfInputLines {
    switch (self.targetSize) {
        case FLEXArgumentInputViewSizeDefault:
            return 2;
        case FLEXArgumentInputViewSizeSmall:
            return 1;
        case FLEXArgumentInputViewSizeLarge:
            return 8;
    }
}

- (CGFloat)inputTextViewHeight {
    return ceil([[self class] inputFont].lineHeight * self.numberOfInputLines) + 16.0;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize fitSize = [super sizeThatFits:size];
    fitSize.height += [self inputTextViewHeight];
    return fitSize;
}


#pragma mark - Class Helpers

+ (UIFont *)inputFont {
    return [UIFont systemFontOfSize:14.0];
}


#pragma mark - UITextViewDelegate

- (void)textViewDidChange:(UITextView *)textView {
    [self.delegate argumentInputViewValueDidChange:self];
    self.placeholderLabel.hidden = !(self.inputPlaceholderText.length && !textView.text.length);
}

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h
================================================
//
//  FLEXArgumentInputView.h
//  Flipboard
//
//  Created by Ryan Olson on 5/30/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSUInteger, FLEXArgumentInputViewSize) {
    /// 2 lines, medium-sized
    FLEXArgumentInputViewSizeDefault = 0,
    /// One line
    FLEXArgumentInputViewSizeSmall,
    /// Several lines
    FLEXArgumentInputViewSizeLarge
};

@protocol FLEXArgumentInputViewDelegate;

@interface FLEXArgumentInputView : UIView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding;

/// The name of the field. Optional (can be nil).
@property (nonatomic, copy) NSString *title;

/// To populate the filed with an initial value, set this property.
/// To reteive the value input by the user, access the property.
/// Primitive types and structs should/will be boxed in NSValue containers.
/// Concrete subclasses should override both the setter and getter for this property.
/// Subclasses can call super.inputValue to access a backing store for the value.
@property (nonatomic) id inputValue;

/// Setting this value to large will make some argument input views increase the size of their input field(s).
/// Useful to increase the use of space if there is only one input view on screen (i.e. for property and ivar editing).
@property (nonatomic) FLEXArgumentInputViewSize targetSize;

/// Users of the input view can get delegate callbacks for incremental changes in user input.
@property (nonatomic, weak) id <FLEXArgumentInputViewDelegate> delegate;

// Subclasses can override

/// If the input view has one or more text views, returns YES when one of them is focused.
@property (nonatomic, readonly) BOOL inputViewIsFirstResponder;

/// For subclasses to indicate that they can handle editing a field the give type and value.
/// Used by FLEXArgumentInputViewFactory to create appropriate input views.
+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value;

// For subclass eyes only

@property (nonatomic, readonly) UILabel *titleLabel;
@property (nonatomic, readonly) NSString *typeEncoding;
@property (nonatomic, readonly) CGFloat topInputFieldVerticalLayoutGuide;

@end

@protocol FLEXArgumentInputViewDelegate <NSObject>

- (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView;

@end


================================================
FILE: Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.m
================================================
//
//  FLEXArgumentInputView.m
//  Flipboard
//
//  Created by Ryan Olson on 5/30/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXArgumentInputView.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"

@interface FLEXArgumentInputView ()

@property (nonatomic) UILabel *titleLabel;
@property (nonatomic) NSString *typeEncoding;

@end

@implementation FLEXArgumentInputView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
    self = [super initWithFrame:CGRectZero];
    if (self) {
        self.typeEncoding = typeEncoding != NULL ? @(typeEncoding) : nil;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    if (self.showsTitle) {
        CGSize constrainSize = CGSizeMake(self.bounds.size.width, CGFLOAT_MAX);
        CGSize labelSize = [self.titleLabel sizeThatFits:constrainSize];
        self.titleLabel.frame = CGRectMake(0, 0, labelSize.width, labelSize.height);
    }
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.titleLabel.backgroundColor = backgroundColor;
}

- (void)setTitle:(NSString *)title {
    if (![_title isEqual:title]) {
        _title = title;
        self.titleLabel.text = title;
        [self setNeedsLayout];
    }
}

- (UILabel *)titleLabel {
    if (!_titleLabel) {
        _titleLabel = [UILabel new];
        _titleLabel.font = [[self class] titleFont];
        _titleLabel.textColor = FLEXColor.primaryTextColor;
        _titleLabel.numberOfLines = 0;
        [self addSubview:_titleLabel];
    }
    return _titleLabel;
}

- (BOOL)showsTitle {
    return self.title.length > 0;
}

- (CGFloat)topInputFieldVerticalLayoutGuide {
    CGFloat verticalLayoutGuide = 0;
    if (self.showsTitle) {
        CGFloat titleHeight = [self.titleLabel sizeThatFits:self.bounds.size].height;
        verticalLayoutGuide = titleHeight + [[self class] titleBottomPadding];
    }
    return verticalLayoutGuide;
}


#pragma mark - Subclasses Can Override

- (BOOL)inputViewIsFirstResponder {
    return NO;
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
    return NO;
}


#pragma mark - Class Helpers

+ (UIFont *)titleFont {
    return [UIFont systemFontOfSize:12.0];
}

+ (CGFloat)titleBottomPadding {
    return 4.0;
}


#pragma mark - Sizing

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat height = 0;
    
    if (self.title.length > 0) {
        CGSize constrainSize = CGSizeMake(size.width, CGFLOAT_MAX);
        height += ceil([self.titleLabel sizeThatFits:constrainSize].height);
        height += [[self class] titleBottomPadding];
    }
    
    return CGSizeMake(size.width, height);
}

@end


================================================
FILE: Classes/Editing/FLEXArgumentInputViewFactory.h
================================================
//
//  FLEXArgumentInputViewFactory.h
//  FLEXInjected
//
//  Created by Ryan Olson on 6/15/14.
//
//

#import <Foundation/Foundation.h>
#import "FLEXArgumentInputSwitchView.h"

@interface FLEXArgumentInputViewFactory : NSObject

/// Forwards to argumentInputViewForTypeEncoding:currentValue: with a nil currentValue.
+ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding;

/// The main factory method for making argument input view subclasses that are the best fit for the type.
+ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue;

/// A way to check if we should try editing a filed given its type encoding and value.
/// Useful when deciding whether to edit or explore a property, ivar, or NSUserDefaults value.
+ (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue;

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;

@end


================================================
FILE: Classes/Editing/FLEXArgumentInputViewFactory.m
================================================
//
//  FLEXArgumentInputViewFactory.m
//  FLEXInjected
//
//  Created by Ryan Olson on 6/15/14.
//
//

#import "FLEXArgumentInputViewFactory.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputObjectView.h"
#import "FLEXArgumentInputNumberView.h"
#import "FLEXArgumentInputSwitchView.h"
#import "FLEXArgumentInputStructView.h"
#import "FLEXArgumentInputNotSupportedView.h"
#import "FLEXArgumentInputStringView.h"
#import "FLEXArgumentInputFontView.h"
#import "FLEXArgumentInputColorView.h"
#import "FLEXArgumentInputDateView.h"
#import "FLEXRuntimeUtility.h"

@implementation FLEXArgumentInputViewFactory

+ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding {
    return [self argumentInputViewForTypeEncoding:typeEncoding currentValue:nil];
}

+ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue {
    Class subclass = [self argumentInputViewSubclassForTypeEncoding:typeEncoding currentValue:currentValue];
    if (!subclass) {
        // Fall back to a FLEXArgumentInputNotSupportedView if we can't find a subclass that fits the type encoding.
        // The unsupported view shows "nil" and does not allow user input.
        subclass = [FLEXArgumentInputNotSupportedView class];
    }
    // Remove the field name if there is any (e.g. \"width\"d -> d)
    const NSUInteger fieldNameOffset = [FLEXRuntimeUtility fieldNameOffsetForTypeEncoding:typeEncoding];
    return [[subclass alloc] initWithArgumentTypeEncoding:typeEncoding + fieldNameOffset];
}

+ (Class)argumentInputViewSubclassForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue {
    // Remove the field name if there is any (e.g. \"width\"d -> d)
    const NSUInteger fieldNameOffset = [FLEXRuntimeUtility fieldNameOffsetForTypeEncoding:typeEncoding];
    Class argumentInputViewSubclass = nil;
    NSArray<Class> *inputViewClasses = @[[FLEXArgumentInputColorView class],
                                         [FLEXArgumentInputFontView class],
                                         [FLEXArgumentInputStringView class],
                                         [FLEXArgumentInputStructView class],
                                         [FLEXArgumentInputSwitchView class],
                                         [FLEXArgumentInputDateView class],
                                         [FLEXArgumentInputNumberView class],
                                         [FLEXArgumentInputObjectView class]];

    // Note that order is important here since multiple subclasses may support the same type.
    // An example is the number subclass and the bool subclass for the type @encode(BOOL).
    // Both work, but we'd prefer to use the bool subclass.
    for (Class inputViewClass in inputViewClasses) {
        if ([inputViewClass supportsObjCType:typeEncoding + fieldNameOffset withCurrentValue:currentValue]) {
            argumentInputViewSubclass = inputViewClass;
            break;
        }
    }

    return argumentInputViewSubclass;
}

+ (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue {
    return [self argumentInputViewSubclassForTypeEncoding:typeEncoding currentValue:currentValue] != nil;
}

/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
    [FLEXArgumentInputStructView registerFieldNames:names forTypeEncoding:typeEncoding];
}

@end


================================================
FILE: Classes/Editing/FLEXDefaultEditorViewController.h
================================================
//
//  FLEXDefaultEditorViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 5/23/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXFieldEditorViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface FLEXDefaultEditorViewController : FLEXVariableEditorViewController

+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit;

+ (BOOL)canEditDefaultWithValue:(nullable id)currentValue;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Editing/FLEXDefaultEditorViewController.m
================================================
//
//  FLEXDefaultEditorViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 5/23/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXDefaultEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"

@interface FLEXDefaultEditorViewController ()

@property (nonatomic, readonly) NSUserDefaults *defaults;
@property (nonatomic, readonly) NSString *key;

@end

@implementation FLEXDefaultEditorViewController

+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit {
    FLEXDefaultEditorViewController *editor = [self target:defaults data:key commitHandler:onCommit];
    editor.title = @"Edit Default";
    return editor;
}

- (NSUserDefaults *)defaults {
    return [_target isKindOfClass:[NSUserDefaults class]] ? _target : nil;
}

- (NSString *)key {
    return _data;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.fieldEditorView.fieldDescription = self.key;

    id currentValue = [self.defaults objectForKey:self.key];
    FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory
        argumentInputViewForTypeEncoding:FLEXEncodeObject(currentValue)
        currentValue:currentValue
    ];
    inputView.backgroundColor = self.view.backgroundColor;
    inputView.inputValue = currentValue;
    self.fieldEditorView.argumentInputViews = @[inputView];
}

- (void)actionButtonPressed:(id)sender {
    id value = self.firstInputView.inputValue;
    if (value) {
        [self.defaults setObject:value forKey:self.key];
    } else {
        [self.defaults removeObjectForKey:self.key];
    }
    [self.defaults synchronize];
    
    // Dismiss keyboard and handle committed changes
    [super actionButtonPressed:sender];
    
    // Go back after setting, but not for switches.
    if (sender) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        self.firstInputView.inputValue = [self.defaults objectForKey:self.key];
    }
}

+ (BOOL)canEditDefaultWithValue:(id)currentValue {
    return [FLEXArgumentInputViewFactory
        canEditFieldWithTypeEncoding:FLEXEncodeObject(currentValue)
        currentValue:currentValue
    ];
}

@end


================================================
FILE: Classes/Editing/FLEXFieldEditorView.h
================================================
//
//  FLEXFieldEditorView.h
//  Flipboard
//
//  Created by Ryan Olson on 5/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

@class FLEXArgumentInputView;

@interface FLEXFieldEditorView : UIView

@property (nonatomic, copy) NSString *targetDescription;
@property (nonatomic, copy) NSString *fieldDescription;

@property (nonatomic, copy) NSArray<FLEXArgumentInputView *> *argumentInputViews;

@end


================================================
FILE: Classes/Editing/FLEXFieldEditorView.m
================================================
//
//  FLEXFieldEditorView.m
//  Flipboard
//
//  Created by Ryan Olson on 5/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXFieldEditorView.h"
#import "FLEXArgumentInputView.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"

@interface FLEXFieldEditorView ()

@property (nonatomic) UILabel *targetDescriptionLabel;
@property (nonatomic) UIView *targetDescriptionDivider;
@property (nonatomic) UILabel *fieldDescriptionLabel;
@property (nonatomic) UIView *fieldDescriptionDivider;

@end

@implementation FLEXFieldEditorView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.targetDescriptionLabel = [UILabel new];
        self.targetDescriptionLabel.numberOfLines = 0;
        self.targetDescriptionLabel.font = [[self class] labelFont];
        [self addSubview:self.targetDescriptionLabel];
        
        self.targetDescriptionDivider = [[self class] dividerView];
        [self addSubview:self.targetDescriptionDivider];
        
        self.fieldDescriptionLabel = [UILabel new];
        self.fieldDescriptionLabel.numberOfLines = 0;
        self.fieldDescriptionLabel.font = [[self class] labelFont];
        [self addSubview:self.fieldDescriptionLabel];
        
        self.fieldDescriptionDivider = [[self class] dividerView];
        [self addSubview:self.fieldDescriptionDivider];
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGFloat horizontalPadding = [[self class] horizontalPadding];
    CGFloat verticalPadding = [[self class] verticalPadding];
    CGFloat dividerLineHeight = [[self class] dividerLineHeight];
    
    CGFloat originY = verticalPadding;
    CGFloat originX = horizontalPadding;
    CGFloat contentWidth = self.bounds.size.width - 2.0 * horizontalPadding;
    CGSize constrainSize = CGSizeMake(contentWidth, CGFLOAT_MAX);
    
    CGSize instanceDescriptionSize = [self.targetDescriptionLabel sizeThatFits:constrainSize];
    self.targetDescriptionLabel.frame = CGRectMake(originX, originY, instanceDescriptionSize.width, instanceDescriptionSize.height);
    originY = CGRectGetMaxY(self.targetDescriptionLabel.frame) + verticalPadding;
    
    self.targetDescriptionDivider.frame = CGRectMake(originX, originY, contentWidth, dividerLineHeight);
    originY = CGRectGetMaxY(self.targetDescriptionDivider.frame) + verticalPadding;
    
    CGSize fieldDescriptionSize = [self.fieldDescriptionLabel sizeThatFits:constrainSize];
    self.fieldDescriptionLabel.frame = CGRectMake(originX, originY, fieldDescriptionSize.width, fieldDescriptionSize.height);
    originY = CGRectGetMaxY(self.fieldDescriptionLabel.frame) + verticalPadding;
    
    self.fieldDescriptionDivider.frame = CGRectMake(originX, originY, contentWidth, dividerLineHeight);
    originY = CGRectGetMaxY(self.fieldDescriptionDivider.frame) + verticalPadding;

    for (UIView *argumentInputView in self.argumentInputViews) {
        CGSize inputViewSize = [argumentInputView sizeThatFits:constrainSize];
        argumentInputView.frame = CGRectMake(originX, originY, inputViewSize.width, inputViewSize.height);
        originY = CGRectGetMaxY(argumentInputView.frame) + verticalPadding;
    }
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:backgroundColor];
    self.targetDescriptionLabel.backgroundColor = backgroundColor;
    self.fieldDescriptionLabel.backgroundColor = backgroundColor;
}

- (void)setTargetDescription:(NSString *)targetDescription {
    if (![_targetDescription isEqual:targetDescription]) {
        _targetDescription = targetDescription;
        self.targetDescriptionLabel.text = targetDescription;
        [self setNeedsLayout];
    }
}

- (void)setFieldDescription:(NSString *)fieldDescription {
    if (![_fieldDescription isEqual:fieldDescription]) {
        _fieldDescription = fieldDescription;
        self.fieldDescriptionLabel.text = fieldDescription;
        [self setNeedsLayout];
    }
}

- (void)setArgumentInputViews:(NSArray<FLEXArgumentInputView *> *)argumentInputViews {
    if (![_argumentInputViews isEqual:argumentInputViews]) {
        
        for (FLEXArgumentInputView *inputView in _argumentInputViews) {
            [inputView removeFromSuperview];
        }
        
        _argumentInputViews = argumentInputViews;
        
        for (FLEXArgumentInputView *newInputView in argumentInputViews) {
            [self addSubview:newInputView];
        }
        
        [self setNeedsLayout];
    }
}

+ (UIView *)dividerView {
    UIView *dividerView = [UIView new];
    dividerView.backgroundColor = [self dividerColor];
    return dividerView;
}

+ (UIColor *)dividerColor {
    return FLEXColor.tertiaryBackgroundColor;
}

+ (CGFloat)horizontalPadding {
    return 10.0;
}

+ (CGFloat)verticalPadding {
    return 20.0;
}

+ (UIFont *)labelFont {
    return [UIFont systemFontOfSize:14.0];
}

+ (CGFloat)dividerLineHeight {
    return 1.0;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat horizontalPadding = [[self class] horizontalPadding];
    CGFloat verticalPadding = [[self class] verticalPadding];
    CGFloat dividerLineHeight = [[self class] dividerLineHeight];
    
    CGFloat height = 0;
    CGFloat availableWidth = size.width - 2.0 * horizontalPadding;
    CGSize constrainSize = CGSizeMake(availableWidth, CGFLOAT_MAX);
    
    height += verticalPadding;
    height += ceil([self.targetDescriptionLabel sizeThatFits:constrainSize].height);
    height += verticalPadding;
    height += dividerLineHeight;
    height += verticalPadding;
    height += ceil([self.fieldDescriptionLabel sizeThatFits:constrainSize].height);
    height += verticalPadding;
    height += dividerLineHeight;
    height += verticalPadding;
    
    for (FLEXArgumentInputView *inputView in self.argumentInputViews) {
        height += [inputView sizeThatFits:constrainSize].height;
        height += verticalPadding;
    }
    
    return CGSizeMake(size.width, height);
}

@end


================================================
FILE: Classes/Editing/FLEXFieldEditorViewController.h
================================================
//
//  FLEXFieldEditorViewController.h
//  FLEX
//
//  Created by Tanner on 11/22/18.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXVariableEditorViewController.h"
#import "FLEXProperty.h"
#import "FLEXIvar.h"

NS_ASSUME_NONNULL_BEGIN

@interface FLEXFieldEditorViewController : FLEXVariableEditorViewController

/// @return nil if the property is readonly or if the type is unsupported
+ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)(void))onCommit;
/// @return nil if the ivar type is unsupported
+ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)(void))onCommit;

/// Subclasses can change the button title via the \c title property
@property (nonatomic, readonly) UIBarButtonItem *getterButton;

- (void)getterButtonPressed:(id)sender;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Editing/FLEXFieldEditorViewController.m
================================================
//
//  FLEXFieldEditorViewController.m
//  FLEX
//
//  Created by Tanner on 11/22/18.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXFieldEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXPropertyAttributes.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXMetadataExtras.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "UIBarButtonItem+FLEX.h"

@interface FLEXFieldEditorViewController () <FLEXArgumentInputViewDelegate>

@property (nonatomic, readonly) id<FLEXMetadataAuxiliaryInfo> auxiliaryInfoProvider;
@property (nonatomic) FLEXProperty *property;
@property (nonatomic) FLEXIvar *ivar;

@property (nonatomic, readonly) id currentValue;
@property (nonatomic, readonly) const FLEXTypeEncoding *typeEncoding;
@property (nonatomic, readonly) NSString *fieldDescription;

@end

@implementation FLEXFieldEditorViewController

#pragma mark - Initialization

+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^)(void))onCommit {
    FLEXFieldEditorViewController *editor = [self target:target data:property commitHandler:onCommit];
    editor.title = [@"Property: " stringByAppendingString:property.name];
    editor.property = property;
    return editor;
}

+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^)(void))onCommit {
    FLEXFieldEditorViewController *editor = [self target:target data:ivar commitHandler:onCommit];
    editor.title = [@"Ivar: " stringByAppendingString:ivar.name];
    editor.ivar = ivar;
    return editor;
}

#pragma mark - Overrides

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = FLEXColor.groupedBackgroundColor;

    // Create getter button
    _getterButton = [[UIBarButtonItem alloc]
        initWithTitle:@"Get"
        style:UIBarButtonItemStyleDone
        target:self
        action:@selector(getterButtonPressed:)
    ];
    self.toolbarItems = @[
        UIBarButtonItem.flex_flexibleSpace, self.getterButton, self.actionButton
    ];
    
    [self registerAuxiliaryInfo];

    // Configure input view
    self.fieldEditorView.fieldDescription = self.fieldDescription;
    FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:self.typeEncoding];
    inputView.inputValue = self.currentValue;
    inputView.delegate = self;
    self.fieldEditorView.argumentInputViews = @[inputView];

    // Don't show a "set" button for switches; we mutate when the switch is flipped
    if ([inputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
        self.actionButton.enabled = NO;
        self.actionButton.title = @"Flip the switch to call the setter";
        // Put getter button before setter button 
        self.toolbarItems = @[
            UIBarButtonItem.flex_flexibleSpace, self.actionButton, self.getterButton
        ];
    }
}

- (void)actionButtonPressed:(id)sender {
    if (self.property) {
        id userInputObject = self.firstInputView.inputValue;
        NSArray *arguments = userInputObject ? @[userInputObject] : nil;
        SEL setterSelector = self.property.likelySetter;
        NSError *error = nil;
        [FLEXRuntimeUtility performSelector:setterSelector onObject:self.target withArguments:arguments error:&error];
        if (error) {
            [FLEXAlert showAlert:@"Property Setter Failed" message:error.localizedDescription from:self];
            sender = nil; // Don't pop back
        }
    } else {
        // TODO: check mutability and use mutableCopy if necessary;
        // this currently could and would assign NSArray to NSMutableArray
        [self.ivar setValue:self.firstInputView.inputValue onObject:self.target];
    }
    
    // Dismiss keyboard and handle committed changes
    [super actionButtonPressed:sender];

    // Go back after setting, but not for switches.
    if (sender) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        self.firstInputView.inputValue = self.currentValue;
    }
}

- (void)getterButtonPressed:(id)sender {
    [self.fieldEditorView endEditing:YES];

    [self exploreObjectOrPopViewController:self.currentValue];
}

- (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView {
    if ([argumentInputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
        [self actionButtonPressed:nil];
    }
}

#pragma mark - Private

- (void)registerAuxiliaryInfo {
    // This is how Reflex will get Swift struct field names into the editor at runtime
    NSDictionary<NSString *, NSArray *> *labels = [self.auxiliaryInfoProvider
        auxiliaryInfoForKey:FLEXAuxiliarynfoKeyFieldLabels
    ];
    
    for (NSString *type in labels) {
        [FLEXArgumentInputViewFactory registerFieldNames:labels[type] forTypeEncoding:type];
    }
}

- (id)currentValue {
    if (self.property) {
        return [self.property getValue:self.target];
    } else {
        return [self.ivar getValue:self.target];
    }
}

- (id<FLEXMetadataAuxiliaryInfo>)auxiliaryInfoProvider {
    return self.ivar ?: self.property;
}

- (const FLEXTypeEncoding *)typeEncoding {
    if (self.property) {
        return self.property.attributes.typeEncoding.UTF8String;
    } else {
        return self.ivar.typeEncoding.UTF8String;
    }
}

- (NSString *)fieldDescription {
    if (self.property) {
        return self.property.fullDescription;
    } else {
        return self.ivar.description;
    }
}

@end


================================================
FILE: Classes/Editing/FLEXMethodCallingViewController.h
================================================
//
//  FLEXMethodCallingViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 5/23/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXVariableEditorViewController.h"
#import "FLEXMethod.h"

@interface FLEXMethodCallingViewController : FLEXVariableEditorViewController

+ (instancetype)target:(id)target method:(FLEXMethod *)method;

@end


================================================
FILE: Classes/Editing/FLEXMethodCallingViewController.m
================================================
//
//  FLEXMethodCallingViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 5/23/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXMethodCallingViewController.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXFieldEditorView.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXObjectExplorerViewController.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXUtility.h"

@interface FLEXMethodCallingViewController ()
@property (nonatomic, readonly) FLEXMethod *method;
@end

@implementation FLEXMethodCallingViewController

+ (instancetype)target:(id)target method:(FLEXMethod *)method {
    return [[self alloc] initWithTarget:target method:method];
}

- (id)initWithTarget:(id)target method:(FLEXMethod *)method {
    NSParameterAssert(method.isInstanceMethod == !object_isClass(target));

    self = [super initWithTarget:target data:method commitHandler:nil];
    if (self) {
        self.title = method.isInstanceMethod ? @"Method: " : @"Class Method: ";
        self.title = [self.title stringByAppendingString:method.selectorString];
    }

    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.actionButton.title = @"Call";

    // Configure field editor view
    self.fieldEditorView.argumentInputViews = [self argumentInputViews];
    self.fieldEditorView.fieldDescription = [NSString stringWithFormat:
        @"Signature:\n%@\n\nReturn Type:\n%s",
        self.method.description, (char *)self.method.returnType
    ];
}

- (NSArray<FLEXArgumentInputView *> *)argumentInputViews {
    Method method = self.method.objc_method;
    NSArray *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:method];
    NSMutableArray<FLEXArgumentInputView *> *argumentInputViews = [NSMutableArray new];
    unsigned int argumentIndex = kFLEXNumberOfImplicitArgs;

    for (NSString *methodComponent in methodComponents) {
        char *argumentTypeEncoding = method_copyArgumentType(method, argumentIndex);
        FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:argumentTypeEncoding];
        free(argumentTypeEncoding);

        inputView.backgroundColor = self.view.backgroundColor;
        inputView.title = methodComponent;
        [argumentInputViews addObject:inputView];
        argumentIndex++;
    }

    return argumentInputViews;
}

- (void)actionButtonPressed:(id)sender {
    // Gather arguments
    NSMutableArray *arguments = [NSMutableArray new];
    for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
        // Use NSNull as a nil placeholder; it will be interpreted as nil
        [arguments addObject:inputView.inputValue ?: NSNull.null];
    }

    // Call method
    NSError *error = nil;
    id returnValue = [FLEXRuntimeUtility
        performSelector:self.method.selector
        onObject:self.target
        withArguments:arguments
        error:&error
    ];
    
    // Dismiss keyboard and handle committed changes
    [super actionButtonPressed:sender];

    // Display return value or error
    if (error) {
        [FLEXAlert showAlert:@"Method Call Failed" message:error.localizedDescription from:self];
    } else if (returnValue) {
        // For non-nil (or void) return types, push an explorer view controller to display the returned object
        returnValue = [FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:returnValue type:self.method.returnType];
        FLEXObjectExplorerViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:returnValue];
        [self.navigationController pushViewController:explorer animated:YES];
    } else {
        [self exploreObjectOrPopViewController:returnValue];
    }
}

- (FLEXMethod *)method {
    return _data;
}

@end


================================================
FILE: Classes/Editing/FLEXVariableEditorViewController.h
================================================
//
//  FLEXVariableEditorViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 5/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import <UIKit/UIKit.h>

@class FLEXFieldEditorView;
@class FLEXArgumentInputView;

NS_ASSUME_NONNULL_BEGIN

/// An abstract screen for editing or configuring one or more variables.
/// "Target" is the target of the edit operation, and "data" is the data
/// you want to mutate or pass to the target when the action is performed.
/// The action may be something like calling a method, setting an ivar, etc.
@interface FLEXVariableEditorViewController : UIViewController {
    @protected
    id _target;
    _Nullable id _data;
    void (^_Nullable _commitHandler)(void);
}

/// @param target The target of the operation
/// @param data The data associated with the operation
/// @param onCommit An action to perform when the data changes 
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit;
/// @param target The target of the operation
/// @param data The data associated with the operation
/// @param onCommit An action to perform when the data changes 
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit;

@property (nonatomic, readonly) id target;

/// Convenience accessor since many subclasses only use one input view
@property (nonatomic, readonly, nullable) FLEXArgumentInputView *firstInputView;

@property (nonatomic, readonly) FLEXFieldEditorView *fieldEditorView;
/// Subclasses can change the button title via the button's \c title property
@property (nonatomic, readonly) UIBarButtonItem *actionButton;

/// Subclasses should override to provide "set" functionality.
/// The commit handler--if present--is called here.
- (void)actionButtonPressed:(nullable id)sender;

/// Pushes an explorer view controller for the given object
/// or pops the current view controller.
- (void)exploreObjectOrPopViewController:(nullable id)objectOrNil;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/Editing/FLEXVariableEditorViewController.m
================================================
//
//  FLEXVariableEditorViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 5/16/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXColor.h"
#import "FLEXVariableEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXObjectExplorerViewController.h"
#import "UIBarButtonItem+FLEX.h"

@interface FLEXVariableEditorViewController () <UIScrollViewDelegate>
@property (nonatomic) UIScrollView *scrollView;
@end

@implementation FLEXVariableEditorViewController

#pragma mark - Initialization

+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
    return [[self alloc] initWithTarget:target data:data commitHandler:onCommit];
}

- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
    self = [super init];
    if (self) {
        _target = target;
        _data = data;
        _commitHandler = onCommit;
        [NSNotificationCenter.defaultCenter
            addObserver:self selector:@selector(keyboardDidShow:)
            name:UIKeyboardWillShowNotification object:nil
        ];
        [NSNotificationCenter.defaultCenter
            addObserver:self selector:@selector(keyboardWillHide:)
            name:UIKeyboardWillHideNotification object:nil
        ];
    }
    
    return self;
}

- (void)dealloc {
    [NSNotificationCenter.defaultCenter removeObserver:self];
}

#pragma mark - UIViewController methods

- (void)keyboardDidShow:(NSNotification *)notification {
    CGRect keyboardRectInWindow = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGSize keyboardSize = [self.view convertRect:keyboardRectInWindow fromView:nil].size;
    UIEdgeInsets scrollInsets = self.scrollView.contentInset;
    scrollInsets.bottom = keyboardSize.height;
    self.scrollView.contentInset = scrollInsets;
    self.scrollView.scrollIndicatorInsets = scrollInsets;
    
    // Find the active input view and scroll to make sure it's visible.
    for (FLEXArgumentInputView *argumentInputView in self.fieldEditorView.argumentInputViews) {
        if (argumentInputView.inputViewIsFirstResponder) {
            CGRect scrollToVisibleRect = [self.scrollView convertRect:argumentInputView.bounds fromView:argumentInputView];
            [self.scrollView scrollRectToVisible:scrollToVisibleRect animated:YES];
            break;
        }
    }
}

- (void)keyboardWillHide:(NSNotification *)notification {
    UIEdgeInsets scrollInsets = self.scrollView.contentInset;
    scrollInsets.bottom = 0.0;
    self.scrollView.contentInset = scrollInsets;
    self.scrollView.scrollIndicatorInsets = scrollInsets;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = FLEXColor.scrollViewBackgroundColor;
    
    self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    self.scrollView.backgroundColor = self.view.backgroundColor;
    self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.scrollView.delegate = self;
    [self.view addSubview:self.scrollView];
    
    _fieldEditorView = [FLEXFieldEditorView new];
    self.fieldEditorView.targetDescription = [NSString stringWithFormat:@"%@ %p", [self.target class], self.target];
    [self.scrollView addSubview:self.fieldEditorView];
    
    _actionButton = [[UIBarButtonItem alloc]
        initWithTitle:@"Set"
        style:UIBarButtonItemStyleDone
        target:self
        action:@selector(actionButtonPressed:)
    ];
    
    self.navigationController.toolbarHidden = NO;
    self.toolbarItems = @[UIBarButtonItem.flex_flexibleSpace, self.actionButton];
}

- (void)viewWillLayoutSubviews {
    CGSize constrainSize = CGSizeMake(self.scrollView.bounds.size.width, CGFLOAT_MAX);
    CGSize fieldEditorSize = [self.fieldEditorView sizeThatFits:constrainSize];
    self.fieldEditorView.frame = CGRectMake(0, 0, fieldEditorSize.width, fieldEditorSize.height);
    self.scrollView.contentSize = fieldEditorSize;
}

#pragma mark - Public

- (FLEXArgumentInputView *)firstInputView {
    return [self.fieldEditorView argumentInputViews].firstObject;
}

- (void)actionButtonPressed:(id)sender {
    // Subclasses can override
    [self.fieldEditorView endEditing:YES];
    if (_commitHandler) {
        _commitHandler();
    }
}

- (void)exploreObjectOrPopViewController:(id)objectOrNil {
    if (objectOrNil) {
        // For non-nil (or void) return types, push an explorer view controller to display the object
        FLEXObjectExplorerViewController *explorerViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:objectOrNil];
        [self.navigationController pushViewController:explorerViewController animated:YES];
    } else {
        // If we didn't get a returned object but the method call succeeded,
        // pop this view controller off the stack to indicate that the call went through.
        [self.navigationController popViewControllerAnimated:YES];
    }
}

@end


================================================
FILE: Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.h
================================================
//
//  FLEXBookmarkManager.h
//  FLEX
//
//  Created by Tanner on 2/6/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FLEXBookmarkManager : NSObject

@property (nonatomic, readonly, class) NSMutableArray *bookmarks;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.m
================================================
//
//  FLEXBookmarkManager.m
//  FLEX
//
//  Created by Tanner on 2/6/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXBookmarkManager.h"

static NSMutableArray *kFLEXBookmarkManagerBookmarks = nil;

@implementation FLEXBookmarkManager

+ (void)initialize {
    if (self == [FLEXBookmarkManager class]) {
        kFLEXBookmarkManagerBookmarks = [NSMutableArray new];
    }
}

+ (NSMutableArray *)bookmarks {
    return kFLEXBookmarkManagerBookmarks;
}

@end


================================================
FILE: Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.h
================================================
//
//  FLEXBookmarksViewController.h
//  FLEX
//
//  Created by Tanner on 2/6/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXTableViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface FLEXBookmarksViewController : FLEXTableViewController

@end

NS_ASSUME_NONNULL_END


================================================
FILE: Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m
================================================
//
//  FLEXBookmarksViewController.m
//  FLEX
//
//  Created by Tanner on 2/6/20.
//  Copyright © 2020 FLEX Team. All rights reserved.
//

#import "FLEXBookmarksViewController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXNavigationController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXBookmarkManager.h"
#import "UIBarButtonItem+FLEX.h"
#import "FLEXColor.h"
#import "FLEXUtility.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXTableView.h"

@interface FLEXBookmarksViewController ()
@property (nonatomic, copy) NSArray *bookmarks;
@property (nonatomic, readonly) FLEXExplorerViewController *corePresenter;
@end

@implementation FLEXBookmarksViewController

#pragma mark - Initialization

- (id)init {
    return [self initWithStyle:UITableViewStylePlain];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationController.hidesBarsOnSwipe = NO;
    self.tableView.allowsMultipleSelectionDuringEditing = YES;
    
    [self reloadData];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self setupDefaultBarItems];
}


#pragma mark - Private

- (void)reloadData {
    // We assume the bookmarks aren't going to change out from under us, since
    // presenting any other tool via keyboard shortcuts should dismiss us first
    self.bookmarks = FLEXBookmarkManager.bookmarks;
    self.title = [NSString stringWithFormat:@"Bookmarks (%@)", @(self.bookmarks.count)];
}

- (void)setupDefaultBarItems {
    self.navigationItem.rightBarButtonItem = FLEXBarButtonItemSystem(Done, self, @selector(dismissAnimated));
    self.toolbarItems = @[
        UIBarButtonItem.flex_flexibleSpace,
        FLEXBarButtonItemSystem(Edit, self, @selector(toggleEditing)),
    ];
    
    // Disable editing if no bookmarks available
    self.toolbarItems.lastObject.enabled = self.bookmarks.count > 0;
}

- (void)setupEditingBarItems {
    self.navigationItem.rightBarButtonItem = nil;
    self.toolbarItems = @[
        [UIBarButtonItem flex_itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
        UIBarButtonItem.flex_flexibleSpace,
        // We use a non-system done item because we change its title dynamically
        [UIBarButtonItem flex_doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
    ];
    
    self.toolbarItems.firstObject.tintColor = FLEXColor.destructiveColor;
}

- (FLEXExplorerViewController *)corePresenter {
    // We must be presented by a FLEXExplorerViewController, or presented
    // by another view controller that was presented by FLEXExplorerViewController
    FLEXExplorerViewController *presenter = (id)self.presentingViewController;
    presenter = (id)presenter.presentingViewController ?: presenter;
    presenter = (id)presenter.presentingViewController ?: presenter;
    NSAssert(
        [presenter isKindOfClass:[FLEXExplorerViewController class]],
        @"The bookmarks view controller expects to be presented by the explorer controller"
    );
    return presenter;
}

#pragma mark Button Actions

- (void)dismissAnimated {
    [self dismissAnimated:nil];
}

- (void)dismissAnimated:(id)selectedObject {
    if (selectedObject) {
        UIViewController *explorer = [FLEXObjectExplorerFactory
            explorerViewControllerForObject:selectedObject
        ];
        if ([self.presentingViewController isKindOfClass:[FLEXNavigationController class]]) {
            // I am presented on an existing navigation stack, so
            // dismiss myself and push the bookmark there
            UINavigationController *presenter = (id)self.presentingViewController;
            [presenter dismissViewControllerAnimated:YES completion:^{
                [presenter pushViewController:explorer animated:YES];
            }];
        } else {
            // Dismiss myself and present explorer
            UIViewController *presenter = self.corePresenter;
            [presenter dismissViewControllerAnimated:YES completion:^{
                [presenter presentViewController:[FLEXNavigationController
                    withRootViewController:explorer
                ] animated:YES completion:nil];
            }];
        }
    } else {
        // Just dismiss myself
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

- (void)toggleEditing {
    NSArray<NSIndexPath *> *selected = self.tableView.indexPathsForSelectedRows;
    self.editing = !self.editing;
    
    if (self.isEditing) {
        [self setupEditingBarItems];
    } else {
        [self setupDefaultBarItems];
        
        // Get index set of bookmarks to close
        NSMutableIndexSet *indexes = [NSMutableIndexSet new];
        for (NSIndexPath *ip in selected) {
            [indexes addIndex:ip.row];
        }
        
        if (selected.count) {
            // Close bookmarks and update data source
            [FLEXBookmarkManager.bookmarks removeObjectsAtIndexes:indexes];
            [self reloadData];
            
            // Remove deleted rows
            [self.tableView deleteRowsAtIndexPaths:selected withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }
}

- (void)closeAllButtonPressed:(UIBarButtonItem *)sender {
    [FLEXAlert makeSheet:^(FLEXAlert *make) {
        NSInteger count = self.bookmarks.count;
        NSString *title = FLEXPluralFormatString(count, @"Remove %@ bookmarks", @"Remove %@ bookmark");
        make.button(title).destructiveStyle().handler(^(NSArray<NSString *> *strings) {
            [self closeAll];
            [self toggleEditing];
        });
        make.button(@"Cancel").cancelStyle();
    } showFrom:self source:sender];
}

- (void)closeAll {
    NSInteger rowCount = self.bookmarks.count;
    
    // Close bookmarks and update data source
    [FLEXBookmarkManager.bookmarks removeAllObjects];
    [self reloadData];
    
    // Delete rows from table view
    NSArray<NSIndexPath *> *allRows = [NSArray flex_forEachUpTo:rowCount map:^id(NSUInteger row) {
        return [NSIndexPath indexPathForRow:row inSection:0];
    }];
    [self.tableView deleteRowsAtIndexPaths:allRows withRowAnimation:UITableViewRowAnimationAutomatic];
}


#pragma mark - Table View Data Source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.bookmarks.count;
}

- (UITableViewCell *)tableView:(FLEXTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kFLEXDetailCell forIndexPath:indexPath];
    
    id object = self.bookmarks[indexPath.row];
    cell.textLabel.text = [FLEXRuntimeUtility safeDescriptionForObject:object];
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ — %p", [object class], object];
    
    return cell;
}


#pragma mark - Table View Delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.editing) {
        // Case: editing with multi-select
        self.toolbarItems.lastObject.title = @"Remove Selected";
        self.toolbarItems.lastObject.tintColor = FLEXColor.destructiveColor;
    } else {
        // Case: selected a bookmark
        [self dismissAnimated:self.bookmarks[indexPath.row]];
    }
}

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSParameterAssert(self.editing);
    
    if (tableView.indexPathsForSelectedRows.count == 0) {
        self.toolbarItems.lastObject.title = @"Done";
        self.toolbarItems.lastObject.tintColor = self.view.tintColor;
    }
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (void)tableView:(UITableView *)table
commitEditingStyle:(UITableViewCellEditingStyle)edit
forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSParameterAssert(edit == UITableViewCellEditingStyleDelete);
    
    // Remove bookmark and update data source
    [FLEXBookmarkManager.bookmarks removeObjectAtIndex:indexPath.row];
    [self reloadData];
    
    // Delete row from table view
    [table deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}

@end


================================================
FILE: Classes/ExplorerInterface/FLEXExplorerViewController.h
================================================
//
//  FLEXExplorerViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 4/4/14.
//  Copyright (c) 2020 FLEX Team. All rights reserved.
//

#import "FLEXExplorerToolbar.h"

@class FLEXWindow;
@protocol FLEXExplorerViewControllerDelegate;

/// A view controller that manages the FLEX toolbar.
@interface FLEXExplorerViewController : UIViewController

@property (nonatomic, weak) id <FLEXExplorerViewControllerDelegate> delegate;
@property (nonatomic, readonly) BOOL wantsWindowToBecomeKey;

@property (nonatomic, readonly) FLEXExplorerToolbar *explorerToolbar;

- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates;

/// @br
Download .txt
gitextract_243iz5jb/

├── .clang-format
├── .github/
│   ├── FUNDING.yml
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .travis.yml
├── .vscode/
│   └── settings.json
├── CONTRIBUTING.md
├── Classes/
│   ├── Core/
│   │   ├── Controllers/
│   │   │   ├── FLEXFilteringTableViewController.h
│   │   │   ├── FLEXFilteringTableViewController.m
│   │   │   ├── FLEXNavigationController.h
│   │   │   ├── FLEXNavigationController.m
│   │   │   ├── FLEXTableViewController.h
│   │   │   └── FLEXTableViewController.m
│   │   ├── FLEXSingleRowSection.h
│   │   ├── FLEXSingleRowSection.m
│   │   ├── FLEXTableViewSection.h
│   │   ├── FLEXTableViewSection.m
│   │   └── Views/
│   │       ├── Carousel/
│   │       │   ├── FLEXCarouselCell.h
│   │       │   ├── FLEXCarouselCell.m
│   │       │   ├── FLEXScopeCarousel.h
│   │       │   └── FLEXScopeCarousel.m
│   │       ├── Cells/
│   │       │   ├── FLEXCodeFontCell.h
│   │       │   ├── FLEXCodeFontCell.m
│   │       │   ├── FLEXKeyValueTableViewCell.h
│   │       │   ├── FLEXKeyValueTableViewCell.m
│   │       │   ├── FLEXMultilineTableViewCell.h
│   │       │   ├── FLEXMultilineTableViewCell.m
│   │       │   ├── FLEXSubtitleTableViewCell.h
│   │       │   ├── FLEXSubtitleTableViewCell.m
│   │       │   ├── FLEXTableViewCell.h
│   │       │   └── FLEXTableViewCell.m
│   │       ├── FLEXTableView.h
│   │       └── FLEXTableView.m
│   ├── Editing/
│   │   ├── ArgumentInputViews/
│   │   │   ├── FLEXArgumentInputColorView.h
│   │   │   ├── FLEXArgumentInputColorView.m
│   │   │   ├── FLEXArgumentInputDateView.h
│   │   │   ├── FLEXArgumentInputDateView.m
│   │   │   ├── FLEXArgumentInputFontView.h
│   │   │   ├── FLEXArgumentInputFontView.m
│   │   │   ├── FLEXArgumentInputFontsPickerView.h
│   │   │   ├── FLEXArgumentInputFontsPickerView.m
│   │   │   ├── FLEXArgumentInputNotSupportedView.h
│   │   │   ├── FLEXArgumentInputNotSupportedView.m
│   │   │   ├── FLEXArgumentInputNumberView.h
│   │   │   ├── FLEXArgumentInputNumberView.m
│   │   │   ├── FLEXArgumentInputObjectView.h
│   │   │   ├── FLEXArgumentInputObjectView.m
│   │   │   ├── FLEXArgumentInputStringView.h
│   │   │   ├── FLEXArgumentInputStringView.m
│   │   │   ├── FLEXArgumentInputStructView.h
│   │   │   ├── FLEXArgumentInputStructView.m
│   │   │   ├── FLEXArgumentInputSwitchView.h
│   │   │   ├── FLEXArgumentInputSwitchView.m
│   │   │   ├── FLEXArgumentInputTextView.h
│   │   │   ├── FLEXArgumentInputTextView.m
│   │   │   ├── FLEXArgumentInputView.h
│   │   │   └── FLEXArgumentInputView.m
│   │   ├── FLEXArgumentInputViewFactory.h
│   │   ├── FLEXArgumentInputViewFactory.m
│   │   ├── FLEXDefaultEditorViewController.h
│   │   ├── FLEXDefaultEditorViewController.m
│   │   ├── FLEXFieldEditorView.h
│   │   ├── FLEXFieldEditorView.m
│   │   ├── FLEXFieldEditorViewController.h
│   │   ├── FLEXFieldEditorViewController.m
│   │   ├── FLEXMethodCallingViewController.h
│   │   ├── FLEXMethodCallingViewController.m
│   │   ├── FLEXVariableEditorViewController.h
│   │   └── FLEXVariableEditorViewController.m
│   ├── ExplorerInterface/
│   │   ├── Bookmarks/
│   │   │   ├── FLEXBookmarkManager.h
│   │   │   ├── FLEXBookmarkManager.m
│   │   │   ├── FLEXBookmarksViewController.h
│   │   │   └── FLEXBookmarksViewController.m
│   │   ├── FLEXExplorerViewController.h
│   │   ├── FLEXExplorerViewController.m
│   │   ├── FLEXViewControllersViewController.h
│   │   ├── FLEXViewControllersViewController.m
│   │   ├── FLEXWindow.h
│   │   ├── FLEXWindow.m
│   │   ├── FLEXWindowManagerController.h
│   │   ├── FLEXWindowManagerController.m
│   │   └── Tabs/
│   │       ├── FLEXTabList.h
│   │       ├── FLEXTabList.m
│   │       ├── FLEXTabsViewController.h
│   │       └── FLEXTabsViewController.m
│   ├── FLEX-Categories.h
│   ├── FLEX-Core.h
│   ├── FLEX-ObjectExploring.h
│   ├── FLEX-Runtime.h
│   ├── FLEX.h
│   ├── GlobalStateExplorers/
│   │   ├── DatabaseBrowser/
│   │   │   ├── FLEXDBQueryRowCell.h
│   │   │   ├── FLEXDBQueryRowCell.m
│   │   │   ├── FLEXDatabaseManager.h
│   │   │   ├── FLEXMultiColumnTableView.h
│   │   │   ├── FLEXMultiColumnTableView.m
│   │   │   ├── FLEXRealmDatabaseManager.h
│   │   │   ├── FLEXRealmDatabaseManager.m
│   │   │   ├── FLEXRealmDefines.h
│   │   │   ├── FLEXSQLResult.h
│   │   │   ├── FLEXSQLResult.m
│   │   │   ├── FLEXSQLiteDatabaseManager.h
│   │   │   ├── FLEXSQLiteDatabaseManager.m
│   │   │   ├── FLEXTableColumnHeader.h
│   │   │   ├── FLEXTableColumnHeader.m
│   │   │   ├── FLEXTableContentViewController.h
│   │   │   ├── FLEXTableContentViewController.m
│   │   │   ├── FLEXTableLeftCell.h
│   │   │   ├── FLEXTableLeftCell.m
│   │   │   ├── FLEXTableListViewController.h
│   │   │   ├── FLEXTableListViewController.m
│   │   │   ├── FLEXTableRowDataViewController.h
│   │   │   ├── FLEXTableRowDataViewController.m
│   │   │   └── LICENSE
│   │   ├── FLEXAPNSViewController.h
│   │   ├── FLEXAPNSViewController.m
│   │   ├── FLEXAddressExplorerCoordinator.h
│   │   ├── FLEXAddressExplorerCoordinator.m
│   │   ├── FLEXCookiesViewController.h
│   │   ├── FLEXCookiesViewController.m
│   │   ├── FLEXLiveObjectsController.h
│   │   ├── FLEXLiveObjectsController.m
│   │   ├── FLEXObjectListViewController.h
│   │   ├── FLEXObjectListViewController.m
│   │   ├── FLEXObjectRef.h
│   │   ├── FLEXObjectRef.m
│   │   ├── FLEXWebViewController.h
│   │   ├── FLEXWebViewController.m
│   │   ├── FileBrowser/
│   │   │   ├── FLEXActivityViewController.h
│   │   │   ├── FLEXActivityViewController.m
│   │   │   ├── FLEXFileBrowserController.h
│   │   │   ├── FLEXFileBrowserController.m
│   │   │   ├── FLEXFileBrowserSearchOperation.h
│   │   │   └── FLEXFileBrowserSearchOperation.m
│   │   ├── Globals/
│   │   │   ├── FLEXGlobalsEntry.h
│   │   │   ├── FLEXGlobalsEntry.m
│   │   │   ├── FLEXGlobalsSection.h
│   │   │   ├── FLEXGlobalsSection.m
│   │   │   ├── FLEXGlobalsViewController.h
│   │   │   └── FLEXGlobalsViewController.m
│   │   ├── Keychain/
│   │   │   ├── FLEXKeychain.h
│   │   │   ├── FLEXKeychain.m
│   │   │   ├── FLEXKeychainQuery.h
│   │   │   ├── FLEXKeychainQuery.m
│   │   │   ├── FLEXKeychainViewController.h
│   │   │   ├── FLEXKeychainViewController.m
│   │   │   └── SSKeychain_LICENSE
│   │   ├── RuntimeBrowser/
│   │   │   ├── DataSources/
│   │   │   │   ├── FLEXRuntimeClient.h
│   │   │   │   ├── FLEXRuntimeClient.m
│   │   │   │   ├── FLEXRuntimeController.h
│   │   │   │   ├── FLEXRuntimeController.m
│   │   │   │   ├── FLEXRuntimeExporter.h
│   │   │   │   └── FLEXRuntimeExporter.m
│   │   │   ├── FLEXKBToolbarButton.h
│   │   │   ├── FLEXKBToolbarButton.m
│   │   │   ├── FLEXKeyPathSearchController.h
│   │   │   ├── FLEXKeyPathSearchController.m
│   │   │   ├── FLEXKeyboardToolbar.h
│   │   │   ├── FLEXKeyboardToolbar.m
│   │   │   ├── FLEXObjcRuntimeViewController.h
│   │   │   ├── FLEXObjcRuntimeViewController.m
│   │   │   ├── FLEXRuntimeBrowserToolbar.h
│   │   │   ├── FLEXRuntimeBrowserToolbar.m
│   │   │   ├── FLEXRuntimeKeyPath.h
│   │   │   ├── FLEXRuntimeKeyPath.m
│   │   │   ├── FLEXRuntimeKeyPathTokenizer.h
│   │   │   ├── FLEXRuntimeKeyPathTokenizer.m
│   │   │   ├── FLEXSearchToken.h
│   │   │   └── FLEXSearchToken.m
│   │   └── SystemLog/
│   │       ├── ActivityStreamAPI.h
│   │       ├── FLEXASLLogController.h
│   │       ├── FLEXASLLogController.m
│   │       ├── FLEXLogController.h
│   │       ├── FLEXOSLogController.h
│   │       ├── FLEXOSLogController.m
│   │       ├── FLEXSystemLogCell.h
│   │       ├── FLEXSystemLogCell.m
│   │       ├── FLEXSystemLogMessage.h
│   │       ├── FLEXSystemLogMessage.m
│   │       ├── FLEXSystemLogViewController.h
│   │       ├── FLEXSystemLogViewController.m
│   │       └── LLVM_LICENSE.TXT
│   ├── Info.plist
│   ├── Manager/
│   │   ├── FLEXManager+Extensibility.h
│   │   ├── FLEXManager+Extensibility.m
│   │   ├── FLEXManager+Networking.h
│   │   ├── FLEXManager+Networking.m
│   │   ├── FLEXManager.h
│   │   ├── FLEXManager.m
│   │   └── Private/
│   │       └── FLEXManager+Private.h
│   ├── Network/
│   │   ├── FLEXFirebaseTransaction.mm
│   │   ├── FLEXHTTPTransactionDetailController.h
│   │   ├── FLEXHTTPTransactionDetailController.m
│   │   ├── FLEXMITMDataSource.h
│   │   ├── FLEXMITMDataSource.m
│   │   ├── FLEXNetworkCurlLogger.h
│   │   ├── FLEXNetworkCurlLogger.m
│   │   ├── FLEXNetworkMITMViewController.h
│   │   ├── FLEXNetworkMITMViewController.m
│   │   ├── FLEXNetworkRecorder.h
│   │   ├── FLEXNetworkRecorder.m
│   │   ├── FLEXNetworkSettingsController.h
│   │   ├── FLEXNetworkSettingsController.m
│   │   ├── FLEXNetworkTransaction.h
│   │   ├── FLEXNetworkTransaction.m
│   │   ├── FLEXNetworkTransactionCell.h
│   │   ├── FLEXNetworkTransactionCell.m
│   │   ├── Firestore.h
│   │   ├── OSCache/
│   │   │   ├── LICENSE.md
│   │   │   ├── OSCache.h
│   │   │   └── OSCache.m
│   │   └── PonyDebugger/
│   │       ├── FLEXNetworkObserver.h
│   │       ├── FLEXNetworkObserver.m
│   │       └── LICENSE
│   ├── ObjectExplorers/
│   │   ├── FLEXObjectExplorer.h
│   │   ├── FLEXObjectExplorer.m
│   │   ├── FLEXObjectExplorerFactory.h
│   │   ├── FLEXObjectExplorerFactory.m
│   │   ├── FLEXObjectExplorerViewController.h
│   │   ├── FLEXObjectExplorerViewController.m
│   │   └── Sections/
│   │       ├── FLEXCollectionContentSection.h
│   │       ├── FLEXCollectionContentSection.m
│   │       ├── FLEXColorPreviewSection.h
│   │       ├── FLEXColorPreviewSection.m
│   │       ├── FLEXDefaultsContentSection.h
│   │       ├── FLEXDefaultsContentSection.m
│   │       ├── FLEXMetadataSection.h
│   │       ├── FLEXMetadataSection.m
│   │       ├── FLEXMutableListSection.h
│   │       ├── FLEXMutableListSection.m
│   │       ├── FLEXObjectInfoSection.h
│   │       └── Shortcuts/
│   │           ├── FLEXBlockShortcuts.h
│   │           ├── FLEXBlockShortcuts.m
│   │           ├── FLEXBundleShortcuts.h
│   │           ├── FLEXBundleShortcuts.m
│   │           ├── FLEXClassShortcuts.h
│   │           ├── FLEXClassShortcuts.m
│   │           ├── FLEXImageShortcuts.h
│   │           ├── FLEXImageShortcuts.m
│   │           ├── FLEXLayerShortcuts.h
│   │           ├── FLEXLayerShortcuts.m
│   │           ├── FLEXNSDataShortcuts.h
│   │           ├── FLEXNSDataShortcuts.m
│   │           ├── FLEXNSStringShortcuts.h
│   │           ├── FLEXNSStringShortcuts.m
│   │           ├── FLEXShortcut.h
│   │           ├── FLEXShortcut.m
│   │           ├── FLEXShortcutsFactory+Defaults.h
│   │           ├── FLEXShortcutsFactory+Defaults.m
│   │           ├── FLEXShortcutsSection.h
│   │           ├── FLEXShortcutsSection.m
│   │           ├── FLEXUIAppShortcuts.h
│   │           ├── FLEXUIAppShortcuts.m
│   │           ├── FLEXViewControllerShortcuts.h
│   │           ├── FLEXViewControllerShortcuts.m
│   │           ├── FLEXViewShortcuts.h
│   │           ├── FLEXViewShortcuts.m
│   │           ├── FLEXWindowShortcuts.h
│   │           └── FLEXWindowShortcuts.m
│   ├── Toolbar/
│   │   ├── FLEXExplorerToolbar.h
│   │   ├── FLEXExplorerToolbar.m
│   │   ├── FLEXExplorerToolbarItem.h
│   │   └── FLEXExplorerToolbarItem.m
│   ├── Utility/
│   │   ├── APPLE_LICENSE
│   │   ├── Categories/
│   │   │   ├── CALayer+FLEX.h
│   │   │   ├── CALayer+FLEX.m
│   │   │   ├── FLEXRuntime+Compare.h
│   │   │   ├── FLEXRuntime+Compare.m
│   │   │   ├── FLEXRuntime+UIKitHelpers.h
│   │   │   ├── FLEXRuntime+UIKitHelpers.m
│   │   │   ├── NSArray+FLEX.h
│   │   │   ├── NSArray+FLEX.m
│   │   │   ├── NSDateFormatter+FLEX.h
│   │   │   ├── NSDateFormatter+FLEX.m
│   │   │   ├── NSObject+FLEX_Reflection.h
│   │   │   ├── NSObject+FLEX_Reflection.m
│   │   │   ├── NSTimer+FLEX.h
│   │   │   ├── NSTimer+FLEX.m
│   │   │   ├── NSUserDefaults+FLEX.h
│   │   │   ├── NSUserDefaults+FLEX.m
│   │   │   ├── Private/
│   │   │   │   ├── Cocoa+FLEXShortcuts.h
│   │   │   │   ├── Cocoa+FLEXShortcuts.m
│   │   │   │   ├── NSDictionary+ObjcRuntime.h
│   │   │   │   ├── NSDictionary+ObjcRuntime.m
│   │   │   │   ├── NSMapTable+FLEX_Subscripting.h
│   │   │   │   ├── NSMapTable+FLEX_Subscripting.m
│   │   │   │   ├── NSString+FLEX.h
│   │   │   │   ├── NSString+FLEX.m
│   │   │   │   ├── NSString+ObjcRuntime.h
│   │   │   │   ├── NSString+ObjcRuntime.m
│   │   │   │   ├── UIView+FLEX_Layout.h
│   │   │   │   └── UIView+FLEX_Layout.m
│   │   │   ├── UIBarButtonItem+FLEX.h
│   │   │   ├── UIBarButtonItem+FLEX.m
│   │   │   ├── UIFont+FLEX.h
│   │   │   ├── UIFont+FLEX.m
│   │   │   ├── UIGestureRecognizer+Blocks.h
│   │   │   ├── UIGestureRecognizer+Blocks.m
│   │   │   ├── UIMenu+FLEX.h
│   │   │   ├── UIMenu+FLEX.m
│   │   │   ├── UIPasteboard+FLEX.h
│   │   │   ├── UIPasteboard+FLEX.m
│   │   │   ├── UITextField+Range.h
│   │   │   └── UITextField+Range.m
│   │   ├── FLEXAlert.h
│   │   ├── FLEXAlert.m
│   │   ├── FLEXColor.h
│   │   ├── FLEXColor.m
│   │   ├── FLEXHeapEnumerator.h
│   │   ├── FLEXHeapEnumerator.m
│   │   ├── FLEXMacros.h
│   │   ├── FLEXResources.h
│   │   ├── FLEXResources.m
│   │   ├── FLEXUtility.h
│   │   ├── FLEXUtility.m
│   │   ├── Keyboard/
│   │   │   ├── FLEXKeyboardHelpViewController.h
│   │   │   ├── FLEXKeyboardHelpViewController.m
│   │   │   ├── FLEXKeyboardShortcutManager.h
│   │   │   └── FLEXKeyboardShortcutManager.m
│   │   └── Runtime/
│   │       ├── FLEXRuntimeUtility.h
│   │       ├── FLEXRuntimeUtility.m
│   │       ├── Objc/
│   │       │   ├── FLEXObjcInternal.h
│   │       │   ├── FLEXObjcInternal.mm
│   │       │   ├── FLEXRuntimeConstants.h
│   │       │   ├── FLEXRuntimeConstants.m
│   │       │   ├── FLEXRuntimeSafety.h
│   │       │   ├── FLEXRuntimeSafety.m
│   │       │   ├── FLEXSwiftInternal.h
│   │       │   ├── FLEXSwiftInternal.mm
│   │       │   ├── FLEXTypeEncodingParser.h
│   │       │   ├── FLEXTypeEncodingParser.m
│   │       │   └── Reflection/
│   │       │       ├── FLEXBlockDescription.h
│   │       │       ├── FLEXBlockDescription.m
│   │       │       ├── FLEXClassBuilder.h
│   │       │       ├── FLEXClassBuilder.m
│   │       │       ├── FLEXIvar.h
│   │       │       ├── FLEXIvar.m
│   │       │       ├── FLEXMetadataExtras.h
│   │       │       ├── FLEXMetadataExtras.m
│   │       │       ├── FLEXMethod.h
│   │       │       ├── FLEXMethod.m
│   │       │       ├── FLEXMethodBase.h
│   │       │       ├── FLEXMethodBase.m
│   │       │       ├── FLEXMirror.h
│   │       │       ├── FLEXMirror.m
│   │       │       ├── FLEXProperty.h
│   │       │       ├── FLEXProperty.m
│   │       │       ├── FLEXPropertyAttributes.h
│   │       │       ├── FLEXPropertyAttributes.m
│   │       │       ├── FLEXProtocol.h
│   │       │       ├── FLEXProtocol.m
│   │       │       ├── FLEXProtocolBuilder.h
│   │       │       └── FLEXProtocolBuilder.m
│   │       ├── flex_fishhook.c
│   │       └── flex_fishhook.h
│   └── ViewHierarchy/
│       ├── FLEXHierarchyViewController.h
│       ├── FLEXHierarchyViewController.m
│       ├── FLEXImagePreviewViewController.h
│       ├── FLEXImagePreviewViewController.m
│       ├── SnapshotExplorer/
│       │   ├── FHSRangeSlider.h
│       │   ├── FHSRangeSlider.m
│       │   ├── FHSSnapshotView.h
│       │   ├── FHSSnapshotView.m
│       │   ├── FHSView.h
│       │   ├── FHSView.m
│       │   ├── FHSViewController.h
│       │   ├── FHSViewController.m
│       │   ├── FHSViewSnapshot.h
│       │   ├── FHSViewSnapshot.m
│       │   └── Scene/
│       │       ├── FHSSnapshotNodes.h
│       │       ├── FHSSnapshotNodes.m
│       │       ├── SceneKit+Snapshot.h
│       │       └── SceneKit+Snapshot.m
│       └── TreeExplorer/
│           ├── FLEXHierarchyTableViewCell.h
│           ├── FLEXHierarchyTableViewCell.m
│           ├── FLEXHierarchyTableViewController.h
│           └── FLEXHierarchyTableViewController.m
├── Example/
│   ├── FLEXample/
│   │   ├── App/
│   │   │   ├── Commit.swift
│   │   │   ├── CommitListViewController.h
│   │   │   ├── CommitListViewController.m
│   │   │   ├── Person.h
│   │   │   └── Person.m
│   │   ├── AppDelegate.swift
│   │   ├── MiscNetworkRequests.h
│   │   ├── MiscNetworkRequests.m
│   │   ├── SceneDelegate.swift
│   │   └── Supporting Files/
│   │       ├── Assets.xcassets/
│   │       │   ├── AppIcon.appiconset/
│   │       │   │   └── Contents.json
│   │       │   └── Contents.json
│   │       ├── Base.lproj/
│   │       │   └── LaunchScreen.storyboard
│   │       ├── Bundle/
│   │       │   ├── dogs.realm
│   │       │   └── image
│   │       ├── FLEXample-Bridging-Header.h
│   │       ├── Info.plist
│   │       └── Preview Content/
│   │           └── Preview Assets.xcassets/
│   │               └── Contents.json
│   ├── FLEXample-Cocoapods.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── FLEXample.xcscheme
│   ├── FLEXample-SPM.xcodeproj/
│   │   ├── project.pbxproj
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── FLEXample.xcscheme
│   ├── Podfile
│   └── Realm/
│       ├── Dog.h
│       ├── Dog.m
│       ├── Owner.h
│       └── Owner.m
├── FLEX.podspec
├── FLEX.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── FLEX.xcscheme
│           └── FLEXTests.xcscheme
├── FLEXTests/
│   ├── FLEXTests.m
│   ├── FLEXTestsMethodsList.m
│   ├── FLEXTypeEncodingParserTests.m
│   ├── Info.plist
│   └── Supporting Files/
│       ├── FLEXNewRootClass.h
│       └── FLEXNewRootClass.m
├── Graphics/
│   ├── FLEX-Icons.sketch
│   ├── filetypes/
│   │   └── old/
│   │       ├── audio.pxm
│   │       ├── binary.pxm
│   │       ├── html.pxm
│   │       ├── js.pxm
│   │       ├── json.pxm
│   │       ├── plist.pxm
│   │       ├── text.pxm
│   │       ├── textplain.pxm
│   │       └── video.pxm
│   ├── image_to_code.py
│   ├── images_to_hex.sh
│   └── iterate_hex_to_pasteboard.sh
├── LICENSE
├── Package.swift
├── README.md
├── SM/
│   └── Surfile
└── generate-spm-headers.sh
Download .txt
SYMBOL INDEX (79 symbols across 25 files)

FILE: Classes/Core/Controllers/FLEXTableViewController.h
  type CGFloat (line 13) | typedef CGFloat FLEXDebounceInterval;

FILE: Classes/Core/FLEXTableViewSection.h
  function interface (line 22) | interface FLEXTableViewSection : NSObject {

FILE: Classes/Core/Views/FLEXTableView.h
  type NSString (line 15) | typedef NSString * FLEXTableViewCellReuseIdentifier;

FILE: Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h
  function NS_INLINE (line 17) | NS_INLINE FLEXTableColumnHeaderSortType FLEXNextTableColumnHeaderSortType(

FILE: Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h
  type NSString (line 48) | typedef NSString * _Nonnull (^FLEXGlobalsEntryNameFuture)(void);
  type UIViewController (line 50) | typedef UIViewController * _Nullable (^FLEXGlobalsEntryViewControllerFut...

FILE: Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.h
  type FLEXGlobalsSectionCustom (line 12) | typedef NS_ENUM(NSUInteger, FLEXGlobalsSectionKind) {

FILE: Classes/GlobalStateExplorers/Keychain/FLEXKeychainQuery.h
  type FLEXKeychainQuerySynchronizationModeAny (line 24) | typedef NS_ENUM(NSUInteger, FLEXKeychainQuerySynchronizationMode) {

FILE: Classes/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h
  type os_activity_id_t (line 82) | typedef uint64_t os_activity_id_t;
  type os_activity_stream_s (line 83) | struct os_activity_stream_s
  type os_activity_stream_entry_s (line 84) | struct os_activity_stream_entry_s
  type os_activity_stream_common_s (line 96) | struct os_activity_stream_common_s {
  type os_activity_create_s (line 100) | struct os_activity_create_s {
  type os_activity_transition_s (line 107) | struct os_activity_transition_s {
  type os_log_message_s (line 112) | struct os_log_message_s {
  type os_trace_message_v2_s (line 126) | struct os_trace_message_v2_s {
  type os_activity_useraction_s (line 134) | struct os_activity_useraction_s {
  type os_signpost_s (line 140) | struct os_signpost_s {
  type os_activity_statedump_s (line 154) | struct os_activity_statedump_s {
  type os_activity_stream_entry_s (line 161) | struct os_activity_stream_entry_s {
  type os_activity_stream_t (line 196) | typedef os_activity_stream_t (*os_activity_stream_for_pid_t)(

FILE: Classes/Network/FLEXNetworkTransaction.h
  type FLEXFIRRequestTypeNotFirebase (line 125) | typedef NS_ENUM(NSUInteger, FLEXFIRRequestType) {

FILE: Classes/Network/Firestore.h
  type FIRFirestoreSourceDefault (line 32) | typedef NS_ENUM(NSUInteger, FIRFirestoreSource) {

FILE: Classes/ObjectExplorers/Sections/FLEXCollectionContentSection.h
  type id (line 18) | typedef id<NSObject, NSFastEnumeration /* FLEXCollection */>(^FLEXCollec...
  function interface (line 53) | interface FLEXCollectionContentSection<__covariant ObjectType> : FLEXTab...

FILE: Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h
  type FLEXShortcutsFactory (line 85) | typedef FLEXShortcutsFactory *_Nonnull(^FLEXShortcutsFactoryNames)(NSArr...

FILE: Classes/Utility/Categories/NSDateFormatter+FLEX.h
  type FLEXDateFormatClock (line 11) | typedef NS_ENUM(NSUInteger, FLEXDateFormat) {

FILE: Classes/Utility/FLEXAlert.h
  type FLEXAlert (line 17) | typedef FLEXAlert * _Nonnull (^FLEXAlertStringProperty)(NSString * _Null...
  type FLEXAlert (line 18) | typedef FLEXAlert * _Nonnull (^FLEXAlertStringArg)(NSString * _Nullable);
  type FLEXAlert (line 19) | typedef FLEXAlert * _Nonnull (^FLEXAlertTextField)(void(^configurationHa...
  type FLEXAlertAction (line 20) | typedef FLEXAlertAction * _Nonnull (^FLEXAlertAddAction)(NSString *title);
  type FLEXAlertAction (line 21) | typedef FLEXAlertAction * _Nonnull (^FLEXAlertActionStringProperty)(NSSt...
  type FLEXAlertAction (line 22) | typedef FLEXAlertAction * _Nonnull (^FLEXAlertActionProperty)(void);
  type FLEXAlertAction (line 23) | typedef FLEXAlertAction * _Nonnull (^FLEXAlertActionBOOLProperty)(BOOL);
  type FLEXAlertAction (line 24) | typedef FLEXAlertAction * _Nonnull (^FLEXAlertActionHandler)(void(^handl...

FILE: Classes/Utility/FLEXMacros.h
  function NS_INLINE (line 44) | NS_INLINE CGFloat FLEXFloor(CGFloat x) {
  function NS_INLINE (line 49) | NS_INLINE CGFloat FLEXPointsToPixels(CGFloat points) {
  function NS_INLINE (line 54) | NS_INLINE CGRect FLEXRectMake(CGFloat x, CGFloat y, CGFloat width, CGFlo...
  function NS_INLINE (line 59) | NS_INLINE CGRect FLEXRectSetOrigin(CGRect r, CGPoint origin) {
  function NS_INLINE (line 64) | NS_INLINE CGRect FLEXRectSetSize(CGRect r, CGSize size) {
  function NS_INLINE (line 69) | NS_INLINE CGRect FLEXRectSetX(CGRect r, CGFloat x) {
  function NS_INLINE (line 74) | NS_INLINE CGRect FLEXRectSetY(CGRect r, CGFloat y) {
  function NS_INLINE (line 79) | NS_INLINE CGRect FLEXRectSetWidth(CGRect r, CGFloat width) {
  function NS_INLINE (line 84) | NS_INLINE CGRect FLEXRectSetHeight(CGRect r, CGFloat height) {

FILE: Classes/Utility/FLEXUtility.h
  type objc_method_description (line 61) | struct objc_method_description

FILE: Classes/Utility/Runtime/Objc/FLEXObjcInternal.h
  function NS_INLINE (line 52) | NS_INLINE BOOL flex_isTaggedPointer(const void *ptr)  {

FILE: Classes/Utility/Runtime/Objc/FLEXRuntimeSafety.h
  function FLEXInitKnownRootClasses (line 20) | __attribute__((constructor))
  function BOOL (line 26) | static inline BOOL FLEXClassIsSafe(Class cls) {
  function BOOL (line 41) | static inline BOOL FLEXClassNameIsSafe(NSString *cls) {
  function BOOL (line 52) | static inline BOOL FLEXIvarIsSafe(Ivar ivar) {

FILE: Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h
  function interface (line 16) | interface FLEXMethodBase : NSObject {

FILE: Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.h
  type objc_method_description (line 58) | struct objc_method_description
  type objc_method_description (line 59) | struct objc_method_description

FILE: Classes/Utility/Runtime/flex_fishhook.c
  type mach_header_t (line 40) | typedef struct mach_header_64 mach_header_t;
  type segment_command_t (line 41) | typedef struct segment_command_64 segment_command_t;
  type section_t (line 42) | typedef struct section_64 section_t;
  type nlist_t (line 43) | typedef struct nlist_64 nlist_t;
  type mach_header_t (line 46) | typedef struct mach_header mach_header_t;
  type segment_command_t (line 47) | typedef struct segment_command segment_command_t;
  type section_t (line 48) | typedef struct section section_t;
  type nlist_t (line 49) | typedef struct nlist nlist_t;
  type rebindings_entry (line 57) | struct rebindings_entry {
  type rebindings_entry (line 63) | struct rebindings_entry
  function flex_prepend_rebindings (line 66) | static int flex_prepend_rebindings(struct rebindings_entry **rebindings_...
  function vm_prot_t (line 88) | static vm_prot_t flex_get_protection(void *sectionStart) {
  function flex_perform_rebinding_with_section (line 113) | static void flex_perform_rebinding_with_section(struct rebindings_entry ...
  function flex_rebind_symbols_for_image (line 180) | static void flex_rebind_symbols_for_image(struct rebindings_entry *rebin...
  function _flex_rebind_symbols_for_image (line 249) | static void _flex_rebind_symbols_for_image(const struct mach_header *hea...
  function flex_rebind_symbols_image (line 254) | int flex_rebind_symbols_image(void *header,
  function flex_rebind_symbols (line 272) | int flex_rebind_symbols(struct rebinding rebindings[], size_t rebindings...

FILE: Classes/Utility/Runtime/flex_fishhook.h
  type rebinding (line 44) | struct rebinding {
  type rebinding (line 60) | struct rebinding
  type rebinding (line 70) | struct rebinding

FILE: Classes/ViewHierarchy/SnapshotExplorer/FHSView.h
  function interface (line 10) | interface FHSView : NSObject {

FILE: FLEXTests/Supporting Files/FLEXNewRootClass.h
  function OBJC_ROOT_CLASS (line 12) | OBJC_ROOT_CLASS

FILE: Graphics/image_to_code.py
  function bytes_from_file (line 32) | def bytes_from_file(filename, chunksize=8192):
  function write_header_file (line 42) | def write_header_file(header, className, outputFile):
  function write_implementation_file (line 54) | def write_implementation_file(inputFile, header, className, outputFile):
  function main (line 102) | def main(argv):
Condensed preview — 431 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,863K chars).
[
  {
    "path": ".clang-format",
    "chars": 1360,
    "preview": "---\nBasedOnStyle:  WebKit\nAccessModifierOffset: -2\nAlignEscapedNewlinesLeft: false\nAlignTrailingComments: true\nAllowAllP"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 71,
    "preview": "# These are supported funding model platforms\n\ngithub: [NSExceptional]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1287,
    "preview": "---\nname: Bug report\nabout: Report a bug in FLEX\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n### Environment\n- Platform+ve"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 115,
    "preview": "---\nname: Feature request\nabout: Suggest a new feature for FLEX\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n\n"
  },
  {
    "path": ".gitignore",
    "chars": 297,
    "preview": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!defau"
  },
  {
    "path": ".travis.yml",
    "chars": 360,
    "preview": "language: objective-c\nxcode_workspace: FLEX.xcworkspace\nxcode_sdk: iphonesimulator\nbefore_install:\n    - gem install xcp"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 66,
    "preview": "{\n    \"search.exclude\": {\n        \"Classes/Headers\": true\n    }\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 99,
    "preview": "# Contributing to FLEX #\n\nWe welcome contributions! Please open a pull request with your changes. \n"
  },
  {
    "path": "Classes/Core/Controllers/FLEXFilteringTableViewController.h",
    "chars": 3729,
    "preview": "//\n//  FLEXFilteringTableViewController.h\n//  FLEX\n//\n//  Created by Tanner on 3/9/20.\n//  Copyright © 2020 FLEX Team. A"
  },
  {
    "path": "Classes/Core/Controllers/FLEXFilteringTableViewController.m",
    "chars": 6427,
    "preview": "//\n//  FLEXFilteringTableViewController.m\n//  FLEX\n//\n//  Created by Tanner on 3/9/20.\n//  Copyright © 2020 FLEX Team. A"
  },
  {
    "path": "Classes/Core/Controllers/FLEXNavigationController.h",
    "chars": 657,
    "preview": "//\n//  FLEXNavigationController.h\n//  FLEX\n//\n//  Created by Tanner on 1/30/20.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Core/Controllers/FLEXNavigationController.m",
    "chars": 8181,
    "preview": "//\n//  FLEXNavigationController.m\n//  FLEX\n//\n//  Created by Tanner on 1/30/20.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Core/Controllers/FLEXTableViewController.h",
    "chars": 6667,
    "preview": "//\n//  FLEXTableViewController.h\n//  FLEX\n//\n//  Created by Tanner on 7/5/19.\n//  Copyright © 2020 FLEX Team. All rights"
  },
  {
    "path": "Classes/Core/Controllers/FLEXTableViewController.m",
    "chars": 20656,
    "preview": "//\n//  FLEXTableViewController.m\n//  FLEX\n//\n//  Created by Tanner on 7/5/19.\n//  Copyright © 2020 FLEX Team. All rights"
  },
  {
    "path": "Classes/Core/FLEXSingleRowSection.h",
    "chars": 1084,
    "preview": "//\n//  FLEXSingleRowSection.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 9/25/19.\n//  Copyright © 2020 FLEX Team. All "
  },
  {
    "path": "Classes/Core/FLEXSingleRowSection.m",
    "chars": 2286,
    "preview": "//\n//  FLEXSingleRowSection.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 9/25/19.\n//  Copyright © 2020 FLEX Team. All "
  },
  {
    "path": "Classes/Core/FLEXTableViewSection.h",
    "chars": 6675,
    "preview": "//\n//  FLEXTableViewSection.h\n//  FLEX\n//\n//  Created by Tanner on 1/29/20.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/Core/FLEXTableViewSection.m",
    "chars": 3743,
    "preview": "//\n//  FLEXTableViewSection.m\n//  FLEX\n//\n//  Created by Tanner on 1/29/20.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/Core/Views/Carousel/FLEXCarouselCell.h",
    "chars": 265,
    "preview": "//\n//  FLEXCarouselCell.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/17/19.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Core/Views/Carousel/FLEXCarouselCell.m",
    "chars": 2630,
    "preview": "//\n//  FLEXCarouselCell.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/17/19.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Core/Views/Carousel/FLEXScopeCarousel.h",
    "chars": 548,
    "preview": "//\n//  FLEXScopeCarousel.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/17/19.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/Core/Views/Carousel/FLEXScopeCarousel.m",
    "chars": 7098,
    "preview": "//\n//  FLEXScopeCarousel.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/17/19.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXCodeFontCell.h",
    "chars": 287,
    "preview": "//\n//  FLEXCodeFontCell.h\n//  FLEX\n//\n//  Created by Tanner on 12/27/19.\n//  Copyright © 2020 FLEX Team. All rights rese"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXCodeFontCell.m",
    "chars": 808,
    "preview": "//\n//  FLEXCodeFontCell.m\n//  FLEX\n//\n//  Created by Tanner on 12/27/19.\n//  Copyright © 2020 FLEX Team. All rights rese"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.h",
    "chars": 240,
    "preview": "//\n//  FLEXKeyValueTableViewCell.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 1/23/20.\n//  Copyright © 2020 FLEX Team."
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXKeyValueTableViewCell.m",
    "chars": 423,
    "preview": "//\n//  FLEXKeyValueTableViewCell.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 1/23/20.\n//  Copyright © 2020 FLEX Team."
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXMultilineTableViewCell.h",
    "chars": 753,
    "preview": "//\n//  FLEXMultilineTableViewCell.h\n//  FLEX\n//\n//  Created by Ryan Olson on 2/13/15.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXMultilineTableViewCell.m",
    "chars": 1988,
    "preview": "//\n//  FLEXMultilineTableViewCell.m\n//  FLEX\n//\n//  Created by Ryan Olson on 2/13/15.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.h",
    "chars": 292,
    "preview": "//\n//  FLEXSubtitleTableViewCell.h\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXSubtitleTableViewCell.m",
    "chars": 417,
    "preview": "//\n//  FLEXSubtitleTableViewCell.m\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXTableViewCell.h",
    "chars": 568,
    "preview": "//\n//  FLEXTableViewCell.h\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rights rese"
  },
  {
    "path": "Classes/Core/Views/Cells/FLEXTableViewCell.m",
    "chars": 1460,
    "preview": "//\n//  FLEXTableViewCell.m\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rights rese"
  },
  {
    "path": "Classes/Core/Views/FLEXTableView.h",
    "chars": 1934,
    "preview": "//\n//  FLEXTableView.h\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rights reserved"
  },
  {
    "path": "Classes/Core/Views/FLEXTableView.m",
    "chars": 2708,
    "preview": "//\n//  FLEXTableView.m\n//  FLEX\n//\n//  Created by Tanner on 4/17/19.\n//  Copyright © 2020 FLEX Team. All rights reserved"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.h",
    "chars": 253,
    "preview": "//\n//  FLEXArgumentInputColorView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/30/14.\n//  Copyright (c) 2020 FLEX T"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.m",
    "chars": 11566,
    "preview": "//\n//  FLEXArgumentInputColorView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/30/14.\n//  Copyright (c) 2020 FLEX T"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.h",
    "chars": 266,
    "preview": "//\n//  FLEXArgumentInputDataView.h\n//  Flipboard\n//\n//  Created by Daniel Rodriguez Troitino on 2/14/15.\n//  Copyright ("
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.m",
    "chars": 1575,
    "preview": "//\n//  FLEXArgumentInputDataView.m\n//  Flipboard\n//\n//  Created by Daniel Rodriguez Troitino on 2/14/15.\n//  Copyright ("
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.h",
    "chars": 251,
    "preview": "//\n//  FLEXArgumentInputFontView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.m",
    "chars": 3697,
    "preview": "//\n//  FLEXArgumentInputFontView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.h",
    "chars": 303,
    "preview": "//\n//  FLEXArgumentInputFontsPickerView.h\n//  FLEX\n//\n//  Created by 啟倫 陳 on 2014/7/27.\n//  Copyright (c) 2014年 f. All r"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.m",
    "chars": 3464,
    "preview": "//\n//  FLEXArgumentInputFontsPickerView.m\n//  FLEX\n//\n//  Created by 啟倫 陳 on 2014/7/27.\n//  Copyright (c) 2014年 f. All r"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.h",
    "chars": 275,
    "preview": "//\n//  FLEXArgumentInputNotSupportedView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/18/14.\n//  Copyright (c) 2020"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.m",
    "chars": 743,
    "preview": "//\n//  FLEXArgumentInputNotSupportedView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/18/14.\n//  Copyright (c) 2020"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.h",
    "chars": 263,
    "preview": "//\n//  FLEXArgumentInputNumberView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.m",
    "chars": 1806,
    "preview": "//\n//  FLEXArgumentInputNumberView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.h",
    "chars": 263,
    "preview": "//\n//  FLEXArgumentInputObjectView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.m",
    "chars": 8151,
    "preview": "//\n//  FLEXArgumentInputJSONObjectView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2020 F"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.h",
    "chars": 263,
    "preview": "//\n//  FLEXArgumentInputStringView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.m",
    "chars": 4310,
    "preview": "//\n//  FLEXArgumentInputStringView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.h",
    "chars": 411,
    "preview": "//\n//  FLEXArgumentInputStructView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.m",
    "chars": 9844,
    "preview": "//\n//  FLEXArgumentInputStructView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.h",
    "chars": 255,
    "preview": "//\n//  FLEXArgumentInputSwitchView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.m",
    "chars": 2152,
    "preview": "//\n//  FLEXArgumentInputSwitchView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2020 FLEX "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h",
    "chars": 364,
    "preview": "//\n//  FLEXArgumentInputTextView.h\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXArgumen"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.m",
    "chars": 4853,
    "preview": "//\n//  FLEXArgumentInputTextView.m\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXColor.h"
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h",
    "chars": 2328,
    "preview": "//\n//  FLEXArgumentInputView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/30/14.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.m",
    "chars": 2708,
    "preview": "//\n//  FLEXArgumentInputView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/30/14.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/Editing/FLEXArgumentInputViewFactory.h",
    "chars": 1071,
    "preview": "//\n//  FLEXArgumentInputViewFactory.h\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import <Foundati"
  },
  {
    "path": "Classes/Editing/FLEXArgumentInputViewFactory.m",
    "chars": 3512,
    "preview": "//\n//  FLEXArgumentInputViewFactory.m\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXArgu"
  },
  {
    "path": "Classes/Editing/FLEXDefaultEditorViewController.h",
    "chars": 509,
    "preview": "//\n//  FLEXDefaultEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2020 F"
  },
  {
    "path": "Classes/Editing/FLEXDefaultEditorViewController.m",
    "chars": 2306,
    "preview": "//\n//  FLEXDefaultEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2020 F"
  },
  {
    "path": "Classes/Editing/FLEXFieldEditorView.h",
    "chars": 442,
    "preview": "//\n//  FLEXFieldEditorView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2020 FLEX Team. Al"
  },
  {
    "path": "Classes/Editing/FLEXFieldEditorView.m",
    "chars": 6005,
    "preview": "//\n//  FLEXFieldEditorView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2020 FLEX Team. Al"
  },
  {
    "path": "Classes/Editing/FLEXFieldEditorViewController.h",
    "chars": 900,
    "preview": "//\n//  FLEXFieldEditorViewController.h\n//  FLEX\n//\n//  Created by Tanner on 11/22/18.\n//  Copyright © 2020 FLEX Team. Al"
  },
  {
    "path": "Classes/Editing/FLEXFieldEditorViewController.m",
    "chars": 5520,
    "preview": "//\n//  FLEXFieldEditorViewController.m\n//  FLEX\n//\n//  Created by Tanner on 11/22/18.\n//  Copyright © 2020 FLEX Team. Al"
  },
  {
    "path": "Classes/Editing/FLEXMethodCallingViewController.h",
    "chars": 372,
    "preview": "//\n//  FLEXMethodCallingViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2020 F"
  },
  {
    "path": "Classes/Editing/FLEXMethodCallingViewController.m",
    "chars": 3829,
    "preview": "//\n//  FLEXMethodCallingViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2020 F"
  },
  {
    "path": "Classes/Editing/FLEXVariableEditorViewController.h",
    "chars": 2040,
    "preview": "//\n//  FLEXVariableEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2020 "
  },
  {
    "path": "Classes/Editing/FLEXVariableEditorViewController.m",
    "chars": 5218,
    "preview": "//\n//  FLEXVariableEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2020 "
  },
  {
    "path": "Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.h",
    "chars": 329,
    "preview": "//\n//  FLEXBookmarkManager.h\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All rights res"
  },
  {
    "path": "Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.m",
    "chars": 483,
    "preview": "//\n//  FLEXBookmarkManager.m\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All rights res"
  },
  {
    "path": "Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.h",
    "chars": 295,
    "preview": "//\n//  FLEXBookmarksViewController.h\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.m",
    "chars": 8196,
    "preview": "//\n//  FLEXBookmarksViewController.m\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXExplorerViewController.h",
    "chars": 2347,
    "preview": "//\n//  FLEXExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXExplorerViewController.m",
    "chars": 42708,
    "preview": "//\n//  FLEXExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXViewControllersViewController.h",
    "chars": 399,
    "preview": "//\n//  FLEXViewControllersViewController.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 2/13/20.\n//  Copyright © 2020 FL"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXViewControllersViewController.m",
    "chars": 2470,
    "preview": "//\n//  FLEXViewControllersViewController.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 2/13/20.\n//  Copyright © 2020 FL"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXWindow.h",
    "chars": 786,
    "preview": "//\n//  FLEXWindow.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/13/14.\n//  Copyright (c) 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/ExplorerInterface/FLEXWindow.m",
    "chars": 2631,
    "preview": "//\n//  FLEXWindow.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/13/14.\n//  Copyright (c) 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/ExplorerInterface/FLEXWindowManagerController.h",
    "chars": 295,
    "preview": "//\n//  FLEXWindowManagerController.h\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/ExplorerInterface/FLEXWindowManagerController.m",
    "chars": 11096,
    "preview": "//\n//  FLEXWindowManagerController.m\n//  FLEX\n//\n//  Created by Tanner on 2/6/20.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/ExplorerInterface/Tabs/FLEXTabList.h",
    "chars": 1546,
    "preview": "//\n//  FLEXTabList.h\n//  FLEX\n//\n//  Created by Tanner on 2/1/20.\n//  Copyright © 2020 FLEX Team. All rights reserved.\n/"
  },
  {
    "path": "Classes/ExplorerInterface/Tabs/FLEXTabList.m",
    "chars": 3546,
    "preview": "//\n//  FLEXTabList.m\n//  FLEX\n//\n//  Created by Tanner on 2/1/20.\n//  Copyright © 2020 FLEX Team. All rights reserved.\n/"
  },
  {
    "path": "Classes/ExplorerInterface/Tabs/FLEXTabsViewController.h",
    "chars": 237,
    "preview": "//\n//  FLEXTabsViewController.h\n//  FLEX\n//\n//  Created by Tanner on 2/4/20.\n//  Copyright © 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/ExplorerInterface/Tabs/FLEXTabsViewController.m",
    "chars": 12369,
    "preview": "//\n//  FLEXTabsViewController.m\n//  FLEX\n//\n//  Created by Tanner on 2/4/20.\n//  Copyright © 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/FLEX-Categories.h",
    "chars": 486,
    "preview": "//\n//  FLEX-Categories.h\n//  FLEX\n//\n//  Created by Tanner on 3/12/20.\n//  Copyright © 2020 FLEX Team. All rights reserv"
  },
  {
    "path": "Classes/FLEX-Core.h",
    "chars": 509,
    "preview": "//\n//  FLEX-Core.h\n//  FLEX\n//\n//  Created by Tanner on 3/11/20.\n//  Copyright © 2020 FLEX Team. All rights reserved.\n//"
  },
  {
    "path": "Classes/FLEX-ObjectExploring.h",
    "chars": 525,
    "preview": "//\n//  FLEX-ObjectExploring.h\n//  FLEX\n//\n//  Created by Tanner on 3/11/20.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/FLEX-Runtime.h",
    "chars": 624,
    "preview": "//\n//  FLEX-Runtime.h\n//  FLEX\n//\n//  Created by Tanner on 3/11/20.\n//  Copyright © 2020 FLEX Team. All rights reserved."
  },
  {
    "path": "Classes/FLEX.h",
    "chars": 544,
    "preview": "//\n//  FLEX.h\n//  FLEX\n//\n//  Created by Eric Horacek on 7/18/15.\n//  Modified by Tanner Bennett on 3/12/20.\n//  Copyrig"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.h",
    "chars": 709,
    "preview": "//\n//  FLEXDBQueryRowCell.h\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights reserve"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.m",
    "chars": 2110,
    "preview": "//\n//  FLEXDBQueryRowCell.m\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights reserve"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h",
    "chars": 1010,
    "preview": "//\n//  PTDatabaseManager.h\n//  Derived from:\n//\n//  FMDatabase.h\n//  FMDB( https://github.com/ccgus/fmdb )\n//\n//  Create"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h",
    "chars": 1571,
    "preview": "//\n//  PTMultiColumnTableView.h\n//  PTMultiColumnTableViewDemo\n//\n//  Created by Peng Tao on 15/11/16.\n//  Copyright © 2"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.m",
    "chars": 11017,
    "preview": "//\n//  PTMultiColumnTableView.m\n//  PTMultiColumnTableViewDemo\n//\n//  Created by Peng Tao on 15/11/16.\n//  Copyright © 2"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.h",
    "chars": 282,
    "preview": "//\n//  FLEXRealmDatabaseManager.h\n//  FLEX\n//\n//  Created by Tim Oliver on 28/01/2016.\n//  Copyright © 2016 Realm. All r"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.m",
    "chars": 2831,
    "preview": "//\n//  FLEXRealmDatabaseManager.m\n//  FLEX\n//\n//  Created by Tim Oliver on 28/01/2016.\n//  Copyright © 2016 Realm. All r"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDefines.h",
    "chars": 1183,
    "preview": "//\n//  Realm.h\n//  FLEX\n//\n//  Created by Tim Oliver on 16/02/2016.\n//  Copyright © 2016 Realm. All rights reserved.\n//\n"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.h",
    "chars": 1703,
    "preview": "//\n//  FLEXSQLResult.h\n//  FLEX\n//\n//  Created by Tanner on 3/3/20.\n//  Copyright © 2020 FLEX Team. All rights reserved."
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.m",
    "chars": 1437,
    "preview": "//\n//  FLEXSQLResult.m\n//  FLEX\n//\n//  Created by Tanner on 3/3/20.\n//  Copyright © 2020 FLEX Team. All rights reserved."
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.h",
    "chars": 1177,
    "preview": "//\n//  PTDatabaseManager.h\n//  Derived from:\n//\n//  FMDatabase.h\n//  FMDB( https://github.com/ccgus/fmdb )\n//\n//  Create"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.m",
    "chars": 10876,
    "preview": "//\n//  PTDatabaseManager.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Peng Tao. "
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h",
    "chars": 1003,
    "preview": "//\n//  FLEXTableContentHeaderCell.h\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/26.\n//  Copyright © 2015年 f. All rights"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.m",
    "chars": 2220,
    "preview": "//\n//  FLEXTableContentHeaderCell.m\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/26.\n//  Copyright © 2015年 f. All rights"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h",
    "chars": 1343,
    "preview": "//\n//  PTTableContentViewController.h\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.m",
    "chars": 12605,
    "preview": "//\n//  PTTableContentViewController.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.h",
    "chars": 309,
    "preview": "//\n//  FLEXTableLeftCell.h\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights reserved"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.m",
    "chars": 960,
    "preview": "//\n//  FLEXTableLeftCell.m\n//  FLEX\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights reserved"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.h",
    "chars": 376,
    "preview": "//\n//  PTTableListViewController.h\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Pe"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.m",
    "chars": 6286,
    "preview": "//\n//  PTTableListViewController.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Pe"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableRowDataViewController.h",
    "chars": 287,
    "preview": "//\n//  FLEXTableRowDataViewController.h\n//  FLEX\n//\n//  Created by Chaoshuai Lu on 7/8/20.\n//\n\n#import \"FLEXFilteringTab"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableRowDataViewController.m",
    "chars": 1838,
    "preview": "//\n//  FLEXTableRowDataViewController.m\n//  FLEX\n//\n//  Created by Chaoshuai Lu on 7/8/20.\n//\n\n#import \"FLEXTableRowData"
  },
  {
    "path": "Classes/GlobalStateExplorers/DatabaseBrowser/LICENSE",
    "chars": 1070,
    "preview": "\nFMDB\nCopyright (c) 2008-2014 Flying Meat Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXAPNSViewController.h",
    "chars": 312,
    "preview": "//\n//  FLEXAPNSViewController.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 6/28/22.\n//  Copyright © 2022 FLEX Team. Al"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXAPNSViewController.m",
    "chars": 14012,
    "preview": "//\n//  FLEXAPNSViewController.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 6/28/22.\n//  Copyright © 2022 FLEX Team. Al"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.h",
    "chars": 259,
    "preview": "//\n//  FLEXAddressExplorerCoordinator.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/10/19.\n//  Copyright © 2020 FLEX "
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.m",
    "chars": 3368,
    "preview": "//\n//  FLEXAddressExplorerCoordinator.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/10/19.\n//  Copyright © 2020 FLEX "
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXCookiesViewController.h",
    "chars": 320,
    "preview": "//\n//  FLEXCookiesViewController.h\n//  FLEX\n//\n//  Created by Rich Robinson on 19/10/2015.\n//  Copyright © 2020 FLEX Tea"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXCookiesViewController.m",
    "chars": 2644,
    "preview": "//\n//  FLEXCookiesViewController.m\n//  FLEX\n//\n//  Created by Rich Robinson on 19/10/2015.\n//  Copyright © 2020 FLEX Tea"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXLiveObjectsController.h",
    "chars": 303,
    "preview": "//\n//  FLEXLiveObjectsController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXLiveObjectsController.m",
    "chars": 9743,
    "preview": "//\n//  FLEXLiveObjectsController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2020 FLEX Te"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXObjectListViewController.h",
    "chars": 649,
    "preview": "//\n//  FLEXObjectListViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXObjectListViewController.m",
    "chars": 8646,
    "preview": "//\n//  FLEXObjectListViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXObjectRef.h",
    "chars": 1640,
    "preview": "//\n//  FLEXObjectRef.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/24/18.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXObjectRef.m",
    "chars": 3276,
    "preview": "//\n//  FLEXObjectRef.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/24/18.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXWebViewController.h",
    "chars": 352,
    "preview": "//\n//  FLEXWebViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/10/14.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/GlobalStateExplorers/FLEXWebViewController.m",
    "chars": 5152,
    "preview": "//\n//  FLEXWebViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/10/14.\n//  Copyright (c) 2020 FLEX Team. "
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXActivityViewController.h",
    "chars": 474,
    "preview": "//\n//  FLEXActivityViewController.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 5/26/22.\n//\n\n#import <UIKit/UIKit.h>\n\nN"
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXActivityViewController.m",
    "chars": 1111,
    "preview": "//\n//  FLEXActivityViewController.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 5/26/22.\n//\n\n#import \"FLEXActivityViewC"
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.h",
    "chars": 364,
    "preview": "//\n//  FLEXFileBrowserController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/9/14.\n//  Based on previous work by E"
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.m",
    "chars": 24221,
    "preview": "//\n//  FLEXFileBrowserController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/9/14.\n//\n//\n\n#import \"FLEXFileBrowser"
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserSearchOperation.h",
    "chars": 616,
    "preview": "//\n//  FLEXFileBrowserSearchOperation.h\n//  FLEX\n//\n//  Created by 啟倫 陳 on 2014/8/4.\n//  Copyright (c) 2014年 f. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserSearchOperation.m",
    "chars": 3698,
    "preview": "//\n//  FLEXFileBrowserSearchOperation.m\n//  FLEX\n//\n//  Created by 啟倫 陳 on 2014/8/4.\n//  Copyright (c) 2014年 f. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h",
    "chars": 4049,
    "preview": "//\n//  FLEXGlobalsEntry.h\n//  FLEX\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.m",
    "chars": 2401,
    "preview": "//\n//  FLEXGlobalsEntry.m\n//  FLEX\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsSection.h",
    "chars": 392,
    "preview": "//\n//  FLEXGlobalsSection.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/11/19.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsSection.m",
    "chars": 2089,
    "preview": "//\n//  FLEXGlobalsSection.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/11/19.\n//  Copyright © 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.h",
    "chars": 857,
    "preview": "//\n//  FLEXGlobalsViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.m",
    "chars": 8467,
    "preview": "//\n//  FLEXGlobalsViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychain.h",
    "chars": 6395,
    "preview": "//\n//  FLEXKeychain.h\n//\n//  Derived from:\n//  SSKeychain.h in SSKeychain\n//  Created by Sam Soffes on 5/19/10.\n//  Copy"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychain.m",
    "chars": 4200,
    "preview": "//\n//  FLEXKeychain.m\n//\n//  Forked from:\n//  SSKeychain.m in SSKeychain\n//  Created by Sam Soffes on 5/19/10.\n//  Copyr"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychainQuery.h",
    "chars": 3801,
    "preview": "//\n//  FLEXKeychainQuery.h\n//\n//  Derived from:\n//  SSKeychainQuery.h in SSKeychain\n//  Created by Caleb Davenport on 3/"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychainQuery.m",
    "chars": 9577,
    "preview": "//\n//  FLEXKeychainQuery.m\n//  FLEXKeychain\n//\n//  Created by Caleb Davenport on 3/19/13.\n//  Copyright (c) 2013-2014 Sa"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychainViewController.h",
    "chars": 311,
    "preview": "//\n//  FLEXKeychainViewController.h\n//  FLEX\n//\n//  Created by ray on 2019/8/17.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/FLEXKeychainViewController.m",
    "chars": 8796,
    "preview": "//\n//  FLEXKeychainViewController.m\n//  FLEX\n//\n//  Created by ray on 2019/8/17.\n//  Copyright © 2020 FLEX Team. All rig"
  },
  {
    "path": "Classes/GlobalStateExplorers/Keychain/SSKeychain_LICENSE",
    "chars": 1060,
    "preview": "Copyright (c) 2010-2012 Sam Soffes.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of thi"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeClient.h",
    "chars": 2134,
    "preview": "//\n//  FLEXRuntimeClient.h\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All rights"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeClient.m",
    "chars": 14972,
    "preview": "//\n//  FLEXRuntimeClient.m\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All rights"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeController.h",
    "chars": 1369,
    "preview": "//\n//  FLEXRuntimeController.h\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeController.m",
    "chars": 5735,
    "preview": "//\n//  FLEXRuntimeController.m\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeExporter.h",
    "chars": 866,
    "preview": "//\n//  FLEXRuntimeExporter.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 3/26/20.\n//  Copyright (c) 2020 FLEX Team. All"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/DataSources/FLEXRuntimeExporter.m",
    "chars": 30339,
    "preview": "//\n//  FLEXRuntimeExporter.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 3/26/20.\n//  Copyright (c) 2020 FLEX Team. All"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKBToolbarButton.h",
    "chars": 1002,
    "preview": "//\n//  FLEXKBToolbarButton.h\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKBToolbarButton.m",
    "chars": 5042,
    "preview": "//\n//  FLEXKBToolbarButton.m\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKeyPathSearchController.h",
    "chars": 1131,
    "preview": "//\n//  FLEXKeyPathSearchController.h\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett. "
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKeyPathSearchController.m",
    "chars": 15005,
    "preview": "//\n//  FLEXKeyPathSearchController.m\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett. "
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKeyboardToolbar.h",
    "chars": 390,
    "preview": "//\n//  FLEXKeyboardToolbar.h\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXKeyboardToolbar.m",
    "chars": 7586,
    "preview": "//\n//  FLEXKeyboardToolbar.m\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. All righ"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXObjcRuntimeViewController.h",
    "chars": 305,
    "preview": "//\n//  FLEXObjcRuntimeViewController.h\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXObjcRuntimeViewController.m",
    "chars": 6564,
    "preview": "//\n//  FLEXObjcRuntimeViewController.m\n//  FLEX\n//\n//  Created by Tanner on 3/23/17.\n//  Copyright © 2017 Tanner Bennett"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeBrowserToolbar.h",
    "chars": 486,
    "preview": "//\n//  FLEXRuntimeBrowserToolbar.h\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. Al"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeBrowserToolbar.m",
    "chars": 3312,
    "preview": "//\n//  FLEXRuntimeBrowserToolbar.m\n//  FLEX\n//\n//  Created by Tanner on 6/11/17.\n//  Copyright © 2017 Tanner Bennett. Al"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeKeyPath.h",
    "chars": 1438,
    "preview": "//\n//  FLEXRuntimeKeyPath.h\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeKeyPath.m",
    "chars": 1785,
    "preview": "//\n//  FLEXRuntimeKeyPath.m\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeKeyPathTokenizer.h",
    "chars": 396,
    "preview": "//\n//  FLEXRuntimeKeyPathTokenizer.h\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. "
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXRuntimeKeyPathTokenizer.m",
    "chars": 8306,
    "preview": "//\n//  FLEXRuntimeKeyPathTokenizer.m\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. "
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXSearchToken.h",
    "chars": 1000,
    "preview": "//\n//  FLEXSearchToken.h\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/RuntimeBrowser/FLEXSearchToken.m",
    "chars": 1932,
    "preview": "//\n//  FLEXSearchToken.m\n//  FLEX\n//\n//  Created by Tanner on 3/22/17.\n//  Copyright © 2017 Tanner Bennett. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/ActivityStreamAPI.h",
    "chars": 7027,
    "preview": "//\n// Taken from https://github.com/llvm-mirror/lldb/blob/master/tools/debugserver/source/MacOSX/DarwinLog/ActivityStrea"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXASLLogController.h",
    "chars": 417,
    "preview": "//\n//  FLEXASLLogController.h\n//  FLEX\n//\n//  Created by Tanner on 3/14/19.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXASLLogController.m",
    "chars": 4726,
    "preview": "//\n//  FLEXASLLogController.m\n//  FLEX\n//\n//  Created by Tanner on 3/14/19.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXLogController.h",
    "chars": 427,
    "preview": "//\n//  FLEXLogController.h\n//  FLEX\n//\n//  Created by Tanner on 3/17/19.\n//  Copyright © 2020 FLEX Team. All rights rese"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXOSLogController.h",
    "chars": 900,
    "preview": "//\n//  FLEXOSLogController.h\n//  FLEX\n//\n//  Created by Tanner on 12/19/18.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXOSLogController.m",
    "chars": 7290,
    "preview": "//\n//  FLEXOSLogController.m\n//  FLEX\n//\n//  Created by Tanner on 12/19/18.\n//  Copyright © 2020 FLEX Team. All rights r"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.h",
    "chars": 595,
    "preview": "//\n//  FLEXSystemLogCell.h\n//  FLEX\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogCell.m",
    "chars": 4294,
    "preview": "//\n//  FLEXSystemLogCell.m\n//  FLEX\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2020 FLEX Team. All right"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogMessage.h",
    "chars": 756,
    "preview": "//\n//  FLEXSystemLogMessage.h\n//  FLEX\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogMessage.m",
    "chars": 2529,
    "preview": "//\n//  FLEXSystemLogMessage.m\n//  FLEX\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2020 FLEX Team. All ri"
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogViewController.h",
    "chars": 320,
    "preview": "//\n//  FLEXSystemLogViewController.h\n//  FLEX\n//\n//  Created by Ryan Olson on 1/19/15.\n//  Copyright (c) 2020 FLEX Team."
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogViewController.m",
    "chars": 10482,
    "preview": "//\n//  FLEXSystemLogViewController.m\n//  FLEX\n//\n//  Created by Ryan Olson on 1/19/15.\n//  Copyright (c) 2020 FLEX Team."
  },
  {
    "path": "Classes/GlobalStateExplorers/SystemLog/LLVM_LICENSE.TXT",
    "chars": 15032,
    "preview": "==============================================================================\nThe LLVM Project is under the Apache Lice"
  },
  {
    "path": "Classes/Info.plist",
    "chars": 806,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "Classes/Manager/FLEXManager+Extensibility.h",
    "chars": 4335,
    "preview": "//\n//  FLEXManager+Extensibility.h\n//  FLEX\n//\n//  Created by Tanner on 2/2/20.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Manager/FLEXManager+Extensibility.m",
    "chars": 10814,
    "preview": "//\n//  FLEXManager+Extensibility.m\n//  FLEX\n//\n//  Created by Tanner on 2/2/20.\n//  Copyright © 2020 FLEX Team. All righ"
  },
  {
    "path": "Classes/Manager/FLEXManager+Networking.h",
    "chars": 2010,
    "preview": "//\n//  FLEXManager+Networking.h\n//  FLEX\n//\n//  Created by Tanner on 2/1/20.\n//  Copyright © 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/Manager/FLEXManager+Networking.m",
    "chars": 2379,
    "preview": "//\n//  FLEXManager+Networking.m\n//  FLEX\n//\n//  Created by Tanner on 2/1/20.\n//  Copyright © 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/Manager/FLEXManager.h",
    "chars": 2090,
    "preview": "//\n//  FLEXManager.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/Manager/FLEXManager.m",
    "chars": 4740,
    "preview": "//\n//  FLEXManager.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2020 FLEX Team. All rights "
  },
  {
    "path": "Classes/Manager/Private/FLEXManager+Private.h",
    "chars": 720,
    "preview": "//\n//  FLEXManager+Private.h\n//  PebbleApp\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2020 FLEX Team. A"
  },
  {
    "path": "Classes/Network/FLEXFirebaseTransaction.mm",
    "chars": 9373,
    "preview": "//\n//  FLEXFirebaseTransaction.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 12/24/21.\n//\n\n#import \"FLEXNetworkTransact"
  },
  {
    "path": "Classes/Network/FLEXHTTPTransactionDetailController.h",
    "chars": 359,
    "preview": "//\n//  FLEXHTTPTransactionDetailController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/10/15.\n//  Copyright (c) 20"
  },
  {
    "path": "Classes/Network/FLEXHTTPTransactionDetailController.m",
    "chars": 22566,
    "preview": "//\n//  FLEXNetworkTransactionDetailController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/10/15.\n//  Copyright (c)"
  },
  {
    "path": "Classes/Network/FLEXMITMDataSource.h",
    "chars": 1123,
    "preview": "//\n//  FLEXMITMDataSource.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 8/22/21.\n//\n\n#import <Foundation/Foundation.h>\n"
  },
  {
    "path": "Classes/Network/FLEXMITMDataSource.m",
    "chars": 3113,
    "preview": "//\n//  FLEXMITMDataSource.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 8/22/21.\n//\n\n#import \"FLEXMITMDataSource.h\"\n#im"
  },
  {
    "path": "Classes/Network/FLEXNetworkCurlLogger.h",
    "chars": 328,
    "preview": "//\n// FLEXCurlLogger.h\n//\n//\n// Created by Ji Pei on 07/27/16\n//\n\n#import <Foundation/Foundation.h>\n\n@interface FLEXNetw"
  },
  {
    "path": "Classes/Network/FLEXNetworkCurlLogger.m",
    "chars": 1862,
    "preview": "//\n// FLEXCurlLogger.m\n//\n//\n// Created by Ji Pei on 07/27/16\n//\n\n#import \"FLEXNetworkCurlLogger.h\"\n#import \"FLEXUtility"
  },
  {
    "path": "Classes/Network/FLEXNetworkMITMViewController.h",
    "chars": 403,
    "preview": "//\n//  FLEXNetworkMITMViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/Network/FLEXNetworkMITMViewController.m",
    "chars": 24302,
    "preview": "//\n//  FLEXNetworkMITMViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2020 FLEX"
  },
  {
    "path": "Classes/Network/FLEXNetworkRecorder.h",
    "chars": 6007,
    "preview": "//\n//  FLEXNetworkRecorder.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/4/15.\n//  Copyright (c) 2020 FLEX Team. All"
  }
]

// ... and 231 more files (download for full content)

About this extraction

This page contains the full source code of the FLEXTool/FLEX GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 431 files (2.6 MB), approximately 710.6k tokens, and a symbol index with 79 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!