Full Code of irccloud/ios for AI

master f223343e3269 cached
516 files
5.3 MB
1.4M tokens
193 symbols
1 requests
Download .txt
Showing preview only (5,718K chars total). Download the full file or copy to clipboard to get everything.
Repository: irccloud/ios
Branch: master
Commit: f223343e3269
Files: 516
Total size: 5.3 MB

Directory structure:
gitextract_d9aulut5/

├── .gitignore
├── ARChromeActivity/
│   ├── ARChromeActivity.h
│   └── ARChromeActivity.m
├── CSURITemplate/
│   ├── CSURITemplate.h
│   └── CSURITemplate.m
├── ECSlidingViewController/
│   ├── ECSlidingViewController.h
│   ├── ECSlidingViewController.m
│   ├── UIImage+ImageWithUIView.h
│   └── UIImage+ImageWithUIView.m
├── FLEX/
│   ├── Editing/
│   │   ├── ArgumentInputViews/
│   │   │   ├── FLEXArgumentInputColorView.h
│   │   │   ├── FLEXArgumentInputColorView.m
│   │   │   ├── FLEXArgumentInputDateView.h
│   │   │   ├── FLEXArgumentInputDateView.m
│   │   │   ├── FLEXArgumentInputFontView.h
│   │   │   ├── FLEXArgumentInputFontView.m
│   │   │   ├── FLEXArgumentInputFontsPickerView.h
│   │   │   ├── FLEXArgumentInputFontsPickerView.m
│   │   │   ├── FLEXArgumentInputJSONObjectView.h
│   │   │   ├── FLEXArgumentInputJSONObjectView.m
│   │   │   ├── FLEXArgumentInputNotSupportedView.h
│   │   │   ├── FLEXArgumentInputNotSupportedView.m
│   │   │   ├── FLEXArgumentInputNumberView.h
│   │   │   ├── FLEXArgumentInputNumberView.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
│   │   ├── FLEXIvarEditorViewController.h
│   │   ├── FLEXIvarEditorViewController.m
│   │   ├── FLEXMethodCallingViewController.h
│   │   ├── FLEXMethodCallingViewController.m
│   │   ├── FLEXPropertyEditorViewController.h
│   │   └── FLEXPropertyEditorViewController.m
│   ├── ExplorerInterface/
│   │   ├── FLEXExplorerViewController.h
│   │   ├── FLEXExplorerViewController.m
│   │   ├── FLEXWindow.h
│   │   └── FLEXWindow.m
│   ├── FLEX.h
│   ├── FLEXManager.h
│   ├── GlobalStateExplorers/
│   │   ├── DatabaseBrowser/
│   │   │   ├── FLEXDatabaseManager.h
│   │   │   ├── FLEXMultiColumnTableView.h
│   │   │   ├── FLEXMultiColumnTableView.m
│   │   │   ├── FLEXRealmDatabaseManager.h
│   │   │   ├── FLEXRealmDatabaseManager.m
│   │   │   ├── FLEXRealmDefines.h
│   │   │   ├── FLEXSQLiteDatabaseManager.h
│   │   │   ├── FLEXSQLiteDatabaseManager.m
│   │   │   ├── FLEXTableColumnHeader.h
│   │   │   ├── FLEXTableColumnHeader.m
│   │   │   ├── FLEXTableContentCell.h
│   │   │   ├── FLEXTableContentCell.m
│   │   │   ├── FLEXTableContentViewController.h
│   │   │   ├── FLEXTableContentViewController.m
│   │   │   ├── FLEXTableLeftCell.h
│   │   │   ├── FLEXTableLeftCell.m
│   │   │   ├── FLEXTableListViewController.h
│   │   │   ├── FLEXTableListViewController.m
│   │   │   └── LICENSE
│   │   ├── FLEXClassesTableViewController.h
│   │   ├── FLEXClassesTableViewController.m
│   │   ├── FLEXCookiesTableViewController.h
│   │   ├── FLEXCookiesTableViewController.m
│   │   ├── FLEXFileBrowserFileOperationController.h
│   │   ├── FLEXFileBrowserFileOperationController.m
│   │   ├── FLEXFileBrowserSearchOperation.h
│   │   ├── FLEXFileBrowserSearchOperation.m
│   │   ├── FLEXFileBrowserTableViewController.h
│   │   ├── FLEXFileBrowserTableViewController.m
│   │   ├── FLEXGlobalsTableViewController.h
│   │   ├── FLEXGlobalsTableViewController.m
│   │   ├── FLEXInstancesTableViewController.h
│   │   ├── FLEXInstancesTableViewController.m
│   │   ├── FLEXLibrariesTableViewController.h
│   │   ├── FLEXLibrariesTableViewController.m
│   │   ├── FLEXLiveObjectsTableViewController.h
│   │   ├── FLEXLiveObjectsTableViewController.m
│   │   ├── FLEXObjectRef.h
│   │   ├── FLEXObjectRef.m
│   │   ├── FLEXWebViewController.h
│   │   ├── FLEXWebViewController.m
│   │   └── SystemLog/
│   │       ├── FLEXSystemLogMessage.h
│   │       ├── FLEXSystemLogMessage.m
│   │       ├── FLEXSystemLogTableViewCell.h
│   │       ├── FLEXSystemLogTableViewCell.m
│   │       ├── FLEXSystemLogTableViewController.h
│   │       └── FLEXSystemLogTableViewController.m
│   ├── Info.plist
│   ├── Manager/
│   │   ├── FLEXManager+Private.h
│   │   └── FLEXManager.m
│   ├── Network/
│   │   ├── FLEXNetworkCurlLogger.h
│   │   ├── FLEXNetworkCurlLogger.m
│   │   ├── FLEXNetworkHistoryTableViewController.h
│   │   ├── FLEXNetworkHistoryTableViewController.m
│   │   ├── FLEXNetworkRecorder.h
│   │   ├── FLEXNetworkRecorder.m
│   │   ├── FLEXNetworkSettingsTableViewController.h
│   │   ├── FLEXNetworkSettingsTableViewController.m
│   │   ├── FLEXNetworkTransaction.h
│   │   ├── FLEXNetworkTransaction.m
│   │   ├── FLEXNetworkTransactionDetailTableViewController.h
│   │   ├── FLEXNetworkTransactionDetailTableViewController.m
│   │   ├── FLEXNetworkTransactionTableViewCell.h
│   │   ├── FLEXNetworkTransactionTableViewCell.m
│   │   └── PonyDebugger/
│   │       ├── FLEXNetworkObserver.h
│   │       ├── FLEXNetworkObserver.m
│   │       └── LICENSE
│   ├── ObjectExplorers/
│   │   ├── FLEXArrayExplorerViewController.h
│   │   ├── FLEXArrayExplorerViewController.m
│   │   ├── FLEXClassExplorerViewController.h
│   │   ├── FLEXClassExplorerViewController.m
│   │   ├── FLEXDefaultsExplorerViewController.h
│   │   ├── FLEXDefaultsExplorerViewController.m
│   │   ├── FLEXDictionaryExplorerViewController.h
│   │   ├── FLEXDictionaryExplorerViewController.m
│   │   ├── FLEXGlobalsTableViewControllerEntry.h
│   │   ├── FLEXGlobalsTableViewControllerEntry.m
│   │   ├── FLEXImageExplorerViewController.h
│   │   ├── FLEXImageExplorerViewController.m
│   │   ├── FLEXLayerExplorerViewController.h
│   │   ├── FLEXLayerExplorerViewController.m
│   │   ├── FLEXObjectExplorerFactory.h
│   │   ├── FLEXObjectExplorerFactory.m
│   │   ├── FLEXObjectExplorerViewController.h
│   │   ├── FLEXObjectExplorerViewController.m
│   │   ├── FLEXSetExplorerViewController.h
│   │   ├── FLEXSetExplorerViewController.m
│   │   ├── FLEXViewControllerExplorerViewController.h
│   │   ├── FLEXViewControllerExplorerViewController.m
│   │   ├── FLEXViewExplorerViewController.h
│   │   └── FLEXViewExplorerViewController.m
│   ├── Toolbar/
│   │   ├── FLEXExplorerToolbar.h
│   │   ├── FLEXExplorerToolbar.m
│   │   ├── FLEXToolbarItem.h
│   │   └── FLEXToolbarItem.m
│   ├── Utility/
│   │   ├── FLEXHeapEnumerator.h
│   │   ├── FLEXHeapEnumerator.m
│   │   ├── FLEXKeyboardHelpViewController.h
│   │   ├── FLEXKeyboardHelpViewController.m
│   │   ├── FLEXKeyboardShortcutManager.h
│   │   ├── FLEXKeyboardShortcutManager.m
│   │   ├── FLEXMultilineTableViewCell.h
│   │   ├── FLEXMultilineTableViewCell.m
│   │   ├── FLEXResources.h
│   │   ├── FLEXResources.m
│   │   ├── FLEXRuntimeUtility.h
│   │   ├── FLEXRuntimeUtility.m
│   │   ├── FLEXUtility.h
│   │   └── FLEXUtility.m
│   └── ViewHierarchy/
│       ├── FLEXHierarchyTableViewCell.h
│       ├── FLEXHierarchyTableViewCell.m
│       ├── FLEXHierarchyTableViewController.h
│       ├── FLEXHierarchyTableViewController.m
│       ├── FLEXImagePreviewViewController.h
│       └── FLEXImagePreviewViewController.m
├── IRCCloud/
│   ├── 1Password.xcassets/
│   │   ├── onepassword-button-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-button.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-extension-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-extension.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-navbar-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-navbar.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-toolbar-light.imageset/
│   │   │   └── Contents.json
│   │   └── onepassword-toolbar.imageset/
│   │       └── Contents.json
│   ├── Classes/
│   │   ├── AppDelegate.h
│   │   ├── AppDelegate.m
│   │   ├── AvatarsDataSource.h
│   │   ├── AvatarsDataSource.m
│   │   ├── AvatarsTableViewController.h
│   │   ├── AvatarsTableViewController.m
│   │   ├── BuffersDataSource.h
│   │   ├── BuffersDataSource.m
│   │   ├── BuffersTableView.h
│   │   ├── BuffersTableView.m
│   │   ├── CallerIDTableViewController.h
│   │   ├── CallerIDTableViewController.m
│   │   ├── ChannelInfoViewController.h
│   │   ├── ChannelInfoViewController.m
│   │   ├── ChannelListTableViewController.h
│   │   ├── ChannelListTableViewController.m
│   │   ├── ChannelModeListTableViewController.h
│   │   ├── ChannelModeListTableViewController.m
│   │   ├── ChannelsDataSource.h
│   │   ├── ChannelsDataSource.m
│   │   ├── CollapsedEvents.h
│   │   ├── CollapsedEvents.m
│   │   ├── ColorFormatter.h
│   │   ├── ColorFormatter.m
│   │   ├── DisplayOptionsViewController.h
│   │   ├── DisplayOptionsViewController.m
│   │   ├── EditConnectionViewController.h
│   │   ├── EditConnectionViewController.m
│   │   ├── EventsDataSource.h
│   │   ├── EventsDataSource.m
│   │   ├── EventsTableView.h
│   │   ├── EventsTableView.m
│   │   ├── FileMetadataViewController.h
│   │   ├── FileMetadataViewController.m
│   │   ├── FileUploader.h
│   │   ├── FileUploader.m
│   │   ├── FilesTableViewController.h
│   │   ├── FilesTableViewController.m
│   │   ├── FontAwesome.h
│   │   ├── HighlightsCountView.h
│   │   ├── HighlightsCountView.m
│   │   ├── IRCCloudJSONObject.h
│   │   ├── IRCCloudJSONObject.m
│   │   ├── IRCCloudSafariViewController.h
│   │   ├── IRCCloudSafariViewController.m
│   │   ├── IRCColorPickerView.h
│   │   ├── IRCColorPickerView.m
│   │   ├── Ignore.h
│   │   ├── Ignore.m
│   │   ├── IgnoresTableViewController.h
│   │   ├── IgnoresTableViewController.m
│   │   ├── ImageCache.h
│   │   ├── ImageCache.m
│   │   ├── ImageViewController.h
│   │   ├── ImageViewController.m
│   │   ├── ImageViewController.xib
│   │   ├── LicenseViewController.h
│   │   ├── LicenseViewController.m
│   │   ├── LinkLabel.h
│   │   ├── LinkLabel.m
│   │   ├── LinkTextView.h
│   │   ├── LinkTextView.m
│   │   ├── LinksListTableViewController.h
│   │   ├── LinksListTableViewController.m
│   │   ├── LogExportsTableViewController.h
│   │   ├── LogExportsTableViewController.m
│   │   ├── LoginSplashViewController.h
│   │   ├── LoginSplashViewController.m
│   │   ├── MainViewController.h
│   │   ├── MainViewController.m
│   │   ├── NamesListTableViewController.h
│   │   ├── NamesListTableViewController.m
│   │   ├── NetworkConnection.h
│   │   ├── NetworkConnection.m
│   │   ├── NickCompletionView.h
│   │   ├── NickCompletionView.m
│   │   ├── NotificationsDataSource.h
│   │   ├── NotificationsDataSource.m
│   │   ├── PastebinEditorViewController.h
│   │   ├── PastebinEditorViewController.m
│   │   ├── PastebinViewController.h
│   │   ├── PastebinViewController.m
│   │   ├── PastebinsTableViewController.h
│   │   ├── PastebinsTableViewController.m
│   │   ├── PinReorderViewController.h
│   │   ├── PinReorderViewController.m
│   │   ├── SamlLoginViewController.h
│   │   ├── SamlLoginViewController.m
│   │   ├── SendMessageIntentHandler.h
│   │   ├── SendMessageIntentHandler.m
│   │   ├── ServerReorderViewController.h
│   │   ├── ServerReorderViewController.m
│   │   ├── ServersDataSource.h
│   │   ├── ServersDataSource.m
│   │   ├── SettingsViewController.h
│   │   ├── SettingsViewController.m
│   │   ├── SpamViewController.h
│   │   ├── SpamViewController.m
│   │   ├── SplashViewController.h
│   │   ├── SplashViewController.m
│   │   ├── TextTableViewController.h
│   │   ├── TextTableViewController.m
│   │   ├── UIColor+IRCCloud.h
│   │   ├── UIColor+IRCCloud.m
│   │   ├── UIDevice+UIDevice_iPhone6Hax.h
│   │   ├── UIDevice+UIDevice_iPhone6Hax.m
│   │   ├── UINavigationController+iPadSux.h
│   │   ├── UINavigationController+iPadSux.m
│   │   ├── UITableViewController+HeaderColorFix.h
│   │   ├── UITableViewController+HeaderColorFix.m
│   │   ├── URLHandler.h
│   │   ├── URLHandler.m
│   │   ├── UsersDataSource.h
│   │   ├── UsersDataSource.m
│   │   ├── UsersTableView.h
│   │   ├── UsersTableView.m
│   │   ├── WhoListTableViewController.h
│   │   ├── WhoListTableViewController.m
│   │   ├── WhoWasTableViewController.h
│   │   ├── WhoWasTableViewController.m
│   │   ├── WhoisViewController.h
│   │   ├── WhoisViewController.m
│   │   ├── YouTubeViewController.h
│   │   └── YouTubeViewController.m
│   ├── EventsTableCell.xib
│   ├── EventsTableCell_File.xib
│   ├── EventsTableCell_ReplyCount.xib
│   ├── EventsTableCell_Thumbnail.xib
│   ├── IRCCloud-Enterprise-Info.plist
│   ├── IRCCloud-Info.plist
│   ├── IRCCloud-Prefix.pch
│   ├── IRCCloud.entitlements
│   ├── Launch.storyboard
│   ├── MainStoryboard.storyboard
│   ├── OnePasswordExtension.h
│   ├── OnePasswordExtension.m
│   ├── Resources/
│   │   ├── EnterpriseImages.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   ├── EnterpriseLogo.xcassets/
│   │   │   └── login_logo.imageset/
│   │   │       └── Contents.json
│   │   ├── FontAwesome.otf
│   │   ├── Icons.xcassets/
│   │   │   ├── accept.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_bottom_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_button.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_mid_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_only_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_top_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── menu.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── send_fail.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── settings.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── signup_button.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── tip_bg.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── upload_arrow.imageset/
│   │   │   │   └── Contents.json
│   │   │   └── users.imageset/
│   │   │       └── Contents.json
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── Logo.xcassets/
│   │   │   └── login_logo.imageset/
│   │   │       └── Contents.json
│   │   ├── SourceSansPro-LightIt.otf
│   │   ├── SourceSansPro-Regular.otf
│   │   ├── SourceSansPro-Semibold.otf
│   │   ├── a.caf
│   │   ├── en.lproj/
│   │   │   └── Localizable.strings
│   │   └── licenses.txt
│   ├── UIExpandingTextView.h
│   ├── UIExpandingTextView.m
│   ├── UIExpandingTextViewInternal.h
│   ├── UIExpandingTextViewInternal.m
│   └── main.m
├── IRCCloud.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── IRCCloud Enterprise.xcscheme
│           ├── IRCCloud Mock Data.xcscheme
│           └── IRCCloud.xcscheme
├── IRCCloudUnitTests/
│   ├── CollapsedEventsTests.m
│   ├── Info.plist
│   ├── MessageTypeTests.m
│   └── URLtoBIDTests.m
├── IRCEnterprise.entitlements
├── LICENSE.txt
├── NSURL+IDN/
│   ├── NSURL+IDN.h
│   └── NSURL+IDN.m
├── NotificationService/
│   ├── Info.plist
│   ├── NotificationService.entitlements
│   ├── NotificationService.h
│   └── NotificationService.m
├── NotificationService Enterprise.entitlements
├── OpenInChrome/
│   ├── OpenInChromeController.h
│   └── OpenInChromeController.m
├── OpenInFirefoxClient/
│   ├── LICENSE
│   ├── OpenInFirefoxControllerObjC.h
│   └── OpenInFirefoxControllerObjC.m
├── Podfile
├── README.md
├── SBJson/
│   ├── SBJson5.h
│   ├── SBJson5Parser.h
│   ├── SBJson5Parser.m
│   ├── SBJson5StreamParser.h
│   ├── SBJson5StreamParser.m
│   ├── SBJson5StreamParserState.h
│   ├── SBJson5StreamParserState.m
│   ├── SBJson5StreamTokeniser.h
│   ├── SBJson5StreamTokeniser.m
│   ├── SBJson5StreamWriter.h
│   ├── SBJson5StreamWriter.m
│   ├── SBJson5StreamWriterState.h
│   ├── SBJson5StreamWriterState.m
│   ├── SBJson5Writer.h
│   └── SBJson5Writer.m
├── SECURITY.md
├── ShareExtension/
│   ├── Info-Enterprise.plist
│   ├── Info.plist
│   ├── ShareExtension.entitlements
│   ├── ShareViewController.h
│   └── ShareViewController.m
├── ShareExtension Enterprise.entitlements
├── StringScore/
│   ├── NSString+Score.h
│   └── NSString+Score.m
├── TUSafariActivity/
│   ├── TUSafariActivity.h
│   ├── TUSafariActivity.m
│   └── en.lproj/
│       └── TUSafariActivity.strings
├── TrustKit/
│   ├── Dependencies/
│   │   ├── README.md
│   │   ├── RSSwizzle/
│   │   │   ├── RSSwizzle.h
│   │   │   └── RSSwizzle.m
│   │   └── domain_registry/
│   │       ├── domain_registry.h
│   │       ├── private/
│   │       │   ├── assert.c
│   │       │   ├── assert.h
│   │       │   ├── init_registry_tables.c
│   │       │   ├── registry_search.c
│   │       │   ├── registry_types.h
│   │       │   ├── string_util.h
│   │       │   ├── trie_node.h
│   │       │   ├── trie_search.c
│   │       │   └── trie_search.h
│   │       └── registry_tables_genfiles/
│   │           └── registry_tables.h
│   ├── Info.plist
│   ├── Pinning/
│   │   ├── public_key_utils.h
│   │   ├── public_key_utils.m
│   │   ├── ssl_pin_verifier.h
│   │   └── ssl_pin_verifier.m
│   ├── Reporting/
│   │   ├── TSKBackgroundReporter.h
│   │   ├── TSKBackgroundReporter.m
│   │   ├── TSKPinFailureReport.h
│   │   ├── TSKPinFailureReport.m
│   │   ├── TSKReportsRateLimiter.h
│   │   ├── TSKReportsRateLimiter.m
│   │   ├── reporting_utils.h
│   │   ├── reporting_utils.m
│   │   ├── vendor_identifier.h
│   │   └── vendor_identifier.m
│   ├── Swizzling/
│   │   ├── TSKNSURLConnectionDelegateProxy.h
│   │   ├── TSKNSURLConnectionDelegateProxy.m
│   │   ├── TSKNSURLSessionDelegateProxy.h
│   │   └── TSKNSURLSessionDelegateProxy.m
│   ├── TSKPinningValidator.h
│   ├── TSKPinningValidator.m
│   ├── TrustKit+Private.h
│   ├── TrustKit.h
│   ├── TrustKit.m
│   ├── configuration_utils.h
│   ├── configuration_utils.m
│   ├── module.modulemap
│   ├── parse_configuration.h
│   └── parse_configuration.m
├── UITests/
│   ├── Info.plist
│   ├── SnapshotHelper.swift
│   ├── UITests-Bridging-Header.h
│   └── UITests.swift
├── WebP.framework/
│   ├── Headers/
│   │   ├── config.h
│   │   ├── decode.h
│   │   ├── demux.h
│   │   ├── encode.h
│   │   ├── format_constants.h
│   │   ├── mux.h
│   │   ├── mux_types.h
│   │   └── types.h
│   └── WebP
├── WebSocket/
│   ├── AsyncSocket.h
│   ├── AsyncSocket.m
│   ├── HandshakeHeader.h
│   ├── HandshakeHeader.m
│   ├── MutableQueue.h
│   ├── MutableQueue.m
│   ├── NSData+Base64.h
│   ├── NSData+Base64.m
│   ├── UnittWebSocketClient-Prefix.pch
│   ├── WebSocket.h
│   ├── WebSocket.m
│   ├── WebSocketConnectConfig.h
│   ├── WebSocketConnectConfig.m
│   ├── WebSocketFragment.h
│   ├── WebSocketFragment.m
│   ├── WebSocketMessage.h
│   └── WebSocketMessage.m
├── YYImage/
│   ├── YYAnimatedImageView.h
│   ├── YYAnimatedImageView.m
│   ├── YYFrameImage.h
│   ├── YYFrameImage.m
│   ├── YYImage.h
│   ├── YYImage.m
│   ├── YYImageCoder.h
│   ├── YYImageCoder.m
│   ├── YYSpriteSheetImage.h
│   └── YYSpriteSheetImage.m
├── build-scripts/
│   ├── BUILD
│   ├── VERSION
│   ├── ace-modes.js
│   ├── emocode-data.js
│   └── git-revision.sh
└── fastlane/
    ├── Fastfile
    ├── README.md
    ├── Snapfile
    ├── metadata/
    │   ├── copyright.txt
    │   ├── en-US/
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── release_notes.txt
    │   │   └── support_url.txt
    │   ├── primary_category.txt
    │   ├── primary_first_sub_category.txt
    │   ├── primary_second_sub_category.txt
    │   ├── review_notes.txt
    │   ├── secondary_category.txt
    │   ├── secondary_first_sub_category.txt
    │   └── secondary_second_sub_category.txt
    ├── metadata-enterprise/
    │   ├── copyright.txt
    │   ├── en-US/
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── release_notes.txt
    │   │   └── support_url.txt
    │   ├── primary_category.txt
    │   ├── primary_first_sub_category.txt
    │   ├── primary_second_sub_category.txt
    │   ├── review_notes.txt
    │   ├── secondary_category.txt
    │   ├── secondary_first_sub_category.txt
    │   └── secondary_second_sub_category.txt
    └── review_info.json

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

================================================
FILE: .gitignore
================================================
*.xcodeproj/project.xcworkspace
*.xcodeproj/xcuserdata
*.xcworkspace
build/
IRCCloud/config.h
IRCCloud/InfoPlist.h
IRCCloud/GoogleService-Info.plist
/*.png
/*.sh
/*.mobileprovision
/*.ipa
infer-out/
Preview.html
/*.dSYM.zip
fastlane/report.xml
fastlane/.env
screenshots/
Gemfile.lock
Podfile.lock
Pods/
.env
IRCCloud.app
IRCCloud.pkg


================================================
FILE: ARChromeActivity/ARChromeActivity.h
================================================
/*
  ARChromeActivity.h
  Copyright (c) 2012 Alex Robinson
  
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#import <UIKit/UIKit.h>

@interface ARChromeActivity : UIActivity

/// Uses the "CFBundleName" from your Info.plist by default.
@property (strong, nonatomic, nonnull) NSString *callbackSource;

/// The text beneath the icon. Defaults to "Open in Chrome".
@property (strong, nonatomic, nonnull) NSString *activityTitle;

/// Empty by default. Either set this in the initializer, or set this property. For iOS 9+, make sure you register the Chrome URL scheme in your Info.plist. See the demo project.
@property (strong, nonatomic, nullable) NSURL *callbackURL;

- (nonnull id)initWithCallbackURL:(nullable NSURL *)callbackURL;

@end


================================================
FILE: ARChromeActivity/ARChromeActivity.m
================================================
/*
  ARChromeActivity.m

  Copyright (c) 2012 Alex Robinson
 
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#import "ARChromeActivity.h"

@implementation ARChromeActivity {
    NSURL *_activityURL;
}
@synthesize activityTitle = _title;

static NSString *encodeByAddingPercentEscapes(NSString *input) {
    return [input stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!*'();:@&=+$,/?%#[] "].invertedSet];
}

- (void)commonInit {
    _callbackSource = [[NSBundle mainBundle]objectForInfoDictionaryKey:@"CFBundleName"];
    _title = @"Open in Chrome";
}

- (NSString *)activityTitle
{
    return _title;
}

- (id)init {
    self = [super init];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (id)initWithCallbackURL:(NSURL *)callbackURL {
    self = [super init];
    if (self) {
        [self commonInit];
        _callbackURL = callbackURL;
    }
    return self;
}

- (UIImage *)activityImage {
    if ([[UIImage class] respondsToSelector:@selector(imageNamed:inBundle:compatibleWithTraitCollection:)]) {
        return [UIImage imageNamed:@"ARChromeActivity" inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil];
    } else {
        return [UIImage imageNamed:@"ARChromeActivity"];
    }
}

- (NSString *)activityType {
    return NSStringFromClass([self class]);
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
    if (![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"googlechrome://"]]) {
        return NO;
    }
    if (_callbackURL && ![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"googlechrome-x-callback://"]]) {
        return NO;
    }
    for (id item in activityItems){
        if ([item isKindOfClass:NSURL.class]){
            NSURL *url = (NSURL *)item;
            if ([url.scheme isEqualToString:@"http"] || [url.scheme isEqualToString:@"https"]) {
                return YES;
            }
        }
    }
    return NO;
}

- (void)prepareWithActivityItems:(NSArray *)activityItems {
    for (id item in activityItems) {
        if ([item isKindOfClass:NSURL.class]) {
            NSURL *url = (NSURL *)item;
            if ([url.scheme isEqualToString:@"http"] || [url.scheme isEqualToString:@"https"]) {
                _activityURL = (NSURL *)item;
                return;
            }
            
        }
    }
}

- (void)performActivity {
    
    BOOL success = NO;
    
    if (_activityURL != nil) {
        
        if (self.callbackURL && self.callbackSource) {
            NSString *openingURL = encodeByAddingPercentEscapes(_activityURL.absoluteString);
            NSString *callbackURL = encodeByAddingPercentEscapes(self.callbackURL.absoluteString);
            NSString *sourceName = encodeByAddingPercentEscapes(self.callbackSource);
            
            NSURL *activityURL = [NSURL URLWithString:[NSString stringWithFormat:@"googlechrome-x-callback://x-callback-url/open/?url=%@&x-success=%@&x-source=%@", openingURL, callbackURL, sourceName]];
            [[UIApplication sharedApplication] openURL:activityURL options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:nil];
            success = YES;
        } else {
            
            NSString *scheme = _activityURL.scheme;
            
            NSString *chromeScheme = nil;
            if ([scheme isEqualToString:@"http"]) {
                chromeScheme = @"googlechrome";
            } else if ([scheme isEqualToString:@"https"]) {
                chromeScheme = @"googlechromes";
            }
            
            if (chromeScheme) {
                NSString *absoluteString = [_activityURL absoluteString];
                NSRange rangeForScheme = [absoluteString rangeOfString:@":"];
                NSString *urlNoScheme = [absoluteString substringFromIndex:rangeForScheme.location];
                NSString *chromeURLString = [chromeScheme stringByAppendingString:urlNoScheme];
                NSURL *chromeURL = [NSURL URLWithString:chromeURLString];
                
                [[UIApplication sharedApplication] openURL:chromeURL options:@{UIApplicationOpenURLOptionUniversalLinksOnly:@NO} completionHandler:nil];
                success = YES;
            }
        }
    }
    
    [self activityDidFinish:success];
}

@end


================================================
FILE: CSURITemplate/CSURITemplate.h
================================================
//
//  CSURITemplate.h
//  CSURITemplate
//
//  Created by Will Harris on 26/02/2013.
//  Copyright (c) 2013 Cogenta Systems Ltd. All rights reserved.
//

#import <Foundation/Foundation.h>

/**
 The domain of errors returned by `CSURITemplate` objects.
 */
extern NSString *const CSURITemplateErrorDomain;

typedef NS_ENUM(NSInteger, CSURITemplateError) {
    // Parsing Errors
    CSURITemplateErrorExpressionClosedButNeverOpened    = 100,
    CSURITemplateErrorExpressionOpenedButNeverClosed    = 101,
    CSURITemplateErrorInvalidOperator                   = 102,
    CSURITemplateErrorUnknownOperator                   = 103,
    CSURITemplateErrorInvalidVariableKey                = 104,
    CSURITemplateErrorInvalidVariableModifier           = 105,
    
    // Expansion Errors
    CSURITemplateErrorNoVariables                       = 200,
    CSURITemplateErrorInvalidExpansionValue             = 201
};

/**
 An `NSNumber` value in the `userInfo` dictionary of errors returned while parsing a URI template that indicates 
 the position in the string at which the error was encountered.
 */
extern NSString *const CSURITemplateErrorScanLocationErrorKey;

/**
 Expand URI Templates.
 
 This class implements Level 4 of the URI Template specification, defined by
 [RFC6570: URI Template](http://tools.ietf.org/html/rfc6570). URI Templates are
 a compact string representation of a set of URIs.
 
 Each CSURITemplate instance has a single URI Template. The URI template can be
 expanded into a URI reference by invoking the instance's URIWithVariables: with
 a dictionary of variables.
 
 For example:
 
     NSError *error = nil;
     CSURITemplate *template = [CSURITemplate URITemplateWithString:@"/search{?q}" error:&error];
     NSString *uri1 = [template relativeStringWithVariables:@{@"q": @"hateoas"}];
     NSString *uri2 = [template relativeStringWithVariables:@{@"q": @"hal"}];
     assert([uri1 isEqualToString:@"/search?q=hateoas"]);
     assert([uri2 isEqualToString:@"/search?q=hal"]);
 
 */
@interface CSURITemplate : NSObject

///---------------------------------
/// @name Initializing URI Templates
///---------------------------------

/**
 Creates and returns a URI template object initialized with the given template string.
 
 @param templateString The RFC6570 conformant string with which to initialize the URI template object.
 @param error A pointer to an `NSError` object. If parsing the URI template string fails then the error will 
    be set to an instance of `NSError` that describes the problem.
 @return A new URI template object, or `nil` if the template string could not be parsed.
 */
+ (instancetype)URITemplateWithString:(NSString *)templateString error:(NSError **)error;

/**
 The URI template string that was used to initialize the receiver.
 */
@property (nonatomic, copy, readonly) NSString *templateString;

/**
 *  The keys of the variable terms in the receiver
 */
@property (nonatomic, readonly) NSArray *keysOfVariables;

///--------------------------------------------
/// @name Expanding the Template with Variables
///--------------------------------------------

/** 
 Expands the template with the given variables.
 
 This method expands the URI template using the variables provided and returns a string.
 If the URI template is valid but has no valid expansion for the given variables, then `nil` is returned and an `error` is set.
 For example, if the URI template is `"{keys:1}"` and `variables` is `{@"semi":@";",@"dot":@".",@"comma":@","}`, 
 this method will return nil because the prefix modifier is not applicable to composite values.
 
 @param variables a dictionary of variables to use when expanding the template.
 @param error A pointer to an `NSError` object. If an error occurs while expanding the template then the error will
    be set to an instance of `NSError` that describes the problem.
 @returns A string containing the expanded URI reference, or nil if an error was encountered.
 */
- (NSString *)relativeStringWithVariables:(NSDictionary *)variables error:(NSError **)error;

/**
 Expands the template with the given variables and constructs a new URL relative to the given base URL.
 
 This method expands the URI template using the variables provided and then constructs a new URL object relative to 
 the base URL provided. If the URI template is valid but has no valid expansion for the given variables, then `nil` is returned 
 and an `error` is set. For example, if the URI template is `"{keys:1}"` and `variables` is `{@"semi":@";",@"dot":@".",@"comma":@","}`,
 this method will return nil because the prefix modifier is not applicable to composite values.
 
 @param variables a dictionary of variables to use when expanding the template.
 @param error A pointer to an `NSError` object. If an error occurs while expanding the template then the error will
    be set to an instance of `NSError` that describes the problem.
 @returns A URL constructed by evaluating the expanded template relative to the given baseURL, or nil if an error was encountered.
 */
- (NSURL *)URLWithVariables:(NSDictionary *)variables relativeToBaseURL:(NSURL *)baseURL error:(NSError **)error;

@end

@interface CSURITemplate (Deprecations)
- (id)initWithURITemplate:(NSString *)URITemplate __attribute__((deprecated ("Use `URITemplateWithString:error:` instead")));
- (NSString *)URIWithVariables:(NSDictionary *)variables __attribute__((deprecated ("Use `relativeStringWithVariables:error:` instead")));;
@end


================================================
FILE: CSURITemplate/CSURITemplate.m
================================================
//
//  CSURITemplate.m
//  CSURITemplate
//
//  Created by Will Harris on 26/02/2013.
//  Copyright (c) 2013 Cogenta Systems Ltd. All rights reserved.
//

#import "CSURITemplate.h"

NSString *const CSURITemplateErrorDomain = @"com.cogenta.CSURITemplate.errors";
NSString *const CSURITemplateErrorScanLocationErrorKey = @"location";

@protocol CSURITemplateTerm <NSObject>

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError **)error;

@end

@protocol CSURITemplateEscaper <NSObject>

- (NSString *)escapeItem:(id)item;

@end

@protocol CSURITemplateVariable <NSObject>

@property (nonatomic, readonly) NSString *key;
- (NSArray *)valuesWithVariables:(NSDictionary *)variables escaper:(id<CSURITemplateEscaper>)escaper error:(NSError **)error;
- (BOOL)enumerateKeyValuesWithVariables:(NSDictionary *)variables
                                escaper:(id<CSURITemplateEscaper>)escaper
                                  error:(NSError **)error
                                  block:(void (^)(NSString *key, NSString *value))block;

@end

@interface CSURITemplateEscaping : NSObject

+ (NSObject<CSURITemplateEscaper> *)uriEscaper;
+ (NSObject<CSURITemplateEscaper> *)fragmentEscaper;

@end

@interface CSURITemplateURIEscaper : NSObject <CSURITemplateEscaper>

@end

@interface CSURITemplateFragmentEscaper : NSObject <CSURITemplateEscaper>

@end

@implementation CSURITemplateEscaping

+ (NSObject<CSURITemplateEscaper> *)uriEscaper
{
    return [[CSURITemplateURIEscaper alloc] init];
}

+ (NSObject<CSURITemplateEscaper> *)fragmentEscaper
{
    return [[CSURITemplateFragmentEscaper alloc] init];
}

@end

@interface NSObject (URITemplateAdditions)

- (NSString *)csuri_stringEscapedForURI;
- (NSString *)csuri_stringEscapedForFragment;
- (NSString *)csuri_basicString;
- (NSArray *)csuri_explodedItems;
- (NSArray *)csuri_explodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper;
- (NSString *)csuri_escapeWithEscaper:(id<CSURITemplateEscaper>)escaper;
- (void)csuri_enumerateExplodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper
                                      defaultKey:(NSString *)key
                                           block:(void (^)(NSString *key, NSString *value))block;
@end

@implementation CSURITemplateURIEscaper

- (NSString *)escapeItem:(NSObject *)item
{
    return [item csuri_stringEscapedForURI];
}

@end

@implementation CSURITemplateFragmentEscaper

- (NSString *)escapeItem:(NSObject *)item
{
    return [item csuri_stringEscapedForFragment];
}

@end

@implementation NSObject (URITemplateAdditions)

- (NSString *)csuri_escapeWithEscaper:(id<CSURITemplateEscaper>)escaper
{
    return [escaper escapeItem:self];
}

- (NSString *)csuri_stringEscapedForURI
{
    return [[self csuri_basicString] csuri_stringEscapedForURI];
}

- (NSString *)csuri_stringEscapedForFragment
{
    return [[self csuri_basicString] csuri_stringEscapedForFragment];
}

- (NSString *)csuri_basicString
{
    return [self description];
}

- (NSArray *)csuri_explodedItems
{
    return [NSArray arrayWithObject:self];
}

- (NSArray *)csuri_explodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper
{
    NSMutableArray *result = [NSMutableArray array];
    for (id value in [self csuri_explodedItems]) {
        [result addObject:[value csuri_escapeWithEscaper:escaper]];
    }
    return [NSArray arrayWithArray:result];
}

- (void)csuri_enumerateExplodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper
                                      defaultKey:(NSString *)key
                                           block:(void (^)(NSString *, NSString *))block
{
    for (NSString *value in [self csuri_explodedItemsEscapedWithEscaper:escaper]) {
        block(key, value);
    }
}

@end

@implementation NSString (URITemplateAdditions)

- (NSString *)csuri_stringEscapedForURI
{
    return [self stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet];
}

- (NSString *)csuri_stringEscapedForFragment
{
    return [self stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLFragmentAllowedCharacterSet];
}

- (NSString *)csuri_basicString
{
    return self;
}

@end

@implementation NSArray (URITemplateAdditions)

- (NSString *)csuri_stringEscapedForURI
{
    NSMutableArray *result = [NSMutableArray array];
    for (id item in self) {
        [result addObject:[item csuri_stringEscapedForURI]];
    }
    return [result componentsJoinedByString:@","];
}


- (NSString *)csuri_stringEscapedForFragment
{
    NSMutableArray *result = [NSMutableArray array];
    for (id item in self) {
        [result addObject:[item csuri_stringEscapedForFragment]];
    }
    return [result componentsJoinedByString:@","];
}

- (NSString *)csuri_basicString
{
    NSMutableArray *result = [NSMutableArray array];
    for (id item in self) {
        [result addObject:[item csuri_basicString]];
    }
    return [result componentsJoinedByString:@","];
}

- (NSArray *)csuri_explodedItems
{
    return self;
}

@end

@implementation NSDictionary (URITemplateAdditions)

- (NSString *)csuri_stringEscapedForURI
{
    NSMutableArray *result = [NSMutableArray array];
    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [result addObject:[key csuri_stringEscapedForURI]];
        [result addObject:[obj csuri_stringEscapedForURI]];
    }];
    return [result componentsJoinedByString:@","];
}

- (NSString *)csuri_stringEscapedForFragment
{
    NSMutableArray *result = [NSMutableArray array];
    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [result addObject:[key csuri_stringEscapedForFragment]];
        [result addObject:[obj csuri_stringEscapedForFragment]];
    }];
    return [result componentsJoinedByString:@","];
}

- (NSString *)csuri_basicString
{
    NSMutableArray *result = [NSMutableArray array];
    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [result addObject:[key csuri_basicString]];
        [result addObject:[obj csuri_basicString]];
    }];
    return [result componentsJoinedByString:@","];
}

- (NSArray *)csuri_explodedItems
{
    NSMutableArray *result = [NSMutableArray array];
    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [result addObject:key];
        [result addObject:obj];
    }];
    return [NSArray arrayWithArray:result];
}

- (NSArray *)csuri_explodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper
{
    NSMutableArray *result = [NSMutableArray array];
    [self csuri_enumerateExplodedItemsEscapedWithEscaper:escaper
                                        defaultKey:nil
                                             block:^(NSString *k, NSString *v)
    {
        [result addObject:[NSString stringWithFormat:@"%@=%@", k, v]];
    }];
    return [NSArray arrayWithArray:result];
}

- (void)csuri_enumerateExplodedItemsEscapedWithEscaper:(id<CSURITemplateEscaper>)escaper
                                      defaultKey:(NSString *)defaultKey
                                           block:(void (^)(NSString *, NSString *))block
{
    [self enumerateKeysAndObjectsUsingBlock:^(id k, id obj, BOOL *stop) {
        block([k csuri_escapeWithEscaper:escaper],
              [obj csuri_escapeWithEscaper:escaper]);
    }];
}

@end

@implementation NSNull (URITemplateDescriptions)

- (NSArray *)csuri_explodedItems
{
    return [NSArray array];
}

@end

#pragma mark -

@interface CSURITemplateLiteralTerm : NSObject <CSURITemplateTerm>

@property (nonatomic, strong) NSString *literal;

- (id)initWithLiteral:(NSString *)literal;

@end

@implementation CSURITemplateLiteralTerm

@synthesize literal;

- (id)initWithLiteral:(NSString *)aLiteral
{
    self = [super init];
    if (self) {
        literal = aLiteral;
    }
    return self;
}

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError *__autoreleasing *)error
{
    return literal;
}

@end

@interface CSURITemplateInfixExpressionTerm : NSObject <CSURITemplateTerm>

@property (nonatomic, strong) NSArray *variablesExpression;
- (id)initWithVariables:(NSArray *)variables;
- (NSString *)infix;
- (NSString *)prepend;

@end

@implementation CSURITemplateInfixExpressionTerm

@synthesize variablesExpression;

- (id)initWithVariables:(NSArray *)theVariables
{
    self = [super init];
    if (self) {
        variablesExpression = theVariables;
    }
    return self;
}

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping uriEscaper];
}

- (NSString *)prepend
{
    return @"";
}

- (NSString *)infix
{
    return @"";
}

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError *__autoreleasing *)error
{
    BOOL isFirst = YES;
    NSMutableString *result = [NSMutableString string];
    for (NSObject<CSURITemplateVariable> *variable in variablesExpression) {
        NSArray *values = [variable valuesWithVariables:variables
                                                escaper:[self escaper]
                                                  error:error];
        if ( ! values) {
            // An error was encountered expanding the variable.
            return nil;
        }
        
        for (NSString *value in values) {
            if (isFirst) {
                isFirst = NO;
                [result appendString:[self prepend]];
            } else {
                [result appendString:[self infix]];
            }
            
            [result appendString:value];
        }
    }
    
    return [NSString stringWithString:result];
}

@end

@interface CSURITemplateCommaExpressionTerm : CSURITemplateInfixExpressionTerm

@end

@implementation CSURITemplateCommaExpressionTerm

- (NSString *)infix
{
    return @",";
}

@end

@interface CSURITemplatePrependExpressionTerm : NSObject <CSURITemplateTerm>

@property (nonatomic, strong) NSArray *variablesExpression;

- (id)initWithVariables:(NSArray *)variables;

@end

@implementation CSURITemplatePrependExpressionTerm

@synthesize variablesExpression;

- (id)initWithVariables:(NSArray *)theVariables
{
    self = [super init];
    if (self) {
        variablesExpression = theVariables;
    }
    return self;
}

- (NSString *)prepend
{
    return @"";
}

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping uriEscaper];
}

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError *__autoreleasing *)error
{
    NSMutableString *result = [NSMutableString string];
    for (NSObject<CSURITemplateVariable> *variable in variablesExpression) {
        for (NSString *value in [variable valuesWithVariables:variables
                                                      escaper:[self escaper]
                                                        error:error]) {
            [result appendString:[self prepend]];
            [result appendString:value];
        }
    }
    
    return [NSString stringWithString:result];
}


@end

@interface CSURITemplateSolidusExpressionTerm : CSURITemplatePrependExpressionTerm

@end

@implementation CSURITemplateSolidusExpressionTerm

- (NSString *)prepend
{
    return @"/";
}

@end


@interface CSURITemplateDotExpressionTerm : CSURITemplatePrependExpressionTerm

@end

@implementation CSURITemplateDotExpressionTerm

- (NSString *)prepend
{
    return @".";
}

@end


@interface CSURITemplateHashExpressionTerm : CSURITemplateCommaExpressionTerm

@end

@implementation CSURITemplateHashExpressionTerm

- (NSString *)prepend
{
    return @"#";
}

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping fragmentEscaper];
}

@end

@interface CSURITemplateQueryExpressionTerm : NSObject <CSURITemplateTerm>

@property (nonatomic, strong) NSArray *variablesExpression;
- (id)initWithVariables:(NSArray *)variables;
- (NSString *)prepend;

@end

@implementation CSURITemplateQueryExpressionTerm

@synthesize variablesExpression;

- (id)initWithVariables:(NSArray *)theVariables
{
    self = [super init];
    if (self) {
        variablesExpression = theVariables;
    }
    return self;
}

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping uriEscaper];
}

- (NSString *)prepend
{
    return @"?";
}

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError *__autoreleasing *)error
{
    __block BOOL isFirst = YES;
    NSMutableString *result = [NSMutableString string];
    for (NSObject<CSURITemplateVariable> *variable in variablesExpression) {
        BOOL success = [variable enumerateKeyValuesWithVariables:variables
                                                         escaper:[self escaper]
                                                           error:error
                                                           block:^(NSString *key, NSString *value) {
            
            if (isFirst) {
                isFirst = NO;
                [result appendString:[self prepend]];
            } else {
                [result appendString:@"&"];
            }
            
            [result appendString:key];
            [result appendString:@"="];
            [result appendString:value];
        }];
        
        if ( ! success) return nil;
    }
    
    return [NSString stringWithString:result];
}

@end

@interface CSURITemplateParameterExpressionTerm : NSObject <CSURITemplateTerm>

@property (nonatomic, strong) NSArray *variablesExpression;
- (id)initWithVariables:(NSArray *)variables;

@end

@implementation CSURITemplateParameterExpressionTerm

@synthesize variablesExpression;

- (id)initWithVariables:(NSArray *)theVariables
{
    self = [super init];
    if (self) {
        variablesExpression = theVariables;
    }
    return self;
}

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping uriEscaper];
}

- (NSString *)expandWithVariables:(NSDictionary *)variables error:(NSError *__autoreleasing *)error
{
    NSMutableString *result = [NSMutableString string];
    for (NSObject<CSURITemplateVariable> *variable in variablesExpression) {
        BOOL success = [variable enumerateKeyValuesWithVariables:variables escaper:[self escaper] error:error block:^(NSString *key, NSString *value) {
             [result appendString:@";"];
             
             [result appendString:key];
             
             if ( ! [value isEqualToString:@""]) {
                 [result appendString:@"="];
                 [result appendString:value];
             }
         }];
        
        if ( ! success) return nil;
    }
    
    return [NSString stringWithString:result];
}

@end

@interface CSURITemplateReservedExpressionTerm : CSURITemplateCommaExpressionTerm

@end

@implementation CSURITemplateReservedExpressionTerm

- (id<CSURITemplateEscaper>)escaper
{
    return [CSURITemplateEscaping fragmentEscaper];
}

@end

@interface CSURITemplateQueryContinuationExpressionTerm : CSURITemplateQueryExpressionTerm

@end

@implementation CSURITemplateQueryContinuationExpressionTerm

- (NSString *)prepend
{
    return @"&";
}

@end

#pragma mark -

@interface CSURITemplateUnmodifiedVariable : NSObject <CSURITemplateVariable>

- (id)initWithKey:(NSString *)key;

@end

@implementation CSURITemplateUnmodifiedVariable

@synthesize key;

- (id)initWithKey:(NSString *)aKey
{
    self = [super init];
    if (self) {
        key = aKey;
    }
    return self;
}

- (NSArray *)valuesWithVariables:(NSDictionary *)variables escaper:(id<CSURITemplateEscaper>)escaper error:(NSError *__autoreleasing *)error
{
    id value = [variables objectForKey:key];
    if ( ! value || (NSNull *) value == [NSNull null]) {
        return [NSArray array];
    }
    
    if ([value isKindOfClass:[NSArray class]] && [(NSArray *)value count] == 0) {
        return [NSArray array];
    }
    
    NSMutableArray *result = [NSMutableArray array];
    NSString *escaped = [value csuri_escapeWithEscaper:escaper];
    [result addObject:escaped];
    
    return [NSArray arrayWithArray:result];
}

- (BOOL)enumerateKeyValuesWithVariables:(NSDictionary *)variables
                                escaper:(id<CSURITemplateEscaper>)escaper
                                  error:(NSError *__autoreleasing *)error
                                  block:(void (^)(NSString *, NSString *))block
{
    id value = [variables objectForKey:key];
    if ( ! value || (NSNull *) value == [NSNull null]) {
        return YES;
    }
    
    if ([value isEqual:@[]]) {
        block(key, @"");
        return YES;
    }
    
    NSString *escaped = [value csuri_escapeWithEscaper:escaper];
    block(key, escaped);
    return YES;
}

@end

@interface CSURITemplateExplodedVariable : NSObject <CSURITemplateVariable>

- (id)initWithKey:(NSString *)key;

@end

@implementation CSURITemplateExplodedVariable

@synthesize key;

- (id)initWithKey:(NSString *)aKey
{
    self = [super init];
    if (self) {
        key = aKey;
    }
    return self;
}

- (NSArray *)valuesWithVariables:(NSDictionary *)variables escaper:(id<CSURITemplateEscaper>)escaper error:(NSError *__autoreleasing *)error
{
    id values = [variables objectForKey:key];
    if ( ! values) {
        return [NSArray array];
    }
    
    NSMutableArray *result = [NSMutableArray array];
    
    for (id value in [values csuri_explodedItemsEscapedWithEscaper:escaper]) {
        [result addObject:value];
    }
    
    return [NSArray arrayWithArray:result];
}

- (BOOL)enumerateKeyValuesWithVariables:(NSDictionary *)variables
                                escaper:(id<CSURITemplateEscaper>)escaper
                                  error:(NSError *__autoreleasing *)error
                                  block:(void (^)(NSString *, NSString *))block
{
    id values = [variables objectForKey:key];
    if ( ! values) {
        return YES;
    }
    
    [values csuri_enumerateExplodedItemsEscapedWithEscaper:escaper
                                          defaultKey:key
                                               block:block];
    return YES;
}

@end

@interface CSURITemplatePrefixedVariable : NSObject <CSURITemplateVariable>

@property (nonatomic, assign) NSUInteger maxLength;

- (id)initWithKey:(NSString *)key maxLength:(NSUInteger)maxLength;

@end

@implementation CSURITemplatePrefixedVariable

@synthesize key;
@synthesize maxLength;

- (id)initWithKey:(NSString *)aKey maxLength:(NSUInteger)aMaxLength
{
    self = [super init];
    if (self) {
        key = aKey;
        maxLength = aMaxLength;
    }
    return self;
}

- (NSArray *)valuesWithVariables:(NSDictionary *)variables escaper:(id<CSURITemplateEscaper>)escaper error:(NSError *__autoreleasing *)error
{
    id value = [variables objectForKey:key];
    
    if ( ! [value isKindOfClass:[NSString class]]) {
        NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Variables with a maximum length modifier can only be expanded with string values, but a value of type '%@' given.", nil), [value class]];
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"An unexpandable value was given for a template variable.", nil), NSLocalizedFailureReasonErrorKey: failureReason };
        if (error) *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidExpansionValue userInfo:userInfo];
        return nil;
    }
    
    if ( ! value || (NSNull *) value == [NSNull null]) {
        return [NSArray array];
    }

    NSMutableArray *result = [NSMutableArray array];
    NSString *description = [value csuri_basicString];
    if (maxLength <= [description length]) {
        description = [description substringToIndex:maxLength];
    }
    
    [result addObject:[description csuri_escapeWithEscaper:escaper]];
    
    return [NSArray arrayWithArray:result];
}

- (BOOL)enumerateKeyValuesWithVariables:(NSDictionary *)variables
                                escaper:(id<CSURITemplateEscaper>)escaper
                                  error:(NSError *__autoreleasing *)error
                                  block:(void (^)(NSString *, NSString *))block
{
    NSArray *values = [self valuesWithVariables:variables escaper:escaper error:error];
    if ( ! values) {
        // An error was encountered expanding the variables.
        return NO;
    }
    
    for (NSString *value in values) {
        block(key, value);
    }
    return YES;
}

@end

#pragma mark -

@interface CSURITemplate ()

@property (nonatomic, copy, readwrite) NSString *templateString;
@property (nonatomic, copy, readwrite) NSURL *baseURL;
@property (nonatomic, strong) NSMutableArray *terms;

@end

@implementation CSURITemplate

+ (instancetype)URITemplateWithString:(NSString *)templateString error:(NSError **)error
{
    CSURITemplate *URITemplate = [[self alloc] initWithTemplateString:templateString];
    BOOL success = [URITemplate parseTemplate:error];
    return success ? URITemplate : nil;
}

+ (instancetype)URITemplateWithString:(NSString *)templateString relativeToURL:(NSURL *)baseURL error:(NSError **)error
{
    CSURITemplate *URITemplate = [self URITemplateWithString:templateString error:error];
    URITemplate.baseURL = baseURL;
    return URITemplate;
}

- (id)initWithTemplateString:(NSString *)templateString
{
    self = [super init];
    if (self) {
        self.templateString = templateString;
        self.terms = [NSMutableArray array];
    }
    return self;
}

- (id)init
{
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Failed to call designated initializer. Invoke `URITemplateWithString:error:` or `URITemplateWithString:relativeToURL:error:` instead" userInfo:nil];
}

- (NSObject<CSURITemplateVariable> *)variableWithVarspec:(NSString *)varspec error:(NSError **)error
{
    NSParameterAssert(varspec);
    NSParameterAssert(error);
    if ([varspec rangeOfString:@"$"].location != NSNotFound) {
        // Varspec contains a forbidden character.
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The template contains an invalid variable key.", nil),
                                    NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"A variable key containing the forbidden character '$' was encountered.", nil) };
        *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidVariableKey userInfo:userInfo];
        return nil;
    }
    NSMutableCharacterSet *varchars = [NSMutableCharacterSet alphanumericCharacterSet];
    [varchars addCharactersInString:@"._%"];
                                
    NSCharacterSet *modifierStartCharacters = [NSCharacterSet characterSetWithCharactersInString:@":*"];
    NSScanner *scanner = [NSScanner scannerWithString:varspec];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]];
    NSString *key = nil;
    [scanner scanCharactersFromSet:varchars intoString:&key];
    
    NSString *modifierStart = nil;
    [scanner scanCharactersFromSet:modifierStartCharacters intoString:&modifierStart];
    
    if ([modifierStart isEqualToString:@"*"]) {
        // Modifier is explode.

        if ( ! [scanner isAtEnd]) {
            // There were extra characters after the explode modifier.
            NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Extra characters were found after the explode modifier ('*') for the variable '%@'.", nil), key];
            NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The template contains an invalid variable modifier.", nil),
                                        NSLocalizedFailureReasonErrorKey: failureReason };
            *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidVariableModifier userInfo:userInfo];
            return nil;
        }
        
        return [[CSURITemplateExplodedVariable alloc] initWithKey:key];
    } else if ([modifierStart isEqualToString:@":"]) {
        // Modifier is prefix.
        NSCharacterSet *oneToNine = [NSCharacterSet characterSetWithCharactersInString:@"123456789"];
        NSCharacterSet *zeroToNine = [NSCharacterSet decimalDigitCharacterSet];
        NSString *firstDigit = @"";
        if ( ! [scanner scanCharactersFromSet:oneToNine intoString:&firstDigit]) {
            // The max-chars does not start with a valid digit.
            NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"The variable '%@' was followed by the maximum length modifier (':'), but the maximum length argument was prefixed with an invalid character.", nil), key];
            NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The template contains an invalid variable modifier.", nil),
                                        NSLocalizedFailureReasonErrorKey: failureReason };
            *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidVariableModifier userInfo:userInfo];
            return nil;
        }
        NSString *restDigits = @"";
        [scanner scanCharactersFromSet:zeroToNine intoString:&restDigits];
        NSString *digits = [firstDigit stringByAppendingString:restDigits];
        
        if ( ! [scanner isAtEnd]) {
            // The max-chars is not entirely digits.
            NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"The variable '%@' was followed by the maximum length modifier (':'), but the maximum length argument is not numeric.", nil), key];
            NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The template contains an invalid variable modifier.", nil),
                                        NSLocalizedFailureReasonErrorKey: failureReason };
            *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidVariableModifier userInfo:userInfo];
            return nil;
        }

        NSUInteger maxLength = (NSUInteger)ABS([digits integerValue]);
        return [[CSURITemplatePrefixedVariable alloc] initWithKey:key
                                                        maxLength:maxLength];
    } else {
        // No modifier.
        
        if ( ! [scanner isAtEnd]) {
            // There were extra characters after the key.
            NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"The variable key '%@' is invalid.", nil), varspec];
            NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The template contains an invalid variable key.", nil),
                                        NSLocalizedFailureReasonErrorKey: failureReason };
            *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidVariableKey userInfo:userInfo];
            return nil;
        }
        
        return [[CSURITemplateUnmodifiedVariable alloc] initWithKey:key];
    }
    
    return nil;
}

- (NSArray *)variablesWithVariableList:(NSString *)variableList error:(NSError **)error
{
    NSParameterAssert(variableList);
    NSParameterAssert(error);
    NSMutableArray *variables = [NSMutableArray array];
    NSScanner *scanner = [NSScanner scannerWithString:variableList];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]];

    while ( ! [scanner isAtEnd]) {
        NSString *varspec = nil;
        [scanner scanUpToString:@"," intoString:&varspec];
        [scanner scanString:@"," intoString:NULL];
        NSObject<CSURITemplateVariable> *variable = [self variableWithVarspec:varspec error:error];
        if ( ! variable) {
            // An error was encountered parsing the varspec.
            return nil;
        }
        [variables addObject:variable];
    }
    return variables;
}

- (NSObject<CSURITemplateTerm> *)termWithOperator:(NSString *)operator
                                     variableList:(NSString *)variableList
                                            error:(NSError **)error
{
    NSParameterAssert(variableList);
    NSParameterAssert(error);
    if ([operator length] > 1) {
        // The term has an invalid operator.
        NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"An operator was encountered with a length greater than 1 character ('%@').", nil), operator];
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"An invalid operator was encountered.", nil),
                                    NSLocalizedFailureReasonErrorKey : failureReason };
        *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorInvalidOperator userInfo:userInfo];
        return nil;
    }
    
    NSArray *variables = [self variablesWithVariableList:variableList error:error];
    if ( ! variables) {
        // An error was encountered parsing a variable.
        return nil;
    }
    
    if ([operator isEqualToString:@"/"]) {
        return [[CSURITemplateSolidusExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@"."]) {
        return [[CSURITemplateDotExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@"#"]) {
        return [[CSURITemplateHashExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@"?"]) {
        return [[CSURITemplateQueryExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@";"]) {
        return [[CSURITemplateParameterExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@"+"]) {
        return [[CSURITemplateReservedExpressionTerm alloc] initWithVariables:variables];
    } else if ([operator isEqualToString:@"&"]) {
        return [[CSURITemplateQueryContinuationExpressionTerm alloc] initWithVariables:variables];
    } else if ( ! operator) {
        return [[CSURITemplateCommaExpressionTerm alloc] initWithVariables:variables];
    } else {
        // The operator is unknown or reserved.
        NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"The URI template specification does not include an operator for the character '%@'.", nil), operator];
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"An unknown operator was encountered.", nil),
                                    NSLocalizedFailureReasonErrorKey : failureReason };
        *error = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorUnknownOperator userInfo:userInfo];
        return nil;
    }
}

- (NSObject<CSURITemplateTerm> *)termWithExpression:(NSString *)expression error:(NSError **)error
{
    NSCharacterSet *operators = [NSCharacterSet characterSetWithCharactersInString:@"+#./;?&=,!@|"];
    NSScanner *scanner = [NSScanner scannerWithString:expression];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]];

    NSString *operator = nil;
    [scanner scanCharactersFromSet:operators intoString:&operator];
    return [self termWithOperator:operator
                     variableList:[expression substringFromIndex:scanner.scanLocation]
                            error:error];
}

- (BOOL)parseTemplate:(NSError **)error
{
    NSError *parsingError = nil;
    NSScanner *scanner = [NSScanner scannerWithString:self.templateString];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]];
    while ( ! [scanner isAtEnd]) {
        NSCharacterSet *curlyBrackets = [NSCharacterSet
                                         characterSetWithCharactersInString:@"{}"];
        NSString *literal = nil;
        if ([scanner scanUpToCharactersFromSet:curlyBrackets
                                    intoString:&literal]) {
            CSURITemplateLiteralTerm *term = [[CSURITemplateLiteralTerm alloc]
                                                 initWithLiteral:literal];
            [self.terms addObject:term];
        }
        
        NSString *curlyBracket = nil;
        [scanner scanCharactersFromSet:curlyBrackets intoString:&curlyBracket];
        if ([curlyBracket isEqualToString:@"}"]) {
            // An expression was closed but not opened.
            NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"An expression was closed that was never opened.", nil),
                                        NSLocalizedFailureReasonErrorKey : NSLocalizedString(@"A closing '}' character was encountered that was not preceeded by an opening '{' character.", nil),
                                        CSURITemplateErrorScanLocationErrorKey: @(scanner.scanLocation) };
            parsingError = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorExpressionClosedButNeverOpened userInfo:userInfo];
            break;
        }
        
        NSString *expression = nil;
        if ([scanner scanUpToString:@"}" intoString:&expression]) {
            if ( ! [scanner scanString:@"}" intoString:NULL]) {
                // An expression was opened not closed.
                NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"An expression was opened but never closed.", nil),
                                            NSLocalizedFailureReasonErrorKey : NSLocalizedString(@"An opening '{' character was never terminated by  '}' character.", nil),
                                            CSURITemplateErrorScanLocationErrorKey: @(scanner.scanLocation) };
                parsingError = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorExpressionOpenedButNeverClosed userInfo:userInfo];
                break;
            }
            
            NSObject<CSURITemplateTerm> *term = [self termWithExpression:expression error:&parsingError];
            if ( ! term) {
                // An error was encountered parsing the term expression. Include the scan location in the error
                NSMutableDictionary *mutableUserInfo = [[parsingError userInfo] mutableCopy];
                mutableUserInfo[CSURITemplateErrorScanLocationErrorKey] = @(scanner.scanLocation);
                break;
            }
            
            [self.terms addObject:term];
        }
    }
    
    if (parsingError && error) *error = parsingError;
    return parsingError ? NO : YES;
}

- (NSString *)relativeStringWithVariables:(NSDictionary *)variables error:(NSError **)error
{
    NSError *expansionError = nil;
    if ( ! variables) {
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"A template cannot be expanded without a dictionary of variables.", nil) };
        expansionError = [NSError errorWithDomain:CSURITemplateErrorDomain code:CSURITemplateErrorNoVariables userInfo:userInfo];
        if (error) *error = expansionError;
        return nil;
    }
    NSMutableString *result = [NSMutableString string];
    BOOL errorEncountered = NO;
    for (NSObject<CSURITemplateTerm> *term in self.terms) {
        NSString *value = [term expandWithVariables:variables error:&expansionError];
        if ( ! value) {
            // An error was encountered expanding the term.
            errorEncountered = YES;
            break;
        }
        [result appendString:value];
    }
    if (expansionError && error) *error = expansionError;
    return errorEncountered ? nil : [result copy];
}

- (NSURL *)URLWithVariables:(NSDictionary *)variables relativeToBaseURL:(NSURL *)baseURL error:(NSError **)error
{
    NSString *expandedTemplate = [self relativeStringWithVariables:variables error:error];
    if ( ! expandedTemplate) return nil;
    return [NSURL URLWithString:expandedTemplate relativeToURL:baseURL];
}

- (NSArray *)keysOfVariables
{
    NSMutableArray *keys = [NSMutableArray arrayWithCapacity:self.terms.count];
    for (id <CSURITemplateTerm> term in self.terms) {
        if (![term respondsToSelector:@selector(variablesExpression)]) continue;
        for (id <CSURITemplateVariable> variable in [term performSelector:@selector(variablesExpression)]) {
            [keys addObject:variable.key];
        }
    }
    return keys;
}

- (NSString *)description
{
    return [NSString stringWithFormat:@"<%@: %p templateString=\"%@\"", self.class, self, self.templateString];
}

@end

@implementation CSURITemplate (Deprecations)

- (id)initWithURITemplate:(NSString *)URITemplate
{
    self = [self initWithTemplateString:URITemplate];
    BOOL success = [self parseTemplate:nil];
    return success ? self : nil;
}

- (NSString *)URIWithVariables:(NSDictionary *)variables
{
    return [self relativeStringWithVariables:variables ?: @{} error:nil];
}

@end


================================================
FILE: ECSlidingViewController/ECSlidingViewController.h
================================================
//
//  ECSlidingViewController.h
//  ECSlidingViewController
//
//  Created by Michael Enriquez on 1/23/12.
//  Copyright (c) 2012 EdgeCase. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "UIImage+ImageWithUIView.h"

/** Notification that gets posted when the underRight view will appear */
extern NSString *const ECSlidingViewUnderRightWillAppear;

/** Notification that gets posted when the underLeft view will appear */
extern NSString *const ECSlidingViewUnderLeftWillAppear;

/** Notification that gets posted when the underLeft view will disappear */
extern NSString *const ECSlidingViewUnderLeftWillDisappear;

/** Notification that gets posted when the underRight view will disappear */
extern NSString *const ECSlidingViewUnderRightWillDisappear;

/** Notification that gets posted when the top view is anchored to the left side of the screen */
extern NSString *const ECSlidingViewTopDidAnchorLeft;

/** Notification that gets posted when the top view is anchored to the right side of the screen */
extern NSString *const ECSlidingViewTopDidAnchorRight;

/** Notification that gets posted when the top view will be centered on the screen */
extern NSString *const ECSlidingViewTopWillReset;

/** Notification that gets posted when the top view is centered on the screen */
extern NSString *const ECSlidingViewTopDidReset;

/** @constant ECViewWidthLayout width of under views */
typedef enum {
  /** Under view will take up the full width of the screen */
  ECFullWidth,
  /** Under view will have a fixed width equal to anchorRightRevealAmount or anchorLeftRevealAmount. */
  ECFixedRevealWidth,
  /** Under view will have a variable width depending on rotation equal to the screen's width - anchorRightPeekAmount or anchorLeftPeekAmount. */
  ECVariableRevealWidth
} ECViewWidthLayout;

/** @constant ECSide side of screen */
typedef enum {
  /** Left side of screen */
  ECLeft,
  /** Right side of screen */
  ECRight
} ECSide;

/** @constant ECResetStrategy top view behavior while anchored. */
typedef enum {
  /** No reset strategy will be used */
  ECNone = 0,
  /** Tapping the top view will reset it */
  ECTapping = 1 << 0,
  /** Panning will be enabled on the top view. If it is panned and released towards the reset position it will reset, otherwise it will slide towards the anchored position. */
  ECPanning = 1 << 1
} ECResetStrategy;

/** ECSlidingViewController is a view controller container that presents its child view controllers in two layers. The top layer can be panned to reveal the layers below it. */
@interface ECSlidingViewController : UIViewController<UIGestureRecognizerDelegate> {
  CGPoint startTouchPosition;
  BOOL topViewHasFocus;
}

/** Returns the view controller that will be visible when the top view is slide to the right.
 
 This view controller is typically a menu or top-level view that switches out the top view controller.
 */
@property (nonatomic, strong) UIViewController *underLeftViewController;

/** Returns the view controller that will be visible when the top view is slide to the left.
 
 This view controller is typically a supplemental view to the top view.
 */
@property (nonatomic, strong) UIViewController *underRightViewController;

/** Returns the top view controller.
 
 This is the main view controller that is presented above the other view controllers.
 */
@property (nonatomic, strong) UIViewController *topViewController;

/** Returns the number of points the top view is visible when the top view is anchored to the left side.
 
 This value is fixed after rotation. If the number of points to reveal needs to be fixed, use anchorLeftRevealAmount.
 
 @see anchorLeftRevealAmount
 */
@property (nonatomic, assign) CGFloat anchorLeftPeekAmount;

/** Returns the number of points the top view is visible when the top view is anchored to the right side.
 
 This value is fixed after rotation. If the number of points to reveal needs to be fixed, use anchorRightRevealAmount.
 
 @see anchorRightRevealAmount
 */
@property (nonatomic, assign) CGFloat anchorRightPeekAmount;

/** Returns the number of points the under right view is visible when the top view is anchored to the left side.
 
 This value is fixed after rotation. If the number of points to peek needs to be fixed, use anchorLeftPeekAmount.
 
 @see anchorLeftPeekAmount
 */
@property (nonatomic, assign) CGFloat anchorLeftRevealAmount;

/** Returns the number of points the under left view is visible when the top view is anchored to the right side.
 
 This value is fixed after rotation. If the number of points to peek needs to be fixed, use anchorRightPeekAmount.
 
 @see anchorRightPeekAmount
 */
@property (nonatomic, assign) CGFloat anchorRightRevealAmount;

/** Specifies whether or not the top view can be panned past the anchor point.
 
 Set to NO if you don't want to show the empty space behind the top and under view.
 
 By defaut, this is set to YES
 */
@property (nonatomic, assign) BOOL shouldAllowPanningPastAnchor;

/** Specifies if the user should be able to interact with the top view when it is anchored.
 
 By default, this is set to NO
 */
@property (nonatomic, assign) BOOL shouldAllowUserInteractionsWhenAnchored;

/** Specifies if the top view snapshot requires a pan gesture recognizer.
 
 This is useful when panGesture is added to the navigation bar instead of the main view.
 
 By default, this is set to NO
 */
@property (nonatomic, assign) BOOL shouldAddPanGestureRecognizerToTopViewSnapshot;

/** Specifies the behavior for the under left width
 
 By default, this is set to ECFullWidth
 */
@property (nonatomic, assign) ECViewWidthLayout underLeftWidthLayout;

/** Specifies the behavior for the under right width
 
 By default, this is set to ECFullWidth
 */
@property (nonatomic, assign) ECViewWidthLayout underRightWidthLayout;

/** Returns the strategy for resetting the top view when it is anchored.
 
 By default, this is set to ECPanning | ECTapping to allow both panning and tapping to reset the top view.
 
 If this is set to ECNone, then there must be a custom way to reset the top view otherwise it will stay anchored.
 */
@property (nonatomic, assign) ECResetStrategy resetStrategy;

/** Returns a horizontal panning gesture for moving the top view.
 
 This is typically added to the top view or a top view's navigation bar.
 */
- (UIPanGestureRecognizer *)panGesture;

/** Slides the top view in the direction of the specified side.
 
 A peek amount or reveal amount must be set for the given side. The top view will anchor to one of those specified values.
 
 @param side The side for the top view to slide towards.
 */
- (void)anchorTopViewTo:(ECSide)side;

/** Slides the top view in the direction of the specified side.
 
 A peek amount or reveal amount must be set for the given side. The top view will anchor to one of those specified values.
 
 @param side The side for the top view to slide towards.
 @param animations Perform changes to properties that will be animated while top view is moved off screen. Can be nil.
 @param onComplete Executed after the animation is completed. Can be nil.
 */
- (void)anchorTopViewTo:(ECSide)side animations:(void(^)(void))animations onComplete:(void(^)(void))onComplete;

/** Slides the top view off of the screen in the direction of the specified side.
 
 @param side The side for the top view to slide off the screen towards.
 */
- (void)anchorTopViewOffScreenTo:(ECSide)side;

/** Slides the top view off of the screen in the direction of the specified side.
 
 @param side The side for the top view to slide off the screen towards.
 @param animations Perform changes to properties that will be animated while top view is moved off screen. Can be nil.
 @param onComplete Executed after the animation is completed. Can be nil.
 */
- (void)anchorTopViewOffScreenTo:(ECSide)side animations:(void(^)(void))animations onComplete:(void(^)(void))onComplete;

/** Slides the top view back to the center. */
- (void)resetTopView;

/** Slides the top view back to the center.

 @param animations Perform changes to properties that will be animated while top view is moved back to the center of the screen. Can be nil.
 @param onComplete Executed after the animation is completed. Can be nil.
 */
- (void)resetTopViewWithAnimations:(void(^)(void))animations onComplete:(void(^)(void))onComplete;

/** Returns true if the underLeft view is showing (even partially) */
- (BOOL)underLeftShowing;

/** Returns true if the underRight view is showing (even partially) */
- (BOOL)underRightShowing;

/** Returns true if the top view is completely off the screen */
- (BOOL)topViewIsOffScreen;

-(void)updateUnderLeftLayout;
-(void)updateUnderRightLayout;
-(BOOL)topViewHasFocus;
-(void)adjustLayout;
@end

/** UIViewController extension */
@interface UIViewController(SlidingViewExtension)
/** Convience method for getting access to the ECSlidingViewController instance */
- (ECSlidingViewController *)slidingViewController;
@end


================================================
FILE: ECSlidingViewController/ECSlidingViewController.m
================================================
//
//  ECSlidingViewController.m
//  ECSlidingViewController
//
//  Created by Michael Enriquez on 1/23/12.
//  Copyright (c) 2012 EdgeCase. All rights reserved.
//

#import "ECSlidingViewController.h"

NSString *const ECSlidingViewUnderRightWillAppear    = @"ECSlidingViewUnderRightWillAppear";
NSString *const ECSlidingViewUnderLeftWillAppear     = @"ECSlidingViewUnderLeftWillAppear";
NSString *const ECSlidingViewUnderLeftWillDisappear  = @"ECSlidingViewUnderLeftWillDisappear";
NSString *const ECSlidingViewUnderRightWillDisappear = @"ECSlidingViewUnderRightWillDisappear";
NSString *const ECSlidingViewTopDidAnchorLeft        = @"ECSlidingViewTopDidAnchorLeft";
NSString *const ECSlidingViewTopDidAnchorRight       = @"ECSlidingViewTopDidAnchorRight";
NSString *const ECSlidingViewTopWillReset            = @"ECSlidingViewTopWillReset";
NSString *const ECSlidingViewTopDidReset             = @"ECSlidingViewTopDidReset";

@interface ECSlidingViewController()

@property (nonatomic, strong) UIView *topViewSnapshot;
@property (nonatomic, assign) CGFloat initialTouchPositionX;
@property (nonatomic, assign) CGFloat initialHoizontalCenter;
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
@property (nonatomic, strong) UITapGestureRecognizer *resetTapGesture;
@property (nonatomic, strong) UIPanGestureRecognizer *topViewSnapshotPanGesture;
@property (nonatomic, assign) BOOL underLeftShowing;
@property (nonatomic, assign) BOOL underRightShowing;
@property (nonatomic, assign) BOOL topViewIsOffScreen;

- (NSUInteger)autoResizeToFillScreen;
- (UIView *)topView;
- (UIView *)underLeftView;
- (UIView *)underRightView;
- (void)adjustLayout;
- (void)updateTopViewHorizontalCenterWithRecognizer:(UIPanGestureRecognizer *)recognizer;
- (void)updateTopViewHorizontalCenter:(CGFloat)newHorizontalCenter;
- (void)topViewHorizontalCenterWillChange:(CGFloat)newHorizontalCenter;
- (void)topViewHorizontalCenterDidChange:(CGFloat)newHorizontalCenter;
- (void)addTopViewSnapshot;
- (void)removeTopViewSnapshot;
- (CGFloat)anchorRightTopViewCenter;
- (CGFloat)anchorLeftTopViewCenter;
- (CGFloat)resettedCenter;
- (void)underLeftWillAppear;
- (void)underRightWillAppear;
- (void)topDidReset;
- (BOOL)topViewHasFocus;
- (void)updateUnderLeftLayout;
- (void)updateUnderRightLayout;

@end

@implementation UIViewController(SlidingViewExtension)

- (ECSlidingViewController *)slidingViewController
{
  UIViewController *viewController = self.parentViewController;
  while (!(viewController == nil || [viewController isKindOfClass:[ECSlidingViewController class]])) {
    viewController = viewController.parentViewController;
  }
  
  return (ECSlidingViewController *)viewController;
}

@end

@implementation ECSlidingViewController

// public properties
@synthesize underLeftViewController  = _underLeftViewController;
@synthesize underRightViewController = _underRightViewController;
@synthesize topViewController        = _topViewController;
@synthesize anchorLeftPeekAmount;
@synthesize anchorRightPeekAmount;
@synthesize anchorLeftRevealAmount;
@synthesize anchorRightRevealAmount;
@synthesize underRightWidthLayout = _underRightWidthLayout;
@synthesize underLeftWidthLayout  = _underLeftWidthLayout;
@synthesize shouldAllowPanningPastAnchor;
@synthesize shouldAllowUserInteractionsWhenAnchored;
@synthesize shouldAddPanGestureRecognizerToTopViewSnapshot;
@synthesize resetStrategy = _resetStrategy;

// category properties
@synthesize topViewSnapshot;
@synthesize initialTouchPositionX;
@synthesize initialHoizontalCenter;
@synthesize panGesture = _panGesture;
@synthesize resetTapGesture;
@synthesize underLeftShowing   = _underLeftShowing;
@synthesize underRightShowing  = _underRightShowing;
@synthesize topViewIsOffScreen = _topViewIsOffScreen;
@synthesize topViewSnapshotPanGesture = _topViewSnapshotPanGesture;

-(void)applicationDidResume {
    //We do our own layout higher up in the stack, so override this to prevent a crash on iOS 8
}

- (void)setTopViewController:(UIViewController *)theTopViewController
{
  CGRect topViewFrame = _topViewController ? _topViewController.view.frame : self.view.bounds;
  
  [self removeTopViewSnapshot];
  [_topViewController.view removeFromSuperview];
  [_topViewController willMoveToParentViewController:nil];
  [_topViewController removeFromParentViewController];
  
  _topViewController = theTopViewController;
  
  [self addChildViewController:self.topViewController];
  [self.topViewController didMoveToParentViewController:self];
  
  [_topViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
  [_topViewController.view setFrame:topViewFrame];
  _topViewController.view.layer.shadowOffset = CGSizeZero;
  _topViewController.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.layer.bounds].CGPath;
  
  [self.view addSubview:_topViewController.view];
}

- (void)setUnderLeftViewController:(UIViewController *)theUnderLeftViewController
{
  [_underLeftViewController.view removeFromSuperview];
  [_underLeftViewController willMoveToParentViewController:nil];
  [_underLeftViewController removeFromParentViewController];
  
  _underLeftViewController = theUnderLeftViewController;
  
  if (_underLeftViewController) {
    _underLeftViewController.view.hidden = YES;
    @try {
        [self addChildViewController:self.underLeftViewController];
    } @catch (NSException *e) {
    }
    @try {
        [self.view insertSubview:_underLeftViewController.view belowSubview:self.topView];
    } @catch (NSException *e) {
    }
    @try {
        [self addChildViewController:self.underLeftViewController];
    } @catch (NSException *e) {
    }
    [self.underLeftViewController didMoveToParentViewController:self];
    [self updateUnderLeftLayout];
  }
}

- (void)setUnderRightViewController:(UIViewController *)theUnderRightViewController
{
  [_underRightViewController.view removeFromSuperview];
  [_underRightViewController willMoveToParentViewController:nil];
  [_underRightViewController removeFromParentViewController];
  
  _underRightViewController = theUnderRightViewController;
  
  if (_underRightViewController) {
    _underRightViewController.view.hidden = YES;
    [self.view insertSubview:_underRightViewController.view belowSubview:self.topView];
    [self updateUnderRightLayout];
    [self addChildViewController:self.underRightViewController];
    [self.underRightViewController didMoveToParentViewController:self];
  }
}

- (void)setUnderLeftWidthLayout:(ECViewWidthLayout)underLeftWidthLayout
{
  if (underLeftWidthLayout == ECVariableRevealWidth && self.anchorRightPeekAmount <= 0) {
    [NSException raise:@"Invalid Width Layout" format:@"anchorRightPeekAmount must be set"];
  } else if (underLeftWidthLayout == ECFixedRevealWidth && self.anchorRightRevealAmount <= 0) {
    [NSException raise:@"Invalid Width Layout" format:@"anchorRightRevealAmount must be set"];
  }
  
  _underLeftWidthLayout = underLeftWidthLayout;
}

- (void)setUnderRightWidthLayout:(ECViewWidthLayout)underRightWidthLayout
{
  if (underRightWidthLayout == ECVariableRevealWidth && self.anchorLeftPeekAmount <= 0) {
    [NSException raise:@"Invalid Width Layout" format:@"anchorLeftPeekAmount must be set"];
  } else if (underRightWidthLayout == ECFixedRevealWidth && self.anchorLeftRevealAmount <= 0) {
    [NSException raise:@"Invalid Width Layout" format:@"anchorLeftRevealAmount must be set"];
  }
  
  _underRightWidthLayout = underRightWidthLayout;
}

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.shouldAllowPanningPastAnchor = YES;
  self.shouldAllowUserInteractionsWhenAnchored = NO;
  self.shouldAddPanGestureRecognizerToTopViewSnapshot = NO;
  self.resetTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resetTopView)];
  _panGesture          = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(updateTopViewHorizontalCenterWithRecognizer:)];
  _panGesture.delegate = self;
    _panGesture.maximumNumberOfTouches = 1;
  self.resetTapGesture.enabled = NO;
  self.resetStrategy = ECTapping | ECPanning;
  
  self.topViewSnapshot = [[UIView alloc] initWithFrame:self.topView.bounds];
  [self.topViewSnapshot setAutoresizingMask:self.autoResizeToFillScreen];
  [self.topViewSnapshot addGestureRecognizer:self.resetTapGesture];
}

-(SupportedOrientationsReturnType)supportedInterfaceOrientations {
    if([self.topViewController isKindOfClass:[UINavigationController class]])
        return [((UINavigationController *)self.topViewController).topViewController supportedInterfaceOrientations];
    else
        return [self.topViewController supportedInterfaceOrientations];
}

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)recognizer {
    CGPoint velocity = [recognizer velocityInView:self.view];
    return ABS(velocity.x) > ABS(velocity.y);
}

- (void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  self.topView.layer.shadowOffset = CGSizeZero;
  self.topView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.layer.bounds].CGPath;
  [self adjustLayout];
}

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        self.topView.layer.shadowPath = nil;
        self.topView.layer.shouldRasterize = YES;
        
        if(![self topViewHasFocus]){
            [self removeTopViewSnapshot];
        }
        
        [self adjustLayout];
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        self.topView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.layer.bounds].CGPath;
        self.topView.layer.shouldRasterize = NO;
        
        if(![self topViewHasFocus]){
            [self addTopViewSnapshot];
        }
    }
     ];
}

- (void)setResetStrategy:(ECResetStrategy)theResetStrategy
{
  _resetStrategy = theResetStrategy;
  if (_resetStrategy & ECTapping) {
    self.resetTapGesture.enabled = YES;
  } else {
    self.resetTapGesture.enabled = NO;
  }
}

- (void)adjustLayout
{
  if(@available(iOS 13, *)) {
      BOOL hasGestureBar = NO;
      hasGestureBar = self.view.window.safeAreaInsets.bottom > 0 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad;
      if(!hasGestureBar) {
        int sbheight = [UIApplication sharedApplication].statusBarFrame.size.height;
        if(sbheight > 20 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
          sbheight -= 20;
        if(self.view.window.safeAreaInsets.bottom) {
            sbheight = self.view.window.safeAreaInsets.top;
        }
#if !TARGET_OS_MACCATALYST
        if (@available(iOS 14.0, *)) {
          if([NSProcessInfo processInfo].isiOSAppOnMac) {
              sbheight = 0;
          }
        }
#endif
        CGRect frame = self.topView.frame;
        frame.origin.y = sbheight;
        frame.size.height = self.view.bounds.size.height - sbheight;
        if([UIApplication sharedApplication].statusBarFrame.size.height > 20 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
          frame.size.height += 20;
        if([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad && self.view.window.safeAreaInsets.bottom) {
          frame.size.height -= self.view.window.safeAreaInsets.bottom;
        }
        self.topView.frame = frame;
        _topViewController.view.layer.shadowOffset = CGSizeZero;
        _topViewController.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
      }
  }

  self.topViewSnapshot.frame = self.topView.bounds;
    
  if ([self underRightShowing] && ![self topViewIsOffScreen]) {
    [self updateUnderRightLayout];
    [self updateTopViewHorizontalCenter:self.anchorLeftTopViewCenter];
  } else if ([self underRightShowing] && [self topViewIsOffScreen]) {
    [self updateUnderRightLayout];
    [self updateTopViewHorizontalCenter:-self.resettedCenter];
  } else if ([self underLeftShowing] && ![self topViewIsOffScreen]) {
    [self updateUnderLeftLayout];
    [self updateTopViewHorizontalCenter:self.anchorRightTopViewCenter];
  } else if ([self underLeftShowing] && [self topViewIsOffScreen]) {
    [self updateUnderLeftLayout];
    [self updateTopViewHorizontalCenter:self.view.bounds.size.width + self.resettedCenter];
  }
}

- (void)updateTopViewHorizontalCenterWithRecognizer:(UIPanGestureRecognizer *)recognizer
{
    static BOOL underLeftWasShowing = NO;
    static BOOL underRightWasShowing = NO;
  CGPoint currentTouchPoint     = [recognizer locationInView:self.view];
  CGFloat currentTouchPositionX = currentTouchPoint.x;
  
  if (recognizer.state == UIGestureRecognizerStateBegan) {
    self.initialTouchPositionX = currentTouchPositionX;
    self.initialHoizontalCenter = self.topView.center.x;
  } else if (recognizer.state == UIGestureRecognizerStateChanged) {
    CGFloat panAmount = self.initialTouchPositionX - currentTouchPositionX;
    CGFloat newCenterPosition = self.initialHoizontalCenter - panAmount;
    
    if ((newCenterPosition < self.resettedCenter && (self.anchorLeftTopViewCenter == NSNotFound || self.underRightViewController == nil)) ||
        (newCenterPosition > self.resettedCenter && (self.anchorRightTopViewCenter == NSNotFound || self.underLeftViewController == nil))) {
      newCenterPosition = self.resettedCenter;
    }
    
      if((newCenterPosition > self.resettedCenter && underRightWasShowing) || (newCenterPosition < self.resettedCenter && underLeftWasShowing)) {
          newCenterPosition = self.resettedCenter;
      }
          
      
    BOOL newCenterPositionIsOutsideAnchor = newCenterPosition < self.anchorLeftTopViewCenter || self.anchorRightTopViewCenter < newCenterPosition;
    
    if (newCenterPosition != self.topView.center.x && ((newCenterPositionIsOutsideAnchor && self.shouldAllowPanningPastAnchor) || !newCenterPositionIsOutsideAnchor)) {
      [self topViewHorizontalCenterWillChange:newCenterPosition];
      [self updateTopViewHorizontalCenter:newCenterPosition];
      [self topViewHorizontalCenterDidChange:newCenterPosition];
        if(self.underLeftShowing)
            underLeftWasShowing = self.underLeftShowing;
        
        if(self.underRightShowing)
            underRightWasShowing = self.underRightShowing;
    }
  } else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
      underLeftWasShowing = NO;
      underRightWasShowing = NO;
    CGFloat panAmount            = currentTouchPositionX - self.initialTouchPositionX;
    CGPoint currentVelocityPoint = [recognizer velocityInView:self.view];
    CGFloat currentVelocityX     = currentVelocityPoint.x;
        
    if ([self underLeftShowing] && (currentVelocityX > 50 || (currentVelocityX >= 0 && panAmount >= anchorRightRevealAmount/6.0f))) {
      [self anchorTopViewTo:ECRight];
    } else if ([self underRightShowing] && (currentVelocityX < -50 || (currentVelocityX <= 0 && panAmount <= -anchorLeftRevealAmount/6.0))) {
      [self anchorTopViewTo:ECLeft];
    } else {
      [self resetTopView];
    }
  }
}

- (UIPanGestureRecognizer *)panGesture
{
  return _panGesture;
}

- (void)anchorTopViewTo:(ECSide)side
{
  [self anchorTopViewTo:side animations:nil onComplete:nil];
}

- (void)anchorTopViewTo:(ECSide)side animations:(void (^)(void))animations onComplete:(void (^)(void))complete
{
  CGFloat newCenter = self.topView.center.x;
  
  if (side == ECLeft) {
    newCenter = self.anchorLeftTopViewCenter;
  } else if (side == ECRight) {
    newCenter = self.anchorRightTopViewCenter;
  }
  
  [self topViewHorizontalCenterWillChange:newCenter];
  
  [UIView animateWithDuration:0.15f animations:^{
    if (animations) {
      animations();
    }
    [self updateTopViewHorizontalCenter:newCenter];
  } completion:^(BOOL finished){
      if (self->_resetStrategy & ECPanning) {
      self.panGesture.enabled = YES;
    } else {
      self.panGesture.enabled = NO;
    }
    if (complete) {
      complete();
    }
      self->_topViewIsOffScreen = NO;
    [self addTopViewSnapshot];
    dispatch_async(dispatch_get_main_queue(), ^{
      NSString *key = (side == ECLeft) ? ECSlidingViewTopDidAnchorLeft : ECSlidingViewTopDidAnchorRight;
      [[NSNotificationCenter defaultCenter] postNotificationName:key object:self userInfo:nil];
        (side == ECRight) ? [self->_underLeftViewController viewDidAppear:NO] : [self->_underRightViewController viewDidAppear:NO];
    });
  }];
}

- (void)anchorTopViewOffScreenTo:(ECSide)side
{
  [self anchorTopViewOffScreenTo:side animations:nil onComplete:nil];
}

- (void)anchorTopViewOffScreenTo:(ECSide)side animations:(void(^)(void))animations onComplete:(void(^)(void))complete
{
  CGFloat newCenter = self.topView.center.x;
  
  if (side == ECLeft) {
    newCenter = -self.resettedCenter;
  } else if (side == ECRight) {
    newCenter = self.view.bounds.size.width + self.resettedCenter;
  }
  
  [self topViewHorizontalCenterWillChange:newCenter];
  
  [UIView animateWithDuration:0.15f animations:^{
    if (animations) {
      animations();
    }
    [self updateTopViewHorizontalCenter:newCenter];
  } completion:^(BOOL finished){
    if (complete) {
      complete();
    }
      self->_topViewIsOffScreen = YES;
    [self addTopViewSnapshot];
    dispatch_async(dispatch_get_main_queue(), ^{
      NSString *key = (side == ECLeft) ? ECSlidingViewTopDidAnchorLeft : ECSlidingViewTopDidAnchorRight;
      [[NSNotificationCenter defaultCenter] postNotificationName:key object:self userInfo:nil];
    });
  }];
}

- (void)resetTopView
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewTopWillReset object:self userInfo:nil];
  });
  [self resetTopViewWithAnimations:nil onComplete:nil];
}

- (void)resetTopViewWithAnimations:(void(^)(void))animations onComplete:(void(^)(void))complete
{
    if(self.topView.center.x != self.resettedCenter) {
      [self topViewHorizontalCenterWillChange:self.resettedCenter];
      
      [UIView animateWithDuration:0.15f animations:^{
        if (animations) {
          animations();
        }
        [self updateTopViewHorizontalCenter:self.resettedCenter];
      } completion:^(BOOL finished) {
        [self topViewHorizontalCenterDidChange:self.resettedCenter];
        if (complete) {
          complete();
        }
      }];
    } else {
        if (complete) {
            complete();
        }
    }
}

- (NSUInteger)autoResizeToFillScreen
{
  return (UIViewAutoresizingFlexibleWidth |
          UIViewAutoresizingFlexibleHeight);
}

- (UIView *)topView
{
  return self.topViewController.view;
}

- (UIView *)underLeftView
{
  return self.underLeftViewController.view;
}

- (UIView *)underRightView
{
  return self.underRightViewController.view;
}

- (void)updateTopViewHorizontalCenter:(CGFloat)newHorizontalCenter
{
  CGPoint center = self.topView.center;
  center.x = newHorizontalCenter;
  self.topView.layer.position = center;
}

- (void)topViewHorizontalCenterWillChange:(CGFloat)newHorizontalCenter
{
  CGPoint center = self.topView.center;
  
	if (center.x >= self.resettedCenter && newHorizontalCenter == self.resettedCenter) {
		dispatch_async(dispatch_get_main_queue(), ^{
			[[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewUnderLeftWillDisappear object:self userInfo:nil];
		});
	}
	
	if (center.x <= self.resettedCenter && newHorizontalCenter == self.resettedCenter) {
		dispatch_async(dispatch_get_main_queue(), ^{
			[[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewUnderRightWillDisappear object:self userInfo:nil];
		});
	}
	
  if (center.x <= self.resettedCenter && newHorizontalCenter > self.resettedCenter) {
    [self underLeftWillAppear];
  } else if (center.x >= self.resettedCenter && newHorizontalCenter < self.resettedCenter) {
    [self underRightWillAppear];
  }
    
    [self.view sendSubviewToBack:self.underLeftView];
    [self.view sendSubviewToBack:self.underRightView];
}

- (void)topViewHorizontalCenterDidChange:(CGFloat)newHorizontalCenter
{
  if (newHorizontalCenter == self.resettedCenter) {
    [self topDidReset];
  }
}

- (void)addTopViewSnapshot
{
  if (!self.topViewSnapshot.superview && !self.shouldAllowUserInteractionsWhenAnchored) {
    //topViewSnapshot.layer.contents = (id)[UIImage imageWithUIView:self.topView].CGImage;
    
    if (self.shouldAddPanGestureRecognizerToTopViewSnapshot && (_resetStrategy & ECPanning)) {
      if (!_topViewSnapshotPanGesture) {
        _topViewSnapshotPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(updateTopViewHorizontalCenterWithRecognizer:)];
      }
      [topViewSnapshot addGestureRecognizer:_topViewSnapshotPanGesture];
    }
    self.topViewSnapshot.frame = self.topView.bounds;
    [self.topView addSubview:self.topViewSnapshot];
  }
}

- (void)removeTopViewSnapshot
{
  if (self.topViewSnapshot.superview) {
    [self.topViewSnapshot removeFromSuperview];
  }
}

- (CGFloat)anchorRightTopViewCenter
{
  if (self.anchorRightPeekAmount) {
    return self.view.bounds.size.width + self.resettedCenter - self.anchorRightPeekAmount;
  } else if (self.anchorRightRevealAmount) {
    return self.resettedCenter + self.anchorRightRevealAmount;
  } else {
    return NSNotFound;
  }
}

- (CGFloat)anchorLeftTopViewCenter
{
  if (self.anchorLeftPeekAmount) {
    return -self.resettedCenter + self.anchorLeftPeekAmount;
  } else if (self.anchorLeftRevealAmount) {
    return -self.resettedCenter + (self.view.bounds.size.width - self.anchorLeftRevealAmount);
  } else {
    return NSNotFound;
  }
}

- (CGFloat)resettedCenter
{
  return (self.view.bounds.size.width / 2);
}

- (void)underLeftWillAppear
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewUnderLeftWillAppear object:self userInfo:nil];
  });
  [self updateUnderLeftLayout];
  self.underRightView.hidden = YES;
  self.underLeftView.hidden = NO;
  _underLeftShowing  = YES;
  _underRightShowing = NO;
}

- (void)underRightWillAppear
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewUnderRightWillAppear object:self userInfo:nil];
  });
  [self updateUnderRightLayout];
  self.underRightView.hidden = NO;
  self.underLeftView.hidden = YES;
  _underLeftShowing  = NO;
  _underRightShowing = YES;
}

- (void)topDidReset
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:ECSlidingViewTopDidReset object:self userInfo:nil];
    if([self.topViewController isKindOfClass:UINavigationController.class]) {
      [((UINavigationController *)self.topViewController).visibleViewController viewDidAppear:NO];
    } else {
      [self.topViewController viewDidAppear:NO];
    }
  });
  [self.topView removeGestureRecognizer:self.resetTapGesture];
  [self removeTopViewSnapshot];
  self.panGesture.enabled = YES;
  self.underRightView.hidden = YES;
  self.underLeftView.hidden = YES;
  _underLeftShowing   = NO;
  _underRightShowing  = NO;
  _topViewIsOffScreen = NO;
}

- (BOOL)topViewHasFocus
{
  return !_underLeftShowing && !_underRightShowing && !_topViewIsOffScreen;
}

- (void)updateUnderLeftLayout
{
    if (self.underLeftWidthLayout == ECFullWidth) {
        [self.underLeftView setAutoresizingMask:self.autoResizeToFillScreen];
        [self.underLeftView setFrame:self.view.bounds];
    } else if (self.underLeftWidthLayout == ECVariableRevealWidth && !self.topViewIsOffScreen) {
        CGRect frame = self.view.bounds;

        frame.size.width = frame.size.width - self.anchorRightPeekAmount;
        self.underLeftView.frame = frame;
    } else if (self.underLeftWidthLayout == ECFixedRevealWidth) {
        CGRect frame = self.view.bounds;

        frame.size.width = self.anchorRightRevealAmount;
        self.underLeftView.frame = frame;
    } else {
        [NSException raise:@"Invalid Width Layout" format:@"underLeftWidthLayout must be a valid ECViewWidthLayout"];
    }
    int sbheight = [UIApplication sharedApplication].statusBarFrame.size.height;
    if(sbheight > 20 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
        sbheight -= 20;
#if TARGET_OS_MACCATALYST
    sbheight = self.view.window.safeAreaInsets.top;
#else
    if(self.view.window.safeAreaInsets.bottom) {
        sbheight = self.view.window.safeAreaInsets.top;
    }
    if (@available(iOS 14.0, *)) {
        if([NSProcessInfo processInfo].isiOSAppOnMac) {
            sbheight = 0;
        }
    }
#endif
    CGRect frame = self.underLeftView.frame;
    frame.origin.y = sbheight;
    frame.size.height = self.view.bounds.size.height - sbheight;
    if([UIApplication sharedApplication].statusBarFrame.size.height > 20 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
        frame.size.height += 20;
    self.underLeftView.frame = frame;
}

- (void)updateUnderRightLayout
{
    if (self.underRightWidthLayout == ECFullWidth) {
        [self.underRightViewController.view setAutoresizingMask:self.autoResizeToFillScreen];
        self.underRightView.frame = self.view.bounds;
    } else if (self.underRightWidthLayout == ECVariableRevealWidth) {
        CGRect frame = self.view.bounds;

        CGFloat newLeftEdge;
        CGFloat newWidth = frame.size.width;

        if (self.topViewIsOffScreen) {
          newLeftEdge = 0;
        } else {
          newLeftEdge = self.anchorLeftPeekAmount;
          newWidth   -= self.anchorLeftPeekAmount;
        }

        frame.origin.x   = newLeftEdge;
        frame.size.width = newWidth;

        self.underRightView.frame = frame;
    } else if (self.underRightWidthLayout == ECFixedRevealWidth) {
        CGRect frame = self.view.bounds;

        CGFloat newLeftEdge = frame.size.width - self.anchorLeftRevealAmount;
        CGFloat newWidth = self.anchorLeftRevealAmount;

        frame.origin.x   = newLeftEdge;
        frame.size.width = newWidth;

        self.underRightView.frame = frame;
    } else {
        [NSException raise:@"Invalid Width Layout" format:@"underRightWidthLayout must be a valid ECViewWidthLayout"];
    }
    int sbheight = [UIApplication sharedApplication].statusBarFrame.size.height;
    if(sbheight > 20)
        sbheight -= 20;
#if TARGET_OS_MACCATALYST
    sbheight = self.view.window.safeAreaInsets.top;
#else
    if(self.view.window.safeAreaInsets.bottom) {
        sbheight = self.view.window.safeAreaInsets.top;
    }
    if (@available(iOS 14.0, *)) {
        if([NSProcessInfo processInfo].isiOSAppOnMac) {
            sbheight = 0;
        }
    }
#endif
    CGRect frame = self.underRightView.frame;
    frame.origin.y = sbheight;
    frame.size.height = self.view.bounds.size.height - sbheight;
    if([UIApplication sharedApplication].statusBarFrame.size.height > 20 && [[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
        frame.size.height += 20;
    self.underRightView.frame = frame;
}

-(UIStatusBarStyle)preferredStatusBarStyle {
    if(self.topViewController)
        return self.topViewController.childViewControllerForStatusBarStyle ? self.topViewController.childViewControllerForStatusBarStyle.preferredStatusBarStyle : self.topViewController.preferredStatusBarStyle;
    else
        return UIStatusBarStyleDefault;
}

-(BOOL)prefersStatusBarHidden {
    if(self.topViewController)
        return self.topViewController.childViewControllerForStatusBarHidden ? self.topViewController.childViewControllerForStatusBarHidden.prefersStatusBarHidden : self.topViewController.prefersStatusBarHidden;
    else
        return NO;
}
@end


================================================
FILE: ECSlidingViewController/UIImage+ImageWithUIView.h
================================================
//
//  UIImage+ImageWithUIView.h
//

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface UIImage (ImageWithUIView)
+ (UIImage *)imageWithUIView:(UIView *)view;
@end

================================================
FILE: ECSlidingViewController/UIImage+ImageWithUIView.m
================================================
//
//  UIImage+ImageWithUIView.m
//

#import "UIImage+ImageWithUIView.h"

@implementation UIImage (ImageWithUIView)
#pragma mark -
#pragma mark TakeScreenShot

+ (UIImage *)imageWithUIView:(UIView *)view
{
  CGSize screenShotSize = view.bounds.size;
  UIImage *img;  
  UIGraphicsBeginImageContext(screenShotSize);
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  [view drawLayer:view.layer inContext:ctx];
  img = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  
  return img;
}
@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputColorView : FLEXArgumentInputView

@end


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

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

@protocol FLEXColorComponentInputViewDelegate;

@interface FLEXColorComponentInputView : UIView

@property (nonatomic, strong) UISlider *slider;
@property (nonatomic, strong) 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 alloc] init];
        self.slider.backgroundColor = self.backgroundColor;
        [self.slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSubview:self.slider];
        
        self.valueLabel = [[UILabel alloc] init];
        self.valueLabel.backgroundColor = self.backgroundColor;
        self.valueLabel.font = [FLEXUtility defaultFontOfSize: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, strong) UIColor *color;

@property (nonatomic, strong) 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, strong) FLEXColorPreviewBox *colorPreviewBox;
@property (nonatomic, strong) UILabel *hexLabel;
@property (nonatomic, strong) FLEXColorComponentInputView *alphaInput;
@property (nonatomic, strong) FLEXColorComponentInputView *redInput;
@property (nonatomic, strong) FLEXColorComponentInputView *greenInput;
@property (nonatomic, strong) FLEXColorComponentInputView *blueInput;

@end

@implementation FLEXArgumentInputColorView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.colorPreviewBox = [[FLEXColorPreviewBox alloc] init];
        [self addSubview:self.colorPreviewBox];
        
        self.hexLabel = [[UILabel alloc] init];
        self.hexLabel.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.9];
        self.hexLabel.textAlignment = NSTextAlignmentCenter;
        self.hexLabel.font = [FLEXUtility defaultFontOfSize:12.0];
        [self addSubview:self.hexLabel];
        
        self.alphaInput = [[FLEXColorComponentInputView alloc] init];
        self.alphaInput.slider.minimumTrackTintColor = [UIColor blackColor];
        self.alphaInput.delegate = self;
        [self addSubview:self.alphaInput];
        
        self.redInput = [[FLEXColorComponentInputView alloc] init];
        self.redInput.slider.minimumTrackTintColor = [UIColor redColor];
        self.redInput.delegate = self;
        [self addSubview:self.redInput];
        
        self.greenInput = [[FLEXColorComponentInputView alloc] init];
        self.greenInput.slider.minimumTrackTintColor = [UIColor greenColor];
        self.greenInput.delegate = self;
        [self addSubview:self.greenInput];
        
        self.blueInput = [[FLEXColorComponentInputView alloc] init];
        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 kLabelHorizonalOutsetAmount = 2.0;
    UIEdgeInsets labelOutset = UIEdgeInsetsMake(-kLabelVerticalOutsetAmount, -kLabelHorizonalOutsetAmount, -kLabelVerticalOutsetAmount, -kLabelHorizonalOutsetAmount);
    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];
        }
    }
}

- (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
{
    return (type && (strcmp(type, @encode(CGColorRef)) == 0 || strcmp(type, FLEXEncodeClass(UIColor)) == 0)) || [value isKindOfClass:[UIColor class]];
}

@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputDateView : FLEXArgumentInputView

@end


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

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

@interface FLEXArgumentInputDateView ()

@property (nonatomic, strong) UIDatePicker *datePicker;

@end

@implementation FLEXArgumentInputDateView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.datePicker = [[UIDatePicker alloc] init];
        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
{
    return (type && (strcmp(type, FLEXEncodeClass(NSDate)) == 0)) || [value isKindOfClass:[NSDate class]];
}

@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputFontView : FLEXArgumentInputView

@end


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

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

@interface FLEXArgumentInputFontView ()

@property (nonatomic, strong) FLEXArgumentInputView *fontNameInput;
@property (nonatomic, strong) 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.backgroundColor = self.backgroundColor;
        self.fontNameInput.targetSize = FLEXArgumentInputViewSizeSmall;
        self.fontNameInput.title = @"Font Name:";
        [self addSubview:self.fontNameInput];
        
        self.pointSizeInput = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:@encode(CGFloat)];
        self.pointSizeInput.backgroundColor = self.backgroundColor;
        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
{
    BOOL supported = type && strcmp(type, FLEXEncodeClass(UIFont)) == 0;
    supported = supported || (value && [value isKindOfClass:[UIFont class]]);
    return supported;
}

@end


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

#import "FLEXArgumentInputTextView.h"

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


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

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

@interface FLEXArgumentInputFontsPickerView ()

@property (nonatomic, strong) 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;
    fontsPicker.showsSelectionIndicator = YES;
    return fontsPicker;
}

- (void)createAvailableFonts
{
    NSMutableArray<NSString *> *unsortedFontsArray = [NSMutableArray array];
    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: FLEX/Editing/ArgumentInputViews/FLEXArgumentInputJSONObjectView.h
================================================
//
//  FLEXArgumentInputJSONObjectView.h
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputJSONObjectView : FLEXArgumentInputTextView

@end


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

#import "FLEXArgumentInputJSONObjectView.h"
#import "FLEXRuntimeUtility.h"

@implementation FLEXArgumentInputJSONObjectView

- (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;
    }
    return self;
}

- (void)setInputValue:(id)inputValue
{
    self.inputTextView.text = [FLEXRuntimeUtility editableJSONStringForObject:inputValue];
}

- (id)inputValue
{
    return [FLEXRuntimeUtility objectValueFromEditableJSONString:self.inputTextView.text];
}

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value
{
    // Must be object type.
    BOOL supported = type && type[0] == '@';
    
    if (supported) {
        if (value) {
            // If there's a current value, it must be serializable to JSON
            supported = [FLEXRuntimeUtility editableJSONStringForObject:value] != nil;
        } 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;
                // Note: we can't use @encode(NSString) here because that drops the string information and just goes to @encode(id).
                isJSONSerializableType = isJSONSerializableType || strcmp(type, FLEXEncodeClass(NSString)) == 0;
                isJSONSerializableType = isJSONSerializableType || strcmp(type, FLEXEncodeClass(NSNumber)) == 0;
                isJSONSerializableType = isJSONSerializableType || strcmp(type, FLEXEncodeClass(NSArray)) == 0;
                isJSONSerializableType = isJSONSerializableType || strcmp(type, FLEXEncodeClass(NSDictionary)) == 0;
                
                supported = isJSONSerializableType;
            }
        }
    }
    
    return supported;
}

@end


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

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputNotSupportedView : FLEXArgumentInputTextView

@end


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

#import "FLEXArgumentInputNotSupportedView.h"

@implementation FLEXArgumentInputNotSupportedView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputTextView.userInteractionEnabled = NO;
        self.inputTextView.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1.0];
        self.inputTextView.text = @"nil";
        self.targetSize = FLEXArgumentInputViewSizeSmall;
    }
    return self;
}

@end


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

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputNumberView : FLEXArgumentInputTextView

@end


================================================
FILE: FLEX/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.m
================================================
//
//  FLEXArgumentInputNumberView.m
//  Flipboard
//
//  Created by Ryan Olson on 6/15/14.
//  Copyright (c) 2014 Flipboard. 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
{
    static NSArray<NSString *> *primitiveTypes = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        primitiveTypes = @[@(@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))];
    });
    return type && [primitiveTypes containsObject:@(type)];
}

@end


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

#import "FLEXArgumentInputTextView.h"

@interface FLEXArgumentInputStringView : FLEXArgumentInputTextView

@end


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

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

@implementation FLEXArgumentInputStringView

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

- (void)setInputValue:(id)inputValue
{
    self.inputTextView.text = inputValue;
}

- (id)inputValue
{
    // Interpret empty string as nil. We loose the ablitiy to set empty string as a string value,
    // but we accept that tradeoff in exchange for not having to type quotes for every string.
    return [self.inputTextView.text length] > 0 ? [self.inputTextView.text copy] : nil;
}


#pragma mark -

+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value
{
    BOOL supported = type && strcmp(type, FLEXEncodeClass(NSString)) == 0;
    supported = supported || (value && [value isKindOfClass:[NSString class]]);
    return supported;
}

@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputStructView : FLEXArgumentInputView

@end


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

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

@interface FLEXArgumentInputStructView ()

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

@end

@implementation FLEXArgumentInputStructView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        NSMutableArray<FLEXArgumentInputView *> *inputViews = [NSMutableArray array];
        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.backgroundColor = self.backgroundColor;
            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;
            @try {
                // NSGetSizeAndAlignment barfs on type encoding for bitfields.
                NSGetSizeAndAlignment(structTypeEncoding, &valueSize, NULL);
            } @catch (NSException *exception) { }
            
            if (valueSize > 0) {
                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] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
                        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;
    @try {
        // NSGetSizeAndAlignment barfs on type encoding for bitfields.
        NSGetSizeAndAlignment(structTypeEncoding, &structSize, NULL);
    } @catch (NSException *exception) { }
    
    if (structSize > 0) {
        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] == @encode(id)[0] || fieldTypeEncoding[0] == @encode(Class)[0]) {
                // 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
{
    return type && type[0] == '{';
}

+ (NSArray<NSString *> *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding
{
    NSArray<NSString *> *customTitles = nil;
    if (strcmp(typeEncoding, @encode(CGRect)) == 0) {
        customTitles = @[@"CGPoint origin", @"CGSize size"];
    } else if (strcmp(typeEncoding, @encode(CGPoint)) == 0) {
        customTitles = @[@"CGFloat x", @"CGFloat y"];
    } else if (strcmp(typeEncoding, @encode(CGSize)) == 0) {
        customTitles = @[@"CGFloat width", @"CGFloat height"];
    } else if (strcmp(typeEncoding, @encode(UIEdgeInsets)) == 0) {
        customTitles = @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"];
    } else if (strcmp(typeEncoding, @encode(UIOffset)) == 0) {
        customTitles = @[@"CGFloat horizontal", @"CGFloat vertical"];
    } else if (strcmp(typeEncoding, @encode(NSRange)) == 0) {
        customTitles = @[@"NSUInteger location", @"NSUInteger length"];
    } else if (strcmp(typeEncoding, @encode(CATransform3D)) == 0) {
        customTitles = @[@"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"];
    } else if (strcmp(typeEncoding, @encode(CGAffineTransform)) == 0) {
        customTitles = @[@"CGFloat a", @"CGFloat b",
                         @"CGFloat c", @"CGFloat d",
                         @"CGFloat tx", @"CGFloat ty"];
    }
    return customTitles;
}

@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputSwitchView : FLEXArgumentInputView

@end


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

#import "FLEXArgumentInputSwitchView.h"

@interface FLEXArgumentInputSwitchView ()

@property (nonatomic, strong) UISwitch *inputSwitch;

@end

@implementation FLEXArgumentInputSwitchView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputSwitch = [[UISwitch alloc] init];
        [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
{
    // Only BOOLs. Current value is irrelevant.
    return type && strcmp(type, @encode(BOOL)) == 0;
}

@end


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

#import "FLEXArgumentInputView.h"

@interface FLEXArgumentInputTextView : FLEXArgumentInputView

// For subclass eyes only

@property (nonatomic, strong, readonly) UITextView *inputTextView;

@end


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

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

@interface FLEXArgumentInputTextView () <UITextViewDelegate>

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

@end

@implementation FLEXArgumentInputTextView

- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
{
    self = [super initWithArgumentTypeEncoding:typeEncoding];
    if (self) {
        self.inputTextView = [[UITextView alloc] init];
        self.inputTextView.font = [[self class] inputFont];
        self.inputTextView.backgroundColor = [UIColor whiteColor];
        self.inputTextView.layer.borderColor = [[UIColor blackColor] CGColor];
        self.inputTextView.layer.borderWidth = 1.0;
        self.inputTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
        self.inputTextView.autocorrectionType = UITextAutocorrectionTypeNo;
        self.inputTextView.delegate = self;
        self.inputTextView.inputAccessoryView = [self createToolBar];
        [self addSubview:self.inputTextView];
    }
    return self;
}

#pragma mark - private

- (UIToolbar*)createToolBar
{
    UIToolbar *toolBar = [UIToolbar new];
    [toolBar sizeToFit];
    UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
    UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(textViewDone)];
    toolBar.items = @[spaceItem, doneItem];
    return toolBar;
}

- (void)textViewDone
{
    [self.inputTextView resignFirstResponder];
}


#pragma mark - Text View Changes

- (void)textViewDidChange:(UITextView *)textView
{
    [self.delegate argumentInputViewValueDidChange:self];
}


#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]);
}

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

- (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 [FLEXUtility defaultFontOfSize:14.0];
}

@end


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

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSUInteger, FLEXArgumentInputViewSize) {
    FLEXArgumentInputViewSizeDefault = 0,
    FLEXArgumentInputViewSizeSmall,
    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 *must* override both the setter and getter for this property.
@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, assign) 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, strong, readonly) UILabel *titleLabel;
@property (nonatomic, strong, readonly) NSString *typeEncoding;
@property (nonatomic, readonly) CGFloat topInputFieldVerticalLayoutGuide;

@end

@protocol FLEXArgumentInputViewDelegate <NSObject>

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

@end


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

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

@interface FLEXArgumentInputView ()

@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) 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 alloc] init];
        _titleLabel.font = [[self class] titleFont];
        _titleLabel.backgroundColor = self.backgroundColor;
        _titleLabel.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
        _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;
}

- (void)setInputValue:(id)inputValue
{
    // Subclasses should override.
}

- (id)inputValue
{
    // Subclasses should override.
    return nil;
}

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


#pragma mark - Class Helpers

+ (UIFont *)titleFont
{
    return [FLEXUtility defaultFontOfSize: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: FLEX/Editing/ArgumentInputViews/FLEXArgumentInputViewFactory.h
================================================
//
//  FLEXArgumentInputViewFactory.h
//  FLEXInjected
//
//  Created by Ryan Olson on 6/15/14.
//
//

#import <Foundation/Foundation.h>

@class FLEXArgumentInputView;

@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;

@end


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

#import "FLEXArgumentInputViewFactory.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputJSONObjectView.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"

@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];
    }
    return [[subclass alloc] initWithArgumentTypeEncoding:typeEncoding];
}

+ (Class)argumentInputViewSubclassForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue
{
    Class argumentInputViewSubclass = nil;
    
    // 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.
    if ([FLEXArgumentInputColorView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputColorView class];
    } else if ([FLEXArgumentInputFontView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputFontView class];
    } else if ([FLEXArgumentInputStringView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputStringView class];
    } else if ([FLEXArgumentInputStructView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputStructView class];
    } else if ([FLEXArgumentInputSwitchView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputSwitchView class];
    } else if ([FLEXArgumentInputDateView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputDateView class];
    } else if ([FLEXArgumentInputNumberView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputNumberView class];
    } else if ([FLEXArgumentInputJSONObjectView supportsObjCType:typeEncoding withCurrentValue:currentValue]) {
        argumentInputViewSubclass = [FLEXArgumentInputJSONObjectView class];
    }
    
    return argumentInputViewSubclass;
}

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

@end


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

#import "FLEXFieldEditorViewController.h"

@interface FLEXDefaultEditorViewController : FLEXFieldEditorViewController

- (id)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key;

+ (BOOL)canEditDefaultWithValue:(id)currentValue;

@end


================================================
FILE: FLEX/Editing/FLEXDefaultEditorViewController.m
================================================
//
//  FLEXDefaultEditorViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 5/23/14.
//  Copyright (c) 2014 Flipboard. 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, strong) NSString *key;

@end

@implementation FLEXDefaultEditorViewController

- (id)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key
{
    self = [super initWithTarget:defaults];
    if (self) {
        self.key = key;
        self.title = @"Edit Default";
    }
    return self;
}

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

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

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

- (void)actionButtonPressed:(id)sender
{
    [super actionButtonPressed:sender];
    
    id value = self.firstInputView.inputValue;
    if (value) {
        [self.defaults setObject:value forKey:self.key];
    } else {
        [self.defaults removeObjectForKey:self.key];
    }
    [self.defaults synchronize];

    self.firstInputView.inputValue = [self.defaults objectForKey:self.key];
}

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

@end


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

#import <UIKit/UIKit.h>

@class FLEXArgumentInputView;

@interface FLEXFieldEditorView : UIView

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

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

@end


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

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

@interface FLEXFieldEditorView ()

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

@end

@implementation FLEXFieldEditorView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.targetDescriptionLabel = [[UILabel alloc] init];
        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 alloc] init];
        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 alloc] init];
    dividerView.backgroundColor = [self dividerColor];
    return dividerView;
}

+ (UIColor *)dividerColor
{
    return [UIColor lightGrayColor];
}

+ (CGFloat)horizontalPadding
{
    return 10.0;
}

+ (CGFloat)verticalPadding
{
    return 20.0;
}

+ (UIFont *)labelFont
{
    return [FLEXUtility defaultFontOfSize: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: FLEX/Editing/FLEXFieldEditorViewController.h
================================================
//
//  FLEXFieldEditorViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 5/16/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import <UIKit/UIKit.h>

@class FLEXFieldEditorView;
@class FLEXArgumentInputView;

@interface FLEXFieldEditorViewController : UIViewController

- (id)initWithTarget:(id)target;

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

// For subclass use only.
@property (nonatomic, strong, readonly) id target;
@property (nonatomic, strong, readonly) FLEXFieldEditorView *fieldEditorView;
@property (nonatomic, strong, readonly) UIBarButtonItem *setterButton;
- (void)actionButtonPressed:(id)sender;
- (NSString *)titleForActionButton;

@end


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

#import "FLEXFieldEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"

@interface FLEXFieldEditorViewController () <UIScrollViewDelegate>

@property (nonatomic, strong) UIScrollView *scrollView;

@property (nonatomic, strong, readwrite) id target;
@property (nonatomic, strong, readwrite) FLEXFieldEditorView *fieldEditorView;
@property (nonatomic, strong, readwrite) UIBarButtonItem *setterButton;

@end

@implementation FLEXFieldEditorViewController

- (id)initWithTarget:(id)target
{
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
        self.target = target;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

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

- (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 = [FLEXUtility scrollViewGrayColor];
    
    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];
    
    self.fieldEditorView = [[FLEXFieldEditorView alloc] init];
    self.fieldEditorView.backgroundColor = self.view.backgroundColor;
    self.fieldEditorView.targetDescription = [NSString stringWithFormat:@"%@ %p", [self.target class], self.target];
    [self.scrollView addSubview:self.fieldEditorView];
    
    self.setterButton = [[UIBarButtonItem alloc] initWithTitle:[self titleForActionButton] style:UIBarButtonItemStyleDone target:self action:@selector(actionButtonPressed:)];
    self.navigationItem.rightBarButtonItem = self.setterButton;
}

- (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;
}

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

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

- (NSString *)titleForActionButton
{
    // Subclasses can override.
    return @"Set";
}

@end


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

#import "FLEXFieldEditorViewController.h"
#import <objc/runtime.h>

@interface FLEXIvarEditorViewController : FLEXFieldEditorViewController

- (id)initWithTarget:(id)target ivar:(Ivar)ivar;

+ (BOOL)canEditIvar:(Ivar)ivar currentValue:(id)value;

@end


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

#import "FLEXIvarEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXArgumentInputSwitchView.h"

@interface FLEXIvarEditorViewController () <FLEXArgumentInputViewDelegate>

@property (nonatomic, assign) Ivar ivar;

@end

@implementation FLEXIvarEditorViewController

- (id)initWithTarget:(id)target ivar:(Ivar)ivar
{
    self = [super initWithTarget:target];
    if (self) {
        self.ivar = ivar;
        self.title = @"Instance Variable";
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility prettyNameForIvar:self.ivar];
    
    FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:ivar_getTypeEncoding(self.ivar)];
    inputView.backgroundColor = self.view.backgroundColor;
    inputView.inputValue = [FLEXRuntimeUtility valueForIvar:self.ivar onObject:self.target];
    inputView.delegate = self;
    self.fieldEditorView.argumentInputViews = @[inputView];
    
    // Don't show a "set" button for switches. Set the ivar when the switch toggles.
    if ([inputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
        self.navigationItem.rightBarButtonItem = nil;
    }
}

- (void)actionButtonPressed:(id)sender
{
    [super actionButtonPressed:sender];
    
    [FLEXRuntimeUtility setValue:self.firstInputView.inputValue forIvar:self.ivar onObject:self.target];
    self.firstInputView.inputValue = [FLEXRuntimeUtility valueForIvar:self.ivar onObject:self.target];
}

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

+ (BOOL)canEditIvar:(Ivar)ivar currentValue:(id)value
{
    return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:ivar_getTypeEncoding(ivar) currentValue:value];
}

@end


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

#import "FLEXFieldEditorViewController.h"
#import <objc/runtime.h>

@interface FLEXMethodCallingViewController : FLEXFieldEditorViewController

- (id)initWithTarget:(id)target method:(Method)method;

@end


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

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

@interface FLEXMethodCallingViewController ()

@property (nonatomic, assign) Method method;

@end

@implementation FLEXMethodCallingViewController

- (id)initWithTarget:(id)target method:(Method)method
{
    self = [super initWithTarget:target];
    if (self) {
        self.method = method;
        self.title = [self isClassMethod] ? @"Class Method" : @"Method";
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility prettyNameForMethod:self.method isClassMethod:[self isClassMethod]];
    
    NSArray<NSString *> *methodComponents = [FLEXRuntimeUtility prettyArgumentComponentsForMethod:self.method];
    NSMutableArray<FLEXArgumentInputView *> *argumentInputViews = [NSMutableArray array];
    unsigned int argumentIndex = kFLEXNumberOfImplicitArgs;
    for (NSString *methodComponent in methodComponents) {
        char *argumentTypeEncoding = method_copyArgumentType(self.method, argumentIndex);
        FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:argumentTypeEncoding];
        free(argumentTypeEncoding);
        
        inputView.backgroundColor = self.view.backgroundColor;
        inputView.title = methodComponent;
        [argumentInputViews addObject:inputView];
        argumentIndex++;
    }
    self.fieldEditorView.argumentInputViews = argumentInputViews;
}

- (BOOL)isClassMethod
{
    return self.target && self.target == [self.target class];
}

- (NSString *)titleForActionButton
{
    return @"Call";
}

- (void)actionButtonPressed:(id)sender
{
    [super actionButtonPressed:sender];
    
    NSMutableArray *arguments = [NSMutableArray array];
    for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
        id argumentValue = inputView.inputValue;
        if (!argumentValue) {
            // Use NSNulls as placeholders in the array. They will be interpreted as nil arguments.
            argumentValue = [NSNull null];
        }
        [arguments addObject:argumentValue];
    }
    
    NSError *error = nil;
    id returnedObject = [FLEXRuntimeUtility performSelector:method_getName(self.method) onObject:self.target withArguments:arguments error:&error];
    
    if (error) {
        NSString *title = @"Method Call Failed";
        NSString *message = [error localizedDescription];
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
    } else if (returnedObject) {
        // For non-nil (or void) return types, push an explorer view controller to display the returned object
        FLEXObjectExplorerViewController *explorerViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:returnedObject];
        [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: FLEX/Editing/FLEXPropertyEditorViewController.h
================================================
//
//  FLEXPropertyEditorViewController.h
//  Flipboard
//
//  Created by Ryan Olson on 5/20/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import "FLEXFieldEditorViewController.h"
#import <objc/runtime.h>

@interface FLEXPropertyEditorViewController : FLEXFieldEditorViewController

- (id)initWithTarget:(id)target property:(objc_property_t)property;

+ (BOOL)canEditProperty:(objc_property_t)property currentValue:(id)value;

@end


================================================
FILE: FLEX/Editing/FLEXPropertyEditorViewController.m
================================================
//
//  FLEXPropertyEditorViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 5/20/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import "FLEXPropertyEditorViewController.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXFieldEditorView.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXArgumentInputSwitchView.h"

@interface FLEXPropertyEditorViewController () <FLEXArgumentInputViewDelegate>

@property (nonatomic, assign) objc_property_t property;

@end

@implementation FLEXPropertyEditorViewController

- (id)initWithTarget:(id)target property:(objc_property_t)property
{
    self = [super initWithTarget:target];
    if (self) {
        self.property = property;
        self.title = @"Property";
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility fullDescriptionForProperty:self.property];
    id currentValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
    self.setterButton.enabled = [[self class] canEditProperty:self.property currentValue:currentValue];
    
    const char *typeEncoding = [[FLEXRuntimeUtility typeEncodingForProperty:self.property] UTF8String];
    FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:typeEncoding];
    inputView.backgroundColor = self.view.backgroundColor;
    inputView.inputValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
    inputView.delegate = self;
    self.fieldEditorView.argumentInputViews = @[inputView];
    
    // Don't show a "set" button for switches - just call the setter immediately after the switch toggles.
    if ([inputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
        self.navigationItem.rightBarButtonItem = nil;
    }
}

- (void)actionButtonPressed:(id)sender
{
    [super actionButtonPressed:sender];
    
    id userInputObject = self.firstInputView.inputValue;
    NSArray *arguments = userInputObject ? @[userInputObject] : nil;
    SEL setterSelector = [FLEXRuntimeUtility setterSelectorForProperty:self.property];
    NSError *error = nil;
    [FLEXRuntimeUtility performSelector:setterSelector onObject:self.target withArguments:arguments error:&error];
    if (error) {
        NSString *title = @"Property Setter Failed";
        NSString *message = [error localizedDescription];
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        self.firstInputView.inputValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
    } else {
        // If the setter was called without error, pop the view controller to indicate that and make the user's life easier.
        // Don't do this for simulated taps on the action button (i.e. from switch/BOOL editors). The experience is weird there.
        if (sender) {
            [self.navigationController popViewControllerAnimated:YES];
        }
    }
}

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

+ (BOOL)canEditProperty:(objc_property_t)property currentValue:(id)value
{
    const char *typeEncoding = [[FLEXRuntimeUtility typeEncodingForProperty:property] UTF8String];
    BOOL canEditType = [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:value];
    BOOL isReadonly = [FLEXRuntimeUtility isReadonlyProperty:property];
    return canEditType && !isReadonly;
}

@end


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

#import <UIKit/UIKit.h>

@protocol FLEXExplorerViewControllerDelegate;

@interface FLEXExplorerViewController : UIViewController

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

- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates;
- (BOOL)wantsWindowToBecomeKey;

/// @brief Used to present (or dismiss) a modal view controller ("tool"), typically triggered by pressing a button in the toolbar.
///
/// If a tool is already presented, this method simply dismisses it and calls the completion block.
/// If no tool is presented, @code future() @endcode is presented and the completion block is called.
- (void)toggleToolWithViewControllerProvider:(UIViewController *(^)(void))future completion:(void(^)(void))completion;

// Keyboard shortcut helpers

- (void)toggleSelectTool;
- (void)toggleMoveTool;
- (void)toggleViewsTool;
- (void)toggleMenuTool;
- (void)handleDownArrowKeyPressed;
- (void)handleUpArrowKeyPressed;
- (void)handleRightArrowKeyPressed;
- (void)handleLeftArrowKeyPressed;

@end

@protocol FLEXExplorerViewControllerDelegate <NSObject>

- (void)explorerViewControllerDidFinish:(FLEXExplorerViewController *)explorerViewController;

@end


================================================
FILE: FLEX/ExplorerInterface/FLEXExplorerViewController.m
================================================
//
//  FLEXExplorerViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 4/4/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import "FLEXExplorerViewController.h"
#import "FLEXExplorerToolbar.h"
#import "FLEXToolbarItem.h"
#import "FLEXUtility.h"
#import "FLEXHierarchyTableViewController.h"
#import "FLEXGlobalsTableViewController.h"
#import "FLEXObjectExplorerViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXNetworkHistoryTableViewController.h"

static NSString *const kFLEXToolbarTopMarginDefaultsKey = @"com.flex.FLEXToolbar.topMargin";

typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
    FLEXExplorerModeDefault,
    FLEXExplorerModeSelect,
    FLEXExplorerModeMove
};

@interface FLEXExplorerViewController () <FLEXHierarchyTableViewControllerDelegate, FLEXGlobalsTableViewControllerDelegate>

@property (nonatomic, strong) FLEXExplorerToolbar *explorerToolbar;

/// Tracks the currently active tool/mode
@property (nonatomic, assign) FLEXExplorerMode currentMode;

/// Gesture recognizer for dragging a view in move mode
@property (nonatomic, strong) UIPanGestureRecognizer *movePanGR;

/// Gesture recognizer for showing additional details on the selected view
@property (nonatomic, strong) UITapGestureRecognizer *detailsTapGR;

/// Only valid while a move pan gesture is in progress.
@property (nonatomic, assign) CGRect selectedViewFrameBeforeDragging;

/// Only valid while a toolbar drag pan gesture is in progress.
@property (nonatomic, assign) CGRect toolbarFrameBeforeDragging;

/// Borders of all the visible views in the hierarchy at the selection point.
/// The keys are NSValues with the correponding view (nonretained).
@property (nonatomic, strong) NSDictionary<NSValue *, UIView *> *outlineViewsForVisibleViews;

/// The actual views at the selection point with the deepest view last.
@property (nonatomic, strong) NSArray<UIView *> *viewsAtTapPoint;

/// The view that we're currently highlighting with an overlay and displaying details for.
@property (nonatomic, strong) UIView *selectedView;

/// A colored transparent overlay to indicate that the view is selected.
@property (nonatomic, strong) UIView *selectedViewOverlay;

/// Tracked so we can restore the key window after dismissing a modal.
/// We need to become key after modal presentation so we can correctly capture intput.
/// If we're just showing the toolbar, we want the main app's window to remain key so that we don't interfere with input, status bar, etc.
@property (nonatomic, strong) UIWindow *previousKeyWindow;

/// Similar to the previousKeyWindow property above, we need to track status bar styling if
/// the app doesn't use view controller based status bar management. When we present a modal,
/// we want to change the status bar style to UIStausBarStyleDefault. Before changing, we stash
/// the current style. On dismissal, we return the staus bar to the style that the app was using previously.
@property (nonatomic, assign) UIStatusBarStyle previousStatusBarStyle;

/// All views that we're KVOing. Used to help us clean up properly.
@property (nonatomic, strong) NSMutableSet<UIView *> *observedViews;

@end

@implementation FLEXExplorerViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.observedViews = [NSMutableSet set];
    }
    return self;
}

-(void)dealloc
{
    for (UIView *view in _observedViews) {
        [self stopObservingView:view];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
	
    // Toolbar
    self.explorerToolbar = [[FLEXExplorerToolbar alloc] init];

    // Start the toolbar off below any bars that may be at the top of the view.
    id toolbarOriginYDefault = [[NSUserDefaults standardUserDefaults] objectForKey:kFLEXToolbarTopMarginDefaultsKey];
    CGFloat toolbarOriginY = toolbarOriginYDefault ? [toolbarOriginYDefault doubleValue] : 100;

    CGRect safeArea = [self viewSafeArea];
    CGSize toolbarSize = [self.explorerToolbar sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(safeArea))];
    [self updateToolbarPositionWithUnconstrainedFrame:CGRectMake(CGRectGetMinX(safeArea), toolbarOriginY, toolbarSize.width, toolbarSize.height)];
    self.explorerToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
    [self.view addSubview:self.explorerToolbar];
    [self setupToolbarActions];
    [self setupToolbarGestures];
    
    // View selection
    UITapGestureRecognizer *selectionTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSelectionTap:)];
    [self.view addGestureRecognizer:selectionTapGR];
    
    // View moving
    self.movePanGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMovePan:)];
    self.movePanGR.enabled = self.currentMode == FLEXExplorerModeMove;
    [self.view addGestureRecognizer:self.movePanGR];
}

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


#pragma mark - Rotation

- (UIViewController *)viewControllerForRotationAndOrientation
{
    UIWindow *window = self.previousKeyWindow ?: [[UIApplication sharedApplication] keyWindow];
    UIViewController *viewController = window.rootViewController;
    NSString *viewControllerSelectorString = [@[@"_vie", @"wContro", @"llerFor", @"Supported", @"Interface", @"Orientations"] componentsJoinedByString:@""];
    SEL viewControllerSelector = NSSelectorFromString(viewControllerSelectorString);
    if ([viewController respondsToSelector:viewControllerSelector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        viewController = [viewController performSelector:viewControllerSelector];
#pragma clang diagnostic pop
    }
    return viewController;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    UIViewController *viewControllerToAsk = [self viewControllerForRotationAndOrientation];
    UIInterfaceOrientationMask supportedOrientations = [FLEXUtility infoPlistSupportedInterfaceOrientationsMask];
    if (viewControllerToAsk && viewControllerToAsk != self) {
        supportedOrientations = [viewControllerToAsk supportedInterfaceOrientations];
    }
    
    // The UIViewController docs state that this method must not return zero.
    // If we weren't able to get a valid value for the supported interface orientations, default to all supported.
    if (supportedOrientations == 0) {
        supportedOrientations = UIInterfaceOrientationMaskAll;
    }
    
    return supportedOrientations;
}

- (BOOL)shouldAutorotate
{
    UIViewController *viewControllerToAsk = [self viewControllerForRotationAndOrientation];
    BOOL shouldAutorotate = YES;
    if (viewControllerToAsk && viewControllerToAsk != self) {
        shouldAutorotate = [viewControllerToAsk shouldAutorotate];
    }
    return shouldAutorotate;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
         for (UIView *outlineView in [self.outlineViewsForVisibleViews allValues]) {
             outlineView.hidden = YES;
         }
         self.selectedViewOverlay.hidden = YES;
     } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
         for (UIView *view in self.viewsAtTapPoint) {
             NSValue *key = [NSValue valueWithNonretainedObject:view];
             UIView *outlineView = self.outlineViewsForVisibleViews[key];
             outlineView.frame = [self frameInLocalCoordinatesForView:view];
             if (self.currentMode == FLEXExplorerModeSelect) {
                 outlineView.hidden = NO;
             }
         }

         if (self.selectedView) {
             self.selectedViewOverlay.frame = [self frameInLocalCoordinatesForView:self.selectedView];
             self.selectedViewOverlay.hidden = NO;
         }
     }];
}

#pragma mark - Setter Overrides

- (void)setSelectedView:(UIView *)selectedView
{
    if (![_selectedView isEqual:selectedView]) {
        if (![self.viewsAtTapPoint containsObject:_selectedView]) {
            [self stopObservingView:_selectedView];
        }
        
        _selectedView = selectedView;
        
        [self beginObservingView:selectedView];

        // Update the toolbar and selected overlay
        self.explorerToolbar.selectedViewDescription = [FLEXUtility descriptionForView:selectedView includingFrame:YES];
        self.explorerToolbar.selectedViewOverlayColor = [FLEXUtility consistentRandomColorForObject:selectedView];

        if (selectedView) {
            if (!self.selectedViewOverlay) {
                self.selectedViewOverlay = [[UIView alloc] init];
                [self.view addSubview:self.selectedViewOverlay];
                self.selectedViewOverlay.layer.borderWidth = 1.0;
            }
            UIColor *outlineColor = [FLEXUtility consistentRandomColorForObject:selectedView];
            self.selectedViewOverlay.backgroundColor = [outlineColor colorWithAlphaComponent:0.2];
            self.selectedViewOverlay.layer.borderColor = [outlineColor CGColor];
            self.selectedViewOverlay.frame = [self.view convertRect:selectedView.bounds fromView:selectedView];
            
            // Make sure the selected overlay is in front of all the other subviews except the toolbar, which should always stay on top.
            [self.view bringSubviewToFront:self.selectedViewOverlay];
            [self.view bringSubviewToFront:self.explorerToolbar];
        } else {
            [self.selectedViewOverlay removeFromSuperview];
            self.selectedViewOverlay = nil;
        }
        
        // Some of the button states depend on whether we have a selected view.
        [self updateButtonStates];
    }
}

- (void)setViewsAtTapPoint:(NSArray<UIView *> *)viewsAtTapPoint
{
    if (![_viewsAtTapPoint isEqual:viewsAtTapPoint]) {
        for (UIView *view in _viewsAtTapPoint) {
            if (view != self.selectedView) {
                [self stopObservingView:view];
            }
        }
        
        _viewsAtTapPoint = viewsAtTapPoint;
        
        for (UIView *view in viewsAtTapPoint) {
            [self beginObservingView:view];
        }
    }
}

- (void)setCurrentMode:(FLEXExplorerMode)currentMode
{
    if (_currentMode != currentMode) {
        _currentMode = currentMode;
        switch (currentMode) {
            case FLEXExplorerModeDefault:
                [self removeAndClearOutlineViews];
                self.viewsAtTapPoint = nil;
                self.selectedView = nil;
                break;
                
            case FLEXExplorerModeSelect:
                // Make sure the outline views are unhidden in case we came from the move mode.
                for (NSValue *key in self.outlineViewsForVisibleViews) {
                    UIView *outlineView = self.outlineViewsForVisibleViews[key];
                    outlineView.hidden = NO;
                }
                break;
                
            case FLEXExplorerModeMove:
                // Hide all the outline views to focus on the selected view, which is the only one that will move.
                for (NSValue *key in self.outlineViewsForVisibleViews) {
                    UIView *outlineView = self.outlineViewsForVisibleViews[key];
                    outlineView.hidden = YES;
                }
                break;
        }
        self.movePanGR.enabled = currentMode == FLEXExplorerModeMove;
        [self updateButtonStates];
    }
}


#pragma mark - View Tracking

- (void)beginObservingView:(UIView *)view
{
    // Bail if we're already observing this view or if there's nothing to observe.
    if (!view || [self.observedViews containsObject:view]) {
        return;
    }
    
    for (NSString *keyPath in [[self class] viewKeyPathsToTrack]) {
        [view addObserver:self forKeyPath:keyPath options:0 context:NULL];
    }
    
    [self.observedViews addObject:view];
}

- (void)stopObservingView:(UIView *)view
{
    if (!view) {
        return;
    }
    
    for (NSString *keyPath in [[self class] viewKeyPathsToTrack]) {
        [view removeObserver:self forKeyPath:keyPath];
    }
    
    [self.observedViews removeObject:view];
}

+ (NSArray<NSString *> *)viewKeyPathsToTrack
{
    static NSArray<NSString *> *trackedViewKeyPaths = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSString *frameKeyPath = NSStringFromSelector(@selector(frame));
        trackedViewKeyPaths = @[frameKeyPath];
    });
    return trackedViewKeyPaths;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context
{
    [self updateOverlayAndDescriptionForObjectIfNeeded:object];
}

- (void)updateOverlayAndDescriptionForObjectIfNeeded:(id)object
{
    NSUInteger indexOfView = [self.viewsAtTapPoint indexOfObject:object];
    if (indexOfView != NSNotFound) {
        UIView *view = self.viewsAtTapPoint[indexOfView];
        NSValue *key = [NSValue valueWithNonretainedObject:view];
        UIView *outline = self.outlineViewsForVisibleViews[key];
        if (outline) {
            outline.frame = [self frameInLocalCoordinatesForView:view];
        }
    }
    if (object == self.selectedView) {
        // Update the selected view description since we show the frame value there.
        self.explorerToolbar.selectedViewDescription = [FLEXUtility descriptionForView:self.selectedView includingFrame:YES];
        CGRect selectedViewOutlineFrame = [self frameInLocalCoordinatesForView:self.selectedView];
        self.selectedViewOverlay.frame = selectedViewOutlineFrame;
    }
}

- (CGRect)frameInLocalCoordinatesForView:(UIView *)view
{
    // First convert to window coordinates since the view may be in a different window than our view.
    CGRect frameInWindow = [view convertRect:view.bounds toView:nil];
    // Then convert from the window to our view's coordinate space.
    return [self.view convertRect:frameInWindow fromView:nil];
}


#pragma mark - Toolbar Buttons

- (void)setupToolbarActions
{
    [self.explorerToolbar.selectItem addTarget:self action:@selector(selectButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.explorerToolbar.hierarchyItem addTarget:self action:@selector(hierarchyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.explorerToolbar.moveItem addTarget:self action:@selector(moveButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.explorerToolbar.globalsItem addTarget:self action:@selector(globalsButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    [self.explorerToolbar.closeItem addTarget:self action:@selector(closeButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)selectButtonTapped:(FLEXToolbarItem *)sender
{
    [self toggleSelectTool];
}

- (void)hierarchyButtonTapped:(FLEXToolbarItem *)sender
{
    [self toggleViewsTool];
}

- (NSArray<UIView *> *)allViewsInHierarchy
{
    NSMutableArray<UIView *> *allViews = [NSMutableArray array];
    NSArray<UIWindow *> *windows = [FLEXUtility allWindows];
    for (UIWindow *window in windows) {
        if (window != self.view.window) {
            [allViews addObject:window];
            [allViews addObjectsFromArray:[self allRecursiveSubviewsInView:window]];
        }
    }
    return allViews;
}

- (UIWindow *)statusWindow
{
    NSString *statusBarString = [NSString stringWithFormat:@"%@arWindow", @"_statusB"];
    return [[UIApplication sharedApplication] valueForKey:statusBarString];
}

- (void)moveButtonTapped:(FLEXToolbarItem *)sender
{
    [self toggleMoveTool];
}

- (void)globalsButtonTapped:(FLEXToolbarItem *)sender
{
    [self toggleMenuTool];
}

- (void)closeButtonTapped:(FLEXToolbarItem *)sender
{
    self.currentMode = FLEXExplorerModeDefault;
    [self.delegate explorerViewControllerDidFinish:self];
}

- (void)updateButtonStates
{
    // Move and details only active when an object is selected.
    BOOL hasSelectedObject = self.selectedView != nil;
    self.explorerToolbar.moveItem.enabled = hasSelectedObject;
    self.explorerToolbar.selectItem.selected = self.currentMode == FLEXExplorerModeSelect;
    self.explorerToolbar.moveItem.selected = self.currentMode == FLEXExplorerModeMove;
}


#pragma mark - Toolbar Dragging

- (void)setupToolbarGestures
{
    // Pan gesture for dragging.
    UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleToolbarPanGesture:)];
    [self.explorerToolbar.dragHandle addGestureRecognizer:panGR];
    
    // Tap gesture for hinting.
    UITapGestureRecognizer *hintTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleToolbarHintTapGesture:)];
    [self.explorerToolbar.dragHandle addGestureRecognizer:hintTapGR];
    
    // Tap gesture for showing additional details
    self.detailsTapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleToolbarDetailsTapGesture:)];
    [self.explorerToolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
}

- (void)handleToolbarPanGesture:(UIPanGestureRecognizer *)panGR
{
    switch (panGR.state) {
        case UIGestureRecognizerStateBegan:
            self.toolbarFrameBeforeDragging = self.explorerToolbar.frame;
            [self updateToolbarPostionWithDragGesture:panGR];
            break;
            
        case UIGestureRecognizerStateChanged:
        case UIGestureRecognizerStateEnded:
            [self updateToolbarPostionWithDragGesture:panGR];
            break;
            
        default:
            break;
    }
}

- (void)updateToolbarPostionWithDragGesture:(UIPanGestureRecognizer *)panGR
{
    CGPoint translation = [panGR translationInView:self.view];
    CGRect newToolbarFrame = self.toolbarFrameBeforeDragging;
    newToolbarFrame.origin.y += translation.y;
    
    [self updateToolbarPositionWithUnconstrainedFrame:newToolbarFrame];
}

- (void)updateToolbarPositionWithUnconstrainedFrame:(CGRect)unconstrainedFrame
{
    CGRect safeArea = [self viewSafeArea];
    // We only constrain the Y-axis because We want the toolbar to handle the X-axis safeArea layout by itself
    CGFloat minY = CGRectGetMinY(safeArea);
    CGFloat maxY = CGRectGetMaxY(safeArea) - unconstrainedFrame.size.height;
    if (unconstrainedFrame.origin.y < minY) {
        unconstrainedFrame.origin.y = minY;
    } else if (unconstrainedFrame.origin.y > maxY) {
        unconstrainedFrame.origin.y = maxY;
    }

    self.explorerToolbar.frame = unconstrainedFrame;

    [[NSUserDefaults standardUserDefaults] setDouble:unconstrainedFrame.origin.y forKey:kFLEXToolbarTopMarginDefaultsKey];
}

- (void)handleToolbarHintTapGesture:(UITapGestureRecognizer *)tapGR
{
    // Bounce the toolbar to indicate that it is draggable.
    // TODO: make it bouncier.
    if (tapGR.state == UIGestureRecognizerStateRecognized) {
        CGRect originalToolbarFrame = self.explorerToolbar.frame;
        const NSTimeInterval kHalfwayDuration = 0.2;
        const CGFloat kVerticalOffset = 30.0;
        [UIView animateWithDuration:kHalfwayDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            CGRect newToolbarFrame = self.explorerToolbar.frame;
            newToolbarFrame.origin.y += kVerticalOffset;
            self.explorerToolbar.frame = newToolbarFrame;
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:kHalfwayDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
                self.explorerToolbar.frame = originalToolbarFrame;
            } completion:nil];
        }];
    }
}

- (void)handleToolbarDetailsTapGesture:(UITapGestureRecognizer *)tapGR
{
    if (tapGR.state == UIGestureRecognizerStateRecognized && self.selectedView) {
        FLEXObjectExplorerViewController *selectedViewExplorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:self.selectedView];
        selectedViewExplorer.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(selectedViewExplorerFinished:)];
        UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:selectedViewExplorer];
        [self makeKeyAndPresentViewController:navigationController animated:YES completion:nil];
    }
}


#pragma mark - View Selection

- (void)handleSelectionTap:(UITapGestureRecognizer *)tapGR
{
    // Only if we're in selection mode
    if (self.currentMode == FLEXExplorerModeSelect && tapGR.state == UIGestureRecognizerStateRecognized) {
        // Note that [tapGR locationInView:nil] is broken in iOS 8, so we have to do a two step conversion to window coordinates.
        // Thanks to @lascorbe for finding this: https://github.com/Flipboard/FLEX/pull/31
        CGPoint tapPointInView = [tapGR locationInView:self.view];
        CGPoint tapPointInWindow = [self.view convertPoint:tapPointInView toView:nil];
        [self updateOutlineViewsForSelectionPoint:tapPointInWindow];
    }
}

- (void)updateOutlineViewsForSelectionPoint:(CGPoint)selectionPointInWindow
{
    [self removeAndClearOutlineViews];
    
    // Include hidden views in the "viewsAtTapPoint" array so we can show them in the hierarchy list.
    self.viewsAtTapPoint = [self viewsAtPoint:selectionPointInWindow skipHiddenViews:NO];
    
    // For outlined views and the selected view, only use visible views.
    // Outlining hidden views adds clutter and makes the selection behavior confusing.
    NSArray<UIView *> *visibleViewsAtTapPoint = [self viewsAtPoint:selectionPointInWindow skipHiddenViews:YES];
    NSMutableDictionary<NSValue *, UIView *> *newOutlineViewsForVisibleViews = [NSMutableDictionary dictionary];
    for (UIView *view in visibleViewsAtTapPoint) {
        UIView *outlineView = [self outlineViewForView:view];
        [self.view addSubview:outlineView];
        NSValue *key = [NSValue valueWithNonretainedObject:view];
        [newOutlineViewsForVisibleViews setObject:outlineView forKey:key];
    }
    self.outlineViewsForVisibleViews = newOutlineViewsForVisibleViews;
    self.selectedView = [self viewForSelectionAtPoint:selectionPointInWindow];
    
    // Make sure the explorer toolbar doesn't end up behind the newly added outline views.
    [self.view bringSubviewToFront:self.explorerToolbar];
    
    [self updateButtonStates];
}

- (UIView *)outlineViewForView:(UIView *)view
{
    CGRect outlineFrame = [self frameInLocalCoordinatesForView:view];
    UIView *outlineView = [[UIView alloc] initWithFrame:outlineFrame];
    outlineView.backgroundColor = [UIColor clearColor];
    outlineView.layer.borderColor = [[FLEXUtility consistentRandomColorForObject:view] CGColor];
    outlineView.layer.borderWidth = 1.0;
    return outlineView;
}

- (void)removeAndClearOutlineViews
{
    for (NSValue *key in self.outlineViewsForVisibleViews) {
        UIView *outlineView = self.outlineViewsForVisibleViews[key];
        [outlineView removeFromSuperview];
    }
    self.outlineViewsForVisibleViews = nil;
}

- (NSArray<UIView *> *)viewsAtPoint:(CGPoint)tapPointInWindow skipHiddenViews:(BOOL)skipHidden
{
    NSMutableArray<UIView *> *views = [NSMutableArray array];
    for (UIWindow *window in [FLEXUtility allWindows]) {
        // Don't include the explorer's own window or subviews.
        if (window != self.view.window && [window pointInside:tapPointInWindow withEvent:nil]) {
            [views addObject:window];
            [views addObjectsFromArray:[self recursiveSubviewsAtPoint:tapPointInWindow inView:window skipHiddenViews:skipHidden]];
        }
    }
    return views;
}

- (UIView *)viewForSelectionAtPoint:(CGPoint)tapPointInWindow
{
    // Select in the window that would handle the touch, but don't just use the result of hitTest:withEvent: so we can still select views with interaction disabled.
    // Default to the the application's key window if none of the windows want the touch.
    UIWindow *windowForSelection = [[UIApplication sharedApplication] keyWindow];
    for (UIWindow *window in [[FLEXUtility allWindows] reverseObjectEnumerator]) {
        // Ignore the explorer's own window.
        if (window != self.view.window) {
            if ([window hitTest:tapPointInWindow withEvent:nil]) {
                windowForSelection = window;
                break;
            }
        }
    }
    
    // Select the deepest visible view at the tap point. This generally corresponds to what the user wants to select.
    return [[self recursiveSubviewsAtPoint:tapPointInWindow inView:windowForSelection skipHiddenViews:YES] lastObject];
}

- (NSArray<UIView *> *)recursiveSubviewsAtPoint:(CGPoint)pointInView inView:(UIView *)view skipHiddenViews:(BOOL)skipHidden
{
    NSMutableArray<UIView *> *subviewsAtPoint = [NSMutableArray array];
    for (UIView *subview in view.subviews) {
        BOOL isHidden = subview.hidden || subview.alpha < 0.01;
        if (skipHidden && isHidden) {
            continue;
        }
        
        BOOL subviewContainsPoint = CGRectContainsPoint(subview.frame, pointInView);
        if (subviewContainsPoint) {
            [subviewsAtPoint addObject:subview];
        }
        
        // If this view doesn't clip to its bounds, we need to check its subviews even if it doesn't contain the selection point.
        // They may be visible and contain the selection point.
        if (subviewContainsPoint || !subview.clipsToBounds) {
            CGPoint pointInSubview = [view convertPoint:pointInView toView:subview];
            [subviewsAtPoint addObjectsFromArray:[self recursiveSubviewsAtPoint:pointInSubview inView:subview skipHiddenViews:skipHidden]];
        }
    }
    return subviewsAtPoint;
}

- (NSArray<UIView *> *)allRecursiveSubviewsInView:(UIView *)view
{
    NSMutableArray<UIView *> *subviews = [NSMutableArray array];
    for (UIView *subview in view.subviews) {
        [subviews addObject:subview];
        [subviews addObjectsFromArray:[self allRecursiveSubviewsInView:subview]];
    }
    return subviews;
}

- (NSDictionary<NSValue *, NSNumber *> *)hierarchyDepthsForViews:(NSArray<UIView *> *)views
{
    NSMutableDictionary<NSVa
Download .txt
gitextract_d9aulut5/

├── .gitignore
├── ARChromeActivity/
│   ├── ARChromeActivity.h
│   └── ARChromeActivity.m
├── CSURITemplate/
│   ├── CSURITemplate.h
│   └── CSURITemplate.m
├── ECSlidingViewController/
│   ├── ECSlidingViewController.h
│   ├── ECSlidingViewController.m
│   ├── UIImage+ImageWithUIView.h
│   └── UIImage+ImageWithUIView.m
├── FLEX/
│   ├── Editing/
│   │   ├── ArgumentInputViews/
│   │   │   ├── FLEXArgumentInputColorView.h
│   │   │   ├── FLEXArgumentInputColorView.m
│   │   │   ├── FLEXArgumentInputDateView.h
│   │   │   ├── FLEXArgumentInputDateView.m
│   │   │   ├── FLEXArgumentInputFontView.h
│   │   │   ├── FLEXArgumentInputFontView.m
│   │   │   ├── FLEXArgumentInputFontsPickerView.h
│   │   │   ├── FLEXArgumentInputFontsPickerView.m
│   │   │   ├── FLEXArgumentInputJSONObjectView.h
│   │   │   ├── FLEXArgumentInputJSONObjectView.m
│   │   │   ├── FLEXArgumentInputNotSupportedView.h
│   │   │   ├── FLEXArgumentInputNotSupportedView.m
│   │   │   ├── FLEXArgumentInputNumberView.h
│   │   │   ├── FLEXArgumentInputNumberView.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
│   │   ├── FLEXIvarEditorViewController.h
│   │   ├── FLEXIvarEditorViewController.m
│   │   ├── FLEXMethodCallingViewController.h
│   │   ├── FLEXMethodCallingViewController.m
│   │   ├── FLEXPropertyEditorViewController.h
│   │   └── FLEXPropertyEditorViewController.m
│   ├── ExplorerInterface/
│   │   ├── FLEXExplorerViewController.h
│   │   ├── FLEXExplorerViewController.m
│   │   ├── FLEXWindow.h
│   │   └── FLEXWindow.m
│   ├── FLEX.h
│   ├── FLEXManager.h
│   ├── GlobalStateExplorers/
│   │   ├── DatabaseBrowser/
│   │   │   ├── FLEXDatabaseManager.h
│   │   │   ├── FLEXMultiColumnTableView.h
│   │   │   ├── FLEXMultiColumnTableView.m
│   │   │   ├── FLEXRealmDatabaseManager.h
│   │   │   ├── FLEXRealmDatabaseManager.m
│   │   │   ├── FLEXRealmDefines.h
│   │   │   ├── FLEXSQLiteDatabaseManager.h
│   │   │   ├── FLEXSQLiteDatabaseManager.m
│   │   │   ├── FLEXTableColumnHeader.h
│   │   │   ├── FLEXTableColumnHeader.m
│   │   │   ├── FLEXTableContentCell.h
│   │   │   ├── FLEXTableContentCell.m
│   │   │   ├── FLEXTableContentViewController.h
│   │   │   ├── FLEXTableContentViewController.m
│   │   │   ├── FLEXTableLeftCell.h
│   │   │   ├── FLEXTableLeftCell.m
│   │   │   ├── FLEXTableListViewController.h
│   │   │   ├── FLEXTableListViewController.m
│   │   │   └── LICENSE
│   │   ├── FLEXClassesTableViewController.h
│   │   ├── FLEXClassesTableViewController.m
│   │   ├── FLEXCookiesTableViewController.h
│   │   ├── FLEXCookiesTableViewController.m
│   │   ├── FLEXFileBrowserFileOperationController.h
│   │   ├── FLEXFileBrowserFileOperationController.m
│   │   ├── FLEXFileBrowserSearchOperation.h
│   │   ├── FLEXFileBrowserSearchOperation.m
│   │   ├── FLEXFileBrowserTableViewController.h
│   │   ├── FLEXFileBrowserTableViewController.m
│   │   ├── FLEXGlobalsTableViewController.h
│   │   ├── FLEXGlobalsTableViewController.m
│   │   ├── FLEXInstancesTableViewController.h
│   │   ├── FLEXInstancesTableViewController.m
│   │   ├── FLEXLibrariesTableViewController.h
│   │   ├── FLEXLibrariesTableViewController.m
│   │   ├── FLEXLiveObjectsTableViewController.h
│   │   ├── FLEXLiveObjectsTableViewController.m
│   │   ├── FLEXObjectRef.h
│   │   ├── FLEXObjectRef.m
│   │   ├── FLEXWebViewController.h
│   │   ├── FLEXWebViewController.m
│   │   └── SystemLog/
│   │       ├── FLEXSystemLogMessage.h
│   │       ├── FLEXSystemLogMessage.m
│   │       ├── FLEXSystemLogTableViewCell.h
│   │       ├── FLEXSystemLogTableViewCell.m
│   │       ├── FLEXSystemLogTableViewController.h
│   │       └── FLEXSystemLogTableViewController.m
│   ├── Info.plist
│   ├── Manager/
│   │   ├── FLEXManager+Private.h
│   │   └── FLEXManager.m
│   ├── Network/
│   │   ├── FLEXNetworkCurlLogger.h
│   │   ├── FLEXNetworkCurlLogger.m
│   │   ├── FLEXNetworkHistoryTableViewController.h
│   │   ├── FLEXNetworkHistoryTableViewController.m
│   │   ├── FLEXNetworkRecorder.h
│   │   ├── FLEXNetworkRecorder.m
│   │   ├── FLEXNetworkSettingsTableViewController.h
│   │   ├── FLEXNetworkSettingsTableViewController.m
│   │   ├── FLEXNetworkTransaction.h
│   │   ├── FLEXNetworkTransaction.m
│   │   ├── FLEXNetworkTransactionDetailTableViewController.h
│   │   ├── FLEXNetworkTransactionDetailTableViewController.m
│   │   ├── FLEXNetworkTransactionTableViewCell.h
│   │   ├── FLEXNetworkTransactionTableViewCell.m
│   │   └── PonyDebugger/
│   │       ├── FLEXNetworkObserver.h
│   │       ├── FLEXNetworkObserver.m
│   │       └── LICENSE
│   ├── ObjectExplorers/
│   │   ├── FLEXArrayExplorerViewController.h
│   │   ├── FLEXArrayExplorerViewController.m
│   │   ├── FLEXClassExplorerViewController.h
│   │   ├── FLEXClassExplorerViewController.m
│   │   ├── FLEXDefaultsExplorerViewController.h
│   │   ├── FLEXDefaultsExplorerViewController.m
│   │   ├── FLEXDictionaryExplorerViewController.h
│   │   ├── FLEXDictionaryExplorerViewController.m
│   │   ├── FLEXGlobalsTableViewControllerEntry.h
│   │   ├── FLEXGlobalsTableViewControllerEntry.m
│   │   ├── FLEXImageExplorerViewController.h
│   │   ├── FLEXImageExplorerViewController.m
│   │   ├── FLEXLayerExplorerViewController.h
│   │   ├── FLEXLayerExplorerViewController.m
│   │   ├── FLEXObjectExplorerFactory.h
│   │   ├── FLEXObjectExplorerFactory.m
│   │   ├── FLEXObjectExplorerViewController.h
│   │   ├── FLEXObjectExplorerViewController.m
│   │   ├── FLEXSetExplorerViewController.h
│   │   ├── FLEXSetExplorerViewController.m
│   │   ├── FLEXViewControllerExplorerViewController.h
│   │   ├── FLEXViewControllerExplorerViewController.m
│   │   ├── FLEXViewExplorerViewController.h
│   │   └── FLEXViewExplorerViewController.m
│   ├── Toolbar/
│   │   ├── FLEXExplorerToolbar.h
│   │   ├── FLEXExplorerToolbar.m
│   │   ├── FLEXToolbarItem.h
│   │   └── FLEXToolbarItem.m
│   ├── Utility/
│   │   ├── FLEXHeapEnumerator.h
│   │   ├── FLEXHeapEnumerator.m
│   │   ├── FLEXKeyboardHelpViewController.h
│   │   ├── FLEXKeyboardHelpViewController.m
│   │   ├── FLEXKeyboardShortcutManager.h
│   │   ├── FLEXKeyboardShortcutManager.m
│   │   ├── FLEXMultilineTableViewCell.h
│   │   ├── FLEXMultilineTableViewCell.m
│   │   ├── FLEXResources.h
│   │   ├── FLEXResources.m
│   │   ├── FLEXRuntimeUtility.h
│   │   ├── FLEXRuntimeUtility.m
│   │   ├── FLEXUtility.h
│   │   └── FLEXUtility.m
│   └── ViewHierarchy/
│       ├── FLEXHierarchyTableViewCell.h
│       ├── FLEXHierarchyTableViewCell.m
│       ├── FLEXHierarchyTableViewController.h
│       ├── FLEXHierarchyTableViewController.m
│       ├── FLEXImagePreviewViewController.h
│       └── FLEXImagePreviewViewController.m
├── IRCCloud/
│   ├── 1Password.xcassets/
│   │   ├── onepassword-button-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-button.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-extension-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-extension.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-navbar-light.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-navbar.imageset/
│   │   │   └── Contents.json
│   │   ├── onepassword-toolbar-light.imageset/
│   │   │   └── Contents.json
│   │   └── onepassword-toolbar.imageset/
│   │       └── Contents.json
│   ├── Classes/
│   │   ├── AppDelegate.h
│   │   ├── AppDelegate.m
│   │   ├── AvatarsDataSource.h
│   │   ├── AvatarsDataSource.m
│   │   ├── AvatarsTableViewController.h
│   │   ├── AvatarsTableViewController.m
│   │   ├── BuffersDataSource.h
│   │   ├── BuffersDataSource.m
│   │   ├── BuffersTableView.h
│   │   ├── BuffersTableView.m
│   │   ├── CallerIDTableViewController.h
│   │   ├── CallerIDTableViewController.m
│   │   ├── ChannelInfoViewController.h
│   │   ├── ChannelInfoViewController.m
│   │   ├── ChannelListTableViewController.h
│   │   ├── ChannelListTableViewController.m
│   │   ├── ChannelModeListTableViewController.h
│   │   ├── ChannelModeListTableViewController.m
│   │   ├── ChannelsDataSource.h
│   │   ├── ChannelsDataSource.m
│   │   ├── CollapsedEvents.h
│   │   ├── CollapsedEvents.m
│   │   ├── ColorFormatter.h
│   │   ├── ColorFormatter.m
│   │   ├── DisplayOptionsViewController.h
│   │   ├── DisplayOptionsViewController.m
│   │   ├── EditConnectionViewController.h
│   │   ├── EditConnectionViewController.m
│   │   ├── EventsDataSource.h
│   │   ├── EventsDataSource.m
│   │   ├── EventsTableView.h
│   │   ├── EventsTableView.m
│   │   ├── FileMetadataViewController.h
│   │   ├── FileMetadataViewController.m
│   │   ├── FileUploader.h
│   │   ├── FileUploader.m
│   │   ├── FilesTableViewController.h
│   │   ├── FilesTableViewController.m
│   │   ├── FontAwesome.h
│   │   ├── HighlightsCountView.h
│   │   ├── HighlightsCountView.m
│   │   ├── IRCCloudJSONObject.h
│   │   ├── IRCCloudJSONObject.m
│   │   ├── IRCCloudSafariViewController.h
│   │   ├── IRCCloudSafariViewController.m
│   │   ├── IRCColorPickerView.h
│   │   ├── IRCColorPickerView.m
│   │   ├── Ignore.h
│   │   ├── Ignore.m
│   │   ├── IgnoresTableViewController.h
│   │   ├── IgnoresTableViewController.m
│   │   ├── ImageCache.h
│   │   ├── ImageCache.m
│   │   ├── ImageViewController.h
│   │   ├── ImageViewController.m
│   │   ├── ImageViewController.xib
│   │   ├── LicenseViewController.h
│   │   ├── LicenseViewController.m
│   │   ├── LinkLabel.h
│   │   ├── LinkLabel.m
│   │   ├── LinkTextView.h
│   │   ├── LinkTextView.m
│   │   ├── LinksListTableViewController.h
│   │   ├── LinksListTableViewController.m
│   │   ├── LogExportsTableViewController.h
│   │   ├── LogExportsTableViewController.m
│   │   ├── LoginSplashViewController.h
│   │   ├── LoginSplashViewController.m
│   │   ├── MainViewController.h
│   │   ├── MainViewController.m
│   │   ├── NamesListTableViewController.h
│   │   ├── NamesListTableViewController.m
│   │   ├── NetworkConnection.h
│   │   ├── NetworkConnection.m
│   │   ├── NickCompletionView.h
│   │   ├── NickCompletionView.m
│   │   ├── NotificationsDataSource.h
│   │   ├── NotificationsDataSource.m
│   │   ├── PastebinEditorViewController.h
│   │   ├── PastebinEditorViewController.m
│   │   ├── PastebinViewController.h
│   │   ├── PastebinViewController.m
│   │   ├── PastebinsTableViewController.h
│   │   ├── PastebinsTableViewController.m
│   │   ├── PinReorderViewController.h
│   │   ├── PinReorderViewController.m
│   │   ├── SamlLoginViewController.h
│   │   ├── SamlLoginViewController.m
│   │   ├── SendMessageIntentHandler.h
│   │   ├── SendMessageIntentHandler.m
│   │   ├── ServerReorderViewController.h
│   │   ├── ServerReorderViewController.m
│   │   ├── ServersDataSource.h
│   │   ├── ServersDataSource.m
│   │   ├── SettingsViewController.h
│   │   ├── SettingsViewController.m
│   │   ├── SpamViewController.h
│   │   ├── SpamViewController.m
│   │   ├── SplashViewController.h
│   │   ├── SplashViewController.m
│   │   ├── TextTableViewController.h
│   │   ├── TextTableViewController.m
│   │   ├── UIColor+IRCCloud.h
│   │   ├── UIColor+IRCCloud.m
│   │   ├── UIDevice+UIDevice_iPhone6Hax.h
│   │   ├── UIDevice+UIDevice_iPhone6Hax.m
│   │   ├── UINavigationController+iPadSux.h
│   │   ├── UINavigationController+iPadSux.m
│   │   ├── UITableViewController+HeaderColorFix.h
│   │   ├── UITableViewController+HeaderColorFix.m
│   │   ├── URLHandler.h
│   │   ├── URLHandler.m
│   │   ├── UsersDataSource.h
│   │   ├── UsersDataSource.m
│   │   ├── UsersTableView.h
│   │   ├── UsersTableView.m
│   │   ├── WhoListTableViewController.h
│   │   ├── WhoListTableViewController.m
│   │   ├── WhoWasTableViewController.h
│   │   ├── WhoWasTableViewController.m
│   │   ├── WhoisViewController.h
│   │   ├── WhoisViewController.m
│   │   ├── YouTubeViewController.h
│   │   └── YouTubeViewController.m
│   ├── EventsTableCell.xib
│   ├── EventsTableCell_File.xib
│   ├── EventsTableCell_ReplyCount.xib
│   ├── EventsTableCell_Thumbnail.xib
│   ├── IRCCloud-Enterprise-Info.plist
│   ├── IRCCloud-Info.plist
│   ├── IRCCloud-Prefix.pch
│   ├── IRCCloud.entitlements
│   ├── Launch.storyboard
│   ├── MainStoryboard.storyboard
│   ├── OnePasswordExtension.h
│   ├── OnePasswordExtension.m
│   ├── Resources/
│   │   ├── EnterpriseImages.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   ├── EnterpriseLogo.xcassets/
│   │   │   └── login_logo.imageset/
│   │   │       └── Contents.json
│   │   ├── FontAwesome.otf
│   │   ├── Icons.xcassets/
│   │   │   ├── accept.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_bottom_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_button.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_mid_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_only_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── login_top_input.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── menu.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── send_fail.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── settings.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── signup_button.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── tip_bg.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── upload_arrow.imageset/
│   │   │   │   └── Contents.json
│   │   │   └── users.imageset/
│   │   │       └── Contents.json
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── Contents.json
│   │   ├── Logo.xcassets/
│   │   │   └── login_logo.imageset/
│   │   │       └── Contents.json
│   │   ├── SourceSansPro-LightIt.otf
│   │   ├── SourceSansPro-Regular.otf
│   │   ├── SourceSansPro-Semibold.otf
│   │   ├── a.caf
│   │   ├── en.lproj/
│   │   │   └── Localizable.strings
│   │   └── licenses.txt
│   ├── UIExpandingTextView.h
│   ├── UIExpandingTextView.m
│   ├── UIExpandingTextViewInternal.h
│   ├── UIExpandingTextViewInternal.m
│   └── main.m
├── IRCCloud.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── IRCCloud Enterprise.xcscheme
│           ├── IRCCloud Mock Data.xcscheme
│           └── IRCCloud.xcscheme
├── IRCCloudUnitTests/
│   ├── CollapsedEventsTests.m
│   ├── Info.plist
│   ├── MessageTypeTests.m
│   └── URLtoBIDTests.m
├── IRCEnterprise.entitlements
├── LICENSE.txt
├── NSURL+IDN/
│   ├── NSURL+IDN.h
│   └── NSURL+IDN.m
├── NotificationService/
│   ├── Info.plist
│   ├── NotificationService.entitlements
│   ├── NotificationService.h
│   └── NotificationService.m
├── NotificationService Enterprise.entitlements
├── OpenInChrome/
│   ├── OpenInChromeController.h
│   └── OpenInChromeController.m
├── OpenInFirefoxClient/
│   ├── LICENSE
│   ├── OpenInFirefoxControllerObjC.h
│   └── OpenInFirefoxControllerObjC.m
├── Podfile
├── README.md
├── SBJson/
│   ├── SBJson5.h
│   ├── SBJson5Parser.h
│   ├── SBJson5Parser.m
│   ├── SBJson5StreamParser.h
│   ├── SBJson5StreamParser.m
│   ├── SBJson5StreamParserState.h
│   ├── SBJson5StreamParserState.m
│   ├── SBJson5StreamTokeniser.h
│   ├── SBJson5StreamTokeniser.m
│   ├── SBJson5StreamWriter.h
│   ├── SBJson5StreamWriter.m
│   ├── SBJson5StreamWriterState.h
│   ├── SBJson5StreamWriterState.m
│   ├── SBJson5Writer.h
│   └── SBJson5Writer.m
├── SECURITY.md
├── ShareExtension/
│   ├── Info-Enterprise.plist
│   ├── Info.plist
│   ├── ShareExtension.entitlements
│   ├── ShareViewController.h
│   └── ShareViewController.m
├── ShareExtension Enterprise.entitlements
├── StringScore/
│   ├── NSString+Score.h
│   └── NSString+Score.m
├── TUSafariActivity/
│   ├── TUSafariActivity.h
│   ├── TUSafariActivity.m
│   └── en.lproj/
│       └── TUSafariActivity.strings
├── TrustKit/
│   ├── Dependencies/
│   │   ├── README.md
│   │   ├── RSSwizzle/
│   │   │   ├── RSSwizzle.h
│   │   │   └── RSSwizzle.m
│   │   └── domain_registry/
│   │       ├── domain_registry.h
│   │       ├── private/
│   │       │   ├── assert.c
│   │       │   ├── assert.h
│   │       │   ├── init_registry_tables.c
│   │       │   ├── registry_search.c
│   │       │   ├── registry_types.h
│   │       │   ├── string_util.h
│   │       │   ├── trie_node.h
│   │       │   ├── trie_search.c
│   │       │   └── trie_search.h
│   │       └── registry_tables_genfiles/
│   │           └── registry_tables.h
│   ├── Info.plist
│   ├── Pinning/
│   │   ├── public_key_utils.h
│   │   ├── public_key_utils.m
│   │   ├── ssl_pin_verifier.h
│   │   └── ssl_pin_verifier.m
│   ├── Reporting/
│   │   ├── TSKBackgroundReporter.h
│   │   ├── TSKBackgroundReporter.m
│   │   ├── TSKPinFailureReport.h
│   │   ├── TSKPinFailureReport.m
│   │   ├── TSKReportsRateLimiter.h
│   │   ├── TSKReportsRateLimiter.m
│   │   ├── reporting_utils.h
│   │   ├── reporting_utils.m
│   │   ├── vendor_identifier.h
│   │   └── vendor_identifier.m
│   ├── Swizzling/
│   │   ├── TSKNSURLConnectionDelegateProxy.h
│   │   ├── TSKNSURLConnectionDelegateProxy.m
│   │   ├── TSKNSURLSessionDelegateProxy.h
│   │   └── TSKNSURLSessionDelegateProxy.m
│   ├── TSKPinningValidator.h
│   ├── TSKPinningValidator.m
│   ├── TrustKit+Private.h
│   ├── TrustKit.h
│   ├── TrustKit.m
│   ├── configuration_utils.h
│   ├── configuration_utils.m
│   ├── module.modulemap
│   ├── parse_configuration.h
│   └── parse_configuration.m
├── UITests/
│   ├── Info.plist
│   ├── SnapshotHelper.swift
│   ├── UITests-Bridging-Header.h
│   └── UITests.swift
├── WebP.framework/
│   ├── Headers/
│   │   ├── config.h
│   │   ├── decode.h
│   │   ├── demux.h
│   │   ├── encode.h
│   │   ├── format_constants.h
│   │   ├── mux.h
│   │   ├── mux_types.h
│   │   └── types.h
│   └── WebP
├── WebSocket/
│   ├── AsyncSocket.h
│   ├── AsyncSocket.m
│   ├── HandshakeHeader.h
│   ├── HandshakeHeader.m
│   ├── MutableQueue.h
│   ├── MutableQueue.m
│   ├── NSData+Base64.h
│   ├── NSData+Base64.m
│   ├── UnittWebSocketClient-Prefix.pch
│   ├── WebSocket.h
│   ├── WebSocket.m
│   ├── WebSocketConnectConfig.h
│   ├── WebSocketConnectConfig.m
│   ├── WebSocketFragment.h
│   ├── WebSocketFragment.m
│   ├── WebSocketMessage.h
│   └── WebSocketMessage.m
├── YYImage/
│   ├── YYAnimatedImageView.h
│   ├── YYAnimatedImageView.m
│   ├── YYFrameImage.h
│   ├── YYFrameImage.m
│   ├── YYImage.h
│   ├── YYImage.m
│   ├── YYImageCoder.h
│   ├── YYImageCoder.m
│   ├── YYSpriteSheetImage.h
│   └── YYSpriteSheetImage.m
├── build-scripts/
│   ├── BUILD
│   ├── VERSION
│   ├── ace-modes.js
│   ├── emocode-data.js
│   └── git-revision.sh
└── fastlane/
    ├── Fastfile
    ├── README.md
    ├── Snapfile
    ├── metadata/
    │   ├── copyright.txt
    │   ├── en-US/
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── release_notes.txt
    │   │   └── support_url.txt
    │   ├── primary_category.txt
    │   ├── primary_first_sub_category.txt
    │   ├── primary_second_sub_category.txt
    │   ├── review_notes.txt
    │   ├── secondary_category.txt
    │   ├── secondary_first_sub_category.txt
    │   └── secondary_second_sub_category.txt
    ├── metadata-enterprise/
    │   ├── copyright.txt
    │   ├── en-US/
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── release_notes.txt
    │   │   └── support_url.txt
    │   ├── primary_category.txt
    │   ├── primary_first_sub_category.txt
    │   ├── primary_second_sub_category.txt
    │   ├── review_notes.txt
    │   ├── secondary_category.txt
    │   ├── secondary_first_sub_category.txt
    │   └── secondary_second_sub_category.txt
    └── review_info.json
Download .txt
SYMBOL INDEX (193 symbols across 71 files)

FILE: ECSlidingViewController/ECSlidingViewController.h
  type ECViewWidthLayout (line 37) | typedef enum {
  type ECSide (line 47) | typedef enum {
  type ECResetStrategy (line 55) | typedef enum {
  function interface (line 65) | interface ECSlidingViewController : UIViewController<UIGestureRecognizer...

FILE: FLEX/Network/FLEXNetworkTransaction.h
  type FLEXNetworkTransactionStateUnstarted (line 12) | typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) {

FILE: FLEX/ObjectExplorers/FLEXGlobalsTableViewControllerEntry.h
  type NSString (line 12) | typedef NSString *(^FLEXGlobalsTableViewControllerEntryNameFuture)(void);
  type UIViewController (line 13) | typedef UIViewController *(^FLEXGlobalsTableViewControllerViewController...

FILE: FLEX/ObjectExplorers/FLEXObjectExplorerViewController.h
  type FLEXObjectExplorerSectionDescription (line 11) | typedef NS_ENUM(NSUInteger, FLEXObjectExplorerSection) {

FILE: IRCCloud/Classes/AvatarsDataSource.h
  function interface (line 19) | interface Avatar : NSObject {

FILE: IRCCloud/Classes/BuffersDataSource.h
  function interface (line 20) | interface Buffer : NSObject<NSSecureCoding> {

FILE: IRCCloud/Classes/CallerIDTableViewController.h
  function interface (line 21) | interface CallerIDTableViewController : UITableViewController {

FILE: IRCCloud/Classes/ChannelListTableViewController.h
  function interface (line 21) | interface ChannelListTableViewController : UITableViewController {

FILE: IRCCloud/Classes/ChannelModeListTableViewController.h
  function interface (line 21) | interface ChannelModeListTableViewController : UITableViewController {

FILE: IRCCloud/Classes/ChannelsDataSource.h
  function interface (line 20) | interface Channel : NSObject<NSSecureCoding> {

FILE: IRCCloud/Classes/CollapsedEvents.h
  type kCollapsedEvent (line 22) | typedef enum {
  type kCollapsedMode (line 34) | typedef enum {
  function interface (line 50) | interface CollapsedEvent : NSObject {

FILE: IRCCloud/Classes/DisplayOptionsViewController.h
  function interface (line 21) | interface DisplayOptionsViewController : UITableViewController {

FILE: IRCCloud/Classes/EventsDataSource.h
  function interface (line 38) | interface Event : NSObject<NSSecureCoding> {

FILE: IRCCloud/Classes/HighlightsCountView.h
  function interface (line 20) | interface HighlightsCountView : UIView {

FILE: IRCCloud/Classes/IRCCloudJSONObject.h
  function interface (line 20) | interface IRCCloudJSONObject : NSObject {

FILE: IRCCloud/Classes/IRCCloudSafariViewController.h
  function interface (line 19) | interface IRCCloudSafariViewController : SFSafariViewController {

FILE: IRCCloud/Classes/Ignore.h
  function interface (line 20) | interface Ignore : NSObject {

FILE: IRCCloud/Classes/IgnoresTableViewController.h
  function interface (line 21) | interface IgnoresTableViewController : UITableViewController {

FILE: IRCCloud/Classes/ImageCache.h
  function interface (line 22) | interface ImageCache : NSObject {

FILE: IRCCloud/Classes/LinkLabel.h
  function interface (line 21) | interface LinkLabel : UILabel<UIGestureRecognizerDelegate> {

FILE: IRCCloud/Classes/LinkTextView.h
  function interface (line 21) | interface LinkTextView : UITextView<UIGestureRecognizerDelegate> {

FILE: IRCCloud/Classes/LinksListTableViewController.h
  function interface (line 21) | interface LinksListTableViewController : UITableViewController {

FILE: IRCCloud/Classes/MainViewController.h
  function interface (line 31) | interface UpdateSuggestionsTask : NSObject {

FILE: IRCCloud/Classes/NamesListTableViewController.h
  function interface (line 21) | interface NamesListTableViewController : UITableViewController {

FILE: IRCCloud/Classes/NetworkConnection.h
  type kIRCEvent (line 43) | typedef enum {
  type kIRCCloudState (line 108) | typedef enum {
  type kIRCCloudReachability (line 114) | typedef enum {
  function interface (line 122) | interface NetworkConnection : NSObject<WebSocketDelegate> {

FILE: IRCCloud/Classes/NotificationsDataSource.h
  function interface (line 20) | interface NotificationsDataSource : NSObject {

FILE: IRCCloud/Classes/PinReorderViewController.h
  function interface (line 19) | interface PinReorderViewController : UITableViewController {

FILE: IRCCloud/Classes/SamlLoginViewController.h
  function interface (line 20) | interface SamlLoginViewController : UIViewController<WKNavigationDelegat...

FILE: IRCCloud/Classes/ServerReorderViewController.h
  function interface (line 19) | interface ServerReorderViewController : UITableViewController {

FILE: IRCCloud/Classes/ServersDataSource.h
  function interface (line 21) | interface Server : NSObject<NSSecureCoding> {

FILE: IRCCloud/Classes/SettingsViewController.h
  function interface (line 20) | interface FontSizeCell : UITableViewCell {

FILE: IRCCloud/Classes/SpamViewController.h
  function interface (line 20) | interface SpamViewController : UITableViewController {

FILE: IRCCloud/Classes/SplashViewController.h
  function interface (line 20) | interface SplashViewController : UIViewController {

FILE: IRCCloud/Classes/TextTableViewController.h
  function interface (line 21) | interface TextTableViewController : UIViewController {

FILE: IRCCloud/Classes/URLHandler.h
  function interface (line 21) | interface URLHandler : NSObject {

FILE: IRCCloud/Classes/UsersDataSource.h
  function interface (line 20) | interface User : NSObject<NSSecureCoding> {

FILE: IRCCloud/Classes/WhoListTableViewController.h
  function interface (line 21) | interface WhoListTableViewController : UITableViewController {

FILE: IRCCloud/Classes/WhoWasTableViewController.h
  function interface (line 21) | interface WhoWasTableViewController : UITableViewController {

FILE: IRCCloud/Classes/WhoisViewController.h
  function interface (line 22) | interface WhoisViewController : UIViewController<LinkTextViewDelegate> {

FILE: IRCCloud/UIExpandingTextViewInternal.h
  function interface (line 28) | interface UIExpandingTextViewInternal : UITextView { }

FILE: SBJson/SBJson5StreamParser.h
  type SBJson5ParserStatus (line 38) | typedef enum {

FILE: SBJson/SBJson5StreamTokeniser.h
  type sbjson5_token_t (line 9) | typedef enum {

FILE: SBJson/SBJson5StreamWriter.h
  function interface (line 100) | interface SBJson5StreamWriter : NSObject {

FILE: StringScore/NSString+Score.h
  type NSUInteger (line 16) | typedef NSUInteger NSStringScoreOption;

FILE: TrustKit/Dependencies/domain_registry/private/assert.c
  function DefaultAssertHandler (line 23) | static void DefaultAssertHandler(const char* file, int line, const char*...
  function DoAssert (line 30) | void DoAssert(const char* file,
  function SetDomainRegistryAssertHandler (line 39) | void SetDomainRegistryAssertHandler(DomainRegistryAssertHandler handler) {

FILE: TrustKit/Dependencies/domain_registry/private/init_registry_tables.c
  function InitializeDomainRegistry (line 28) | void InitializeDomainRegistry(void) {

FILE: TrustKit/Dependencies/domain_registry/private/registry_search.c
  function StrnLen (line 41) | static size_t StrnLen(const char* s, size_t max) {
  function IsStringASCII (line 50) | static int IsStringASCII(const char* s) {
  function IsValidHostname (line 61) | static int IsValidHostname(const char* hostname) {
  type TrieNode (line 171) | struct TrieNode
  function GetRegistryLengthImpl (line 213) | static size_t GetRegistryLengthImpl(
  function GetRegistryLength (line 260) | size_t GetRegistryLength(const char* hostname) {
  function GetRegistryLengthAllowUnknownRegistries (line 293) | size_t GetRegistryLengthAllowUnknownRegistries(const char* hostname) {

FILE: TrustKit/Dependencies/domain_registry/private/registry_types.h
  type REGISTRY_U16 (line 20) | typedef unsigned short REGISTRY_U16;

FILE: TrustKit/Dependencies/domain_registry/private/string_util.h
  function IsWildcardComponent (line 31) | static __inline__ int IsWildcardComponent(const char* component) {
  function IsExceptionComponent (line 38) | static __inline__ int IsExceptionComponent(const char* component) {
  function IsInvalidComponent (line 45) | static __inline__ int IsInvalidComponent(const char* component) {
  function ReplaceChar (line 55) | static __inline__ void ReplaceChar(char* value, char old, char newval) {
  function ToLowerASCII (line 62) | static __inline__ void ToLowerASCII(char* buf, const char* end) {
  function HostnamePartCmp (line 71) | static __inline__ int HostnamePartCmp(const char *a, const char *b) {

FILE: TrustKit/Dependencies/domain_registry/private/trie_node.h
  type TrieNode (line 27) | struct TrieNode {

FILE: TrustKit/Dependencies/domain_registry/private/trie_search.c
  type TrieNode (line 35) | struct TrieNode
  type TrieNode (line 67) | struct TrieNode
  type TrieNode (line 69) | struct TrieNode
  type TrieNode (line 70) | struct TrieNode
  type TrieNode (line 76) | struct TrieNode
  type TrieNode (line 132) | struct TrieNode
  type TrieNode (line 133) | struct TrieNode
  type TrieNode (line 134) | struct TrieNode
  type TrieNode (line 135) | struct TrieNode
  type TrieNode (line 136) | struct TrieNode
  type TrieNode (line 137) | struct TrieNode
  type TrieNode (line 206) | struct TrieNode
  function HasLeafChildren (line 279) | int HasLeafChildren(const struct TrieNode* node) {
  function SetRegistryTables (line 284) | void SetRegistryTables(const char* string_table,

FILE: TrustKit/Dependencies/domain_registry/private/trie_search.h
  type TrieNode (line 33) | struct TrieNode
  type TrieNode (line 34) | struct TrieNode
  type TrieNode (line 44) | struct TrieNode
  type TrieNode (line 50) | struct TrieNode
  type TrieNode (line 57) | struct TrieNode

FILE: TrustKit/Dependencies/domain_registry/registry_tables_genfiles/registry_tables.h
  type TrieNode (line 908) | struct TrieNode

FILE: TrustKit/Pinning/public_key_utils.h
  type NSMutableDictionary (line 40) | typedef NSMutableDictionary<NSData *, NSData *> SpkiCacheDictionnary;

FILE: TrustKit/Pinning/ssl_pin_verifier.h
  type TSKPinValidationResultSuccess (line 19) | typedef NS_ENUM(NSInteger, TSKPinValidationResult)

FILE: TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h
  function interface (line 12) | interface TSKNSURLConnectionDelegateProxy : NSObject<NSURLConnectionDele...

FILE: TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.h
  function interface (line 12) | interface TSKNSURLSessionDelegateProxy : NSObject

FILE: TrustKit/TrustKit.h
  type NSString (line 33) | typedef NSString *TSKGlobalConfigurationKey;
  type NSString (line 39) | typedef NSString *TSKDomainConfigurationKey;
  type NSString (line 185) | typedef NSString *TSKSupportedAlgorithm;
  type NSString (line 229) | typedef NSString *TSKNotificationUserInfoKey;

FILE: WebP.framework/Headers/decode.h
  type WebPRGBABuffer (line 29) | typedef struct WebPRGBABuffer WebPRGBABuffer;
  type WebPYUVABuffer (line 30) | typedef struct WebPYUVABuffer WebPYUVABuffer;
  type WebPDecBuffer (line 31) | typedef struct WebPDecBuffer WebPDecBuffer;
  type WebPIDecoder (line 32) | typedef struct WebPIDecoder WebPIDecoder;
  type WebPBitstreamFeatures (line 33) | typedef struct WebPBitstreamFeatures WebPBitstreamFeatures;
  type WebPDecoderOptions (line 34) | typedef struct WebPDecoderOptions WebPDecoderOptions;
  type WebPDecoderConfig (line 35) | typedef struct WebPDecoderConfig WebPDecoderConfig;
  type WEBP_CSP_MODE (line 146) | typedef enum WEBP_CSP_MODE {
  function WEBP_INLINE (line 162) | static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) {
  function WEBP_INLINE (line 167) | static WEBP_INLINE int WebPIsAlphaMode(WEBP_CSP_MODE mode) {
  function WEBP_INLINE (line 173) | static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) {
  type WebPRGBABuffer (line 180) | struct WebPRGBABuffer {    // view as RGBA
  type WebPYUVABuffer (line 186) | struct WebPYUVABuffer {              // view as YUVA
  type WebPDecBuffer (line 197) | struct WebPDecBuffer {
  function WEBP_INLINE (line 220) | static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
  type VP8StatusCode (line 231) | typedef enum VP8StatusCode {
  function WEBP_INLINE (line 358) | static WEBP_INLINE uint8_t* WebPIDecGetYUV(
  type WebPBitstreamFeatures (line 408) | struct WebPBitstreamFeatures {
  function WEBP_INLINE (line 427) | static WEBP_INLINE VP8StatusCode WebPGetFeatures(
  type WebPDecoderOptions (line 435) | struct WebPDecoderOptions {
  type WebPDecoderConfig (line 453) | struct WebPDecoderConfig {
  function WEBP_INLINE (line 465) | static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {

FILE: WebP.framework/Headers/demux.h
  type WebPDemuxer (line 64) | typedef struct WebPDemuxer WebPDemuxer;
  type WebPIterator (line 65) | typedef struct WebPIterator WebPIterator;
  type WebPChunkIterator (line 66) | typedef struct WebPChunkIterator WebPChunkIterator;
  type WebPAnimInfo (line 67) | typedef struct WebPAnimInfo WebPAnimInfo;
  type WebPAnimDecoderOptions (line 68) | typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions;
  type WebPDemuxState (line 79) | typedef enum WebPDemuxState {
  function WEBP_INLINE (line 94) | static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
  function WEBP_INLINE (line 106) | static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
  type WebPFormatFeature (line 117) | typedef enum WebPFormatFeature {
  type WebPIterator (line 138) | struct WebPIterator {
  type WebPChunkIterator (line 180) | struct WebPChunkIterator {
  type WebPAnimDecoder (line 243) | typedef struct WebPAnimDecoder WebPAnimDecoder;
  type WebPAnimDecoderOptions (line 246) | struct WebPAnimDecoderOptions {
  function WEBP_INLINE (line 262) | static WEBP_INLINE int WebPAnimDecoderOptionsInit(
  function WEBP_INLINE (line 282) | static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
  type WebPAnimInfo (line 289) | struct WebPAnimInfo {

FILE: WebP.framework/Headers/encode.h
  type WebPConfig (line 31) | typedef struct WebPConfig WebPConfig;
  type WebPPicture (line 32) | typedef struct WebPPicture WebPPicture;
  type WebPAuxStats (line 33) | typedef struct WebPAuxStats WebPAuxStats;
  type WebPMemoryWriter (line 34) | typedef struct WebPMemoryWriter WebPMemoryWriter;
  type WebPImageHint (line 85) | typedef enum WebPImageHint {
  type WebPConfig (line 94) | struct WebPConfig {
  type WebPPreset (line 152) | typedef enum WebPPreset {
  function WEBP_INLINE (line 168) | static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
  function WEBP_INLINE (line 177) | static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
  type WebPAuxStats (line 199) | struct WebPAuxStats {
  type WebPMemoryWriter (line 237) | struct WebPMemoryWriter {
  type WebPEncCSP (line 262) | typedef enum WebPEncCSP {
  type WebPEncodingError (line 271) | typedef enum WebPEncodingError {
  type WebPPicture (line 290) | struct WebPPicture {
  function WEBP_INLINE (line 363) | static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {

FILE: WebP.framework/Headers/format_constants.h
  type VP8LImageTransformType (line 55) | typedef enum {

FILE: WebP.framework/Headers/mux.h
  type WebPMux (line 67) | typedef struct WebPMux WebPMux;
  type WebPMuxFrameInfo (line 68) | typedef struct WebPMuxFrameInfo WebPMuxFrameInfo;
  type WebPMuxAnimParams (line 69) | typedef struct WebPMuxAnimParams WebPMuxAnimParams;
  type WebPAnimEncoderOptions (line 70) | typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
  type WebPMuxError (line 73) | typedef enum WebPMuxError {
  type WebPChunkId (line 83) | typedef enum WebPChunkId {
  function WEBP_INLINE (line 113) | static WEBP_INLINE WebPMux* WebPMuxNew(void) {
  function WEBP_INLINE (line 136) | static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
  type WebPMuxFrameInfo (line 199) | struct WebPMuxFrameInfo {
  type WebPMuxAnimParams (line 281) | struct WebPMuxAnimParams {
  type WebPAnimEncoder (line 417) | typedef struct WebPAnimEncoder WebPAnimEncoder;
  type WebPPicture (line 420) | struct WebPPicture
  type WebPConfig (line 421) | struct WebPConfig
  type WebPAnimEncoderOptions (line 424) | struct WebPAnimEncoderOptions {
  function WEBP_INLINE (line 452) | static WEBP_INLINE int WebPAnimEncoderOptionsInit(
  function WEBP_INLINE (line 469) | static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
  type WebPPicture (line 494) | struct WebPPicture
  type WebPConfig (line 495) | struct WebPConfig

FILE: WebP.framework/Headers/mux_types.h
  type WebPData (line 30) | typedef struct WebPData WebPData;
  type WebPFeatureFlags (line 33) | typedef enum WebPFeatureFlags {
  type WebPMuxAnimDispose (line 45) | typedef enum WebPMuxAnimDispose {
  type WebPMuxAnimBlend (line 52) | typedef enum WebPMuxAnimBlend {
  type WebPData (line 59) | struct WebPData {
  function WEBP_INLINE (line 65) | static WEBP_INLINE void WebPDataInit(WebPData* webp_data) {
  function WEBP_INLINE (line 73) | static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
  function WEBP_INLINE (line 82) | static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {

FILE: WebSocket/AsyncSocket.h
  type AsyncSocketError (line 20) | enum AsyncSocketError
  type AsyncSocketError (line 30) | typedef enum AsyncSocketError AsyncSocketError;

FILE: WebSocket/HandshakeHeader.h
  function interface (line 23) | interface HandshakeHeader : NSObject

FILE: WebSocket/MutableQueue.h
  function interface (line 24) | interface MutableQueue : NSObject

FILE: WebSocket/WebSocket.h
  type NSUInteger (line 68) | typedef NSUInteger WebSocketCloseStatus;
  type NSUInteger (line 77) | typedef NSUInteger WebSocketReadyState;

FILE: WebSocket/WebSocketConnectConfig.h
  type NSUInteger (line 31) | typedef NSUInteger WebSocketVersion;
  function interface (line 34) | interface WebSocketConnectConfig : NSObject

FILE: WebSocket/WebSocketFragment.h
  type NSInteger (line 34) | typedef NSInteger MessageOpCode;
  type NSInteger (line 42) | typedef NSInteger PayloadType;
  type NSInteger (line 51) | typedef NSInteger PayloadLength;
  function interface (line 54) | interface WebSocketFragment : NSObject

FILE: WebSocket/WebSocketMessage.h
  function interface (line 25) | interface WebSocketMessage : NSObject
Condensed preview — 516 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,891K chars).
[
  {
    "path": ".gitignore",
    "chars": 334,
    "preview": "*.xcodeproj/project.xcworkspace\n*.xcodeproj/xcuserdata\n*.xcworkspace\nbuild/\nIRCCloud/config.h\nIRCCloud/InfoPlist.h\nIRCCl"
  },
  {
    "path": "ARChromeActivity/ARChromeActivity.h",
    "chars": 1730,
    "preview": "/*\n  ARChromeActivity.h\n  Copyright (c) 2012 Alex Robinson\n  \n  Permission is hereby granted, free of charge, to any per"
  },
  {
    "path": "ARChromeActivity/ARChromeActivity.m",
    "chars": 5340,
    "preview": "/*\n  ARChromeActivity.m\n\n  Copyright (c) 2012 Alex Robinson\n \n  Permission is hereby granted, free of charge, to any per"
  },
  {
    "path": "CSURITemplate/CSURITemplate.h",
    "chars": 5481,
    "preview": "//\n//  CSURITemplate.h\n//  CSURITemplate\n//\n//  Created by Will Harris on 26/02/2013.\n//  Copyright (c) 2013 Cogenta Sys"
  },
  {
    "path": "CSURITemplate/CSURITemplate.m",
    "chars": 36667,
    "preview": "//\n//  CSURITemplate.m\n//  CSURITemplate\n//\n//  Created by Will Harris on 26/02/2013.\n//  Copyright (c) 2013 Cogenta Sys"
  },
  {
    "path": "ECSlidingViewController/ECSlidingViewController.h",
    "chars": 8952,
    "preview": "//\n//  ECSlidingViewController.h\n//  ECSlidingViewController\n//\n//  Created by Michael Enriquez on 1/23/12.\n//  Copyrigh"
  },
  {
    "path": "ECSlidingViewController/ECSlidingViewController.m",
    "chars": 27902,
    "preview": "//\n//  ECSlidingViewController.m\n//  ECSlidingViewController\n//\n//  Created by Michael Enriquez on 1/23/12.\n//  Copyrigh"
  },
  {
    "path": "ECSlidingViewController/UIImage+ImageWithUIView.h",
    "chars": 182,
    "preview": "//\n//  UIImage+ImageWithUIView.h\n//\n\n#import <UIKit/UIKit.h>\n#import <QuartzCore/QuartzCore.h>\n\n@interface UIImage (Imag"
  },
  {
    "path": "ECSlidingViewController/UIImage+ImageWithUIView.m",
    "chars": 520,
    "preview": "//\n//  UIImage+ImageWithUIView.m\n//\n\n#import \"UIImage+ImageWithUIView.h\"\n\n@implementation UIImage (ImageWithUIView)\n#pra"
  },
  {
    "path": "FLEX/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) 2014 Flipbo"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputColorView.m",
    "chars": 11677,
    "preview": "//\n//  FLEXArgumentInputColorView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/30/14.\n//  Copyright (c) 2014 Flipbo"
  },
  {
    "path": "FLEX/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": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputDateView.m",
    "chars": 1615,
    "preview": "//\n//  FLEXArgumentInputDataView.m\n//  Flipboard\n//\n//  Created by Daniel Rodriguez Troitino on 2/14/15.\n//  Copyright ("
  },
  {
    "path": "FLEX/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) 2014 Flipboa"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputFontView.m",
    "chars": 3937,
    "preview": "//\n//  FLEXArgumentInputFontView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2014 Flipboa"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.h",
    "chars": 308,
    "preview": "//\n//  FLEXArgumentInputFontsPickerView.h\n//  UICatalog\n//\n//  Created by 啟倫 陳 on 2014/7/27.\n//  Copyright (c) 2014年 f. "
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.m",
    "chars": 3280,
    "preview": "//\n//  FLEXArgumentInputFontsPickerView.m\n//  UICatalog\n//\n//  Created by 啟倫 陳 on 2014/7/27.\n//  Copyright (c) 2014年 f. "
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputJSONObjectView.h",
    "chars": 271,
    "preview": "//\n//  FLEXArgumentInputJSONObjectView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputJSONObjectView.m",
    "chars": 2475,
    "preview": "//\n//  FLEXArgumentInputJSONObjectView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/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) 2014"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.m",
    "chars": 679,
    "preview": "//\n//  FLEXArgumentInputNotSupportedView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/18/14.\n//  Copyright (c) 2014"
  },
  {
    "path": "FLEX/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) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.m",
    "chars": 1783,
    "preview": "//\n//  FLEXArgumentInputNumberView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/15/14.\n//  Copyright (c) 2014 Flipb"
  },
  {
    "path": "FLEX/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) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputStringView.m",
    "chars": 1166,
    "preview": "//\n//  FLEXArgumentInputStringView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/28/14.\n//  Copyright (c) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputStructView.h",
    "chars": 255,
    "preview": "//\n//  FLEXArgumentInputStructView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputStructView.m",
    "chars": 8279,
    "preview": "//\n//  FLEXArgumentInputStructView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2014 Flipb"
  },
  {
    "path": "FLEX/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) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.m",
    "chars": 2148,
    "preview": "//\n//  FLEXArgumentInputSwitchView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/16/14.\n//  Copyright (c) 2014 Flipb"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h",
    "chars": 297,
    "preview": "//\n//  FLEXArgumentInputTextView.h\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXArgumen"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputTextView.m",
    "chars": 3143,
    "preview": "//\n//  FLEXArgumentInputTextView.m\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXArgumen"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputView.h",
    "chars": 2201,
    "preview": "//\n//  FLEXArgumentInputView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/30/14.\n//  Copyright (c) 2014 Flipboard. "
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputView.m",
    "chars": 2943,
    "preview": "//\n//  FLEXArgumentInputView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/30/14.\n//  Copyright (c) 2014 Flipboard. "
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputViewFactory.h",
    "chars": 906,
    "preview": "//\n//  FLEXArgumentInputViewFactory.h\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import <Foundati"
  },
  {
    "path": "FLEX/Editing/ArgumentInputViews/FLEXArgumentInputViewFactory.m",
    "chars": 3452,
    "preview": "//\n//  FLEXArgumentInputViewFactory.m\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 6/15/14.\n//\n//\n\n#import \"FLEXArgu"
  },
  {
    "path": "FLEX/Editing/FLEXDefaultEditorViewController.h",
    "chars": 402,
    "preview": "//\n//  FLEXDefaultEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/Editing/FLEXDefaultEditorViewController.m",
    "chars": 1915,
    "preview": "//\n//  FLEXDefaultEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/Editing/FLEXFieldEditorView.h",
    "chars": 444,
    "preview": "//\n//  FLEXFieldEditorView.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Flipboard. Al"
  },
  {
    "path": "FLEX/Editing/FLEXFieldEditorView.m",
    "chars": 6039,
    "preview": "//\n//  FLEXFieldEditorView.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Flipboard. Al"
  },
  {
    "path": "FLEX/Editing/FLEXFieldEditorViewController.h",
    "chars": 782,
    "preview": "//\n//  FLEXFieldEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/Editing/FLEXFieldEditorViewController.m",
    "chars": 4192,
    "preview": "//\n//  FLEXFieldEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/Editing/FLEXIvarEditorViewController.h",
    "chars": 404,
    "preview": "//\n//  FLEXIvarEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 Flip"
  },
  {
    "path": "FLEX/Editing/FLEXIvarEditorViewController.m",
    "chars": 2195,
    "preview": "//\n//  FLEXIvarEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 Flip"
  },
  {
    "path": "FLEX/Editing/FLEXMethodCallingViewController.h",
    "chars": 360,
    "preview": "//\n//  FLEXMethodCallingViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/Editing/FLEXMethodCallingViewController.m",
    "chars": 3621,
    "preview": "//\n//  FLEXMethodCallingViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/Editing/FLEXPropertyEditorViewController.h",
    "chars": 450,
    "preview": "//\n//  FLEXPropertyEditorViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/20/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/Editing/FLEXPropertyEditorViewController.m",
    "chars": 3733,
    "preview": "//\n//  FLEXPropertyEditorViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/20/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/ExplorerInterface/FLEXExplorerViewController.h",
    "chars": 1355,
    "preview": "//\n//  FLEXExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboa"
  },
  {
    "path": "FLEX/ExplorerInterface/FLEXExplorerViewController.m",
    "chars": 37252,
    "preview": "//\n//  FLEXExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboa"
  },
  {
    "path": "FLEX/ExplorerInterface/FLEXWindow.h",
    "chars": 445,
    "preview": "//\n//  FLEXWindow.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/13/14.\n//  Copyright (c) 2014 Flipboard. All rights "
  },
  {
    "path": "FLEX/ExplorerInterface/FLEXWindow.m",
    "chars": 2662,
    "preview": "//\n//  FLEXWindow.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/13/14.\n//  Copyright (c) 2014 Flipboard. All rights "
  },
  {
    "path": "FLEX/FLEX.h",
    "chars": 154,
    "preview": "//\n//  FLEX.h\n//  FLEX\n//\n//  Created by Eric Horacek on 7/18/15.\n//  Copyright (c) 2015 Flipboard. All rights reserved."
  },
  {
    "path": "FLEX/FLEXManager.h",
    "chars": 4754,
    "preview": "//\n//  FLEXManager.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All rights "
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h",
    "chars": 746,
    "preview": "//\n//  PTDatabaseManager.h\n//  Derived from:\n//\n//  FMDatabase.h\n//  FMDB( https://github.com/ccgus/fmdb )\n//\n//  Create"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h",
    "chars": 1636,
    "preview": "//\n//  PTMultiColumnTableView.h\n//  PTMultiColumnTableViewDemo\n//\n//  Created by Peng Tao on 15/11/16.\n//  Copyright © 2"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.m",
    "chars": 10678,
    "preview": "//\n//  PTMultiColumnTableView.m\n//  PTMultiColumnTableViewDemo\n//\n//  Created by Peng Tao on 15/11/16.\n//  Copyright © 2"
  },
  {
    "path": "FLEX/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": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.m",
    "chars": 3098,
    "preview": "//\n//  FLEXRealmDatabaseManager.m\n//  FLEX\n//\n//  Created by Tim Oliver on 28/01/2016.\n//  Copyright © 2016 Realm. All r"
  },
  {
    "path": "FLEX/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": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.h",
    "chars": 503,
    "preview": "//\n//  PTDatabaseManager.h\n//  Derived from:\n//\n//  FMDatabase.h\n//  FMDB( https://github.com/ccgus/fmdb )\n//\n//  Create"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.m",
    "chars": 5684,
    "preview": "//\n//  PTDatabaseManager.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Peng Tao. "
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h",
    "chars": 517,
    "preview": "//\n//  FLEXTableContentHeaderCell.h\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/26.\n//  Copyright © 2015年 f. All r"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.m",
    "chars": 1560,
    "preview": "//\n//  FLEXTableContentHeaderCell.m\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/26.\n//  Copyright © 2015年 f. All r"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.h",
    "chars": 632,
    "preview": "//\n//  FLEXTableContentCell.h\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights "
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.m",
    "chars": 2322,
    "preview": "//\n//  FLEXTableContentCell.m\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights "
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h",
    "chars": 400,
    "preview": "//\n//  PTTableContentViewController.h\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.m",
    "chars": 6126,
    "preview": "//\n//  PTTableContentViewController.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.h",
    "chars": 322,
    "preview": "//\n//  FLEXTableLeftCell.h\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights res"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.m",
    "chars": 1047,
    "preview": "//\n//  FLEXTableLeftCell.m\n//  UICatalog\n//\n//  Created by Peng Tao on 15/11/24.\n//  Copyright © 2015年 f. All rights res"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.h",
    "chars": 344,
    "preview": "//\n//  PTTableListViewController.h\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Pe"
  },
  {
    "path": "FLEX/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.m",
    "chars": 4238,
    "preview": "//\n//  PTTableListViewController.m\n//  PTDatabaseReader\n//\n//  Created by Peng Tao on 15/11/23.\n//  Copyright © 2015年 Pe"
  },
  {
    "path": "FLEX/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": "FLEX/GlobalStateExplorers/FLEXClassesTableViewController.h",
    "chars": 310,
    "preview": "//\n//  FLEXClassesTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2014"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXClassesTableViewController.m",
    "chars": 4339,
    "preview": "//\n//  FLEXClassesTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2014"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXCookiesTableViewController.h",
    "chars": 250,
    "preview": "//\n//  FLEXCookiesTableViewController.h\n//  FLEX\n//\n//  Created by Rich Robinson on 19/10/2015.\n//  Copyright © 2015 Fli"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXCookiesTableViewController.m",
    "chars": 2504,
    "preview": "//\n//  FLEXCookiesTableViewController.m\n//  FLEX\n//\n//  Created by Rich Robinson on 19/10/2015.\n//  Copyright © 2015 Fli"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserFileOperationController.h",
    "chars": 884,
    "preview": "//\n//  FLEXFileBrowserFileOperationController.h\n//  Flipboard\n//\n//  Created by Daniel Rodriguez Troitino on 2/13/15.\n//"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserFileOperationController.m",
    "chars": 4566,
    "preview": "//\n//  FLEXFileBrowserFileOperationController.m\n//  Flipboard\n//\n//  Created by Daniel Rodriguez Troitino on 2/13/15.\n//"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserSearchOperation.h",
    "chars": 621,
    "preview": "//\n//  FLEXFileBrowserSearchOperation.h\n//  UICatalog\n//\n//  Created by 啟倫 陳 on 2014/8/4.\n//  Copyright (c) 2014年 f. All"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserSearchOperation.m",
    "chars": 3738,
    "preview": "//\n//  FLEXFileBrowserSearchOperation.m\n//  UICatalog\n//\n//  Created by 啟倫 陳 on 2014/8/4.\n//  Copyright (c) 2014年 f. All"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserTableViewController.h",
    "chars": 325,
    "preview": "//\n//  FLEXFileBrowserTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/9/14.\n//  Based on previous "
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXFileBrowserTableViewController.m",
    "chars": 15515,
    "preview": "//\n//  FLEXFileBrowserTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/9/14.\n//\n//\n\n#import \"FLEXFi"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXGlobalsTableViewController.h",
    "chars": 815,
    "preview": "//\n//  FLEXGlobalsTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2014"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXGlobalsTableViewController.m",
    "chars": 10970,
    "preview": "//\n//  FLEXGlobalsTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 2014"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXInstancesTableViewController.h",
    "chars": 422,
    "preview": "//\n//  FLEXInstancesTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXInstancesTableViewController.m",
    "chars": 9677,
    "preview": "//\n//  FLEXInstancesTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXLibrariesTableViewController.h",
    "chars": 258,
    "preview": "//\n//  FLEXLibrariesTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-02.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXLibrariesTableViewController.m",
    "chars": 5940,
    "preview": "//\n//  FLEXLibrariesTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-02.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXLiveObjectsTableViewController.h",
    "chars": 259,
    "preview": "//\n//  FLEXLiveObjectsTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXLiveObjectsTableViewController.m",
    "chars": 10160,
    "preview": "//\n//  FLEXLiveObjectsTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXObjectRef.h",
    "chars": 554,
    "preview": "//\n//  FLEXObjectRef.h\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/24/18.\n//  Copyright (c) 2018 Flipboard. All right"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXObjectRef.m",
    "chars": 1133,
    "preview": "//\n//  FLEXObjectRef.m\n//  FLEX\n//\n//  Created by Tanner Bennett on 7/24/18.\n//  Copyright (c) 2018 Flipboard. All right"
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXWebViewController.h",
    "chars": 352,
    "preview": "//\n//  FLEXWebViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/10/14.\n//  Copyright (c) 2014 Flipboard. "
  },
  {
    "path": "FLEX/GlobalStateExplorers/FLEXWebViewController.m",
    "chars": 4347,
    "preview": "//\n//  FLEXWebViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/10/14.\n//  Copyright (c) 2014 Flipboard. "
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogMessage.h",
    "chars": 491,
    "preview": "//\n//  FLEXSystemLogMessage.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2015 f. All right"
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogMessage.m",
    "chars": 1421,
    "preview": "//\n//  FLEXSystemLogMessage.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2015 f. All right"
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewCell.h",
    "chars": 619,
    "preview": "//\n//  FLEXSystemLogTableViewCell.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2015 f. All"
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewCell.m",
    "chars": 4769,
    "preview": "//\n//  FLEXSystemLogTableViewCell.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/25/15.\n//  Copyright (c) 2015 f. All"
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.h",
    "chars": 247,
    "preview": "//\n//  FLEXSystemLogTableViewController.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/19/15.\n//  Copyright (c) 2015 "
  },
  {
    "path": "FLEX/GlobalStateExplorers/SystemLog/FLEXSystemLogTableViewController.m",
    "chars": 8674,
    "preview": "//\n//  FLEXSystemLogTableViewController.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 1/19/15.\n//  Copyright (c) 2015 "
  },
  {
    "path": "FLEX/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": "FLEX/Manager/FLEXManager+Private.h",
    "chars": 461,
    "preview": "//\n//  FLEXManager+Private.h\n//  PebbleApp\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2014 Pebble Techn"
  },
  {
    "path": "FLEX/Manager/FLEXManager.m",
    "chars": 12570,
    "preview": "//\n//  FLEXManager.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All rights "
  },
  {
    "path": "FLEX/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": "FLEX/Network/FLEXNetworkCurlLogger.m",
    "chars": 1389,
    "preview": "//\n// FLEXCurlLogger.m\n//\n//\n// Created by Ji Pei on 07/27/16\n//\n\n#import \"FLEXNetworkCurlLogger.h\"\n\n@implementation FLE"
  },
  {
    "path": "FLEX/Network/FLEXNetworkHistoryTableViewController.h",
    "chars": 264,
    "preview": "//\n//  FLEXNetworkHistoryTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/Network/FLEXNetworkHistoryTableViewController.m",
    "chars": 14701,
    "preview": "//\n//  FLEXNetworkHistoryTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/Network/FLEXNetworkRecorder.h",
    "chars": 2654,
    "preview": "//\n//  FLEXNetworkRecorder.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/4/15.\n//  Copyright (c) 2015 Flipboard. All"
  },
  {
    "path": "FLEX/Network/FLEXNetworkRecorder.m",
    "chars": 10832,
    "preview": "//\n//  FLEXNetworkRecorder.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/4/15.\n//  Copyright (c) 2015 Flipboard. All"
  },
  {
    "path": "FLEX/Network/FLEXNetworkSettingsTableViewController.h",
    "chars": 218,
    "preview": "//\n//  FLEXNetworkSettingsTableViewController.h\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 2/20/15.\n//\n//\n\n#import"
  },
  {
    "path": "FLEX/Network/FLEXNetworkSettingsTableViewController.m",
    "chars": 7325,
    "preview": "//\n//  FLEXNetworkSettingsTableViewController.m\n//  FLEXInjected\n//\n//  Created by Ryan Olson on 2/20/15.\n//\n//\n\n#import"
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransaction.h",
    "chars": 1467,
    "preview": "//\n//  FLEXNetworkTransaction.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2015 Flipboard. "
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransaction.m",
    "chars": 2440,
    "preview": "//\n//  FLEXNetworkTransaction.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 2015 Flipboard. "
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransactionDetailTableViewController.h",
    "chars": 385,
    "preview": "//\n//  FLEXNetworkTransactionDetailTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/10/15.\n//  Copy"
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransactionDetailTableViewController.m",
    "chars": 20551,
    "preview": "//\n//  FLEXNetworkTransactionDetailTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/10/15.\n//  Copy"
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransactionTableViewCell.h",
    "chars": 450,
    "preview": "//\n//  FLEXNetworkTransactionTableViewCell.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/Network/FLEXNetworkTransactionTableViewCell.m",
    "chars": 7475,
    "preview": "//\n//  FLEXNetworkTransactionTableViewCell.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2/8/15.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/Network/PonyDebugger/FLEXNetworkObserver.h",
    "chars": 1045,
    "preview": "//\n//  FLEXNetworkObserver.h\n//  Derived from:\n//\n//  PDAFNetworkDomainController.h\n//  PonyDebugger\n//\n//  Created by M"
  },
  {
    "path": "FLEX/Network/PonyDebugger/FLEXNetworkObserver.m",
    "chars": 59109,
    "preview": "//\n//  FLEXNetworkObserver.m\n//  Derived from:\n//\n//  PDAFNetworkDomainController.m\n//  PonyDebugger\n//\n//  Created by M"
  },
  {
    "path": "FLEX/Network/PonyDebugger/LICENSE",
    "chars": 566,
    "preview": "\nPonyDebugger\nCopyright 2012 Square Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not us"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXArrayExplorerViewController.h",
    "chars": 285,
    "preview": "//\n//  FLEXArrayExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/15/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXArrayExplorerViewController.m",
    "chars": 1691,
    "preview": "//\n//  FLEXArrayExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/15/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXClassExplorerViewController.h",
    "chars": 285,
    "preview": "//\n//  FLEXClassExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/18/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXClassExplorerViewController.m",
    "chars": 3705,
    "preview": "//\n//  FLEXClassExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/18/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXDefaultsExplorerViewController.h",
    "chars": 291,
    "preview": "//\n//  FLEXDefaultsExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXDefaultsExplorerViewController.m",
    "chars": 1850,
    "preview": "//\n//  FLEXDefaultsExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/23/14.\n//  Copyright (c) 201"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXDictionaryExplorerViewController.h",
    "chars": 295,
    "preview": "//\n//  FLEXDictionaryExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXDictionaryExplorerViewController.m",
    "chars": 1381,
    "preview": "//\n//  FLEXDictionaryExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXGlobalsTableViewControllerEntry.h",
    "chars": 840,
    "preview": "//\n//  FLEXGlobalsTableViewControllerEntry.h\n//  UICatalog\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXGlobalsTableViewControllerEntry.m",
    "chars": 734,
    "preview": "//\n//  FLEXGlobalsTableViewControllerEntry.m\n//  UICatalog\n//\n//  Created by Javier Soto on 7/26/14.\n//  Copyright (c) 2"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXImageExplorerViewController.h",
    "chars": 285,
    "preview": "//\n//  FLEXImageExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/12/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXImageExplorerViewController.m",
    "chars": 1480,
    "preview": "//\n//  FLEXImageExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/12/14.\n//  Copyright (c) 2014 F"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXLayerExplorerViewController.h",
    "chars": 278,
    "preview": "//\n//  FLEXLayerExplorerViewController.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 12/14/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXLayerExplorerViewController.m",
    "chars": 2398,
    "preview": "//\n//  FLEXLayerExplorerViewController.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 12/14/14.\n//  Copyright (c) 2014 "
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXObjectExplorerFactory.h",
    "chars": 363,
    "preview": "//\n//  FLEXObjectExplorerFactory.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/15/14.\n//  Copyright (c) 2014 Flipboa"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXObjectExplorerFactory.m",
    "chars": 2987,
    "preview": "//\n//  FLEXObjectExplorerFactory.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/15/14.\n//  Copyright (c) 2014 Flipboa"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXObjectExplorerViewController.h",
    "chars": 2052,
    "preview": "//\n//  FLEXObjectExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXObjectExplorerViewController.m",
    "chars": 41856,
    "preview": "//\n//  FLEXObjectExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-03.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXSetExplorerViewController.h",
    "chars": 281,
    "preview": "//\n//  FLEXSetExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXSetExplorerViewController.m",
    "chars": 1212,
    "preview": "//\n//  FLEXSetExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/16/14.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXViewControllerExplorerViewController.h",
    "chars": 303,
    "preview": "//\n//  FLEXViewControllerExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/11/14.\n//  Copyright ("
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXViewControllerExplorerViewController.m",
    "chars": 2842,
    "preview": "//\n//  FLEXViewControllerExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/11/14.\n//  Copyright ("
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXViewExplorerViewController.h",
    "chars": 283,
    "preview": "//\n//  FLEXViewExplorerViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/11/14.\n//  Copyright (c) 2014 Fl"
  },
  {
    "path": "FLEX/ObjectExplorers/FLEXViewExplorerViewController.m",
    "chars": 9024,
    "preview": "//\n//  FLEXViewExplorerViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/11/14.\n//  Copyright (c) 2014 Fl"
  },
  {
    "path": "FLEX/Toolbar/FLEXExplorerToolbar.h",
    "chars": 2147,
    "preview": "//\n//  FLEXExplorerToolbar.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All"
  },
  {
    "path": "FLEX/Toolbar/FLEXExplorerToolbar.m",
    "chars": 10578,
    "preview": "//\n//  FLEXExplorerToolbar.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All"
  },
  {
    "path": "FLEX/Toolbar/FLEXToolbarItem.h",
    "chars": 287,
    "preview": "//\n//  FLEXToolbarItem.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All rig"
  },
  {
    "path": "FLEX/Toolbar/FLEXToolbarItem.m",
    "chars": 3745,
    "preview": "//\n//  FLEXToolbarItem.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/4/14.\n//  Copyright (c) 2014 Flipboard. All rig"
  },
  {
    "path": "FLEX/Utility/FLEXHeapEnumerator.h",
    "chars": 424,
    "preview": "//\n//  FLEXHeapEnumerator.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2014 Flipboard. All"
  },
  {
    "path": "FLEX/Utility/FLEXHeapEnumerator.m",
    "chars": 4794,
    "preview": "//\n//  FLEXHeapEnumerator.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 5/28/14.\n//  Copyright (c) 2014 Flipboard. All"
  },
  {
    "path": "FLEX/Utility/FLEXKeyboardHelpViewController.h",
    "chars": 236,
    "preview": "//\n//  FLEXKeyboardHelpViewController.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 9/19/15.\n//  Copyright © 2015 f. A"
  },
  {
    "path": "FLEX/Utility/FLEXKeyboardHelpViewController.m",
    "chars": 1373,
    "preview": "//\n//  FLEXKeyboardHelpViewController.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 9/19/15.\n//  Copyright © 2015 f. A"
  },
  {
    "path": "FLEX/Utility/FLEXKeyboardShortcutManager.h",
    "chars": 564,
    "preview": "//\n//  FLEXKeyboardShortcutManager.h\n//  FLEX\n//\n//  Created by Ryan Olson on 9/19/15.\n//  Copyright © 2015 Flipboard. A"
  },
  {
    "path": "FLEX/Utility/FLEXKeyboardShortcutManager.m",
    "chars": 11215,
    "preview": "//\n//  FLEXKeyboardShortcutManager.m\n//  FLEX\n//\n//  Created by Ryan Olson on 9/19/15.\n//  Copyright © 2015 Flipboard. A"
  },
  {
    "path": "FLEX/Utility/FLEXMultilineTableViewCell.h",
    "chars": 483,
    "preview": "//\n//  FLEXMultilineTableViewCell.h\n//  UICatalog\n//\n//  Created by Ryan Olson on 2/13/15.\n//  Copyright (c) 2015 f. All"
  },
  {
    "path": "FLEX/Utility/FLEXMultilineTableViewCell.m",
    "chars": 1683,
    "preview": "//\n//  FLEXMultilineTableViewCell.m\n//  UICatalog\n//\n//  Created by Ryan Olson on 2/13/15.\n//  Copyright (c) 2015 f. All"
  },
  {
    "path": "FLEX/Utility/FLEXResources.h",
    "chars": 652,
    "preview": "//\n//  FLEXResources.h\n//  FLEX\n//\n//  Created by Ryan Olson on 6/8/14.\n//  Copyright (c) 2014 Flipboard. All rights res"
  },
  {
    "path": "FLEX/Utility/FLEXResources.m",
    "chars": 500211,
    "preview": "//\n//  FLEXResources.m\n//  FLEX\n//\n//  Created by Ryan Olson on 6/8/14.\n//  Copyright (c) 2014 Flipboard. All rights res"
  },
  {
    "path": "FLEX/Utility/FLEXRuntimeUtility.h",
    "chars": 2873,
    "preview": "//\n//  FLEXRuntimeUtility.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/8/14.\n//  Copyright (c) 2014 Flipboard. All "
  },
  {
    "path": "FLEX/Utility/FLEXRuntimeUtility.m",
    "chars": 31831,
    "preview": "//\n//  FLEXRuntimeUtility.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/8/14.\n//  Copyright (c) 2014 Flipboard. All "
  },
  {
    "path": "FLEX/Utility/FLEXUtility.h",
    "chars": 2699,
    "preview": "//\n//  FLEXUtility.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/18/14.\n//  Copyright (c) 2014 Flipboard. All rights"
  },
  {
    "path": "FLEX/Utility/FLEXUtility.m",
    "chars": 16866,
    "preview": "//\n//  FLEXUtility.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 4/18/14.\n//  Copyright (c) 2014 Flipboard. All rights"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXHierarchyTableViewCell.h",
    "chars": 402,
    "preview": "//\n//  FLEXHierarchyTableViewCell.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-02.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXHierarchyTableViewCell.m",
    "chars": 3892,
    "preview": "//\n//  FLEXHierarchyTableViewCell.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-02.\n//  Copyright (c) 2014 Fli"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXHierarchyTableViewController.h",
    "chars": 810,
    "preview": "//\n//  FLEXHierarchyTableViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-01.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXHierarchyTableViewController.m",
    "chars": 7750,
    "preview": "//\n//  FLEXHierarchyTableViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 2014-05-01.\n//  Copyright (c) 20"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXImagePreviewViewController.h",
    "chars": 285,
    "preview": "//\n//  FLEXImagePreviewViewController.h\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/12/14.\n//  Copyright (c) 2014 Fl"
  },
  {
    "path": "FLEX/ViewHierarchy/FLEXImagePreviewViewController.m",
    "chars": 3510,
    "preview": "//\n//  FLEXImagePreviewViewController.m\n//  Flipboard\n//\n//  Created by Ryan Olson on 6/12/14.\n//  Copyright (c) 2014 Fl"
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-button-light.imageset/Contents.json",
    "chars": 429,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-button-light.p"
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-button.imageset/Contents.json",
    "chars": 411,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-button.png\"\n  "
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-extension-light.imageset/Contents.json",
    "chars": 696,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-extension-light~c"
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-extension.imageset/Contents.json",
    "chars": 666,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-extension~compact"
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-navbar-light.imageset/Contents.json",
    "chars": 429,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-navbar-light.p"
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-navbar.imageset/Contents.json",
    "chars": 411,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-navbar.png\"\n  "
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-toolbar-light.imageset/Contents.json",
    "chars": 432,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-toolbar-light."
  },
  {
    "path": "IRCCloud/1Password.xcassets/onepassword-toolbar.imageset/Contents.json",
    "chars": 414,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"onepassword-toolbar.png\"\n "
  },
  {
    "path": "IRCCloud/Classes/AppDelegate.h",
    "chars": 3249,
    "preview": "//\n//  AppDelegate.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "IRCCloud/Classes/AppDelegate.m",
    "chars": 62634,
    "preview": "//\n//  AppDelegate.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "IRCCloud/Classes/AvatarsDataSource.h",
    "chars": 1532,
    "preview": "//\n//  AvatarsDataSource.h\n//\n//  Copyright (C) 2016 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "IRCCloud/Classes/AvatarsDataSource.m",
    "chars": 7548,
    "preview": "//\n//  AvatarsDataSource.m\n//\n//  Copyright (C) 2016 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "IRCCloud/Classes/AvatarsTableViewController.h",
    "chars": 964,
    "preview": "//\n//  AvatarsTableViewController.h\n//\n//  Copyright (C) 2018 IRCCloud, Ltd.\n//  Licensed under the Apache License, Vers"
  },
  {
    "path": "IRCCloud/Classes/AvatarsTableViewController.m",
    "chars": 21173,
    "preview": "//\n//  AvatarsTableViewController.m\n//\n//  Copyright (C) 2018 IRCCloud, Ltd.\n//  Licensed under the Apache License, Vers"
  },
  {
    "path": "IRCCloud/Classes/BuffersDataSource.h",
    "chars": 2797,
    "preview": "//\n//  BuffersDataSource.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "IRCCloud/Classes/BuffersDataSource.m",
    "chars": 15506,
    "preview": "//\n//  BuffersDataSource.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "IRCCloud/Classes/BuffersTableView.h",
    "chars": 2512,
    "preview": "//\n//  BuffersTableView.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "IRCCloud/Classes/BuffersTableView.m",
    "chars": 93780,
    "preview": "//\n//  BuffersTableView.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "IRCCloud/Classes/CallerIDTableViewController.h",
    "chars": 962,
    "preview": "//\n//  CallerIDTableViewController.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Ver"
  },
  {
    "path": "IRCCloud/Classes/CallerIDTableViewController.m",
    "chars": 7114,
    "preview": "//\n//  CallerIDTableViewController.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Ver"
  },
  {
    "path": "IRCCloud/Classes/ChannelInfoViewController.h",
    "chars": 1295,
    "preview": "//\n//  ChannelInfoViewController.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Versi"
  },
  {
    "path": "IRCCloud/Classes/ChannelInfoViewController.m",
    "chars": 25073,
    "preview": "//\n//  ChannelInfoViewController.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Versi"
  },
  {
    "path": "IRCCloud/Classes/ChannelListTableViewController.h",
    "chars": 1017,
    "preview": "//\n//  ChannelListTableViewController.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, "
  },
  {
    "path": "IRCCloud/Classes/ChannelListTableViewController.m",
    "chars": 9573,
    "preview": "//\n//  ChannelListTableViewController.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, "
  },
  {
    "path": "IRCCloud/Classes/ChannelModeListTableViewController.h",
    "chars": 1270,
    "preview": "//\n//  ChannelModeListTableViewController.h\n//\n//  Copyright (C) 2014 IRCCloud, Ltd.\n//  Licensed under the Apache Licen"
  },
  {
    "path": "IRCCloud/Classes/ChannelModeListTableViewController.m",
    "chars": 12291,
    "preview": "//\n//  ChannelModeListTableViewController.m\n//\n//  Copyright (C) 2014 IRCCloud, Ltd.\n//  Licensed under the Apache Licen"
  },
  {
    "path": "IRCCloud/Classes/ChannelsDataSource.h",
    "chars": 2056,
    "preview": "//\n//  ChannelsDataSource.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "IRCCloud/Classes/ChannelsDataSource.m",
    "chars": 9440,
    "preview": "//\n//  ChannelsDataSource.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "IRCCloud/Classes/CollapsedEvents.h",
    "chars": 2972,
    "preview": "//\n//  CollapsedEvents.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (th"
  },
  {
    "path": "IRCCloud/Classes/CollapsedEvents.m",
    "chars": 37464,
    "preview": "//\n//  CollapsedEvents.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (th"
  },
  {
    "path": "IRCCloud/Classes/ColorFormatter.h",
    "chars": 2752,
    "preview": "//\n//  ColorFormatter.h\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (the"
  },
  {
    "path": "IRCCloud/Classes/ColorFormatter.m",
    "chars": 148877,
    "preview": "//\n//  ColorFormatter.m\n//\n//  Copyright (C) 2013 IRCCloud, Ltd.\n//  Licensed under the Apache License, Version 2.0 (the"
  }
]

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

About this extraction

This page contains the full source code of the irccloud/ios GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 516 files (5.3 MB), approximately 1.4M tokens, and a symbol index with 193 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!